FourierTransform.cxx

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2001-2006 MUSIC TECHNOLOGY GROUP (MTG)
00003  *                         UNIVERSITAT POMPEU FABRA
00004  *
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  *
00020  */
00021 
00022 #include <cmath>
00023 #include "FourierTransform.hxx"
00024 #include <iostream>
00025 
00026 #define SWAP(a,b) do {double swaptemp=(a); (a)=(b); (b)=swaptemp;} while(false)
00027 
00028 //  constructor
00029 // input points to the input data. n is twice the frame size
00030 // complex = 0 -> augmentation with 0s is necessary
00031 FourierTransform::FourierTransform(unsigned long int framesize, double datanorm, bool isComplex)
00032         : mFrameSize(framesize)
00033         , mIsComplex(isComplex)
00034 {
00035         _spectrum.resize(2*mFrameSize);
00036         #if USE_FFTW3
00037         _realInput = (double*) fftw_malloc(sizeof(double) * mFrameSize);
00038         _complexOutput = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * mFrameSize);
00039         
00040         fftw_import_system_wisdom();
00041         if (isComplex)
00042                 _plan = fftw_plan_dft_1d(framesize, _complexOutput, _complexOutput, 1, FFTW_ESTIMATE);
00043         else
00044                 _plan = fftw_plan_dft_r2c_1d(framesize, _realInput, _complexOutput, FFTW_ESTIMATE);
00045         #endif
00046 }
00047 
00048 FourierTransform::~FourierTransform()
00049 {
00050         #if USE_FFTW3
00051         fftw_destroy_plan(_plan);
00052         fftw_free(_realInput);
00053         fftw_free(_complexOutput);
00054         #endif
00055 }
00056 
00057 //----------------------------------------------------------------------------------------
00058 // FourierTransform transform code adapted from: Chapter 12, Fast Fourier Transform from Numerical
00059 // Recipes in C: The Art of Scientific Computing. Numerical Recipes Software (1988-1992)
00060 // Cambridge University Press, Cambridge, accessed 25.08.04,
00061 // available at http://www.library.cornell.edu/nr/cbookcpdf.html
00062 
00063 void doFourierTransform(double * data, unsigned frameSize)
00064 {
00065         // Matlab indeces, data[0] is out of bounds  TOREMOVE?
00066         const unsigned long n=frameSize<<1; //n is the data array size
00067         for (unsigned long i=1, j=1; i<n; i+=2) {
00068                 if (j>i) {
00069                         SWAP(data[j], data[i]);
00070                         SWAP(data[j+1], data[i+1]);
00071                 }
00072                 unsigned long m=frameSize;
00073                 while (m >= 2 && j>m) {
00074                         j-= m;
00075                         m >>= 1;
00076                 }
00077                 j += (m);
00078         }
00079         //now Danielson-Lanczos
00080         unsigned long istep;
00081         for (unsigned long mmax = 2; mmax<n; mmax = istep)
00082         {
00083                 istep = mmax << 1;
00084                 const double theta =(6.28318530717959/mmax); // multiply by -1 here for ifft
00085                 double wtemp = sin(0.5*theta);
00086                 double wpr = -2.0*wtemp*wtemp;
00087                 double wpi = sin(theta);
00088                 double wr=1.0;
00089                 double wi=0.0;
00090                 for(unsigned long m=1; m<mmax; m+=2) {
00091                         for (unsigned long i=m; i<=n; i+=istep) {
00092                                 unsigned long j = i+mmax;
00093                                 double tempr = float (wr*data[j] - wi*data[j+1]);
00094                                 double tempi = float (wr*data[j+1] + wi*data[j]);
00095                                 data[j] = data[i] - tempr;
00096                                 data[j+1] = data[i+1] - tempi;
00097                                 data[i] += tempr;
00098                                 data[i+1] += tempi;
00099                         }
00100                         wtemp=wr;
00101                         wr = wtemp*wpr - wi*wpi + wr; //trigonometric recurrence
00102                         //wr = (wtemp=wr)*wpr - wi*wpi + wr; //trigonometric recurrence
00103                         wi = wi*wpr + wtemp*wpi + wi;
00104                 }
00105         }
00106 }
00107 
00108 template <typename T>
00109 void FourierTransform::doItGeneric(const T * input)
00110 {
00111         double * spectrum = &_spectrum[0];
00112 #if USE_FFTW3
00113         fftw_complex * complexOutput = &_complexOutput[0];
00114         if (mIsComplex)
00115         {
00116                 for (unsigned long i=0; i<mFrameSize; i++)
00117                 {
00118                         complexOutput[i][0] = input[i<<1];
00119                         complexOutput[i][1] = input[(i<<1)+1];
00120                 }
00121                 fftw_execute(_plan);
00122                 for (unsigned long i=0; i<mFrameSize*2; i+=2)
00123                 {
00124                         spectrum[i] = complexOutput[i/2][0];
00125                         spectrum[i+1] = complexOutput[i/2][1];
00126                 }
00127         }
00128         else
00129         {
00130                 for (unsigned long i=0; i<mFrameSize; i++)
00131                 {
00132                         _realInput[i] = input[i];
00133                 }
00134                 fftw_execute(_plan);
00135                 for (int i=0; i<mFrameSize; i+=2)
00136                 {
00137                         spectrum[i] = complexOutput[i/2][0];
00138                         spectrum[i+1] = - complexOutput[i/2][1];
00139                 }
00140                 for (int i=1; i<mFrameSize; i+=2)
00141                 {
00142                         unsigned j = mFrameSize*2-i;
00143                         spectrum[j] = complexOutput[i/2][0];
00144                         spectrum[j+1] = complexOutput[i/2][1];
00145                 }
00146         }
00147 #else
00148         if (mIsComplex)
00149         {
00150                 for (unsigned long i=0; i<mFrameSize*2; i++)
00151                         spectrum[i] = input[i];
00152         }
00153         else
00154         {
00155                 for (unsigned long i=0; i<mFrameSize*2; i+=2)
00156                 {
00157                         spectrum[i] = input[i/2];
00158                         spectrum[i+1] = 0.0;
00159                 }
00160         }
00161         double * data = spectrum-1; // Hack to use Matlab indeces TOREMOVE?
00162         doFourierTransform(data, mFrameSize);
00163 #endif
00164 }
00165 
00166 void FourierTransform::doIt(const float * input)
00167 {
00168         doItGeneric(input);
00169 }
00170 void FourierTransform::doIt(const double * input)
00171 {
00172         doItGeneric(input);
00173 }
00174 
00175 //-------------------------------------------------------------------------
00176 
Generated by  doxygen 1.6.3