FFT
Go to the documentation of this file.
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2009 Mark Borgerding mark a borgerding net
5 //
6 // This Source Code Form is subject to the terms of the Mozilla
7 // Public License v. 2.0. If a copy of the MPL was not distributed
8 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 
10 #ifndef EIGEN_FFT_MODULE_H
11 #define EIGEN_FFT_MODULE_H
12 
13 #include <complex>
14 #include <vector>
15 #include <map>
16 #include "../../Eigen/Core"
17 
18 
80 #include "../../Eigen/src/Core/util/DisableStupidWarnings.h"
81 
82 // IWYU pragma: begin_exports
83 
84 #ifdef EIGEN_FFTW_DEFAULT
85 // FFTW: faster, GPL -- incompatible with Eigen in LGPL form, bigger code size
86 # include <fftw3.h>
87 # include "src/FFT/ei_fftw_impl.h"
88  namespace Eigen {
89  //template <typename T> typedef struct internal::fftw_impl default_fft_impl; this does not work
90  template <typename T> struct default_fft_impl : public internal::fftw_impl<T> {};
91  }
92 #elif defined EIGEN_MKL_DEFAULT
93 // intel Math Kernel Library: fastest, free -- may be incompatible with Eigen in GPL form
94 # include "src/FFT/ei_imklfft_impl.h"
95  namespace Eigen {
96  template <typename T> struct default_fft_impl : public internal::imklfft::imklfft_impl<T> {};
97  }
98 #elif defined EIGEN_POCKETFFT_DEFAULT
99 // internal::pocketfft_impl: a heavily modified implementation of FFTPack, with many advantages.
100 # include<pocketfft_hdronly.h>
102  namespace Eigen {
103  template <typename T>
104  struct default_fft_impl : public internal::pocketfft_impl<T> {};
105  }
106 #else
107 // internal::kissfft_impl: small, free, reasonably efficient default, derived from kissfft
108 # include "src/FFT/ei_kissfft_impl.h"
109  namespace Eigen {
110  template <typename T>
111  struct default_fft_impl : public internal::kissfft_impl<T> {};
112  }
113 #endif
114 
115 // IWYU pragma: end_exports
116 
117 namespace Eigen {
118 
119 
120 //
121 template<typename T_SrcMat,typename T_FftIfc> struct fft_fwd_proxy;
122 template<typename T_SrcMat,typename T_FftIfc> struct fft_inv_proxy;
123 
124 namespace internal {
125 template<typename T_SrcMat,typename T_FftIfc>
126 struct traits< fft_fwd_proxy<T_SrcMat,T_FftIfc> >
127 {
128  typedef typename T_SrcMat::PlainObject ReturnType;
129 };
130 template<typename T_SrcMat,typename T_FftIfc>
131 struct traits< fft_inv_proxy<T_SrcMat,T_FftIfc> >
132 {
133  typedef typename T_SrcMat::PlainObject ReturnType;
134 };
135 }
136 
137 template<typename T_SrcMat,typename T_FftIfc>
139  : public ReturnByValue<fft_fwd_proxy<T_SrcMat,T_FftIfc> >
140 {
141  typedef DenseIndex Index;
142 
143  fft_fwd_proxy(const T_SrcMat& src,T_FftIfc & fft, Index nfft) : m_src(src),m_ifc(fft), m_nfft(nfft) {}
144 
145  template<typename T_DestMat> void evalTo(T_DestMat& dst) const;
146 
147  Index rows() const { return m_src.rows(); }
148  Index cols() const { return m_src.cols(); }
149 protected:
150  const T_SrcMat & m_src;
151  T_FftIfc & m_ifc;
153 };
154 
155 template<typename T_SrcMat,typename T_FftIfc>
157  : public ReturnByValue<fft_inv_proxy<T_SrcMat,T_FftIfc> >
158 {
159  typedef DenseIndex Index;
160 
161  fft_inv_proxy(const T_SrcMat& src,T_FftIfc & fft, Index nfft) : m_src(src),m_ifc(fft), m_nfft(nfft) {}
162 
163  template<typename T_DestMat> void evalTo(T_DestMat& dst) const;
164 
165  Index rows() const { return m_src.rows(); }
166  Index cols() const { return m_src.cols(); }
167 protected:
168  const T_SrcMat & m_src;
169  T_FftIfc & m_ifc;
171 };
172 
173 
174 template <typename T_Scalar,
175  typename T_Impl=default_fft_impl<T_Scalar> >
176 class FFT
177 {
178  public:
179  typedef T_Impl impl_type;
180  typedef DenseIndex Index;
181  typedef typename impl_type::Scalar Scalar;
182  typedef typename impl_type::Complex Complex;
183 
184  using Flag = int;
185  static constexpr Flag Default = 0;
186  static constexpr Flag Unscaled = 1;
187  static constexpr Flag HalfSpectrum = 2;
188  static constexpr Flag Speedy = 32767;
189 
190  FFT( const impl_type & impl=impl_type() , Flag flags=Default ) :m_impl(impl),m_flag(flags)
191  {
192  eigen_assert((flags == Default || flags == Unscaled || flags == HalfSpectrum || flags == Speedy) && "invalid flags argument");
193  }
194 
195  inline
196  bool HasFlag(Flag f) const { return (m_flag & (int)f) == f;}
197 
198  inline
199  void SetFlag(Flag f) { m_flag |= (int)f;}
200 
201  inline
202  void ClearFlag(Flag f) { m_flag &= (~(int)f);}
203 
204  inline
205  void fwd( Complex * dst, const Scalar * src, Index nfft)
206  {
207  m_impl.fwd(dst,src,static_cast<int>(nfft));
208  if ( HasFlag(HalfSpectrum) == false)
209  ReflectSpectrum(dst,nfft);
210  }
211 
212  inline
213  void fwd( Complex * dst, const Complex * src, Index nfft)
214  {
215  m_impl.fwd(dst,src,static_cast<int>(nfft));
216  }
217 
218 #if defined EIGEN_FFTW_DEFAULT || defined EIGEN_POCKETFFT_DEFAULT || defined EIGEN_MKL_DEFAULT
219  inline
220  void fwd2(Complex * dst, const Complex * src, int n0,int n1)
221  {
222  m_impl.fwd2(dst,src,n0,n1);
223  }
224 #endif
225 
226  template <typename Input_>
227  inline
228  void fwd( std::vector<Complex> & dst, const std::vector<Input_> & src)
229  {
231  dst.resize( (src.size()>>1)+1); // half the bins + Nyquist bin
232  else
233  dst.resize(src.size());
234  fwd(&dst[0],&src[0],src.size());
235  }
236 
237  template<typename InputDerived, typename ComplexDerived>
238  inline
240  {
241  typedef typename ComplexDerived::Scalar dst_type;
242  typedef typename InputDerived::Scalar src_type;
243  EIGEN_STATIC_ASSERT_VECTOR_ONLY(InputDerived)
244  EIGEN_STATIC_ASSERT_VECTOR_ONLY(ComplexDerived)
245  EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(ComplexDerived,InputDerived) // size at compile-time
246  EIGEN_STATIC_ASSERT((internal::is_same<dst_type, Complex>::value),
247  YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
248  EIGEN_STATIC_ASSERT(int(InputDerived::Flags)&int(ComplexDerived::Flags)&DirectAccessBit,
249  THIS_METHOD_IS_ONLY_FOR_EXPRESSIONS_WITH_DIRECT_MEMORY_ACCESS_SUCH_AS_MAP_OR_PLAIN_MATRICES)
250 
251  if (nfft<1)
252  nfft = src.size();
253 
255  dst.derived().resize( (nfft>>1)+1);
256  else
257  dst.derived().resize(nfft);
258 
259  if ( src.innerStride() != 1 || src.size() < nfft ) {
261  if (src.size()<nfft) {
262  tmp.setZero(nfft);
263  tmp.block(0,0,src.size(),1 ) = src;
264  }else{
265  tmp = src;
266  }
267  fwd( &dst[0],&tmp[0],nfft );
268  }else{
269  fwd( &dst[0],&src[0],nfft );
270  }
271  }
272 
273  template<typename InputDerived>
274  inline
276  fwd( const MatrixBase<InputDerived> & src, Index nfft=-1)
277  {
279  }
280 
281  template<typename InputDerived>
282  inline
284  inv( const MatrixBase<InputDerived> & src, Index nfft=-1)
285  {
287  }
288 
289  inline
290  void inv( Complex * dst, const Complex * src, Index nfft)
291  {
292  m_impl.inv( dst,src,static_cast<int>(nfft) );
293  if ( HasFlag( Unscaled ) == false)
294  scale(dst,Scalar(1./nfft),nfft); // scale the time series
295  }
296 
297  inline
298  void inv( Scalar * dst, const Complex * src, Index nfft)
299  {
300  m_impl.inv( dst,src,static_cast<int>(nfft) );
301  if ( HasFlag( Unscaled ) == false)
302  scale(dst,Scalar(1./nfft),nfft); // scale the time series
303  }
304 
305  template<typename OutputDerived, typename ComplexDerived>
306  inline
308  {
309  typedef typename ComplexDerived::Scalar src_type;
310  typedef typename ComplexDerived::RealScalar real_type;
311  typedef typename OutputDerived::Scalar dst_type;
312  const bool realfft= (NumTraits<dst_type>::IsComplex == 0);
313  EIGEN_STATIC_ASSERT_VECTOR_ONLY(OutputDerived)
314  EIGEN_STATIC_ASSERT_VECTOR_ONLY(ComplexDerived)
315  EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(ComplexDerived,OutputDerived) // size at compile-time
316  EIGEN_STATIC_ASSERT((internal::is_same<src_type, Complex>::value),
317  YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
318  EIGEN_STATIC_ASSERT(int(OutputDerived::Flags)&int(ComplexDerived::Flags)&DirectAccessBit,
319  THIS_METHOD_IS_ONLY_FOR_EXPRESSIONS_WITH_DIRECT_MEMORY_ACCESS_SUCH_AS_MAP_OR_PLAIN_MATRICES)
320 
321  if (nfft<1) { //automatic FFT size determination
322  if ( realfft && HasFlag(HalfSpectrum) )
323  nfft = 2*(src.size()-1); //assume even fft size
324  else
325  nfft = src.size();
326  }
327  dst.derived().resize( nfft );
328 
329  // check for nfft that does not fit the input data size
330  Index resize_input= ( realfft && HasFlag(HalfSpectrum) )
331  ? ( (nfft/2+1) - src.size() )
332  : ( nfft - src.size() );
333 
334  if ( src.innerStride() != 1 || resize_input ) {
335  // if the vector is strided, then we need to copy it to a packed temporary
337  if ( resize_input ) {
338  size_t ncopy = (std::min)(src.size(),src.size() + resize_input);
339  tmp.setZero(src.size() + resize_input);
340  if ( realfft && HasFlag(HalfSpectrum) ) {
341  // pad at the Nyquist bin
342  tmp.head(ncopy) = src.head(ncopy);
343  tmp(ncopy-1) = real(tmp(ncopy-1)); // enforce real-only Nyquist bin
344  }else{
345  size_t nhead,ntail;
346  nhead = 1+ncopy/2-1; // range [0:pi)
347  ntail = ncopy/2-1; // range (-pi:0)
348  tmp.head(nhead) = src.head(nhead);
349  tmp.tail(ntail) = src.tail(ntail);
350  if (resize_input<0) { //shrinking -- create the Nyquist bin as the average of the two bins that fold into it
351  tmp(nhead) = ( src(nfft/2) + src( src.size() - nfft/2 ) )*real_type(.5);
352  }else{ // expanding -- split the old Nyquist bin into two halves
353  tmp(nhead) = src(nhead) * real_type(.5);
354  tmp(tmp.size()-nhead) = tmp(nhead);
355  }
356  }
357  }else{
358  tmp = src;
359  }
360  inv( &dst[0],&tmp[0], nfft);
361  }else{
362  inv( &dst[0],&src[0], nfft);
363  }
364  }
365 
366  template <typename Output_>
367  inline
368  void inv( std::vector<Output_> & dst, const std::vector<Complex> & src,Index nfft=-1)
369  {
370  if (nfft<1)
371  nfft = ( NumTraits<Output_>::IsComplex == 0 && HasFlag(HalfSpectrum) ) ? 2*(src.size()-1) : src.size();
372  dst.resize( nfft );
373  inv( &dst[0],&src[0],nfft);
374  }
375 
376 
377 #if defined EIGEN_FFTW_DEFAULT || defined EIGEN_POCKETFFT_DEFAULT || defined EIGEN_MKL_DEFAULT
378  inline
379  void inv2(Complex * dst, const Complex * src, int n0,int n1)
380  {
381  m_impl.inv2(dst,src,n0,n1);
382  if ( HasFlag( Unscaled ) == false)
383  scale(dst,1./(n0*n1),n0*n1);
384  }
385 #endif
386 
387 
388  inline
389  impl_type & impl() {return m_impl;}
390  private:
391 
392  template <typename T_Data>
393  inline
394  void scale(T_Data * x,Scalar s,Index nx)
395  {
396 #if 1
397  for (int k=0;k<nx;++k)
398  *x++ *= s;
399 #else
400  if ( ((ptrdiff_t)x) & 15 )
402  else
404  //Matrix<T_Data, Dynamic, Dynamic>::Map(x,nx) * s;
405 #endif
406  }
407 
408  inline
409  void ReflectSpectrum(Complex * freq, Index nfft)
410  {
411  // create the implicit right-half spectrum (conjugate-mirror of the left-half)
412  Index nhbins=(nfft>>1)+1;
413  for (Index k=nhbins;k < nfft; ++k )
414  freq[k] = conj(freq[nfft-k]);
415  }
416 
418  int m_flag;
419 };
420 
421 template<typename T_SrcMat,typename T_FftIfc>
422 template<typename T_DestMat> inline
424 {
425  m_ifc.fwd( dst, m_src, m_nfft);
426 }
427 
428 template<typename T_SrcMat,typename T_FftIfc>
429 template<typename T_DestMat> inline
431 {
432  m_ifc.inv( dst, m_src, m_nfft);
433 }
434 
435 }
436 
437 #include "../../Eigen/src/Core/util/ReenableStupidWarnings.h"
438 
439 #endif
#define eigen_assert(x)
#define EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(TYPE0, TYPE1)
#define EIGEN_STATIC_ASSERT(X, MSG)
#define EIGEN_STATIC_ASSERT_VECTOR_ONLY(TYPE)
EIGEN_CONSTEXPR Index innerStride() const EIGEN_NOEXCEPT
EIGEN_CONSTEXPR Index size() const EIGEN_NOEXCEPT
Definition: FFT:177
void fwd(std::vector< Complex > &dst, const std::vector< Input_ > &src)
Definition: FFT:228
static constexpr Flag HalfSpectrum
Definition: FFT:187
void fwd(Complex *dst, const Complex *src, Index nfft)
Definition: FFT:213
fft_fwd_proxy< MatrixBase< InputDerived >, FFT< T_Scalar, T_Impl > > fwd(const MatrixBase< InputDerived > &src, Index nfft=-1)
Definition: FFT:276
static constexpr Flag Speedy
Definition: FFT:188
void fwd(Complex *dst, const Scalar *src, Index nfft)
Definition: FFT:205
void ClearFlag(Flag f)
Definition: FFT:202
void inv(Scalar *dst, const Complex *src, Index nfft)
Definition: FFT:298
void inv(MatrixBase< OutputDerived > &dst, const MatrixBase< ComplexDerived > &src, Index nfft=-1)
Definition: FFT:307
impl_type & impl()
Definition: FFT:389
void fwd(MatrixBase< ComplexDerived > &dst, const MatrixBase< InputDerived > &src, Index nfft=-1)
Definition: FFT:239
int Flag
Definition: FFT:184
FFT(const impl_type &impl=impl_type(), Flag flags=Default)
Definition: FFT:190
int m_flag
Definition: FFT:418
impl_type::Complex Complex
Definition: FFT:182
void scale(T_Data *x, Scalar s, Index nx)
Definition: FFT:394
static constexpr Flag Unscaled
Definition: FFT:186
bool HasFlag(Flag f) const
Definition: FFT:196
fft_inv_proxy< MatrixBase< InputDerived >, FFT< T_Scalar, T_Impl > > inv(const MatrixBase< InputDerived > &src, Index nfft=-1)
Definition: FFT:284
static constexpr Flag Default
Definition: FFT:185
void ReflectSpectrum(Complex *freq, Index nfft)
Definition: FFT:409
void inv(Complex *dst, const Complex *src, Index nfft)
Definition: FFT:290
void inv(std::vector< Output_ > &dst, const std::vector< Complex > &src, Index nfft=-1)
Definition: FFT:368
void SetFlag(Flag f)
Definition: FFT:199
impl_type m_impl
Definition: FFT:417
impl_type::Scalar Scalar
Definition: FFT:181
DenseIndex Index
Definition: FFT:180
T_Impl impl_type
Definition: FFT:179
Matrix< Scalar_, Rows_, Cols_, Options_, MaxRows_, MaxCols_ > & setZero(Index rows, Index cols)
const unsigned int DirectAccessBit
: TensorContractionSycl.h, provides various tensor contraction kernel for SYCL backend
CleanedUpDerType< DerType >::type() min(const AutoDiffScalar< DerType > &x, const T &y)
EIGEN_DEFAULT_DENSE_INDEX_TYPE DenseIndex
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_conjugate_op< typename Derived::Scalar >, const Derived > conj(const Eigen::ArrayBase< Derived > &x)
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_real_op< typename Derived::Scalar >, const Derived > real(const Eigen::ArrayBase< Derived > &x)
void evalTo(T_DestMat &dst) const
Definition: FFT:423
fft_fwd_proxy(const T_SrcMat &src, T_FftIfc &fft, Index nfft)
Definition: FFT:143
const T_SrcMat & m_src
Definition: FFT:150
Index rows() const
Definition: FFT:147
Index cols() const
Definition: FFT:148
DenseIndex Index
Definition: FFT:141
Index m_nfft
Definition: FFT:152
T_FftIfc & m_ifc
Definition: FFT:151
DenseIndex Index
Definition: FFT:159
Index m_nfft
Definition: FFT:170
void evalTo(T_DestMat &dst) const
Definition: FFT:430
fft_inv_proxy(const T_SrcMat &src, T_FftIfc &fft, Index nfft)
Definition: FFT:161
T_FftIfc & m_ifc
Definition: FFT:169
Index cols() const
Definition: FFT:166
Index rows() const
Definition: FFT:165
const T_SrcMat & m_src
Definition: FFT:168