lib/qtsFFT.cpp

Go to the documentation of this file.
00001 #include "qtsFFT.h"
00002 #include        <cassert>
00003 #include        <math.h>
00004 
00005 
00006 
00007 qtsFFT::qtsFFT(long n) : _ftt_Real(n)
00008 {
00009     fftReal = new double[n];    // ftt arrays
00010     fftFreq = new double[n];
00011 
00012     length = n;
00013 }
00014 qtsFFT::~qtsFFT()
00015 {
00016     delete [] fftReal;
00017     delete [] fftFreq;
00018 }
00019 
00020 PlotLine * qtsFFT::do_FFTqts(PlotLine *r)
00021 {
00022 
00023     PlotLine * result = new PlotLine;
00024     
00025     int i = 0;
00026 
00027     for (i = 0; i < length; i++)
00028     {
00029         fftReal[i] = r->getData(i); 
00030     }
00031     
00032     _ftt_Real.do_fft(fftFreq, fftReal);
00033 
00034     for (i = 0; i < length; i++)
00035     {
00036         result->append(fftFreq[i]);
00037     }
00038 
00039     return result; 
00040 }
00041 
00042 PlotLine *qtsFFT::do_iFFTqts(PlotLine *f)
00043 {
00044     PlotLine * result = new PlotLine;
00045     
00046     int i = 0;
00047 
00048     for (i = 0; i < length; i++)
00049     {
00050         fftFreq[i] = f->getData(i);
00051     }
00052     
00053      _ftt_Real.do_ifft(fftFreq, fftReal);
00054      _ftt_Real.rescale(fftReal);
00055 
00056     for (i = 0; i < length; i++)
00057     {
00058         result->append(fftReal[i]);
00059     }
00060 
00061     return result;
00062 }
00063 
00064 //
00065 // FFTReal by Laurent de Soras
00066 // Modified to nested class for inclusion in this module
00067 //      -- jim nolen jnolen1@mindspring.com, 29 Nov 2004
00068 //
00069 /*==========================================================================*/
00070 /*      Name: Constructor                                                   */
00071 /*      Input parameters:                                                   */
00072 /*        - length: length of the array on which we want to do a FFT.       */
00073 /*                  Range: power of 2 only, > 0.                            */
00074 /*      Throws: std::bad_alloc, anything                                    */
00075 /*==========================================================================*/
00076 
00077 qtsFFT::FFTReal::FFTReal (const long length)
00078 :       _length (length)
00079 ,       _nbr_bits (int (floor (log (length) / log (2) + 0.5)))
00080 ,       _bit_rev_lut (int (floor (log (length) / log (2) + 0.5)))
00081 ,       _trigo_lut (int (floor (log (length) / log (2) + 0.5)))
00082 ,       _sqrt2_2 (flt_t (sqrt (2) * 0.5))
00083 {
00084         assert ((1L << _nbr_bits) == length);
00085 
00086         _buffer_ptr = 0;
00087         if (_nbr_bits > 2)
00088         {
00089                 _buffer_ptr = new flt_t [_length];
00090         }
00091 }
00092 
00093 qtsFFT::FFTReal::~FFTReal (void)
00094 {
00095         delete [] _buffer_ptr;
00096         _buffer_ptr = 0;
00097 }
00098 
00099 /*==========================================================================*/
00100 /*      Name: do_fft                                                        */
00101 /*      Description: Compute the FFT of the array.                          */
00102 /*      Input parameters:                                                   */
00103 /*        - x: pointer on the source array (time).                          */
00104 /*      Output parameters:                                                  */
00105 /*        - f: pointer on the destination array (frequencies).              */
00106 /*             f [0...length(x)/2] = real values,                           */
00107 /*             f [length(x)/2+1...length(x)-1] = imaginary values of        */
00108 /*               coefficents 1...length(x)/2-1.                             */
00109 /*      Throws: Nothing                                                     */
00110 /*==========================================================================*/
00111 
00112 void    qtsFFT::FFTReal::do_fft (flt_t f [], const flt_t x []) const
00113 {
00114 
00115 /*______________________________________________
00116  *
00117  * General case
00118  *______________________________________________
00119  */
00120 
00121         if (_nbr_bits > 2)
00122         {
00123                 flt_t *                 sf;
00124                 flt_t *                 df;
00125 
00126                 if (_nbr_bits & 1)
00127                 {
00128                         df = _buffer_ptr;
00129                         sf = f;
00130                 }
00131                 else
00132                 {
00133                         df = f;
00134                         sf = _buffer_ptr;
00135                 }
00136 
00137                 /* Do the transformation in several pass */
00138                 {
00139                         int             pass;
00140                         long            nbr_coef;
00141                         long            h_nbr_coef;
00142                         long            d_nbr_coef;
00143                         long            coef_index;
00144 
00145                         /* First and second pass at once */
00146                         {
00147                                 const long * const      bit_rev_lut_ptr = _bit_rev_lut.get_ptr ();
00148                                 coef_index = 0;
00149                                 do
00150                                 {
00151                                         const long              rev_index_0 = bit_rev_lut_ptr [coef_index];
00152                                         const long              rev_index_1 = bit_rev_lut_ptr [coef_index + 1];
00153                                         const long              rev_index_2 = bit_rev_lut_ptr [coef_index + 2];
00154                                         const long              rev_index_3 = bit_rev_lut_ptr [coef_index + 3];
00155 
00156                                         flt_t   * const df2 = df + coef_index;
00157                                         df2 [1] = x [rev_index_0] - x [rev_index_1];
00158                                         df2 [3] = x [rev_index_2] - x [rev_index_3];
00159 
00160                                         const flt_t             sf_0 = x [rev_index_0] + x [rev_index_1];
00161                                         const flt_t             sf_2 = x [rev_index_2] + x [rev_index_3];
00162 
00163                                         df2 [0] = sf_0 + sf_2;
00164                                         df2 [2] = sf_0 - sf_2;
00165                                         
00166                                         coef_index += 4;
00167                                 }
00168                                 while (coef_index < _length);
00169                         }
00170 
00171                         /* Third pass */
00172                         {
00173                                 coef_index = 0;
00174                                 const flt_t             sqrt2_2 = _sqrt2_2;
00175                                 do
00176                                 {
00177                                         flt_t                           v;
00178 
00179                                         sf [coef_index] = df [coef_index] + df [coef_index + 4];
00180                                         sf [coef_index + 4] = df [coef_index] - df [coef_index + 4];
00181                                         sf [coef_index + 2] = df [coef_index + 2];
00182                                         sf [coef_index + 6] = df [coef_index + 6];
00183 
00184                                         v = (df [coef_index + 5] - df [coef_index + 7]) * sqrt2_2;
00185                                         sf [coef_index + 1] = df [coef_index + 1] + v;
00186                                         sf [coef_index + 3] = df [coef_index + 1] - v;
00187 
00188                                         v = (df [coef_index + 5] + df [coef_index + 7]) * sqrt2_2;
00189                                         sf [coef_index + 5] = v + df [coef_index + 3];
00190                                         sf [coef_index + 7] = v - df [coef_index + 3];
00191 
00192                                         coef_index += 8;
00193                                 }
00194                                 while (coef_index < _length);
00195                         }
00196 
00197                         /* Next pass */
00198                         for (pass = 3; pass < _nbr_bits; ++pass)
00199                         {
00200                                 coef_index = 0;
00201                                 nbr_coef = 1 << pass;
00202                                 h_nbr_coef = nbr_coef >> 1;
00203                                 d_nbr_coef = nbr_coef << 1;
00204                                 const flt_t     * const cos_ptr = _trigo_lut.get_ptr (pass);
00205                                 do
00206                                 {
00207                                         long                            i;
00208                                         const flt_t     *       const sf1r = sf + coef_index;
00209                                         const flt_t     *       const sf2r = sf1r + nbr_coef;
00210                                         flt_t *                 const dfr = df + coef_index;
00211                                         flt_t *                 const dfi = dfr + nbr_coef;
00212 
00213                                         /* Extreme coefficients are always real */
00214                                         dfr [0] = sf1r [0] + sf2r [0];
00215                                         dfi [0] = sf1r [0] - sf2r [0];  // dfr [nbr_coef] =
00216                                         dfr [h_nbr_coef] = sf1r [h_nbr_coef];
00217                                         dfi [h_nbr_coef] = sf2r [h_nbr_coef];
00218 
00219                                         /* Others are conjugate complex numbers */
00220                                         const flt_t     * const sf1i = sf1r + h_nbr_coef;
00221                                         const flt_t     * const sf2i = sf1i + nbr_coef;
00222                                         for (i = 1; i < h_nbr_coef; ++ i)
00223                                         {
00224                                                 const flt_t             c = cos_ptr [i];                                        // cos (i*PI/nbr_coef);
00225                                                 const flt_t             s = cos_ptr [h_nbr_coef - i];   // sin (i*PI/nbr_coef);
00226                                                 flt_t                           v;
00227 
00228                                                 v = sf2r [i] * c - sf2i [i] * s;
00229                                                 dfr [i] = sf1r [i] + v;
00230                                                 dfi [-i] = sf1r [i] - v;        // dfr [nbr_coef - i] =
00231 
00232                                                 v = sf2r [i] * s + sf2i [i] * c;
00233                                                 dfi [i] = v + sf1i [i];
00234                                                 dfi [nbr_coef - i] = v - sf1i [i];
00235                                         }
00236 
00237                                         coef_index += d_nbr_coef;
00238                                 }
00239                                 while (coef_index < _length);
00240 
00241                                 /* Prepare to the next pass */
00242                                 {
00243                                         flt_t   * const         temp_ptr = df;
00244                                         df = sf;
00245                                         sf = temp_ptr;
00246                                 }
00247                         }
00248                 }
00249         }
00250 
00251 /*______________________________________________
00252  *
00253  * Special cases
00254  *______________________________________________
00255  */
00256 
00257         /* 4-point FFT */
00258         else if (_nbr_bits == 2)
00259         {
00260                 f [1] = x [0] - x [2];
00261                 f [3] = x [1] - x [3];
00262 
00263                 const flt_t                     b_0 = x [0] + x [2];
00264                 const flt_t                     b_2 = x [1] + x [3];
00265                 
00266                 f [0] = b_0 + b_2;
00267                 f [2] = b_0 - b_2;
00268         }
00269 
00270         /* 2-point FFT */
00271         else if (_nbr_bits == 1)
00272         {
00273                 f [0] = x [0] + x [1];
00274                 f [1] = x [0] - x [1];
00275         }
00276 
00277         /* 1-point FFT */
00278         else
00279         {
00280                 f [0] = x [0];
00281         }
00282 }
00283 
00284 
00285 
00286 /*==========================================================================*/
00287 /*      Name: do_ifft                                                       */
00288 /*      Description: Compute the inverse FFT of the array. Notice that      */
00289 /*                   IFFT (FFT (x)) = x * length (x). Data must be          */
00290 /*                   post-scaled.                                           */
00291 /*      Input parameters:                                                   */
00292 /*        - f: pointer on the source array (frequencies).                   */
00293 /*             f [0...length(x)/2] = real values,                           */
00294 /*             f [length(x)/2+1...length(x)] = imaginary values of          */
00295 /*               coefficents 1...length(x)-1.                               */
00296 /*      Output parameters:                                                  */
00297 /*        - x: pointer on the destination array (time).                     */
00298 /*      Throws: Nothing                                                     */
00299 /*==========================================================================*/
00300 
00301 void    qtsFFT::FFTReal::do_ifft (const flt_t f [], flt_t x []) const
00302 {
00303 
00304 /*______________________________________________
00305  *
00306  * General case
00307  *______________________________________________
00308  */
00309 
00310         if (_nbr_bits > 2)
00311         {
00312                 flt_t *                 sf = const_cast <flt_t *> (f);
00313                 flt_t *                 df;
00314                 flt_t *                 df_temp;
00315 
00316                 if (_nbr_bits & 1)
00317                 {
00318                         df = _buffer_ptr;
00319                         df_temp = x;
00320                 }
00321                 else
00322                 {
00323                         df = x;
00324                         df_temp = _buffer_ptr;
00325                 }
00326 
00327                 /* Do the transformation in several pass */
00328                 {
00329                         int                     pass;
00330                         long                    nbr_coef;
00331                         long                    h_nbr_coef;
00332                         long                    d_nbr_coef;
00333                         long                    coef_index;
00334 
00335                         /* First pass */
00336                         for (pass = _nbr_bits - 1; pass >= 3; --pass)
00337                         {
00338                                 coef_index = 0;
00339                                 nbr_coef = 1 << pass;
00340                                 h_nbr_coef = nbr_coef >> 1;
00341                                 d_nbr_coef = nbr_coef << 1;
00342                                 const flt_t     *const cos_ptr = _trigo_lut.get_ptr (pass);
00343                                 do
00344                                 {
00345                                         long                            i;
00346                                         const flt_t     *       const sfr = sf + coef_index;
00347                                         const flt_t     *       const sfi = sfr + nbr_coef;
00348                                         flt_t *                 const df1r = df + coef_index;
00349                                         flt_t *                 const df2r = df1r + nbr_coef;
00350 
00351                                         /* Extreme coefficients are always real */
00352                                         df1r [0] = sfr [0] + sfi [0];           // + sfr [nbr_coef]
00353                                         df2r [0] = sfr [0] - sfi [0];           // - sfr [nbr_coef]
00354                                         df1r [h_nbr_coef] = sfr [h_nbr_coef] * 2;
00355                                         df2r [h_nbr_coef] = sfi [h_nbr_coef] * 2;
00356 
00357                                         /* Others are conjugate complex numbers */
00358                                         flt_t * const   df1i = df1r + h_nbr_coef;
00359                                         flt_t * const   df2i = df1i + nbr_coef;
00360                                         for (i = 1; i < h_nbr_coef; ++ i)
00361                                         {
00362                                                 df1r [i] = sfr [i] + sfi [-i];          // + sfr [nbr_coef - i]
00363                                                 df1i [i] = sfi [i] - sfi [nbr_coef - i];
00364 
00365                                                 const flt_t             c = cos_ptr [i];                                        // cos (i*PI/nbr_coef);
00366                                                 const flt_t             s = cos_ptr [h_nbr_coef - i];   // sin (i*PI/nbr_coef);
00367                                                 const flt_t             vr = sfr [i] - sfi [-i];                // - sfr [nbr_coef - i]
00368                                                 const flt_t             vi = sfi [i] + sfi [nbr_coef - i];
00369 
00370                                                 df2r [i] = vr * c + vi * s;
00371                                                 df2i [i] = vi * c - vr * s;
00372                                         }
00373 
00374                                         coef_index += d_nbr_coef;
00375                                 }
00376                                 while (coef_index < _length);
00377 
00378                                 /* Prepare to the next pass */
00379                                 if (pass < _nbr_bits - 1)
00380                                 {
00381                                         flt_t   * const temp_ptr = df;
00382                                         df = sf;
00383                                         sf = temp_ptr;
00384                                 }
00385                                 else
00386                                 {
00387                                         sf = df;
00388                                         df = df_temp;
00389                                 }
00390                         }
00391 
00392                         /* Antepenultimate pass */
00393                         {
00394                                 const flt_t             sqrt2_2 = _sqrt2_2;
00395                                 coef_index = 0;
00396                                 do
00397                                 {
00398                                         df [coef_index] = sf [coef_index] + sf [coef_index + 4];
00399                                         df [coef_index + 4] = sf [coef_index] - sf [coef_index + 4];
00400                                         df [coef_index + 2] = sf [coef_index + 2] * 2;
00401                                         df [coef_index + 6] = sf [coef_index + 6] * 2;
00402 
00403                                         df [coef_index + 1] = sf [coef_index + 1] + sf [coef_index + 3];
00404                                         df [coef_index + 3] = sf [coef_index + 5] - sf [coef_index + 7];
00405 
00406                                         const flt_t             vr = sf [coef_index + 1] - sf [coef_index + 3];
00407                                         const flt_t             vi = sf [coef_index + 5] + sf [coef_index + 7];
00408 
00409                                         df [coef_index + 5] = (vr + vi) * sqrt2_2;
00410                                         df [coef_index + 7] = (vi - vr) * sqrt2_2;
00411 
00412                                         coef_index += 8;
00413                                 }
00414                                 while (coef_index < _length);
00415                         }
00416 
00417                         /* Penultimate and last pass at once */
00418                         {
00419                                 coef_index = 0;
00420                                 const long *    bit_rev_lut_ptr = _bit_rev_lut.get_ptr ();
00421                                 const flt_t     *       sf2 = df;
00422                                 do
00423                                 {
00424                                         {
00425                                                 const flt_t             b_0 = sf2 [0] + sf2 [2];
00426                                                 const flt_t             b_2 = sf2 [0] - sf2 [2];
00427                                                 const flt_t             b_1 = sf2 [1] * 2;
00428                                                 const flt_t             b_3 = sf2 [3] * 2;
00429 
00430                                                 x [bit_rev_lut_ptr [0]] = b_0 + b_1;
00431                                                 x [bit_rev_lut_ptr [1]] = b_0 - b_1;
00432                                                 x [bit_rev_lut_ptr [2]] = b_2 + b_3;
00433                                                 x [bit_rev_lut_ptr [3]] = b_2 - b_3;
00434                                         }
00435                                         {
00436                                                 const flt_t             b_0 = sf2 [4] + sf2 [6];
00437                                                 const flt_t             b_2 = sf2 [4] - sf2 [6];
00438                                                 const flt_t             b_1 = sf2 [5] * 2;
00439                                                 const flt_t             b_3 = sf2 [7] * 2;
00440 
00441                                                 x [bit_rev_lut_ptr [4]] = b_0 + b_1;
00442                                                 x [bit_rev_lut_ptr [5]] = b_0 - b_1;
00443                                                 x [bit_rev_lut_ptr [6]] = b_2 + b_3;
00444                                                 x [bit_rev_lut_ptr [7]] = b_2 - b_3;
00445                                         }
00446 
00447                                         sf2 += 8;
00448                                         coef_index += 8;
00449                                         bit_rev_lut_ptr += 8;
00450                                 }
00451                                 while (coef_index < _length);
00452                         }
00453                 }
00454         }
00455 
00456 /*______________________________________________
00457  *
00458  * Special cases
00459  *______________________________________________
00460  */
00461 
00462         /* 4-point IFFT */
00463         else if (_nbr_bits == 2)
00464         {
00465                 const flt_t             b_0 = f [0] + f [2];
00466                 const flt_t             b_2 = f [0] - f [2];
00467 
00468                 x [0] = b_0 + f [1] * 2;
00469                 x [2] = b_0 - f [1] * 2;
00470                 x [1] = b_2 + f [3] * 2;
00471                 x [3] = b_2 - f [3] * 2;
00472         }
00473 
00474         /* 2-point IFFT */
00475         else if (_nbr_bits == 1)
00476         {
00477                 x [0] = f [0] + f [1];
00478                 x [1] = f [0] - f [1];
00479         }
00480 
00481         /* 1-point IFFT */
00482         else
00483         {
00484                 x [0] = f [0];
00485         }
00486 }
00487 
00488 
00489 
00490 /*==========================================================================*/
00491 /*      Name: rescale                                                       */
00492 /*      Description: Scale an array by divide each element by its length.   */
00493 /*                   This function should be called after FFT + IFFT.       */
00494 /*      Input/Output parameters:                                            */
00495 /*        - x: pointer on array to rescale (time or frequency).             */
00496 /*      Throws: Nothing                                                     */
00497 /*==========================================================================*/
00498 
00499 void    qtsFFT::FFTReal::rescale (flt_t x []) const
00500 {
00501         const flt_t             mul = flt_t (1.0 / _length);
00502         long                            i = _length - 1;
00503 
00504         do
00505         {
00506                 x [i] *= mul;
00507                 --i;
00508         }
00509         while (i >= 0);
00510 }
00511 
00512 // nested classes
00513 /*==========================================================================*/
00514 /*      Name: Constructor                                                   */
00515 /*      Input parameters:                                                   */
00516 /*        - nbr_bits: number of bits of the array on which we want to do a  */
00517 /*                    FFT. Range: > 0                                       */
00518 /*      Throws: std::bad_alloc                                              */
00519 /*==========================================================================*/
00520 
00521 
00522 qtsFFT::FFTReal::BitReversedLUT::BitReversedLUT (const int nbr_bits)
00523 {
00524         long                            length;
00525         long                            cnt;
00526         long                            br_index;
00527         long                            bit;
00528 
00529         length = 1L << nbr_bits;
00530         _ptr = new long [length];
00531 
00532         br_index = 0;
00533         _ptr [0] = 0;
00534         for (cnt = 1; cnt < length; ++cnt)
00535         {
00536                 /* ++br_index (bit reversed) */
00537                 bit = length >> 1;
00538                 while (((br_index ^= bit) & bit) == 0)
00539                 {
00540                         bit >>= 1;
00541                 }
00542 
00543                 _ptr [cnt] = br_index;
00544         }
00545 }
00546 
00547 
00548 qtsFFT::FFTReal::BitReversedLUT::~BitReversedLUT (void)
00549 {
00550         delete [] _ptr;
00551         _ptr = 0;
00552 }
00553 
00554 
00555 
00556 /*==========================================================================*/
00557 /*      Name: Constructor                                                   */
00558 /*      Input parameters:                                                   */
00559 /*        - nbr_bits: number of bits of the array on which we want to do a  */
00560 /*                    FFT. Range: > 0                                       */
00561 /*      Throws: std::bad_alloc, anything                                    */
00562 /*==========================================================================*/
00563 
00564 
00565 qtsFFT::FFTReal::TrigoLUT::TrigoLUT (const int nbr_bits)
00566 {
00567         long            total_len;
00568 
00569         _ptr = 0;
00570         if (nbr_bits > 3)
00571         {
00572                 total_len = (1L << (nbr_bits - 1)) - 4;
00573                 _ptr = new flt_t [total_len];
00574 
00575                 const double    PI = atan (1) * 4;
00576                 for (int level = 3; level < nbr_bits; ++level)
00577                 {
00578                         const long              level_len = 1L << (level - 1);
00579                         flt_t   * const level_ptr = const_cast<flt_t *> (get_ptr (level));
00580                         const double    mul = PI / (level_len << 1);
00581 
00582                         for (long i = 0; i < level_len; ++ i)
00583                         {
00584                                 level_ptr [i] = (flt_t) cos (i * mul);
00585                         }
00586                 }
00587         }
00588 }
00589 
00590 qtsFFT::FFTReal::TrigoLUT::~TrigoLUT (void)
00591 {
00592         delete [] _ptr;
00593         _ptr = 0;
00594 }
00595 
00596 
00597 /*****************************************************************************
00598 
00599         LEGAL: FTTReal
00600 
00601         Source code may be freely used for any purpose, including commercial
00602         applications. Programs must display in their "About" dialog-box (or
00603         documentation) a text telling they use these routines by Laurent de Soras.
00604         Modified source code can be distributed, but modifications must be clearly
00605         indicated.
00606 
00607         CONTACT
00608 
00609         Laurent de Soras
00610         92 avenue Albert 1er
00611         92500 Rueil-Malmaison
00612         France
00613 
00614         ldesoras@club-internet.fr
00615 
00616 *****************************************************************************/