头文件:
/* * Copyright (c) 2008-2011 Zhang Ming (M. Zhang), [email protected] * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 2 or any later version. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. A copy of the GNU General Public License is available at: * http://www.fsf.org/licensing/licenses */ /***************************************************************************** * fftpf.h * * Fast Fourier Transform with prime factor algorithm * * This class is designed for calculating discrete Fourier transform and * inverse discrete Fourier transform of 1D signals by using prime factor * algorithms. The signals can be arbitrary length. The largest prime factor * of n must be less than or equal to the constant PRIMEFACTOR defined below. * * The general idea is to factor the length of the DFT "n" into factors that are * efficiently handled by the routines. A number of short DFT's are implemented * with a minimum of arithmetical operations and using(almost) straight line * code resultingin very fast execution when the factors of n belong to this * set. Especially radix-10 is optimized. Prime factors, that are not in the * set of short DFT's are handled with direct evaluation of the DFP expression. * * The algorithm is modified from "xFFT.h" of "Pratical Fourier Transform * and C++ Implementation" written by Hequan Sun. * * Zhang Ming, 2010-09, Xi'an Jiaotong University. *****************************************************************************/ #ifndef FFTPF_H #define FFTPF_H #include <vector.h> #define PRIMEFACTOR 37 #define PRIMEFACTORHALF (PRIMEFACTOR+1)/2 #define PRIMECOUNT 20 namespace splab { template<class Type> class FFTPF { public: FFTPF(); ~FFTPF(); void fft( const Vector<Type> &xn, Vector< complex<Type> > &Xk ); void ifft( const Vector< complex<Type> > &Xk, Vector<Type> &xn ); void fft( const Vector< complex<Type> > &xn, Vector< complex<Type> > &Xk ); void ifft( const Vector< complex<Type> > &Xk, Vector< complex<Type> > &xn ); private: bool bAlloc; int mNOldSize, mNFactor, nNewFactorSize, nHalfFactorSize, groupOffset, dataOffset, blockOffset, adr, groupNo, dataNo, blockNo, twNo; int mSofarRadix[PRIMECOUNT], mActualRadix[PRIMECOUNT], mRemainRadix[PRIMECOUNT]; Type tPI, t2PI, tIRT2, tIRT3, omega, twRe, twIim; Type *pftwRe, *pftgRe, *pfzRe, *pfvRe, *pfwRe, *pftwIm, *pftgIm, *pfzIm, *pfvIm, *pfwIm; Type twiddleRe[PRIMEFACTOR], trigRe[PRIMEFACTOR], zRe[PRIMEFACTOR], twiddleIm[PRIMEFACTOR], trigIm[PRIMEFACTOR], zIm[PRIMEFACTOR], vRe[PRIMEFACTORHALF], wRe[PRIMEFACTORHALF], vIm[PRIMEFACTORHALF], wIm[PRIMEFACTORHALF]; Type c3_1, c5_1, c5_2, c5_3, c5_4, c5_5, c7_1, c7_2, c7_3, c7_4, c7_5, c7_6, c9_2, c9_3, c9_4, c9_5, c9_6, c9_7, c9_8, c9_9, c11_1, c11_2, c11_3, c11_4, c11_5, c11_6, c11_7, c11_8, c11_9, c11_10, c13_1, c13_2, c13_3, c13_4, c13_5, c13_6, c13_7, c13_8, c13_9, c13_10, c13_11, c13_12, c16_2, c16_3, c16_4, c16_5; Type ttmp, t1_re, t1_im, t2_re, t2_im, t3_re, t3_im, t4_re, t4_im, t5_re, t5_im, t6_re, t6_im, t7_re, t7_im, t8_re, t8_im, t9_re, t9_im, t10_re, t10_im, t11_re, t11_im, t12_re, t12_im, t13_re, t13_im, t14_re, t14_im, t15_re, t15_im, t16_re, t16_im, t17_re, t17_im, t18_re, t18_im, t19_re, t19_im, t20_re, t20_im, t21_re, t21_im, t22_re, t22_im, m1_re, m1_im, m2_re, m2_im, m3_re, m3_im, m4_re, m4_im, m5_re, m5_im, m6_re, m6_im, m7_re, m7_im, m8_re, m8_im, m9_re, m9_im, m10_re, m10_im, m11_re, m11_im, m12_re, m12_im; void releaseMem(); void allocateMem(); void factorize( int n, int &nFact, int *fact); void primeSetup( int nPoints ); void permute( const Vector<Type> &xn, Vector< complex<Type> > &yn ); void permute( const Vector< complex<Type> > &xn, Vector< complex<Type> > &yn, bool bTrans=true ); void initTrig( int radix ); void radix2( Type *aRe, Type *aIm ); void radix3( Type *aRe, Type *aIm ); void radix4( Type *aRe, Type *aIm ); void radix5( Type *aRe, Type *aIm ); void radix7( Type *aRe, Type *aIm ); void radix8( Type *aRe, Type *aIm ); void radix9( Type *aRe, Type *aIm ); void radix10( Type *aRe, Type *aIm ); void radix11( Type *aRe, Type *aIm ); void radix13( Type *aRe, Type *aIm ); void radix16( Type *aRe, Type *aIm ); void radixOther( int radix ); void twiddleFFT( int sofarRadix, int radix, int remainRadix, Vector< complex<Type> > &yn ); }; // class FFTPF #include <fftpf-impl.h> } // namespace splab #endif //FFTPF_H
实现文件:
/* * Copyright (c) 2008-2011 Zhang Ming (M. Zhang), [email protected] * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 2 or any later version. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. A copy of the GNU General Public License is available at: * http://www.fsf.org/licensing/licenses */ /***************************************************************************** * fftpf-impl.h * * Implementation for FFTPF class. * * Zhang Ming, 2010-09, Xi'an Jiaotong University. *****************************************************************************/ /** * constructors and destructor */ template<class Type> FFTPF<Type>::FFTPF() { bAlloc = false; mNOldSize = nNewFactorSize = nHalfFactorSize = 0; pftwRe = twiddleRe; pftwIm = twiddleIm; pftgRe = trigRe; pftgIm = trigIm; pfzRe = zRe; pfzIm = zIm; pfvRe = vRe; pfvIm = vIm; pfwRe = wRe; pfwIm = wIm; tIRT2 = Type(sqrt(2.0)/2); tIRT3 = Type(sqrt(3.0)/2); tPI = Type(4*atan(1.0)); t2PI = 2*tPI; Type tphi = t2PI/5; c3_1 = -1.5; c5_1 = Type((cos(tphi)-cos(2*tphi))/2); c5_2 = Type(sin(tphi)); c5_3 = Type(sin(2*tphi)); c5_4 = Type((c5_3+c5_2)); c5_3 = c5_2-c5_3; c5_5 = 1.25; tphi = t2PI/7; c7_1 = Type(cos(tphi)); c7_2 = Type(cos(2*tphi)); c7_3 = Type(cos(3*tphi)); c7_4 = Type(sin(tphi)); c7_5 = Type(sin(2*tphi)); c7_6 = Type(sin(3*tphi)); tphi = t2PI/9; c9_4 = Type(cos(tphi)); c9_8 = Type(sin(8*tphi)); c9_3 = Type(cos(2*tphi)); c9_7 = Type(sin(2*tphi)); c9_5 = Type(cos(3*tphi)); c9_2 = Type(cos(4*tphi)); c9_6 = Type(sin(5*tphi)); tphi = t2PI/11; c11_1 = Type(cos(tphi)); c11_2 = Type(cos(2*tphi)); c11_3 = Type(cos(3*tphi)); c11_4 = Type(cos(4*tphi)); c11_5 = Type(cos(5*tphi)); c11_6 = Type(sin(tphi)); c11_7 = Type(sin(2*tphi)); c11_8 = Type(sin(3*tphi)); c11_9 = Type(sin(4*tphi)); c11_10 = Type(sin(5*tphi)); tphi = t2PI/13; c13_1 = Type(cos(tphi)); c13_2 = Type(cos(2*tphi)); c13_3 = Type(cos(3*tphi)); c13_4 = Type(cos(4*tphi)); c13_5 = Type(cos(5*tphi)); c13_6 = Type(cos(6*tphi)); c13_7 = Type(sin(tphi)); c13_8 = Type(sin(2*tphi)); c13_9 = Type(sin(3*tphi)); c13_10 = Type(sin(4*tphi)); c13_11 = Type(sin(5*tphi)); c13_12 = Type(sin(6*tphi)); tphi = t2PI/16; c16_2 = Type(sin(tphi)); c16_5 = Type(cos(tphi)); c16_3 = c16_2+c16_5; c16_4 = c16_5-c16_2; } template<class Type> FFTPF<Type>::~FFTPF() { releaseMem(); } template<class Type> void FFTPF<Type>::releaseMem() { if ( !bAlloc) return; if ( NULL != pftwRe ) delete []pftwRe; if ( NULL != pftwIm ) delete []pftwIm; if ( NULL != pftgRe ) delete []pftgRe; if ( NULL != pftgIm ) delete []pftgIm; if ( NULL != pfzRe ) delete []pfzRe; if ( NULL != pfzIm ) delete []pfzIm; if ( NULL != pfvRe ) delete []pfvRe; if ( NULL != pfvIm ) delete []pfvIm; if ( NULL != pfwRe ) delete []pfwRe; if ( NULL != pfwIm ) delete []pfwIm; bAlloc = false; nNewFactorSize = nHalfFactorSize = 0; } /** * allocate memory */ template<class Type> inline void FFTPF<Type>::allocateMem() { pftwRe = new Type[nNewFactorSize]; pftwIm = new Type[nNewFactorSize]; pftgRe = new Type[nNewFactorSize]; pftgIm = new Type[nNewFactorSize]; pfzRe = new Type[nNewFactorSize]; pfzIm = new Type[nNewFactorSize]; pfvRe = new Type[nHalfFactorSize]; pfvIm = new Type[nHalfFactorSize]; pfwRe = new Type[nHalfFactorSize]; pfwIm = new Type[nHalfFactorSize]; bAlloc = true; } /** * factoring the transformation length. */ template<class Type> void FFTPF<Type>::factorize( int n, int &nFact, int *fact ) { int i, j=0, k, nRadix = 11, radices[12], factors[PRIMECOUNT]; radices[1] = 2; radices[2] = 3; radices[3] = 4; radices[4] = 5; radices[5] = 7; radices[6] = 8; radices[7] = 9; radices[8] = 10; radices[9] = 11; radices[10] = 13; radices[11] = 16; if( 1 == n ) { j = 1; factors[1] = 1; } i = nRadix; while( (n>1) && (i>0) ) { if( (n%radices[i]) != 0 ) --i; else { n = n/radices[i]; j++; factors[j] = radices[i]; } } if( 2 == factors[j] ) { i = j-1; while( (i>0) && (factors[i]!=8) ) i--; if( i > 0 ) { factors[j] = 4; factors[i] = 4; } } if( n > 1 ) { for( k=2; k<sqrt(1.0*n)+1; ++k ) while( 0 == (n%k) ) { n = n/k; j++; factors[j] = k; } if( n > 1 ) { j++; factors[j] = n; } } for( i=1; i<=j; ++i ) fact[i] = factors[j-i+1]; nFact = j; } /** * After N is factored the parameters that control the stages are generated. * For each stage we have: * mSofarRadix : the product of the radices so far. * mActualRadix : the radix handled in this stage. * mRemainRadix : the product of the remaining radices. */ template<class Type> void FFTPF<Type>::primeSetup( int nPoints ) { factorize( nPoints, mNFactor, mActualRadix ); if( mActualRadix[1] > PRIMEFACTOR ) { bool bdone = true; if( bAlloc ) { if( mActualRadix[1] <= nNewFactorSize ) bdone=false; else { releaseMem(); bdone=true; } } if( bdone ) { nNewFactorSize = mActualRadix[1]; nHalfFactorSize = (nNewFactorSize+1)/2; allocateMem(); } } mSofarRadix[1] = 1; mRemainRadix[0] = nPoints; mRemainRadix[1] = nPoints/mActualRadix[1]; for( int i=2; i<=mNFactor; ++i ) { mSofarRadix[i] = mSofarRadix[i-1] * mActualRadix[i-1]; mRemainRadix[i] = mRemainRadix[i-1] / mActualRadix[i]; } mNOldSize = nPoints; } /** * The sequence "yn" is the permuted input sequence "xn" so that the * following transformations can be performed in-place,and the final * result is the normal order. */ template<class Type> void FFTPF<Type>::permute( const Vector<Type> &xn, Vector< complex<Type> > &yn ) { int i, j, k=0, nPoint = xn.size(), count[PRIMECOUNT]; for( i=1; i<=mNFactor; ++i ) count[i] = 0; for( i=0; i<=nPoint-2; ++i ) { yn[i] = xn[k]; j = 1; k += mRemainRadix[j]; count[1] = count[1]+1; while( count[j] >= mActualRadix[j] ) { count[j] = 0; k = k - mRemainRadix[j-1] + mRemainRadix[j+1]; j++; count[j] = count[j] + 1; } } yn[nPoint-1] = xn[nPoint-1]; } template<class Type> void FFTPF<Type>::permute( const Vector< complex<Type> > &xn, Vector< complex<Type> > &yn, bool bTrans ) { int i, j, k=0, nPoint = xn.size(), count[PRIMECOUNT]; for( i=1; i<=mNFactor; ++i ) count[i] = 0; for( i=0; i<=nPoint-2; ++i ) { yn[i] = xn[k]; j = 1; k += mRemainRadix[j]; count[1] = count[1]+1; while( count[j] >= mActualRadix[j] ) { count[j] = 0; k = k - mRemainRadix[j-1] + mRemainRadix[j+1]; j++; count[j] = count[j] + 1; } } yn[nPoint-1] = xn[nPoint-1]; if( !bTrans ) for( i=0; i< nPoint; ++i ) yn[i] = conj(yn[i]); } /** * initialise sine/cosine table. */ template<class Type> inline void FFTPF<Type>::initTrig( int radix ) { Type w, xre, xim; w = 2*tPI/radix; pftgRe[0] = 1; pftgIm[0] = 0; xre = Type(cos(w)); xim = -Type(sin(w)); pftgRe[1] = xre; pftgIm[1] = xim; for( int i=2; i<radix; ++i ) { pftgRe[i] = xre*pftgRe[i-1] - xim*pftgIm[i-1]; pftgIm[i] = xim*pftgRe[i-1] + xre*pftgIm[i-1]; } } /** * length 2 DFT */ template<class Type> inline void FFTPF<Type>::radix2( Type *aRe, Type *aIm ) { t1_re = aRe[0]; aRe[0] = t1_re+aRe[1]; aRe[1] = t1_re-aRe[1]; t1_im = aIm[0]; aIm[0] = t1_im+aIm[1]; aIm[1] = t1_im-aIm[1]; } /** * length 3 DFT */ template<class Type> inline void FFTPF<Type>::radix3( Type *aRe, Type *aIm ) { t1_re = aRe[1]+aRe[2]; t2_re = (aRe[2]-aRe[1])*tIRT3; aRe[0] = aRe[0]+t1_re; t1_re = aRe[0]+t1_re*c3_1; t1_im = aIm[1]+aIm[2]; t2_im = (aIm[2]-aIm[1])*tIRT3; aIm[0] = aIm[0]+t1_im; t1_im = aIm[0]+t1_im*c3_1; aRe[1] = t1_re-t2_im; aRe[2] = t1_re+t2_im; aIm[1] = t1_im+t2_re; aIm[2] = t1_im-t2_re; } /** * length 4 DFT */ template<class Type> inline void FFTPF<Type>::radix4( Type *aRe, Type *aIm ) { t1_re = aRe[0]+aRe[2]; m2_re = aRe[0]-aRe[2]; t2_re = aRe[1]+aRe[3]; aRe[0] = t1_re+t2_re; aRe[2] = t1_re-t2_re; t1_re = aIm[0]+aIm[2]; m2_im = aIm[0]-aIm[2]; t2_re = aIm[1]+aIm[3]; aIm[0] = t1_re+t2_re; aIm[2] = t1_re-t2_re; t1_re = aRe[1]-aRe[3]; t2_re = aIm[1]-aIm[3]; aRe[1] = m2_re+t2_re; aRe[3] = m2_re-t2_re; aIm[1] = m2_im-t1_re; aIm[3] = m2_im+t1_re; } /** * length 5 DFT */ template<class Type> inline void FFTPF<Type>::radix5( Type *aRe, Type *aIm ) { t1_re = aRe[1]+aRe[4]; t2_re = aRe[2]-aRe[3]; t3_re = aRe[1]-aRe[4]; t4_re = aRe[2]+aRe[3]; t5_re = (t1_re-t4_re)*c5_1; t1_re = t1_re+t4_re; aRe[0] = aRe[0]+t1_re; t1_re = aRe[0]-t1_re*c5_5; t4_re = t1_re-t5_re; t1_re = t1_re+t5_re; t5_re = (t3_re+t2_re)*c5_2; t3_re = t5_re-t3_re*c5_4; t2_re = t5_re-t2_re*c5_3; t1_im = aIm[1]+aIm[4]; t2_im = aIm[2]-aIm[3]; t3_im = aIm[1]-aIm[4]; t4_im = aIm[2]+aIm[3]; t5_re = (t1_im-t4_im)*c5_1; t1_im = t1_im+t4_im; aIm[0] = aIm[0]+t1_im; t1_im = aIm[0]-t1_im*c5_5; t4_im = t1_im-t5_re; t1_im = t1_im+t5_re; t5_re = (t3_im+t2_im)*c5_2; t3_im = t5_re-t3_im*c5_4; t2_im = t5_re-t2_im*c5_3; aRe[1] = t1_re+t2_im; aIm[1] = t1_im-t2_re; aRe[2] = t4_re-t3_im; aIm[2] = t4_im+t3_re; aRe[3] = t4_re+t3_im; aIm[3] = t4_im-t3_re; aRe[4] = t1_re-t2_im; aIm[4] = t1_im+t2_re; } /** * length 7 DFT */ template<class Type> inline void FFTPF<Type>::radix7( Type *aRe, Type *aIm ) { t1_re = aRe[1]+aRe[6]; t1_im = aIm[1]+aIm[6]; t2_re = aRe[2]+aRe[5]; t2_im = aIm[2]+aIm[5]; t3_re = aRe[3]+aRe[4]; t3_im = aIm[3]+aIm[4]; t4_re = aRe[6]-aRe[1]; t4_im = aIm[6]-aIm[1]; t5_re = aRe[5]-aRe[2]; t5_im = aIm[5]-aIm[2]; t6_re = aRe[4]-aRe[3]; t6_im = aIm[4]-aIm[3]; t7_re = aRe[0]-Type(0.5*t3_re); t7_im = aIm[0]-Type(0.5*t3_im); t8_re = t1_re-t3_re; t8_im = t1_im-t3_im; t9_re = t2_re-t3_re; t9_im = t2_im-t3_im; m1_re = t7_re+c7_1*t8_re+c7_2*t9_re; m1_im = t7_im+c7_1*t8_im+c7_2*t9_im; m2_re = t7_re+c7_2*t8_re+c7_3*t9_re; m2_im = t7_im+c7_2*t8_im+c7_3*t9_im; m3_re = t7_re+c7_3*t8_re+c7_1*t9_re; m3_im = t7_im+c7_3*t8_im+c7_1*t9_im; m4_re = c7_6*t4_re-c7_4*t5_re+c7_5*t6_re; m4_im = c7_6*t4_im-c7_4*t5_im+c7_5*t6_im; m5_re = c7_5*t4_re-c7_6*t5_re-c7_4*t6_re; m5_im = c7_5*t4_im-c7_6*t5_im-c7_4*t6_im; m6_re = c7_4*t4_re+c7_5*t5_re+c7_6*t6_re; m6_im = c7_4*t4_im+c7_5*t5_im+c7_6*t6_im; aRe[0] = aRe[0]+t1_re+t2_re+t3_re; aIm[0] = aIm[0]+t1_im+t2_im+t3_im; aRe[1] = m1_re-m6_im; aIm[1] = m1_im+m6_re; aRe[2] = m2_re-m5_im; aIm[2] = m2_im+m5_re; aRe[3] = m3_re-m4_im; aIm[3] = m3_im+m4_re; aRe[4] = m3_re+m4_im; aIm[4] = m3_im-m4_re; aRe[5] = m2_re+m5_im; aIm[5] = m2_im-m5_re; aRe[6] = m1_re+m6_im; aIm[6] = m1_im-m6_re; } /** * length 8 DFT */ template<class Type> inline void FFTPF<Type>::radix8( Type *aRe, Type *aIm ) { t1_re = aRe[0]+aRe[4]; t2_re = aRe[0]-aRe[4]; t3_re = aRe[1]-aRe[7]; t4_re = aRe[1]+aRe[7]; t7_re = aRe[2]+aRe[6]; t6_re = aRe[2]-aRe[6]; t5_re = aRe[3]+aRe[5]; t8_re = aRe[3]-aRe[5]; m2_re = t1_re+t7_re; m2_im = t1_re-t7_re; m1_re = t4_re+t5_re; t4_re = (t4_re-t5_re)*tIRT2; aRe[0] = m2_re+m1_re; aRe[4] = m2_re-m1_re; m2_re = t2_re+t4_re; m1_re = t2_re-t4_re; t1_im = t3_re-t8_re; t3_re = (t3_re+t8_re)*tIRT2; t2_im = t3_re+t6_re; t4_im = t3_re-t6_re; t1_re = aIm[0]+aIm[4]; t2_re = aIm[0]-aIm[4]; t3_re = aIm[1]-aIm[7]; t4_re = aIm[1]+aIm[7]; t5_re = aIm[3]+aIm[5]; t6_re = aIm[2]-aIm[6]; t7_re = aIm[2]+aIm[6]; t8_re = aIm[3]-aIm[5]; m1_im = t1_re+t7_re; t1_re = t1_re-t7_re; t7_re = t4_re+t5_re; t4_re = (t4_re-t5_re)*tIRT2; aIm[0] = m1_im+t7_re; aIm[4] = m1_im-t7_re; t7_re = t2_re+t4_re; t2_re = t2_re-t4_re; t4_re = t3_re-t8_re; t3_re = (t3_re+t8_re)*tIRT2; t5_re = t3_re+t6_re; t3_re = t3_re-t6_re; aRe[1] = m2_re+t5_re; aIm[1] = t7_re-t2_im; aRe[2] = m2_im+t4_re; aIm[2] = t1_re-t1_im; aRe[3] = m1_re+t3_re; aIm[3] = t2_re-t4_im; aRe[5] = m1_re-t3_re; aIm[5] = t2_re+t4_im; aRe[6] = m2_im-t4_re; aIm[6] = t1_re+t1_im; aRe[7] = m2_re-t5_re; aIm[7] = t7_re+t2_im; } /** * length 9 DFT */ template<class Type> inline void FFTPF<Type>::radix9( Type *aRe, Type *aIm ) { t1_re = aRe[1]+aRe[8]; t2_re = aRe[1]-aRe[8]; t3_re = aRe[2]+aRe[7]; t4_re = aRe[2]-aRe[7]; t5_re = aRe[3]+aRe[6]; ttmp = aRe[0]+t5_re; t7_re = aRe[4]+aRe[5]; t8_re = aRe[4]-aRe[5]; t8_im = (aRe[6]-aRe[3])*tIRT3; t7_im = aRe[0]+t5_re*c9_5; t5_re = t1_re+t3_re+t7_re; aRe[0] = ttmp+t5_re; t5_im = ttmp+t5_re*c9_5; t3_im = (t7_re-t3_re)*c9_2; t7_re = (t7_re-t1_re)*c9_3; t3_re = (t1_re-t3_re)*c9_4; t1_im = t7_im+t3_im+t3_re; t3_im = t7_im-t3_im-t7_re; t7_im = t7_im+t7_re-t3_re; t6_im = (t4_re-t2_re-t8_re)*tIRT3; t4_im = (t4_re+t8_re)*c9_6; t8_re = (t8_re-t2_re)*c9_7; t2_re = (t2_re+t4_re)*c9_8; t2_im = t8_im+t4_im+t2_re; t4_im = t8_im-t4_im-t8_re; t8_im = t8_im+t8_re-t2_re; t1_re = aIm[1]+aIm[8]; t2_re = aIm[1]-aIm[8]; t3_re = aIm[2]+aIm[7]; t4_re = aIm[2]-aIm[7]; t5_re = aIm[3]+aIm[6]; t6_re = (aIm[6]-aIm[3])*tIRT3; t7_re = aIm[4]+aIm[5]; t8_re = aIm[4]-aIm[5]; ttmp = aIm[0]+t5_re; t9_im = aIm[0]+t5_re*c9_5; t5_re = t1_re+t3_re+t7_re; aIm[0] = ttmp+t5_re; t5_re = ttmp+t5_re*c9_5; ttmp = (t7_re-t3_re)*c9_2; t7_re = (t7_re-t1_re)*c9_3; t3_re = (t1_re-t3_re)*c9_4; t1_re = t9_im+ttmp+t3_re; ttmp = t9_im-ttmp-t7_re; t7_re = t9_im+t7_re-t3_re; t9_re = (t4_re-t2_re-t8_re)*tIRT3; t3_re = (t4_re+t8_re)*c9_6; t8_re = (t8_re-t2_re)*c9_7; t4_re = (t2_re+t4_re)*c9_8; t2_re = t6_re+t3_re+t4_re; t3_re = t6_re-t8_re-t3_re; t8_re = t6_re+t8_re-t4_re; aRe[1] = t1_im-t2_re; aIm[1] = t1_re+t2_im; aRe[2] = t3_im+t3_re; aIm[2] = ttmp-t4_im; aRe[3] = t5_im-t9_re; aIm[3] = t5_re+t6_im; aRe[4] = t7_im-t8_re; aIm[4] = t7_re+t8_im; aRe[5] = t7_im+t8_re; aIm[5] = t7_re-t8_im; aRe[6] = t5_im+t9_re; aIm[6] = t5_re-t6_im; aRe[7] = t3_im-t3_re; aIm[7] = ttmp+t4_im; aRe[8] = t1_im+t2_re; aIm[8] = t1_re-t2_im; } /** * length 10 DFT */ template<class Type> inline void FFTPF<Type>::radix10( Type *aRe, Type *aIm ) { t1_re = aRe[2]+aRe[8]; t2_re = aRe[4]-aRe[6]; t3_re = aRe[2]-aRe[8]; t4_re = aRe[4]+aRe[6]; t5_re = (t1_re-t4_re)*c5_1; t1_re = t1_re+t4_re; m9_re = aRe[0]+t1_re; t1_re = m9_re-t1_re*c5_5; t4_re = t1_re-t5_re; t1_re = t1_re+t5_re; t5_re = (t3_re+t2_re)*c5_2; t3_re = t5_re-t3_re*c5_4; t2_re = t5_re-t2_re*c5_3; t1_im = aIm[2]+aIm[8]; t2_im = aIm[4]-aIm[6]; t3_im = aIm[2]-aIm[8]; t4_im = aIm[4]+aIm[6]; t5_re = (t1_im-t4_im)*c5_1; t1_im = t1_im+t4_im; m9_im = aIm[0]+t1_im; t1_im = m9_im-t1_im*c5_5; t4_im = t1_im-t5_re; t1_im = t1_im+t5_re; t5_re = (t3_im+t2_im)*c5_2; t3_im = t5_re-t3_im*c5_4; t2_im = t5_re-t2_im*c5_3; m1_re = t1_re+t2_im; m1_im = t1_im-t2_re; m2_re = t4_re-t3_im; m2_im = t4_im+t3_re; m3_re = t4_re+t3_im; m3_im = t4_im-t3_re; m4_re = t1_re-t2_im; m4_im = t1_im+t2_re; t1_re = aRe[7]+aRe[3]; t2_re = aRe[9]-aRe[1]; t3_re = aRe[7]-aRe[3]; t4_re = aRe[9]+aRe[1]; t5_re = (t1_re-t4_re)*c5_1; t1_re = t1_re+t4_re; t9_re = aRe[5]+t1_re; t1_re = t9_re-t1_re*c5_5; t4_re = t1_re-t5_re; t1_re = t1_re+t5_re; t5_re = (t3_re+t2_re)*c5_2; t3_re = t5_re-t3_re*c5_4; t2_re = t5_re-t2_re*c5_3; t1_im = aIm[7]+aIm[3]; t2_im = aIm[9]-aIm[1]; t3_im = aIm[7]-aIm[3]; t4_im = aIm[9]+aIm[1]; t5_re = (t1_im-t4_im)*c5_1; t1_im = t1_im+t4_im; t9_im = aIm[5]+t1_im; t1_im = t9_im-t1_im*c5_5; t4_im = t1_im-t5_re; t1_im = t1_im+t5_re; t5_re = (t3_im+t2_im)*c5_2; t3_im = t5_re-t3_im*c5_4; t2_im = t5_re-t2_im*c5_3; m5_re = t1_re+t2_im; m5_im = t1_im-t2_re; m6_re = t4_re-t3_im; m6_im = t4_im+t3_re; m7_re = t4_re+t3_im; m7_im = t4_im-t3_re; m8_re = t1_re-t2_im; m8_im = t1_im+t2_re; aRe[0] = m9_re+t9_re; aIm[0] = m9_im+t9_im; aRe[1] = m1_re-m5_re; aIm[1] = m1_im-m5_im; aRe[2] = m2_re+m6_re; aIm[2] = m2_im+m6_im; aRe[3] = m3_re-m7_re; aIm[3] = m3_im-m7_im; aRe[4] = m4_re+m8_re; aIm[4] = m4_im+m8_im; aRe[5] = m9_re-t9_re; aIm[5] = m9_im-t9_im; aRe[6] = m1_re+m5_re; aIm[6] = m1_im+m5_im; aRe[7] = m2_re-m6_re; aIm[7] = m2_im-m6_im; aRe[8] = m3_re+m7_re; aIm[8] = m3_im+m7_im; aRe[9] = m4_re-m8_re; aIm[9] = m4_im-m8_im; } /** * length 11 DFT */ template<class Type> inline void FFTPF<Type>::radix11( Type *aRe, Type *aIm ) { t1_re = aRe[1]+aRe[10]; t1_im = aIm[1]+aIm[10]; t2_re = aRe[2]+aRe[9]; t2_im = aIm[2]+aIm[9]; t3_re = aRe[3]+aRe[8]; t3_im = aIm[3]+aIm[8]; t4_re = aRe[4]+aRe[7]; t4_im = aIm[4]+aIm[7]; t5_re = aRe[5]+aRe[6]; t5_im = aIm[5]+aIm[6]; t6_re = aRe[10]-aRe[1]; t6_im = aIm[10]-aIm[1]; t7_re = aRe[9]-aRe[2]; t7_im = aIm[9]-aIm[2]; t8_re = aRe[8]-aRe[3]; t8_im = aIm[8]-aIm[3]; t9_re = aRe[7]-aRe[4]; t9_im = aIm[7]-aIm[4]; t10_re = aRe[6]-aRe[5]; t10_im = aIm[6]-aIm[5]; t11_re = aRe[0]-Type(0.5*t5_re); t11_im = aIm[0]-Type(0.5*t5_im); t12_re = t1_re-t5_re; t12_im = t1_im-t5_im; t13_re = t2_re-t5_re; t13_im = t2_im-t5_im; t14_re = t3_re-t5_re; t14_im = t3_im-t5_im; t15_re = t4_re-t5_re; t15_im = t4_im-t5_im; m1_re = t11_re+c11_1*t12_re+c11_2*t13_re+c11_3*t14_re+c11_4*t15_re; m1_im = t11_im+c11_1*t12_im+c11_2*t13_im+c11_3*t14_im+c11_4*t15_im; m2_re = t11_re+c11_2*t12_re+c11_4*t13_re+c11_5*t14_re+c11_3*t15_re; m2_im = t11_im+c11_2*t12_im+c11_4*t13_im+c11_5*t14_im+c11_3*t15_im; m3_re = t11_re+c11_3*t12_re+c11_5*t13_re+c11_2*t14_re+c11_1*t15_re; m3_im = t11_im+c11_3*t12_im+c11_5*t13_im+c11_2*t14_im+c11_1*t15_im; m4_re = t11_re+c11_4*t12_re+c11_3*t13_re+c11_1*t14_re+c11_5*t15_re; m4_im = t11_im+c11_4*t12_im+c11_3*t13_im+c11_1*t14_im+c11_5*t15_im; m5_re = t11_re+c11_5*t12_re+c11_1*t13_re+c11_4*t14_re+c11_2*t15_re; m5_im = t11_im+c11_5*t12_im+c11_1*t13_im+c11_4*t14_im+c11_2*t15_im; m6_re = c11_10*t6_re-c11_6*t7_re+c11_9*t8_re-c11_7*t9_re+c11_8*t10_re; m6_im = c11_10*t6_im-c11_6*t7_im+c11_9*t8_im-c11_7*t9_im+c11_8*t10_im; m7_re = c11_9*t6_re-c11_8*t7_re+c11_6*t8_re+c11_10*t9_re-c11_7*t10_re; m7_im = c11_9*t6_im-c11_8*t7_im+c11_6*t8_im+c11_10*t9_im-c11_7*t10_im; m8_re = c11_8*t6_re-c11_10*t7_re-c11_7*t8_re+c11_6*t9_re+c11_9*t10_re; m8_im = c11_8*t6_im-c11_10*t7_im-c11_7*t8_im+c11_6*t9_im+c11_9*t10_im; m9_re = c11_7*t6_re+c11_9*t7_re-c11_10*t8_re-c11_8*t9_re-c11_6*t10_re; m9_im = c11_7*t6_im+c11_9*t7_im-c11_10*t8_im-c11_8*t9_im-c11_6*t10_im; m10_re = c11_6*t6_re+c11_7*t7_re+c11_8*t8_re+c11_9*t9_re+c11_10*t10_re; m10_im = c11_6*t6_im+c11_7*t7_im+c11_8*t8_im+c11_9*t9_im+c11_10*t10_im; aRe[0] = aRe[0]+t1_re+t2_re+t3_re+t4_re+t5_re; aIm[0] = aIm[0]+t1_im+t2_im+t3_im+t4_im+t5_im; aRe[1] = m1_re-m10_im; aIm[1] = m1_im+m10_re; aRe[2] = m2_re-m9_im; aIm[2] = m2_im+m9_re; aRe[3] = m3_re-m8_im; aIm[3] = m3_im+m8_re; aRe[4] = m4_re-m7_im; aIm[4] = m4_im+m7_re; aRe[5] = m5_re-m6_im; aIm[5] = m5_im+m6_re; aRe[6] = m5_re+m6_im; aIm[6] = m5_im-m6_re; aRe[7] = m4_re+m7_im; aIm[7] = m4_im-m7_re; aRe[8] = m3_re+m8_im; aIm[8] = m3_im-m8_re; aRe[9] = m2_re+m9_im; aIm[9] = m2_im-m9_re; aRe[10] = m1_re+m10_im; aIm[10] = m1_im-m10_re; } /** * length 13 DFT */ template<class Type> inline void FFTPF<Type>::radix13( Type *aRe, Type *aIm ) { t1_re = aRe[1]+aRe[12]; t1_im = aIm[1]+aIm[12]; t2_re = aRe[2]+aRe[11]; t2_im = aIm[2]+aIm[11]; t3_re = aRe[3]+aRe[10]; t3_im = aIm[3]+aIm[10]; t4_re = aRe[4]+aRe[9]; t4_im = aIm[4]+aIm[9]; t5_re = aRe[5]+aRe[8]; t5_im = aIm[5]+aIm[8]; t6_re = aRe[6]+aRe[7]; t6_im = aIm[6]+aIm[7]; t7_re = aRe[12]-aRe[1]; t7_im = aIm[12]-aIm[1]; t8_re = aRe[11]-aRe[2]; t8_im = aIm[11]-aIm[2]; t9_re = aRe[10]-aRe[3]; t9_im = aIm[10]-aIm[3]; t10_re = aRe[9]-aRe[4]; t10_im = aIm[9]-aIm[4]; t11_re = aRe[8]-aRe[5]; t11_im = aIm[8]-aIm[5]; t12_re = aRe[7]-aRe[6]; t12_im = aIm[7]-aIm[6]; t13_re = aRe[0]-Type(0.5*t6_re); t13_im = aIm[0]-Type(0.5*t6_im); t14_re = t1_re-t6_re; t14_im = t1_im-t6_im; t15_re = t2_re-t6_re; t15_im = t2_im-t6_im; t16_re = t3_re-t6_re; t16_im = t3_im-t6_im; t17_re = t4_re-t6_re; t17_im = t4_im-t6_im; t18_re = t5_re-t6_re; t18_im = t5_im-t6_im; m1_re = t13_re + c13_1*t14_re + c13_2*t15_re + c13_3*t16_re + c13_4*t17_re + c13_5*t18_re; m1_im = t13_im + c13_1*t14_im + c13_2*t15_im + c13_3*t16_im + c13_4*t17_im + c13_5*t18_im; m2_re = t13_re + c13_2*t14_re + c13_4*t15_re + c13_6*t16_re + c13_5*t17_re + c13_3*t18_re; m2_im = t13_im + c13_2*t14_im + c13_4*t15_im + c13_6*t16_im + c13_5*t17_im + c13_3*t18_im; m3_re = t13_re + c13_3*t14_re + c13_6*t15_re + c13_4*t16_re + c13_1*t17_re + c13_2*t18_re; m3_im = t13_im + c13_3*t14_im + c13_6*t15_im + c13_4*t16_im + c13_1*t17_im + c13_2*t18_im; m4_re = t13_re + c13_4*t14_re + c13_5*t15_re + c13_1*t16_re + c13_3*t17_re + c13_6*t18_re; m4_im = t13_im + c13_4*t14_im + c13_5*t15_im + c13_1*t16_im + c13_3*t17_im + c13_6*t18_im; m5_re = t13_re + c13_5*t14_re + c13_3*t15_re + c13_2*t16_re + c13_6*t17_re + c13_1*t18_re; m5_im = t13_im + c13_5*t14_im + c13_3*t15_im + c13_2*t16_im + c13_6*t17_im + c13_1*t18_im; m6_re = t13_re + c13_6*t14_re + c13_1*t15_re + c13_5*t16_re + c13_2*t17_re + c13_4*t18_re; m6_im = t13_im + c13_6*t14_im + c13_1*t15_im + c13_5*t16_im + c13_2*t17_im + c13_4*t18_im; m7_re = c13_12*t7_re - c13_7*t8_re + c13_11*t9_re - c13_8*t10_re + c13_10*t11_re - c13_9*t12_re; m7_im = c13_12*t7_im - c13_7*t8_im + c13_11*t9_im - c13_8*t10_im + c13_10*t11_im - c13_9*t12_im; m8_re = c13_11*t7_re - c13_9*t8_re + c13_8*t9_re - c13_12*t10_re - c13_7*t11_re + c13_10*t12_re; m8_im = c13_11*t7_im - c13_9*t8_im + c13_8*t9_im - c13_12*t10_im - c13_7*t11_im + c13_10*t12_im; m9_re = c13_10*t7_re - c13_11*t8_re - c13_7*t9_re + c13_9*t10_re - c13_12*t11_re - c13_8*t12_re; m9_im = c13_10*t7_im - c13_11*t8_im - c13_7*t9_im + c13_9*t10_im - c13_12*t11_im - c13_8*t12_im; m10_re = c13_9*t7_re + c13_12*t8_re - c13_10*t9_re - c13_7*t10_re + c13_8*t11_re + c13_11*t12_re; m10_im = c13_9*t7_im + c13_12*t8_im - c13_10*t9_im - c13_7*t10_im + c13_8*t11_im + c13_11*t12_im; m11_re = c13_8*t7_re + c13_10*t8_re + c13_12*t9_re - c13_11*t10_re - c13_9*t11_re - c13_7*t12_re; m11_im = c13_8*t7_im + c13_10*t8_im + c13_12*t9_im - c13_11*t10_im - c13_9*t11_im - c13_7*t12_im; m12_re = c13_7*t7_re + c13_8*t8_re + c13_9*t9_re + c13_10*t10_re + c13_11*t11_re + c13_12*t12_re; m12_im = c13_7*t7_im + c13_8*t8_im + c13_9*t9_im + c13_10*t10_im + c13_11*t11_im + c13_12*t12_im; aRe[0] = aRe[0]+t1_re+t2_re+t3_re+t4_re+t5_re+t6_re; aIm[0] = aIm[0]+t1_im+t2_im+t3_im+t4_im+t5_im+t6_im; aRe[1] = m1_re-m12_im; aIm[1] = m1_im+m12_re; aRe[2] = m2_re-m11_im; aIm[2] = m2_im+m11_re; aRe[3] = m3_re-m10_im; aIm[3] = m3_im+m10_re; aRe[4] = m4_re-m9_im; aIm[4] = m4_im+m9_re; aRe[5] = m5_re-m8_im; aIm[5] = m5_im+m8_re; aRe[6] = m6_re-m7_im; aIm[6] = m6_im+m7_re; aRe[7] = m6_re+m7_im; aIm[7] = m6_im-m7_re; aRe[8] = m5_re+m8_im; aIm[8] = m5_im-m8_re; aRe[9] = m4_re+m9_im; aIm[9] = m4_im-m9_re; aRe[10] = m3_re+m10_im; aIm[10] = m3_im-m10_re; aRe[11] = m2_re+m11_im; aIm[11] = m2_im-m11_re; aRe[12] = m1_re+m12_im; aIm[12] = m1_im-m12_re; } /** * length 16 DFT */ template<class Type> inline void FFTPF<Type>::radix16( Type *aRe, Type *aIm ) { t1_re = aRe[0]+aRe[8]; t2_re = aRe[0]-aRe[8]; t3_re = aRe[1]+aRe[9]; t4_re = aRe[1]-aRe[9]; t5_re = aRe[2]+aRe[10]; t6_re = aRe[2]-aRe[10]; t7_re = aRe[3]+aRe[11]; t8_re = aRe[3]-aRe[11]; t9_re = aRe[4]+aRe[12]; t10_re = aRe[4]-aRe[12]; t11_re = aRe[5]+aRe[13]; t12_re = aRe[5]-aRe[13]; t13_re = aRe[6]+aRe[14]; t14_re = aRe[6]-aRe[14]; t15_re = aRe[7]+aRe[15]; t16_re = aRe[7]-aRe[15]; t1_im = t1_re+t9_re; t2_im = t1_re-t9_re; t3_im = t3_re+t11_re; t4_im = t3_re-t11_re; t5_im = t5_re+t13_re; t6_im = t5_re-t13_re; t7_im = t7_re+t15_re; t8_im = t7_re-t15_re; t1_re = t1_im+t5_im; t3_re = t1_im-t5_im; t5_re = t3_im+t7_im; t7_re = t3_im-t7_im; aRe[0] = t1_re+t5_re; aRe[8] = t1_re-t5_re; t1_im = tIRT2*(t4_im+t8_im); t5_im = tIRT2*(t4_im-t8_im); t9_re = t2_im+t5_im; t11_re = t2_im-t5_im; t13_re = t6_im+t1_im; t15_re = t6_im-t1_im; t1_im = t4_re+t16_re; t2_im = t4_re-t16_re; t3_im = tIRT2*(t6_re+t14_re); t4_im = tIRT2*(t6_re-t14_re); t5_im = t8_re+t12_re; t6_im = t8_re-t12_re; t7_im = c16_2*(t2_im-t6_im); t2_im = c16_3*t2_im-t7_im; t6_im = c16_4*t6_im-t7_im; t7_im = t2_re+t4_im; t8_im = t2_re-t4_im; t2_re = t7_im+t2_im; t4_re = t7_im-t2_im; t6_re = t8_im+t6_im; t8_re = t8_im-t6_im; t7_im = c16_5*(t1_im+t5_im); t2_im = t7_im-c16_4*t1_im; t4_im = t7_im-c16_3*t5_im; t6_im = t10_re+t3_im; t8_im = t10_re-t3_im; t10_re = t6_im+t2_im; t12_re = t6_im-t2_im; t14_re = t8_im+t4_im; t16_re = t8_im-t4_im; t1_re = aIm[0]+aIm[8]; t9_im = aIm[0]-aIm[8]; t10_im = aIm[1]+aIm[9]; t11_im = aIm[1]-aIm[9]; t5_re = aIm[2]+aIm[10]; t12_im = aIm[2]-aIm[10]; t13_im = aIm[3]+aIm[11]; t14_im = aIm[3]-aIm[11]; t15_im = aIm[4]+aIm[12]; t16_im = aIm[4]-aIm[12]; t17_im = aIm[5]+aIm[13]; t18_im = aIm[5]-aIm[13]; t19_im = aIm[6]+aIm[14]; t20_im = aIm[6]-aIm[14]; t21_im = aIm[7]+aIm[15]; t22_im = aIm[7]-aIm[15]; t1_im = t1_re+t15_im; t2_im = t1_re-t15_im; t3_im = t10_im+t17_im; t4_im = t10_im-t17_im; t5_im = t5_re+t19_im; t6_im = t5_re-t19_im; t7_im = t13_im+t21_im; t8_im = t13_im-t21_im; t1_re = t1_im+t5_im; t10_im = t1_im-t5_im; t5_re = t3_im+t7_im; t13_im = t3_im-t7_im; aIm[0] = t1_re+t5_re; aIm[8] = t1_re-t5_re; aRe[4] = t3_re+t13_im; aIm[4] = t10_im-t7_re; aRe[12] = t3_re-t13_im; aIm[12] = t10_im+t7_re; t1_im = tIRT2*(t4_im+t8_im); t5_im = tIRT2*(t4_im-t8_im); t15_im = t2_im+t5_im; t17_im = t2_im-t5_im; t19_im = t6_im+t1_im; t21_im = t6_im-t1_im; t1_im = t11_im+t22_im; t2_im = t11_im-t22_im; t3_im = tIRT2*(t12_im+t20_im); t4_im = tIRT2*(t12_im-t20_im); t5_im = t14_im+t18_im; t6_im = t14_im-t18_im; t7_im = c16_2*(t2_im-t6_im); t2_im = c16_3*t2_im-t7_im; t6_im = c16_4*t6_im-t7_im; t7_im = t9_im+t4_im; t8_im = t9_im-t4_im; t9_im = t7_im+t2_im; t11_im = t7_im-t2_im; t12_im = t8_im+t6_im; t14_im = t8_im-t6_im; t7_im = c16_5*(t1_im+t5_im); t2_im = t7_im-c16_4*t1_im; t4_im = t7_im-c16_3*t5_im; t6_im = t16_im+t3_im; t8_im = t16_im-t3_im; t16_im = t6_im+t2_im; t18_im = t6_im-t2_im; t20_im = t8_im+t4_im; t22_im = t8_im-t4_im; aRe[1] = t2_re+t16_im; aIm[1] = t9_im-t10_re; aRe[2] = t9_re+t19_im; aIm[2] = t15_im-t13_re; aRe[3] = t8_re-t22_im; aIm[3] = t14_im+t16_re; aRe[5] = t6_re+t20_im; aIm[5] = t12_im-t14_re; aRe[6] = t11_re-t21_im; aIm[6] = t17_im+t15_re; aRe[7] = t4_re-t18_im; aIm[7] = t11_im+t12_re; aRe[9] = t4_re+t18_im; aIm[9] = t11_im-t12_re; aRe[10] = t11_re+t21_im; aIm[10] = t17_im-t15_re; aRe[11] = t6_re-t20_im; aIm[11] = t12_im+t14_re; aRe[13] = t8_re+t22_im; aIm[13] = t14_im-t16_re; aRe[14] = t9_re-t19_im; aIm[14] = t15_im+t13_re; aRe[15] = t2_re-t16_im; aIm[15] = t9_im+t10_re; } /** * other length DFT */ template<class Type> inline void FFTPF<Type>::radixOther( int radix ) { Type rere, reim, imre, imim; int i, j, k, n, max; n = radix; max = (n+1)/2; for( j=1; j<max; ++j ) { pfvRe[j] = pfzRe[j]+pfzRe[n-j]; pfvIm[j] = pfzIm[j]-pfzIm[n-j]; pfwRe[j] = pfzRe[j]-pfzRe[n-j]; pfwIm[j] = pfzIm[j]+pfzIm[n-j]; } for( j=1; j<max; ++j ) { pfzRe[j] = pfzRe[0]; pfzIm[j] = pfzIm[0]; pfzRe[n-j] = pfzRe[0]; pfzIm[n-j] = pfzIm[0]; k = j; for( i=1; i<max; ++i ) { rere = pftgRe[k]*pfvRe[i]; imim = pftgIm[k]*pfvIm[i]; reim = pftgRe[k]*pfwIm[i]; imre = pftgIm[k]*pfwRe[i]; pfzRe[n-j] += rere+imim; pfzIm[n-j] += reim-imre; pfzRe[j] += rere-imim; pfzIm[j] += reim+imre; k = k+j; if( k >= n ) k = k-n; } } for( j=1; j<max; ++j ) { pfzRe[0] = pfzRe[0]+pfvRe[j]; pfzIm[0] = pfzIm[0]+pfwIm[j]; } } /** * twiddle multiplications and DFT's for one stage. */ template<class Type> void FFTPF<Type>::twiddleFFT( int sofarRadix, int radix, int remainRadix, Vector< complex<Type> > &yn ) { Type cosw, sinw; initTrig( radix ); omega = 2*tPI/(Type)(sofarRadix*radix); cosw = Type(cos(omega)); sinw = -Type(sin(omega)); twRe = 1; twIim = 0; dataOffset = 0; groupOffset = dataOffset; adr = groupOffset; for( dataNo=0; dataNo<sofarRadix; ++dataNo ) { if( sofarRadix > 1 ) { pftwRe[0] = 1; pftwIm[0] = 0; pftwRe[1] = twRe; pftwIm[1] = twIim; for( twNo=2; twNo<radix; ++twNo ) { pftwRe[twNo] = twRe*pftwRe[twNo-1]-twIim*pftwIm[twNo-1]; pftwIm[twNo] = twIim*pftwRe[twNo-1]+twRe*pftwIm[twNo-1]; } ttmp = cosw*twRe-sinw*twIim; twIim = sinw*twRe+cosw*twIim; twRe = ttmp; } for( groupNo=0; groupNo<remainRadix; ++groupNo ) { if( (sofarRadix>1) && (dataNo>0) ) { pfzRe[0] = yn[adr].real(); pfzIm[0] = yn[adr].imag(); blockNo = 1; do { adr += sofarRadix; pfzRe[blockNo] = pftwRe[blockNo]*yn[adr].real() - pftwIm[blockNo]*yn[adr].imag(); pfzIm[blockNo] = pftwRe[blockNo]*yn[adr].imag() + pftwIm[blockNo]*yn[adr].real(); blockNo++; } while( blockNo < radix ); } else for( blockNo=0; blockNo<radix; ++blockNo ) { pfzRe[blockNo] = yn[adr].real(); pfzIm[blockNo] = yn[adr].imag(); adr = adr+sofarRadix; } switch( radix ) { case 2 : radix2( pfzRe, pfzIm ); break; case 3 : radix3( pfzRe, pfzIm ); break; case 4 : radix4( pfzRe, pfzIm ); break; case 5 : radix5( pfzRe, pfzIm ); break; case 7 : radix7( pfzRe, pfzIm ); break; case 8 : radix8( pfzRe, pfzIm ); break; case 9 : radix9( pfzRe, pfzIm ); break; case 10 : radix10( pfzRe, pfzIm ); break; case 11 : radix11( pfzRe, pfzIm ); break; case 13 : radix13( pfzRe, pfzIm ); break; case 16 : radix16( pfzRe, pfzIm ); break; default : radixOther( radix ); break; } adr = groupOffset; for( blockNo=0; blockNo<radix; ++blockNo ) { yn[adr] = complex<Type>( pfzRe[blockNo], pfzIm[blockNo] ); adr += sofarRadix; } groupOffset += sofarRadix*radix; adr = groupOffset; } dataOffset = dataOffset+1; groupOffset = dataOffset; adr = groupOffset; } } /** * forward transform */ template<class Type> void FFTPF<Type>::fft( const Vector<Type> &xn, Vector< complex<Type> > &Xk ) { int n = xn.size(); if( n != mNOldSize ) primeSetup( n ); permute( xn, Xk ); for( int i=1; i<=mNFactor; ++i ) twiddleFFT( mSofarRadix[i], mActualRadix[i], mRemainRadix[i], Xk ); } template<class Type> void FFTPF<Type>::fft( const Vector< complex<Type> > &xn, Vector< complex<Type> > &Xk ) { int n = xn.size(); if( n != mNOldSize ) primeSetup( n ); permute( xn, Xk, true ); for( int i=1; i<=mNFactor; ++i ) twiddleFFT( mSofarRadix[i], mActualRadix[i], mRemainRadix[i], Xk ); } /** * inverse transform */ template<class Type> void FFTPF<Type>::ifft( const Vector< complex<Type> > &Xk, Vector<Type> &xn ) { int n = xn.size(); if( n != mNOldSize ) primeSetup( n ); Vector< complex<Type> > Yk(n); permute( Xk, Yk, false ); for( int i=1; i<=mNFactor; ++i ) twiddleFFT( mSofarRadix[i], mActualRadix[i], mRemainRadix[i], Yk ); for( int i=0; i<n; ++i ) xn[i] = Yk[i].real() / Type(n); } template<class Type> void FFTPF<Type>::ifft( const Vector< complex<Type> > &Xk, Vector< complex<Type> > &xn ) { int n = xn.size(); if( n != mNOldSize ) primeSetup( n ); permute( Xk, xn, false ); for( int i=1; i<=mNFactor; ++i ) twiddleFFT( mSofarRadix[i], mActualRadix[i], mRemainRadix[i], xn ); for( int i=0; i<n; ++i ) xn[i] = conj(xn[i]) / Type(n); }
测试代码:
/***************************************************************************** * fftpf_test.cpp * * Prime factor FFT test. * * Zhang Ming, 2010-09, Xi'an Jiaotong University. *****************************************************************************/ #include <iostream> #include <cstdlib> #include <vectormath.h> #include <fftpf.h> using namespace std; using namespace splab; typedef double Type; const int MINLEN = 101; const int MAXLEN = 1000; const int STEP = 10; int main() { Vector< complex<Type> > sn, Rk, Sk, xn; Vector<Type> rn, tn; FFTPF<Type> Fourier; cout << "forward transform: Sk = fft(sn) ( complex to complex )." << endl; cout << "inverse transform: xn = ifft(Sk) ( complex to complex )." << endl << endl; for( int len=MINLEN; len<MAXLEN; len+=STEP ) { sn.resize(len); Sk.resize(len); xn.resize(len); for( int i=0; i<len; ++i ) sn[i] = complex<Type>( rand()%10, rand()%10 ); Fourier.fft( sn, Sk ); Fourier.ifft( Sk, xn ); cout << "N = " << len << "\t\t" << "mean(abs((sn-xn)) = " << sum(abs(sn-xn))/len << endl; } cout << endl << endl; cout << "forward transform: Rk = fft(rn) ( real to complex )." << endl; cout << "inverse transform: tn = ifft(Rk) ( complex to real )." << endl << endl;; for( int len=MINLEN; len<MAXLEN; len+=STEP ) { rn.resize(len); Rk.resize(len); tn.resize(len); for( int i=0; i<len; ++i ) rn[i] = rand()%10; Fourier.fft( rn, Rk ); Fourier.ifft( Rk, tn ); cout << "N = " << len << "\t\t" << "mean(abs((rn-tn)) = " << sum(abs(sn-xn))/len << endl; } cout << endl; return 0; }
运行结果:
forward transform: Sk = fft(sn) ( complex to complex ). inverse transform: xn = ifft(Sk) ( complex to complex ). N = 101 mean(abs((sn-xn)) = 9.56796e-015 N = 111 mean(abs((sn-xn)) = 6.02908e-015 N = 121 mean(abs((sn-xn)) = 3.68512e-015 N = 131 mean(abs((sn-xn)) = 2.0032e-014 N = 141 mean(abs((sn-xn)) = 8.53139e-015 N = 151 mean(abs((sn-xn)) = 1.32487e-014 N = 161 mean(abs((sn-xn)) = 6.01949e-015 N = 171 mean(abs((sn-xn)) = 9.78613e-015 N = 181 mean(abs((sn-xn)) = 4.90428e-015 N = 191 mean(abs((sn-xn)) = 1.28095e-014 N = 201 mean(abs((sn-xn)) = 7.66037e-015 N = 211 mean(abs((sn-xn)) = 2.64879e-014 N = 221 mean(abs((sn-xn)) = 1.23744e-014 N = 231 mean(abs((sn-xn)) = 1.52028e-014 N = 241 mean(abs((sn-xn)) = 1.48443e-014 N = 251 mean(abs((sn-xn)) = 2.23183e-014 N = 261 mean(abs((sn-xn)) = 1.19937e-014 N = 271 mean(abs((sn-xn)) = 1.54789e-014 N = 281 mean(abs((sn-xn)) = 6.37825e-014 N = 291 mean(abs((sn-xn)) = 6.81017e-015 N = 301 mean(abs((sn-xn)) = 3.67519e-014 N = 311 mean(abs((sn-xn)) = 7.74232e-014 N = 321 mean(abs((sn-xn)) = 2.06363e-014 N = 331 mean(abs((sn-xn)) = 2.6944e-014 N = 341 mean(abs((sn-xn)) = 2.32377e-014 N = 351 mean(abs((sn-xn)) = 1.81853e-014 N = 361 mean(abs((sn-xn)) = 2.70795e-014 N = 371 mean(abs((sn-xn)) = 8.89281e-015 N = 381 mean(abs((sn-xn)) = 1.1903e-014 N = 391 mean(abs((sn-xn)) = 9.39787e-015 N = 401 mean(abs((sn-xn)) = 6.26719e-014 N = 411 mean(abs((sn-xn)) = 1.56459e-014 N = 421 mean(abs((sn-xn)) = 5.49224e-014 N = 431 mean(abs((sn-xn)) = 7.13155e-014 N = 441 mean(abs((sn-xn)) = 7.9457e-015 N = 451 mean(abs((sn-xn)) = 2.90133e-014 N = 461 mean(abs((sn-xn)) = 5.84939e-014 N = 471 mean(abs((sn-xn)) = 4.29465e-014 N = 481 mean(abs((sn-xn)) = 4.52387e-014 N = 491 mean(abs((sn-xn)) = 1.10306e-013 N = 501 mean(abs((sn-xn)) = 3.37587e-014 N = 511 mean(abs((sn-xn)) = 4.57228e-014 N = 521 mean(abs((sn-xn)) = 1.11653e-013 N = 531 mean(abs((sn-xn)) = 5.84668e-014 N = 541 mean(abs((sn-xn)) = 1.27624e-013 N = 551 mean(abs((sn-xn)) = 3.54317e-014 N = 561 mean(abs((sn-xn)) = 5.29495e-014 N = 571 mean(abs((sn-xn)) = 3.74233e-014 N = 581 mean(abs((sn-xn)) = 3.8153e-014 N = 591 mean(abs((sn-xn)) = 3.24913e-014 N = 601 mean(abs((sn-xn)) = 1.32896e-013 N = 611 mean(abs((sn-xn)) = 2.92566e-014 N = 621 mean(abs((sn-xn)) = 4.35837e-014 N = 631 mean(abs((sn-xn)) = 1.35408e-013 N = 641 mean(abs((sn-xn)) = 1.35158e-013 N = 651 mean(abs((sn-xn)) = 1.38349e-014 N = 661 mean(abs((sn-xn)) = 1.30397e-013 N = 671 mean(abs((sn-xn)) = 2.18791e-014 N = 681 mean(abs((sn-xn)) = 7.84698e-014 N = 691 mean(abs((sn-xn)) = 1.38373e-013 N = 701 mean(abs((sn-xn)) = 1.66637e-013 N = 711 mean(abs((sn-xn)) = 2.22414e-014 N = 721 mean(abs((sn-xn)) = 3.17155e-014 N = 731 mean(abs((sn-xn)) = 4.88291e-014 N = 741 mean(abs((sn-xn)) = 6.79333e-014 N = 751 mean(abs((sn-xn)) = 6.76077e-014 N = 761 mean(abs((sn-xn)) = 1.4751e-013 N = 771 mean(abs((sn-xn)) = 3.765e-014 N = 781 mean(abs((sn-xn)) = 4.03454e-014 N = 791 mean(abs((sn-xn)) = 3.66948e-014 N = 801 mean(abs((sn-xn)) = 8.22744e-014 N = 811 mean(abs((sn-xn)) = 1.90965e-014 N = 821 mean(abs((sn-xn)) = 1.775e-013 N = 831 mean(abs((sn-xn)) = 1.52596e-014 N = 841 mean(abs((sn-xn)) = 9.06967e-014 N = 851 mean(abs((sn-xn)) = 8.87579e-014 N = 861 mean(abs((sn-xn)) = 6.5877e-015 N = 871 mean(abs((sn-xn)) = 2.90611e-014 N = 881 mean(abs((sn-xn)) = 1.11084e-013 N = 891 mean(abs((sn-xn)) = 2.36818e-014 N = 901 mean(abs((sn-xn)) = 8.32884e-014 N = 911 mean(abs((sn-xn)) = 1.32497e-013 N = 921 mean(abs((sn-xn)) = 5.2289e-014 N = 931 mean(abs((sn-xn)) = 6.6602e-014 N = 941 mean(abs((sn-xn)) = 4.79529e-014 N = 951 mean(abs((sn-xn)) = 5.12486e-014 N = 961 mean(abs((sn-xn)) = 1.3465e-013 N = 971 mean(abs((sn-xn)) = 1.80164e-013 N = 981 mean(abs((sn-xn)) = 8.43108e-014 N = 991 mean(abs((sn-xn)) = 4.85968e-014 forward transform: Rk = fft(rn) ( real to complex ). inverse transform: tn = ifft(Rk) ( complex to real ). N = 101 mean(abs((rn-tn)) = 4.76826e-013 N = 111 mean(abs((rn-tn)) = 4.33869e-013 N = 121 mean(abs((rn-tn)) = 3.98012e-013 N = 131 mean(abs((rn-tn)) = 3.67629e-013 N = 141 mean(abs((rn-tn)) = 3.41556e-013 N = 151 mean(abs((rn-tn)) = 3.18937e-013 N = 161 mean(abs((rn-tn)) = 2.99127e-013 N = 171 mean(abs((rn-tn)) = 2.81634e-013 N = 181 mean(abs((rn-tn)) = 2.66074e-013 N = 191 mean(abs((rn-tn)) = 2.52144e-013 N = 201 mean(abs((rn-tn)) = 2.39599e-013 N = 211 mean(abs((rn-tn)) = 2.28244e-013 N = 221 mean(abs((rn-tn)) = 2.17916e-013 N = 231 mean(abs((rn-tn)) = 2.08482e-013 N = 241 mean(abs((rn-tn)) = 1.99832e-013 N = 251 mean(abs((rn-tn)) = 1.9187e-013 N = 261 mean(abs((rn-tn)) = 1.84519e-013 N = 271 mean(abs((rn-tn)) = 1.7771e-013 N = 281 mean(abs((rn-tn)) = 1.71386e-013 N = 291 mean(abs((rn-tn)) = 1.65496e-013 N = 301 mean(abs((rn-tn)) = 1.59998e-013 N = 311 mean(abs((rn-tn)) = 1.54853e-013 N = 321 mean(abs((rn-tn)) = 1.50029e-013 N = 331 mean(abs((rn-tn)) = 1.45497e-013 N = 341 mean(abs((rn-tn)) = 1.4123e-013 N = 351 mean(abs((rn-tn)) = 1.37206e-013 N = 361 mean(abs((rn-tn)) = 1.33406e-013 N = 371 mean(abs((rn-tn)) = 1.2981e-013 N = 381 mean(abs((rn-tn)) = 1.26403e-013 N = 391 mean(abs((rn-tn)) = 1.2317e-013 N = 401 mean(abs((rn-tn)) = 1.20098e-013 N = 411 mean(abs((rn-tn)) = 1.17176e-013 N = 421 mean(abs((rn-tn)) = 1.14393e-013 N = 431 mean(abs((rn-tn)) = 1.11739e-013 N = 441 mean(abs((rn-tn)) = 1.09205e-013 N = 451 mean(abs((rn-tn)) = 1.06784e-013 N = 461 mean(abs((rn-tn)) = 1.04467e-013 N = 471 mean(abs((rn-tn)) = 1.02249e-013 N = 481 mean(abs((rn-tn)) = 1.00124e-013 N = 491 mean(abs((rn-tn)) = 9.80844e-014 N = 501 mean(abs((rn-tn)) = 9.61266e-014 N = 511 mean(abs((rn-tn)) = 9.42455e-014 N = 521 mean(abs((rn-tn)) = 9.24365e-014 N = 531 mean(abs((rn-tn)) = 9.06957e-014 N = 541 mean(abs((rn-tn)) = 8.90193e-014 N = 551 mean(abs((rn-tn)) = 8.74037e-014 N = 561 mean(abs((rn-tn)) = 8.58457e-014 N = 571 mean(abs((rn-tn)) = 8.43423e-014 N = 581 mean(abs((rn-tn)) = 8.28906e-014 N = 591 mean(abs((rn-tn)) = 8.1488e-014 N = 601 mean(abs((rn-tn)) = 8.01322e-014 N = 611 mean(abs((rn-tn)) = 7.88207e-014 N = 621 mean(abs((rn-tn)) = 7.75514e-014 N = 631 mean(abs((rn-tn)) = 7.63224e-014 N = 641 mean(abs((rn-tn)) = 7.51317e-014 N = 651 mean(abs((rn-tn)) = 7.39776e-014 N = 661 mean(abs((rn-tn)) = 7.28584e-014 N = 671 mean(abs((rn-tn)) = 7.17726e-014 N = 681 mean(abs((rn-tn)) = 7.07187e-014 N = 691 mean(abs((rn-tn)) = 6.96953e-014 N = 701 mean(abs((rn-tn)) = 6.8701e-014 N = 711 mean(abs((rn-tn)) = 6.77348e-014 N = 721 mean(abs((rn-tn)) = 6.67953e-014 N = 731 mean(abs((rn-tn)) = 6.58816e-014 N = 741 mean(abs((rn-tn)) = 6.49925e-014 N = 751 mean(abs((rn-tn)) = 6.41271e-014 N = 761 mean(abs((rn-tn)) = 6.32844e-014 N = 771 mean(abs((rn-tn)) = 6.24636e-014 N = 781 mean(abs((rn-tn)) = 6.16638e-014 N = 791 mean(abs((rn-tn)) = 6.08842e-014 N = 801 mean(abs((rn-tn)) = 6.01241e-014 N = 811 mean(abs((rn-tn)) = 5.93828e-014 N = 821 mean(abs((rn-tn)) = 5.86595e-014 N = 831 mean(abs((rn-tn)) = 5.79536e-014 N = 841 mean(abs((rn-tn)) = 5.72645e-014 N = 851 mean(abs((rn-tn)) = 5.65916e-014 N = 861 mean(abs((rn-tn)) = 5.59343e-014 N = 871 mean(abs((rn-tn)) = 5.52921e-014 N = 881 mean(abs((rn-tn)) = 5.46645e-014 N = 891 mean(abs((rn-tn)) = 5.4051e-014 N = 901 mean(abs((rn-tn)) = 5.34511e-014 N = 911 mean(abs((rn-tn)) = 5.28644e-014 N = 921 mean(abs((rn-tn)) = 5.22904e-014 N = 931 mean(abs((rn-tn)) = 5.17287e-014 N = 941 mean(abs((rn-tn)) = 5.1179e-014 N = 951 mean(abs((rn-tn)) = 5.06408e-014 N = 961 mean(abs((rn-tn)) = 5.01139e-014 N = 971 mean(abs((rn-tn)) = 4.95978e-014 N = 981 mean(abs((rn-tn)) = 4.90922e-014 N = 991 mean(abs((rn-tn)) = 4.85968e-014 Process returned 0 (0x0) execution time : 0.686 s Press any key to continue.