xref: /aosp_15_r20/external/eigen/unsupported/Eigen/FFT (revision bf2c37156dfe67e5dfebd6d394bad8b2ab5804d4)
1*bf2c3715SXin Li// This file is part of Eigen, a lightweight C++ template library
2*bf2c3715SXin Li// for linear algebra.
3*bf2c3715SXin Li//
4*bf2c3715SXin Li// Copyright (C) 2009 Mark Borgerding mark a borgerding net
5*bf2c3715SXin Li//
6*bf2c3715SXin Li// This Source Code Form is subject to the terms of the Mozilla
7*bf2c3715SXin Li// Public License v. 2.0. If a copy of the MPL was not distributed
8*bf2c3715SXin Li// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
9*bf2c3715SXin Li
10*bf2c3715SXin Li#ifndef EIGEN_FFT_H
11*bf2c3715SXin Li#define EIGEN_FFT_H
12*bf2c3715SXin Li
13*bf2c3715SXin Li#include <complex>
14*bf2c3715SXin Li#include <vector>
15*bf2c3715SXin Li#include <map>
16*bf2c3715SXin Li#include "../../Eigen/Core"
17*bf2c3715SXin Li
18*bf2c3715SXin Li
19*bf2c3715SXin Li/**
20*bf2c3715SXin Li  * \defgroup FFT_Module Fast Fourier Transform module
21*bf2c3715SXin Li  *
22*bf2c3715SXin Li  * \code
23*bf2c3715SXin Li  * #include <unsupported/Eigen/FFT>
24*bf2c3715SXin Li  * \endcode
25*bf2c3715SXin Li  *
26*bf2c3715SXin Li  * This module provides Fast Fourier transformation, with a configurable backend
27*bf2c3715SXin Li  * implementation.
28*bf2c3715SXin Li  *
29*bf2c3715SXin Li  * The default implementation is based on kissfft. It is a small, free, and
30*bf2c3715SXin Li  * reasonably efficient default.
31*bf2c3715SXin Li  *
32*bf2c3715SXin Li  * There are currently two implementation backend:
33*bf2c3715SXin Li  *
34*bf2c3715SXin Li  * - fftw (http://www.fftw.org) : faster, GPL -- incompatible with Eigen in LGPL form, bigger code size.
35*bf2c3715SXin Li  * - MKL (http://en.wikipedia.org/wiki/Math_Kernel_Library) : fastest, commercial -- may be incompatible with Eigen in GPL form.
36*bf2c3715SXin Li  *
37*bf2c3715SXin Li  * \section FFTDesign Design
38*bf2c3715SXin Li  *
39*bf2c3715SXin Li  * The following design decisions were made concerning scaling and
40*bf2c3715SXin Li  * half-spectrum for real FFT.
41*bf2c3715SXin Li  *
42*bf2c3715SXin Li  * The intent is to facilitate generic programming and ease migrating code
43*bf2c3715SXin Li  * from  Matlab/octave.
44*bf2c3715SXin Li  * We think the default behavior of Eigen/FFT should favor correctness and
45*bf2c3715SXin Li  * generality over speed. Of course, the caller should be able to "opt-out" from this
46*bf2c3715SXin Li  * behavior and get the speed increase if they want it.
47*bf2c3715SXin Li  *
48*bf2c3715SXin Li  * 1) %Scaling:
49*bf2c3715SXin Li  * Other libraries (FFTW,IMKL,KISSFFT)  do not perform scaling, so there
50*bf2c3715SXin Li  * is a constant gain incurred after the forward&inverse transforms , so
51*bf2c3715SXin Li  * IFFT(FFT(x)) = Kx;  this is done to avoid a vector-by-value multiply.
52*bf2c3715SXin Li  * The downside is that algorithms that worked correctly in Matlab/octave
53*bf2c3715SXin Li  * don't behave the same way once implemented in C++.
54*bf2c3715SXin Li  *
55*bf2c3715SXin Li  * How Eigen/FFT differs: invertible scaling is performed so IFFT( FFT(x) ) = x.
56*bf2c3715SXin Li  *
57*bf2c3715SXin Li  * 2) Real FFT half-spectrum
58*bf2c3715SXin Li  * Other libraries use only half the frequency spectrum (plus one extra
59*bf2c3715SXin Li  * sample for the Nyquist bin) for a real FFT, the other half is the
60*bf2c3715SXin Li  * conjugate-symmetric of the first half.  This saves them a copy and some
61*bf2c3715SXin Li  * memory.  The downside is the caller needs to have special logic for the
62*bf2c3715SXin Li  * number of bins in complex vs real.
63*bf2c3715SXin Li  *
64*bf2c3715SXin Li  * How Eigen/FFT differs: The full spectrum is returned from the forward
65*bf2c3715SXin Li  * transform.  This facilitates generic template programming by obviating
66*bf2c3715SXin Li  * separate specializations for real vs complex.  On the inverse
67*bf2c3715SXin Li  * transform, only half the spectrum is actually used if the output type is real.
68*bf2c3715SXin Li  */
69*bf2c3715SXin Li
70*bf2c3715SXin Li
71*bf2c3715SXin Li#include "../../Eigen/src/Core/util/DisableStupidWarnings.h"
72*bf2c3715SXin Li
73*bf2c3715SXin Li#ifdef EIGEN_FFTW_DEFAULT
74*bf2c3715SXin Li// FFTW: faster, GPL -- incompatible with Eigen in LGPL form, bigger code size
75*bf2c3715SXin Li#  include <fftw3.h>
76*bf2c3715SXin Li#  include "src/FFT/ei_fftw_impl.h"
77*bf2c3715SXin Li   namespace Eigen {
78*bf2c3715SXin Li     //template <typename T> typedef struct internal::fftw_impl  default_fft_impl; this does not work
79*bf2c3715SXin Li     template <typename T> struct default_fft_impl : public internal::fftw_impl<T> {};
80*bf2c3715SXin Li   }
81*bf2c3715SXin Li#elif defined EIGEN_MKL_DEFAULT
82*bf2c3715SXin Li// TODO
83*bf2c3715SXin Li// intel Math Kernel Library: fastest, commercial -- may be incompatible with Eigen in GPL form
84*bf2c3715SXin Li#  include "src/FFT/ei_imklfft_impl.h"
85*bf2c3715SXin Li   namespace Eigen {
86*bf2c3715SXin Li     template <typename T> struct default_fft_impl : public internal::imklfft_impl {};
87*bf2c3715SXin Li   }
88*bf2c3715SXin Li#else
89*bf2c3715SXin Li// internal::kissfft_impl:  small, free, reasonably efficient default, derived from kissfft
90*bf2c3715SXin Li//
91*bf2c3715SXin Li# include "src/FFT/ei_kissfft_impl.h"
92*bf2c3715SXin Li  namespace Eigen {
93*bf2c3715SXin Li     template <typename T>
94*bf2c3715SXin Li       struct default_fft_impl : public internal::kissfft_impl<T> {};
95*bf2c3715SXin Li  }
96*bf2c3715SXin Li#endif
97*bf2c3715SXin Li
98*bf2c3715SXin Linamespace Eigen {
99*bf2c3715SXin Li
100*bf2c3715SXin Li
101*bf2c3715SXin Li//
102*bf2c3715SXin Litemplate<typename T_SrcMat,typename T_FftIfc> struct fft_fwd_proxy;
103*bf2c3715SXin Litemplate<typename T_SrcMat,typename T_FftIfc> struct fft_inv_proxy;
104*bf2c3715SXin Li
105*bf2c3715SXin Linamespace internal {
106*bf2c3715SXin Litemplate<typename T_SrcMat,typename T_FftIfc>
107*bf2c3715SXin Listruct traits< fft_fwd_proxy<T_SrcMat,T_FftIfc> >
108*bf2c3715SXin Li{
109*bf2c3715SXin Li  typedef typename T_SrcMat::PlainObject ReturnType;
110*bf2c3715SXin Li};
111*bf2c3715SXin Litemplate<typename T_SrcMat,typename T_FftIfc>
112*bf2c3715SXin Listruct traits< fft_inv_proxy<T_SrcMat,T_FftIfc> >
113*bf2c3715SXin Li{
114*bf2c3715SXin Li  typedef typename T_SrcMat::PlainObject ReturnType;
115*bf2c3715SXin Li};
116*bf2c3715SXin Li}
117*bf2c3715SXin Li
118*bf2c3715SXin Litemplate<typename T_SrcMat,typename T_FftIfc>
119*bf2c3715SXin Listruct fft_fwd_proxy
120*bf2c3715SXin Li : public ReturnByValue<fft_fwd_proxy<T_SrcMat,T_FftIfc> >
121*bf2c3715SXin Li{
122*bf2c3715SXin Li  typedef DenseIndex Index;
123*bf2c3715SXin Li
124*bf2c3715SXin Li  fft_fwd_proxy(const T_SrcMat& src,T_FftIfc & fft, Index nfft) : m_src(src),m_ifc(fft), m_nfft(nfft) {}
125*bf2c3715SXin Li
126*bf2c3715SXin Li  template<typename T_DestMat> void evalTo(T_DestMat& dst) const;
127*bf2c3715SXin Li
128*bf2c3715SXin Li  Index rows() const { return m_src.rows(); }
129*bf2c3715SXin Li  Index cols() const { return m_src.cols(); }
130*bf2c3715SXin Liprotected:
131*bf2c3715SXin Li  const T_SrcMat & m_src;
132*bf2c3715SXin Li  T_FftIfc & m_ifc;
133*bf2c3715SXin Li  Index m_nfft;
134*bf2c3715SXin Li};
135*bf2c3715SXin Li
136*bf2c3715SXin Litemplate<typename T_SrcMat,typename T_FftIfc>
137*bf2c3715SXin Listruct fft_inv_proxy
138*bf2c3715SXin Li : public ReturnByValue<fft_inv_proxy<T_SrcMat,T_FftIfc> >
139*bf2c3715SXin Li{
140*bf2c3715SXin Li  typedef DenseIndex Index;
141*bf2c3715SXin Li
142*bf2c3715SXin Li  fft_inv_proxy(const T_SrcMat& src,T_FftIfc & fft, Index nfft) : m_src(src),m_ifc(fft), m_nfft(nfft) {}
143*bf2c3715SXin Li
144*bf2c3715SXin Li  template<typename T_DestMat> void evalTo(T_DestMat& dst) const;
145*bf2c3715SXin Li
146*bf2c3715SXin Li  Index rows() const { return m_src.rows(); }
147*bf2c3715SXin Li  Index cols() const { return m_src.cols(); }
148*bf2c3715SXin Liprotected:
149*bf2c3715SXin Li  const T_SrcMat & m_src;
150*bf2c3715SXin Li  T_FftIfc & m_ifc;
151*bf2c3715SXin Li  Index m_nfft;
152*bf2c3715SXin Li};
153*bf2c3715SXin Li
154*bf2c3715SXin Li
155*bf2c3715SXin Litemplate <typename T_Scalar,
156*bf2c3715SXin Li         typename T_Impl=default_fft_impl<T_Scalar> >
157*bf2c3715SXin Liclass FFT
158*bf2c3715SXin Li{
159*bf2c3715SXin Li  public:
160*bf2c3715SXin Li    typedef T_Impl impl_type;
161*bf2c3715SXin Li    typedef DenseIndex Index;
162*bf2c3715SXin Li    typedef typename impl_type::Scalar Scalar;
163*bf2c3715SXin Li    typedef typename impl_type::Complex Complex;
164*bf2c3715SXin Li
165*bf2c3715SXin Li    enum Flag {
166*bf2c3715SXin Li      Default=0, // goof proof
167*bf2c3715SXin Li      Unscaled=1,
168*bf2c3715SXin Li      HalfSpectrum=2,
169*bf2c3715SXin Li      // SomeOtherSpeedOptimization=4
170*bf2c3715SXin Li      Speedy=32767
171*bf2c3715SXin Li    };
172*bf2c3715SXin Li
173*bf2c3715SXin Li    FFT( const impl_type & impl=impl_type() , Flag flags=Default ) :m_impl(impl),m_flag(flags) { }
174*bf2c3715SXin Li
175*bf2c3715SXin Li    inline
176*bf2c3715SXin Li    bool HasFlag(Flag f) const { return (m_flag & (int)f) == f;}
177*bf2c3715SXin Li
178*bf2c3715SXin Li    inline
179*bf2c3715SXin Li    void SetFlag(Flag f) { m_flag |= (int)f;}
180*bf2c3715SXin Li
181*bf2c3715SXin Li    inline
182*bf2c3715SXin Li    void ClearFlag(Flag f) { m_flag &= (~(int)f);}
183*bf2c3715SXin Li
184*bf2c3715SXin Li    inline
185*bf2c3715SXin Li    void fwd( Complex * dst, const Scalar * src, Index nfft)
186*bf2c3715SXin Li    {
187*bf2c3715SXin Li        m_impl.fwd(dst,src,static_cast<int>(nfft));
188*bf2c3715SXin Li        if ( HasFlag(HalfSpectrum) == false)
189*bf2c3715SXin Li          ReflectSpectrum(dst,nfft);
190*bf2c3715SXin Li    }
191*bf2c3715SXin Li
192*bf2c3715SXin Li    inline
193*bf2c3715SXin Li    void fwd( Complex * dst, const Complex * src, Index nfft)
194*bf2c3715SXin Li    {
195*bf2c3715SXin Li        m_impl.fwd(dst,src,static_cast<int>(nfft));
196*bf2c3715SXin Li    }
197*bf2c3715SXin Li
198*bf2c3715SXin Li    /*
199*bf2c3715SXin Li    inline
200*bf2c3715SXin Li    void fwd2(Complex * dst, const Complex * src, int n0,int n1)
201*bf2c3715SXin Li    {
202*bf2c3715SXin Li      m_impl.fwd2(dst,src,n0,n1);
203*bf2c3715SXin Li    }
204*bf2c3715SXin Li    */
205*bf2c3715SXin Li
206*bf2c3715SXin Li    template <typename _Input>
207*bf2c3715SXin Li    inline
208*bf2c3715SXin Li    void fwd( std::vector<Complex> & dst, const std::vector<_Input> & src)
209*bf2c3715SXin Li    {
210*bf2c3715SXin Li      if ( NumTraits<_Input>::IsComplex == 0 && HasFlag(HalfSpectrum) )
211*bf2c3715SXin Li        dst.resize( (src.size()>>1)+1); // half the bins + Nyquist bin
212*bf2c3715SXin Li      else
213*bf2c3715SXin Li        dst.resize(src.size());
214*bf2c3715SXin Li      fwd(&dst[0],&src[0],src.size());
215*bf2c3715SXin Li    }
216*bf2c3715SXin Li
217*bf2c3715SXin Li    template<typename InputDerived, typename ComplexDerived>
218*bf2c3715SXin Li    inline
219*bf2c3715SXin Li    void fwd( MatrixBase<ComplexDerived> & dst, const MatrixBase<InputDerived> & src, Index nfft=-1)
220*bf2c3715SXin Li    {
221*bf2c3715SXin Li      typedef typename ComplexDerived::Scalar dst_type;
222*bf2c3715SXin Li      typedef typename InputDerived::Scalar src_type;
223*bf2c3715SXin Li      EIGEN_STATIC_ASSERT_VECTOR_ONLY(InputDerived)
224*bf2c3715SXin Li      EIGEN_STATIC_ASSERT_VECTOR_ONLY(ComplexDerived)
225*bf2c3715SXin Li      EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(ComplexDerived,InputDerived) // size at compile-time
226*bf2c3715SXin Li      EIGEN_STATIC_ASSERT((internal::is_same<dst_type, Complex>::value),
227*bf2c3715SXin Li            YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
228*bf2c3715SXin Li      EIGEN_STATIC_ASSERT(int(InputDerived::Flags)&int(ComplexDerived::Flags)&DirectAccessBit,
229*bf2c3715SXin Li            THIS_METHOD_IS_ONLY_FOR_EXPRESSIONS_WITH_DIRECT_MEMORY_ACCESS_SUCH_AS_MAP_OR_PLAIN_MATRICES)
230*bf2c3715SXin Li
231*bf2c3715SXin Li      if (nfft<1)
232*bf2c3715SXin Li        nfft = src.size();
233*bf2c3715SXin Li
234*bf2c3715SXin Li      if ( NumTraits< src_type >::IsComplex == 0 && HasFlag(HalfSpectrum) )
235*bf2c3715SXin Li        dst.derived().resize( (nfft>>1)+1);
236*bf2c3715SXin Li      else
237*bf2c3715SXin Li        dst.derived().resize(nfft);
238*bf2c3715SXin Li
239*bf2c3715SXin Li      if ( src.innerStride() != 1 || src.size() < nfft ) {
240*bf2c3715SXin Li        Matrix<src_type,1,Dynamic> tmp;
241*bf2c3715SXin Li        if (src.size()<nfft) {
242*bf2c3715SXin Li          tmp.setZero(nfft);
243*bf2c3715SXin Li          tmp.block(0,0,src.size(),1 ) = src;
244*bf2c3715SXin Li        }else{
245*bf2c3715SXin Li          tmp = src;
246*bf2c3715SXin Li        }
247*bf2c3715SXin Li        fwd( &dst[0],&tmp[0],nfft );
248*bf2c3715SXin Li      }else{
249*bf2c3715SXin Li        fwd( &dst[0],&src[0],nfft );
250*bf2c3715SXin Li      }
251*bf2c3715SXin Li    }
252*bf2c3715SXin Li
253*bf2c3715SXin Li    template<typename InputDerived>
254*bf2c3715SXin Li    inline
255*bf2c3715SXin Li    fft_fwd_proxy< MatrixBase<InputDerived>, FFT<T_Scalar,T_Impl> >
256*bf2c3715SXin Li    fwd( const MatrixBase<InputDerived> & src, Index nfft=-1)
257*bf2c3715SXin Li    {
258*bf2c3715SXin Li      return fft_fwd_proxy< MatrixBase<InputDerived> ,FFT<T_Scalar,T_Impl> >( src, *this,nfft );
259*bf2c3715SXin Li    }
260*bf2c3715SXin Li
261*bf2c3715SXin Li    template<typename InputDerived>
262*bf2c3715SXin Li    inline
263*bf2c3715SXin Li    fft_inv_proxy< MatrixBase<InputDerived>, FFT<T_Scalar,T_Impl> >
264*bf2c3715SXin Li    inv( const MatrixBase<InputDerived> & src, Index nfft=-1)
265*bf2c3715SXin Li    {
266*bf2c3715SXin Li      return  fft_inv_proxy< MatrixBase<InputDerived> ,FFT<T_Scalar,T_Impl> >( src, *this,nfft );
267*bf2c3715SXin Li    }
268*bf2c3715SXin Li
269*bf2c3715SXin Li    inline
270*bf2c3715SXin Li    void inv( Complex * dst, const Complex * src, Index nfft)
271*bf2c3715SXin Li    {
272*bf2c3715SXin Li      m_impl.inv( dst,src,static_cast<int>(nfft) );
273*bf2c3715SXin Li      if ( HasFlag( Unscaled ) == false)
274*bf2c3715SXin Li        scale(dst,Scalar(1./nfft),nfft); // scale the time series
275*bf2c3715SXin Li    }
276*bf2c3715SXin Li
277*bf2c3715SXin Li    inline
278*bf2c3715SXin Li    void inv( Scalar * dst, const Complex * src, Index nfft)
279*bf2c3715SXin Li    {
280*bf2c3715SXin Li      m_impl.inv( dst,src,static_cast<int>(nfft) );
281*bf2c3715SXin Li      if ( HasFlag( Unscaled ) == false)
282*bf2c3715SXin Li        scale(dst,Scalar(1./nfft),nfft); // scale the time series
283*bf2c3715SXin Li    }
284*bf2c3715SXin Li
285*bf2c3715SXin Li    template<typename OutputDerived, typename ComplexDerived>
286*bf2c3715SXin Li    inline
287*bf2c3715SXin Li    void inv( MatrixBase<OutputDerived> & dst, const MatrixBase<ComplexDerived> & src, Index nfft=-1)
288*bf2c3715SXin Li    {
289*bf2c3715SXin Li      typedef typename ComplexDerived::Scalar src_type;
290*bf2c3715SXin Li      typedef typename ComplexDerived::RealScalar real_type;
291*bf2c3715SXin Li      typedef typename OutputDerived::Scalar dst_type;
292*bf2c3715SXin Li      const bool realfft= (NumTraits<dst_type>::IsComplex == 0);
293*bf2c3715SXin Li      EIGEN_STATIC_ASSERT_VECTOR_ONLY(OutputDerived)
294*bf2c3715SXin Li      EIGEN_STATIC_ASSERT_VECTOR_ONLY(ComplexDerived)
295*bf2c3715SXin Li      EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(ComplexDerived,OutputDerived) // size at compile-time
296*bf2c3715SXin Li      EIGEN_STATIC_ASSERT((internal::is_same<src_type, Complex>::value),
297*bf2c3715SXin Li            YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
298*bf2c3715SXin Li      EIGEN_STATIC_ASSERT(int(OutputDerived::Flags)&int(ComplexDerived::Flags)&DirectAccessBit,
299*bf2c3715SXin Li            THIS_METHOD_IS_ONLY_FOR_EXPRESSIONS_WITH_DIRECT_MEMORY_ACCESS_SUCH_AS_MAP_OR_PLAIN_MATRICES)
300*bf2c3715SXin Li
301*bf2c3715SXin Li      if (nfft<1) { //automatic FFT size determination
302*bf2c3715SXin Li        if ( realfft && HasFlag(HalfSpectrum) )
303*bf2c3715SXin Li          nfft = 2*(src.size()-1); //assume even fft size
304*bf2c3715SXin Li        else
305*bf2c3715SXin Li          nfft = src.size();
306*bf2c3715SXin Li      }
307*bf2c3715SXin Li      dst.derived().resize( nfft );
308*bf2c3715SXin Li
309*bf2c3715SXin Li      // check for nfft that does not fit the input data size
310*bf2c3715SXin Li      Index resize_input= ( realfft && HasFlag(HalfSpectrum) )
311*bf2c3715SXin Li        ? ( (nfft/2+1) - src.size() )
312*bf2c3715SXin Li        : ( nfft - src.size() );
313*bf2c3715SXin Li
314*bf2c3715SXin Li      if ( src.innerStride() != 1 || resize_input ) {
315*bf2c3715SXin Li        // if the vector is strided, then we need to copy it to a packed temporary
316*bf2c3715SXin Li        Matrix<src_type,1,Dynamic> tmp;
317*bf2c3715SXin Li        if ( resize_input ) {
318*bf2c3715SXin Li          size_t ncopy = (std::min)(src.size(),src.size() + resize_input);
319*bf2c3715SXin Li          tmp.setZero(src.size() + resize_input);
320*bf2c3715SXin Li          if ( realfft && HasFlag(HalfSpectrum) ) {
321*bf2c3715SXin Li            // pad at the Nyquist bin
322*bf2c3715SXin Li            tmp.head(ncopy) = src.head(ncopy);
323*bf2c3715SXin Li            tmp(ncopy-1) = real(tmp(ncopy-1)); // enforce real-only Nyquist bin
324*bf2c3715SXin Li          }else{
325*bf2c3715SXin Li            size_t nhead,ntail;
326*bf2c3715SXin Li            nhead = 1+ncopy/2-1; // range  [0:pi)
327*bf2c3715SXin Li            ntail = ncopy/2-1;   // range (-pi:0)
328*bf2c3715SXin Li            tmp.head(nhead) = src.head(nhead);
329*bf2c3715SXin Li            tmp.tail(ntail) = src.tail(ntail);
330*bf2c3715SXin Li            if (resize_input<0) { //shrinking -- create the Nyquist bin as the average of the two bins that fold into it
331*bf2c3715SXin Li              tmp(nhead) = ( src(nfft/2) + src( src.size() - nfft/2 ) )*real_type(.5);
332*bf2c3715SXin Li            }else{ // expanding -- split the old Nyquist bin into two halves
333*bf2c3715SXin Li              tmp(nhead) = src(nhead) * real_type(.5);
334*bf2c3715SXin Li              tmp(tmp.size()-nhead) = tmp(nhead);
335*bf2c3715SXin Li            }
336*bf2c3715SXin Li          }
337*bf2c3715SXin Li        }else{
338*bf2c3715SXin Li          tmp = src;
339*bf2c3715SXin Li        }
340*bf2c3715SXin Li        inv( &dst[0],&tmp[0], nfft);
341*bf2c3715SXin Li      }else{
342*bf2c3715SXin Li        inv( &dst[0],&src[0], nfft);
343*bf2c3715SXin Li      }
344*bf2c3715SXin Li    }
345*bf2c3715SXin Li
346*bf2c3715SXin Li    template <typename _Output>
347*bf2c3715SXin Li    inline
348*bf2c3715SXin Li    void inv( std::vector<_Output> & dst, const std::vector<Complex> & src,Index nfft=-1)
349*bf2c3715SXin Li    {
350*bf2c3715SXin Li      if (nfft<1)
351*bf2c3715SXin Li        nfft = ( NumTraits<_Output>::IsComplex == 0 && HasFlag(HalfSpectrum) ) ? 2*(src.size()-1) : src.size();
352*bf2c3715SXin Li      dst.resize( nfft );
353*bf2c3715SXin Li      inv( &dst[0],&src[0],nfft);
354*bf2c3715SXin Li    }
355*bf2c3715SXin Li
356*bf2c3715SXin Li
357*bf2c3715SXin Li    /*
358*bf2c3715SXin Li    // TODO: multi-dimensional FFTs
359*bf2c3715SXin Li    inline
360*bf2c3715SXin Li    void inv2(Complex * dst, const Complex * src, int n0,int n1)
361*bf2c3715SXin Li    {
362*bf2c3715SXin Li      m_impl.inv2(dst,src,n0,n1);
363*bf2c3715SXin Li      if ( HasFlag( Unscaled ) == false)
364*bf2c3715SXin Li          scale(dst,1./(n0*n1),n0*n1);
365*bf2c3715SXin Li    }
366*bf2c3715SXin Li  */
367*bf2c3715SXin Li
368*bf2c3715SXin Li    inline
369*bf2c3715SXin Li    impl_type & impl() {return m_impl;}
370*bf2c3715SXin Li  private:
371*bf2c3715SXin Li
372*bf2c3715SXin Li    template <typename T_Data>
373*bf2c3715SXin Li    inline
374*bf2c3715SXin Li    void scale(T_Data * x,Scalar s,Index nx)
375*bf2c3715SXin Li    {
376*bf2c3715SXin Li#if 1
377*bf2c3715SXin Li      for (int k=0;k<nx;++k)
378*bf2c3715SXin Li        *x++ *= s;
379*bf2c3715SXin Li#else
380*bf2c3715SXin Li      if ( ((ptrdiff_t)x) & 15 )
381*bf2c3715SXin Li        Matrix<T_Data, Dynamic, 1>::Map(x,nx) *= s;
382*bf2c3715SXin Li      else
383*bf2c3715SXin Li        Matrix<T_Data, Dynamic, 1>::MapAligned(x,nx) *= s;
384*bf2c3715SXin Li         //Matrix<T_Data, Dynamic, Dynamic>::Map(x,nx) * s;
385*bf2c3715SXin Li#endif
386*bf2c3715SXin Li    }
387*bf2c3715SXin Li
388*bf2c3715SXin Li    inline
389*bf2c3715SXin Li    void ReflectSpectrum(Complex * freq, Index nfft)
390*bf2c3715SXin Li    {
391*bf2c3715SXin Li      // create the implicit right-half spectrum (conjugate-mirror of the left-half)
392*bf2c3715SXin Li      Index nhbins=(nfft>>1)+1;
393*bf2c3715SXin Li      for (Index k=nhbins;k < nfft; ++k )
394*bf2c3715SXin Li        freq[k] = conj(freq[nfft-k]);
395*bf2c3715SXin Li    }
396*bf2c3715SXin Li
397*bf2c3715SXin Li    impl_type m_impl;
398*bf2c3715SXin Li    int m_flag;
399*bf2c3715SXin Li};
400*bf2c3715SXin Li
401*bf2c3715SXin Litemplate<typename T_SrcMat,typename T_FftIfc>
402*bf2c3715SXin Litemplate<typename T_DestMat> inline
403*bf2c3715SXin Livoid fft_fwd_proxy<T_SrcMat,T_FftIfc>::evalTo(T_DestMat& dst) const
404*bf2c3715SXin Li{
405*bf2c3715SXin Li    m_ifc.fwd( dst, m_src, m_nfft);
406*bf2c3715SXin Li}
407*bf2c3715SXin Li
408*bf2c3715SXin Litemplate<typename T_SrcMat,typename T_FftIfc>
409*bf2c3715SXin Litemplate<typename T_DestMat> inline
410*bf2c3715SXin Livoid fft_inv_proxy<T_SrcMat,T_FftIfc>::evalTo(T_DestMat& dst) const
411*bf2c3715SXin Li{
412*bf2c3715SXin Li    m_ifc.inv( dst, m_src, m_nfft);
413*bf2c3715SXin Li}
414*bf2c3715SXin Li
415*bf2c3715SXin Li}
416*bf2c3715SXin Li
417*bf2c3715SXin Li#include "../../Eigen/src/Core/util/ReenableStupidWarnings.h"
418*bf2c3715SXin Li
419*bf2c3715SXin Li#endif
420