/*************************************************************************** * rtfft.h * * Mon Feb 22 22:14:17 2010 * Copyright 2010 Ralph Tandetzky * * This header file defines some useful FFT algorithms for C++. * It is not meant to contain the fastest FFT algorithms ever, * but is rather written for educational purposes. However, the * speed is quite acceptable. * * * The following functions are contained in this file: * * DFT(In, Out, N) calculates Discrete Fourier Transform. * FFT(In, Out, N) calculates DFT in O(N*log(N)) time. * FFT_Radix2CooleyTukey(In,Out,Work,N) * Auxiliary function, that calculates DFT in O(N*log(N)) * for N being a power of 2 using a preallocated working * array. * FFT_Bluestein(In,Out,Work,N) * Auxiliary function, that calculates DFT in O(N*log(N)) * for arbitrary N. It is multiple times slower than * FFT_Radix2CooleyTukey(...). * ****************************************************************************/ /* * 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 of the License, or * (at your option) any later version. * * 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 Library General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301, * USA */ #ifndef __RT_FFT_H #define __RT_FFT_H // STL include files #include #include using namespace std; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ Function: DFT Purpose: Calculate the Discrete Fourier-Transform in O(N2) time, where N is the number of array elements given by [N]. Arguments: acIn: Input array of size [N]. aOut: Output array. The space must be allocated. The algorithm works in-place as well as out-of-place, i.e. [aOut] may be equal to [acIn]. However, they may not overlap in any other way. N: Size of the arrays. Return value: None. The results will be stored in [aOut]. \* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ template void DFT(const complex *acIn, complex *aOut, size_t N) { if ( acIn != aOut ) // out-of-place? { for ( size_t k=0; k Sum(0); for (size_t n=0; n >(acIn, acIn+N).front(), aOut, N ); } } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ Function: FFT Purpose: Calculate the Discrete Fourier-Transform in O(N*log(N)) time, where N is the number of array elements given by [N]. Arguments: acIn: Input array of size [N]. aOut: Output array. The space must be allocated. The algorithm works in-place as well as out-of-place, i.e. [aOut] may be equal to [acIn]. However, they may not overlap in any other way. N: Size of the arrays. Return value: None. The results will be stored in [aOut]. \* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ template void FFT(const complex *acIn, complex *aOut, size_t N) { if ( ( N& (N-1) ) == 0 ) // size is a power of 2? FFT_Radix2CooleyTukey(acIn, aOut,&vector >(N).front(), N); else // not a power of 2? FFT_Bluestein(acIn, aOut, N); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ Function: FFT_Radix2CooleyTukey Purpose: Calculate the Discrete Fourier-Transform in O(N*log(N)) time using the Cooley-Tukey-Algorithm, where N is the number of array elements given by [N]. N has to be a power of 2 or zero. Arguments: acIn: Input array of size [N]. aOut: Output array. The space must be allocated. The algorithm works in-place as well as out-of-place, i.e. [aOut] may be equal to [acIn]. However, they may not overlap in any other way. aWork: Array of size [N], that is used to perform the calculations. N: Size of the arrays. Must be a power of 2 or zero. Return value: None. The results will be stored in [aOut]. \* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ template void FFT_Radix2CooleyTukey(const complex *acIn, complex *aOut, complex *aWork, size_t N) { if (N == 1) aOut[0]=acIn[0]; else { size_t N_2=N>>1; // Seperate entries with odd and even indices for ( size_t i=0; i 1 ) { FFT_Radix2CooleyTukey(aWork , aWork , aOut, N_2); FFT_Radix2CooleyTukey(aWork+N_2, aWork+N_2, aOut, N_2); } // Put the two arrays together in the proper way complex MultIncrement( polar((T)1,(T)-3.1415926535798932/N_2) ); complex TwiddleFactor( (T)1 ); for ( size_t i=0; i A = aWork[i]; complex B = TwiddleFactor*aWork[i+N_2]; aOut[i ] = A + B; aOut[i+N_2] = A - B; TwiddleFactor*= MultIncrement; } } } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ Function: FFT_Bluestein Purpose: Calculate the Discrete Fourier-Transform in O(N*log(N)) time using the Bluestein-Algorithm, where N is the number of array elements given by [N]. N can be any positive integer, however, the algorithm takes much more time than the Cooley-Tukey-Algorithm. Arguments: acIn: Input array of size [N]. aOut: Output array. The space must be allocated. The array [aOut] may be equal to [acIn]. N: Size of the arrays. Any positive integer. Return value: None. The results will be stored in [aOut]. \* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ template void FFT_Bluestein(const complex *acIn, complex *aOut, size_t N) { // BUG WORKAROUND: The actual algorithm doesn't work for odd N. It yields // uncorrect results for unknown reasons. Therefore we double the size to // keep the O(N*log(N)) time complexity and still get correct results. if (N % 2 == 1) // N odd? { vector > vInOut2( 2*N, complex(0) ); copy( acIn, acIn+N, vInOut2.begin() ); // copy the original input array FFT_Bluestein(&vInOut2.front(),&vInOut2.front(), 2*N ); for ( size_t i=0; i>1; M|=M>>2; M|=M>>4; M|=M>>8; M|=M>>16; M++; M<<=1; // Calculate the zero-padded a and b. vector > a(M,0), b(M,0); const T MinAngle=(T)3.1415926535897932/N; for ( size_t i=0; i > bNonZeroPadded(b.begin(), b.begin()+N); // Apply Cooley-Tukey-Algorithm to a and b vector > Work(M); FFT_Radix2CooleyTukey(&a.front(),&a.front(),&Work.front(),M); FFT_Radix2CooleyTukey(&b.front(),&b.front(),&Work.front(),M); // Multiply F(a) and F(b) pointwise, assign to a for ( size_t i=0; i