PCL
FFT1D.h
Go to the documentation of this file.
1 // ____ ______ __
2 // / __ \ / ____// /
3 // / /_/ // / / /
4 // / ____// /___ / /___ PixInsight Class Library
5 // /_/ \____//_____/ PCL 2.7.0
6 // ----------------------------------------------------------------------------
7 // pcl/FFT1D.h - Released 2024-06-18T15:48:54Z
8 // ----------------------------------------------------------------------------
9 // This file is part of the PixInsight Class Library (PCL).
10 // PCL is a multiplatform C++ framework for development of PixInsight modules.
11 //
12 // Copyright (c) 2003-2024 Pleiades Astrophoto S.L. All Rights Reserved.
13 //
14 // Redistribution and use in both source and binary forms, with or without
15 // modification, is permitted provided that the following conditions are met:
16 //
17 // 1. All redistributions of source code must retain the above copyright
18 // notice, this list of conditions and the following disclaimer.
19 //
20 // 2. All redistributions in binary form must reproduce the above copyright
21 // notice, this list of conditions and the following disclaimer in the
22 // documentation and/or other materials provided with the distribution.
23 //
24 // 3. Neither the names "PixInsight" and "Pleiades Astrophoto", nor the names
25 // of their contributors, may be used to endorse or promote products derived
26 // from this software without specific prior written permission. For written
27 // permission, please contact info@pixinsight.com.
28 //
29 // 4. All products derived from this software, in any form whatsoever, must
30 // reproduce the following acknowledgment in the end-user documentation
31 // and/or other materials provided with the product:
32 //
33 // "This product is based on software from the PixInsight project, developed
34 // by Pleiades Astrophoto and its contributors (https://pixinsight.com/)."
35 //
36 // Alternatively, if that is where third-party acknowledgments normally
37 // appear, this acknowledgment must be reproduced in the product itself.
38 //
39 // THIS SOFTWARE IS PROVIDED BY PLEIADES ASTROPHOTO AND ITS CONTRIBUTORS
40 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
41 // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PLEIADES ASTROPHOTO OR ITS
43 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
44 // EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, BUSINESS
45 // INTERRUPTION; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; AND LOSS OF USE,
46 // DATA OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
47 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
48 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
49 // POSSIBILITY OF SUCH DAMAGE.
50 // ----------------------------------------------------------------------------
51 
52 #ifndef __PCL_FFT1D_h
53 #define __PCL_FFT1D_h
54 
56 
57 /*
58  * The FFT routines used in this PCL version are based on the KISS FFT library
59  * by Mark Borgerding: http://sourceforge.net/projects/kissfft/
60  *
61  * KISS FFT LICENSE INFORMATION
62  * ============================
63  *
64  * Copyright (c) 2003-2013 Mark Borgerding
65  *
66  * All rights reserved.
67  *
68  * Redistribution and use in source and binary forms, with or without
69  * modification, are permitted provided that the following conditions are met:
70  *
71  * * Redistributions of source code must retain the above copyright notice,
72  * this list of conditions and the following disclaimer.
73  * * Redistributions in binary form must reproduce the above copyright notice,
74  * this list of conditions and the following disclaimer in the documentation
75  * and/or other materials provided with the distribution.
76  * * Neither the author nor the names of any contributors may be used to
77  * endorse or promote products derived from this software without specific
78  * prior written permission.
79  *
80  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
81  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
82  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
83  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
84  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
85  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
86  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
87  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
88  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
89  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
90  * POSSIBILITY OF SUCH DAMAGE.
91  */
92 
93 #include <pcl/Defs.h>
94 
95 #include <pcl/Complex.h>
96 #include <pcl/Vector.h>
97 
98 namespace pcl
99 {
100 
101 // ----------------------------------------------------------------------------
102 
103 class FFT1DBase
104 {
105 protected:
106 
107  static int OptimizedLength( int, fcomplex* );
108  static int OptimizedLength( int, dcomplex* );
109  static int OptimizedLength( int, float* );
110  static int OptimizedLength( int, double* );
111 
112  static void* Create( int, fcomplex* );
113  static void* Create( int, dcomplex* );
114  static void* Create( int, float* );
115  static void* Create( int, double* );
116 
117  static void* CreateInv( int, fcomplex* );
118  static void* CreateInv( int, dcomplex* );
119  static void* CreateInv( int, float* );
120  static void* CreateInv( int, double* );
121 
122  static void Destroy( void* );
123 
124  static void Transform( void*, fcomplex*, const fcomplex* );
125  static void Transform( void*, dcomplex*, const dcomplex* );
126  static void Transform( void*, fcomplex*, const float* );
127  static void Transform( void*, dcomplex*, const double* );
128  static void Transform( void*, float*, const fcomplex* );
129  static void Transform( void*, double*, const dcomplex* );
130 };
131 
132 // ----------------------------------------------------------------------------
133 
143 #define PCL_FFT_FORWARD -1
144 
150 #define PCL_FFT_BACKWARD +1
151 
152 // ----------------------------------------------------------------------------
153 
163 template <typename T>
164 class PCL_CLASS AbstractFFT : public FFT1DBase
165 {
166 public:
167 
171  using scalar = T;
172 
177 
182 
187 
193 
197  AbstractFFT( int length )
198  : m_length( length )
199  {
200  }
201 
206  virtual ~AbstractFFT()
207  {
208  Release();
209  }
210 
216  int Length() const
217  {
218  return m_length;
219  }
220 
231  transform DFT() const
232  {
233  return m_dft;
234  }
235 
247  {
248  return m_dft;
249  }
250 
262  const complex* operator *() const
263  {
264  return *m_dft;
265  }
266 
279  {
280  return *m_dft;
281  }
282 
287  virtual void Release()
288  {
289  if ( m_handle != nullptr )
290  this->Destroy( m_handle ), m_handle = nullptr;
291  if ( m_handleInv != nullptr )
292  this->Destroy( m_handleInv ), m_handleInv = nullptr;
293  m_dft = transform();
294  }
295 
296 private:
297 
298  int m_length;
299 
300 protected:
301 
302  mutable void* m_handle = nullptr; // Opaque pointers to internal control structures
303  mutable void* m_handleInv = nullptr;
304  transform m_dft; // DFT of complex or real data
305 };
306 
307 // ----------------------------------------------------------------------------
308 
309 #define m_handle this->m_handle
310 #define m_handleInv this->m_handleInv
311 #define m_dft this->m_dft
312 #define m_length this->Length()
313 
314 // ----------------------------------------------------------------------------
315 
328 template <typename T>
329 class PCL_CLASS GenericFFT : public AbstractFFT<T>
330 {
331 public:
332 
337 
341  using scalar = typename base::scalar;
342 
346  using complex = typename base::complex;
347 
351  using vector = typename base::vector;
352 
357 
362  using transform = typename base::transform;
363 
378  GenericFFT( int n )
379  : base( n )
380  {
381  }
382 
386  ~GenericFFT() override
387  {
388  }
389 
400  {
401  if ( m_dft.IsEmpty() )
402  m_dft = transform( m_length );
403  if ( m_handle == nullptr )
404  m_handle = this->Create( m_length, static_cast<complex*>( nullptr ) );
405  this->Transform( m_handle, *m_dft, x );
406  return *this;
407  }
408 
422  {
423  if ( m_dft.IsEmpty() )
424  throw Error( "Invalid out-of-place inverse FFT: No FFT has been performed." );
425  if ( m_handleInv == nullptr )
426  m_handleInv = this->CreateInv( m_length, static_cast<complex*>( nullptr ) );
427  this->Transform( m_handleInv, y, *m_dft );
428  return *this;
429  }
430 
440  {
441  PCL_PRECONDITION( x.Length() >= m_length )
442  if ( x.Length() < m_length )
443  throw Error( "Invalid FFT input vector length." );
444  return operator <<( *x );
445  }
446 
460  {
461  if ( y.Length() < m_length )
462  throw Error( "Invalid FFT output vector length." );
463  return operator >>( *y );
464  }
465 
496  GenericFFT& operator()( complex* y, const complex* x, int dir = PCL_FFT_FORWARD ) const
497  {
498  if ( dir == PCL_FFT_BACKWARD )
499  {
500  if ( m_handleInv == nullptr )
501  m_handleInv = this->CreateInv( m_length, static_cast<complex*>( nullptr ) );
502  this->Transform( m_handleInv, y, x );
503  }
504  else
505  {
506  if ( m_handle == nullptr )
507  m_handle = this->Create( m_length, static_cast<complex*>( nullptr ) );
508  this->Transform( m_handle, y, x );
509  }
510  return const_cast<GenericFFT&>( *this );
511  }
512 
520  static int OptimizedLength( int n )
521  {
522  return FFT1DBase::OptimizedLength( n, static_cast<complex*>( nullptr ) );
523  }
524 };
525 
526 // ----------------------------------------------------------------------------
527 
542 template <typename T>
543 class PCL_CLASS GenericRealFFT : public AbstractFFT<T>
544 {
545 public:
546 
551 
555  using scalar = typename base::scalar;
556 
560  using complex = typename base::complex;
561 
565  using vector = typename base::vector;
566 
571 
576  using transform = typename base::transform;
577 
596  GenericRealFFT( int length )
597  : base( length )
598  {
599  PCL_PRECONDITION( (length & 1) == 0 )
600  }
601 
605  ~GenericRealFFT() override
606  {
607  }
608 
619  {
620  if ( m_dft.IsEmpty() )
621  m_dft = transform( m_length/2 + 1 );
622  if ( m_handle == nullptr )
623  m_handle = this->Create( m_length, static_cast<scalar*>( nullptr ) );
624  this->Transform( m_handle, *m_dft, x );
625  return *this;
626  }
627 
641  {
642  if ( m_dft.IsEmpty() )
643  throw Error( "Invalid out-of-place inverse FFT: No FFT has been performed." );
644  if ( m_handleInv == nullptr )
645  m_handleInv = this->CreateInv( m_length, static_cast<scalar*>( nullptr ) );
646  this->Transform( m_handleInv, y, *m_dft );
647  return *this;
648  }
649 
659  {
660  if ( x.Length() < m_length )
661  throw Error( "Invalid FFT input vector length." );
662  return operator <<( *x );
663  }
664 
678  {
679  if ( y.Length() < m_length )
680  throw Error( "Invalid FFT output vector length." );
681  return operator >>( *y );
682  }
683 
704  GenericRealFFT& operator()( complex* y, const scalar* x ) const
705  {
706  if ( m_handle == nullptr )
707  m_handle = this->Create( m_length, static_cast<scalar*>( nullptr ) );
708  this->Transform( m_handle, y, x );
709  return const_cast<GenericRealFFT&>( *this );
710  }
711 
735  GenericRealFFT& operator()( scalar* y, const complex* x ) const
736  {
737  if ( m_handleInv == nullptr )
738  m_handleInv = this->CreateInv( m_length, static_cast<scalar*>( nullptr ) );
739  this->Transform( m_handleInv, y, x );
740  return const_cast<GenericRealFFT&>( *this );
741  }
742 
750  static int OptimizedLength( int n )
751  {
752  return FFT1DBase::OptimizedLength( n, static_cast<scalar*>( nullptr ) );
753  }
754 };
755 
756 // ----------------------------------------------------------------------------
757 
758 #undef m_handle
759 #undef m_handleInv
760 #undef m_dft
761 #undef m_length
762 
763 // ----------------------------------------------------------------------------
764 
765 #ifndef __PCL_NO_FFT1D_INSTANTIATE
766 
778 using FFFT = GenericFFT<float>;
779 
787 using DFFT = GenericFFT<double>;
788 
796 using FRealFFT = GenericRealFFT<float>;
797 
805 using DRealFFT = GenericRealFFT<double>;
806 
815 using FFT = FFFT;
816 
825 using RealFFT = FRealFFT;
826 
827 #endif // __PCL_NO_FFT1D_INSTANTIATE
828 
829 // ----------------------------------------------------------------------------
830 
831 } // pcl
832 
833 #endif // __PCL_FFT1D_h
834 
835 // ----------------------------------------------------------------------------
836 // EOF pcl/FFT1D.h - Released 2024-06-18T15:48:54Z
Abstract base class of all fast Fourier transform classes.
Definition: FFT1D.h:165
int Length() const
Definition: FFT1D.h:216
transform & DFT()
Definition: FFT1D.h:246
virtual void Release()
Definition: FFT1D.h:287
AbstractFFT(int length)
Definition: FFT1D.h:197
transform DFT() const
Definition: FFT1D.h:231
virtual ~AbstractFFT()
Definition: FFT1D.h:206
Generic complex number.
Definition: Complex.h:84
Fast Fourier transform of 64-bit floating point complex data.
Fast Fourier transform of 64-bit floating point real data.
A simple exception with an associated error message.
Definition: Exception.h:239
Fast Fourier transform of 32-bit floating point complex data.
Fast Fourier transform of 32-bit floating point complex data.
Fast Fourier transform of 32-bit floating point real data.
Generic fast Fourier transform of complex data.
Definition: FFT1D.h:330
GenericFFT & operator()(complex *y, const complex *x, int dir=PCL_FFT_FORWARD) const
Definition: FFT1D.h:496
static int OptimizedLength(int n)
Definition: FFT1D.h:520
GenericFFT(int n)
Definition: FFT1D.h:378
~GenericFFT() override
Definition: FFT1D.h:386
Generic fast Fourier transform of real data.
Definition: FFT1D.h:544
static int OptimizedLength(int n)
Definition: FFT1D.h:750
GenericRealFFT(int length)
Definition: FFT1D.h:596
GenericRealFFT & operator()(complex *y, const scalar *x) const
Definition: FFT1D.h:704
GenericRealFFT & operator()(scalar *y, const complex *x) const
Definition: FFT1D.h:735
~GenericRealFFT() override
Definition: FFT1D.h:605
int Length() const noexcept
Definition: Vector.h:1784
Fast Fourier transform of 32-bit floating point real data.
A complex number whose components are 64-bit floating point real numbers.
A complex number whose components are 32-bit floating point real numbers.
Array< T, A > & operator<<(Array< T, A > &x, const V &v)
Definition: Array.h:2295
Complex< T1 > operator*(const Complex< T1 > &c1, const Complex< T2 > &c2) noexcept
Definition: Complex.h:548
Console & operator>>(Console &o, char &c)
Definition: Console.h:803
#define PCL_FFT_BACKWARD
Indicates an inverse Fourier transform.
Definition: FFT1D.h:150
#define PCL_FFT_FORWARD
Indicates a Fourier transform.
Definition: FFT1D.h:143
void Destroy(T *p)
Definition: Allocator.h:277
PCL root namespace.
Definition: AbstractImage.h:77