fft.c

00001 /******************************************************************************
00002 *******************************************************************************
00003 *                European Southern Observatory
00004 *              VLTI MIDI Data Reduction Software
00005 *
00006 * Module name:    fft.c
00007 * Description:    This is the new COMPILER INDEPENDENT fft module for NRTS etc.
00008 *
00009 * History:        
00010 * 03-Feb-03        (jmeisner) Created
00011 * 03-Mar-03        (csabet) Added title, directives and included in the MIDI pipeline
00012 *******************************************************************************
00013 ******************************************************************************/
00014 
00015 /******************************************************************************
00016 *    Compiler directives
00017 ******************************************************************************/
00018 
00019 /******************************************************************************
00020 *    Include files
00021 ******************************************************************************/
00022 #include <stdio.h>
00023 #include <cpl.h>
00024 #include <stdlib.h>
00025 #include <math.h>
00026 #include "complex_midi.h"
00027 #include "compiler.h"
00028 #include "fft.h"
00029 
00030 /**********************************************************
00031 *    Global Variables 
00032 **********************************************************/
00033 //    This number (power of 2) is the maximum array size supported:
00034 //    NOW IN FFT.H:    #define MAXFFTSIZE 1024
00035 //    was called: BIGGER 256   #define BIGGER2 BIGGER/2
00036 int FFTsize = 2;           //    (Formerly XX)
00037 int FFThalfsize = 1;    //    (Formerly XX2)
00038 int FFTlevel = 1;        //    FFTsize = 2^FFTlevel
00039 int shuffle[MAXFFTSIZE];
00040 
00041 //    New, array in which FFT is processed, and results delivered:
00042 struct Complex *FFTarray ; // Changed to dynamic memory (csabet 11-Jan-2007)
00043 
00044 float ScaleFFTby;    // Applies to entire fft
00045                     // REVERSED: Now ScaleFFTby is used by the FFT and NOT by the IFT!! 
00046                     // Only used for IFT, ==1 if forward FT
00047 
00048 struct Complex Twiddle[MAXFFTSIZE/2];    // Now always set for forward xfrm
00049 struct Complex Rotated;
00050 // Now local to DoFFT:   int skip,groups,TwiddleIndex;
00051 
00052 
00053 
00054 /*============================ C O D E    A R E A ===========================*/
00055 
00056 // This function now returns all bit reversals
00057 // First, the QC x86 inline assembly code:
00058 
00059 #ifdef QUICK_C /*---------------------------------------*/
00060 
00061 static int BitReverse(int x,int NumBits)
00062 {
00063     _asm
00064     {
00065         mov cx, NumBits;
00066         mov dx, x;
00067         sub ax, ax;
00068 TOP:
00069         rcr dx,1;
00070         rcl ax,1;
00071         loop TOP;
00072         }
00073 }          // Ignore compiler warning about "no return value"
00074 #else /*---------------------------------------*/
00075 
00076 static int BitReverse(int x, int NumBits)
00077 {
00078    int result = 0;
00079    int i;
00080    for(i=0; i<NumBits; i++)
00081    {
00082       result *= 2;
00083       if(x&1)
00084      result++;
00085       x /= 2 ;
00086    }
00087    return result;
00088 }
00089 #endif /*---------------------------------------*/
00090 
00091 
00092 // used to initialize the shuffled index
00093 // and twiddle arrays:
00094 void FFTInit(int level) // Now only runs when needed!!    // no longer:  , int inverse)
00095 {
00096    int i;
00097    float angle=0.F, incr;
00098 
00099    if(level==FFTlevel)  // If already correctly set...
00100       return;           // then nothing to do!!
00101 
00102    FFTlevel = level;
00103 
00104    FFTsize = 1 << level;
00105    FFThalfsize = FFTsize/2 ;
00106 
00107    if(FFTsize>MAXFFTSIZE)
00108       ERROR(-111)  ; // not!: "requested FFT level exceeds max!");
00109 
00110 // NEW NORMALIZATION SCHEME, Constant division ONLY for INVERSE xfrm:
00111 // Now, only USED by IFT, set regardless:
00112 
00113 //   if(inverse) // REVERSED: Now ScaleFFTby is used by the FFT and NOT by the IFT!!
00114 
00115    ScaleFFTby = 1.F/((double) FFTsize) ;
00116 
00117 //   else
00118 //      ScaleFFTby = 1.F;
00119 
00120 //   Num2shuffle = 0;
00121 
00122    for (i=0; i<FFTsize; i++)
00123    {
00124       shuffle[i] = BitReverse(i, level);
00125    }
00126 
00127    incr = -6.2831853F / ((float) FFTsize) ;  //  (1 << level) ;
00128 
00129 // NAH:    if(inverse) incr = -incr ;
00130 
00131    for (i=0;i < FFThalfsize; i++) // this array needs only be 1/2 the array size
00132    {
00133        GetEtoJtimes(angle, &Twiddle[i]);
00134        angle += incr;
00135    }
00136 }
00137 
00138            // FOR FORWARD XFRM:
00139 static void ButterflyXfwd (int AIndex, int BIndex, int TwiddleIndex,
00140                     struct Complex arr1[])
00141 //  AIndex and BIndex are indices pointing to which elements
00142 //  are to be butterflied
00143 {
00144     MultiplyCptr(&Rotated, &arr1[BIndex],  &Twiddle[TwiddleIndex] );
00145     SubtractCptr( &arr1[BIndex] , &arr1[AIndex] , &Rotated);
00146     AddCptr( &arr1[AIndex] , &arr1[AIndex] , &Rotated);
00147 }
00148            // FOR INVERSE XFRM:
00149 static void ButterflyXinv (int AIndex, int BIndex, int TwiddleIndex,
00150                     struct Complex arr1[])
00151 //  AIndex and BIndex are indices pointing to which elements
00152 //  are to be butterflied
00153 {
00154     MultiplyConjPtr(&Rotated, &arr1[BIndex],  &Twiddle[TwiddleIndex] );
00155     SubtractCptr( &arr1[BIndex] , &arr1[AIndex] , &Rotated);
00156     AddCptr( &arr1[AIndex] , &arr1[AIndex] , &Rotated);
00157 }
00158 
00159      // For type2 algorithm:
00160 static void Type2ButterflyXinv (int AIndex, int BIndex, int TwiddleIndex,
00161                     struct Complex arr1[])
00162 //  AIndex and BIndex are indices pointing to which elements
00163 //  are to be butterflied
00164 {
00165     struct Complex temp;
00166     SubtractCptr(&temp,  &arr1[AIndex], &arr1[BIndex]);  // To become a index
00167     AddCptr(&arr1[AIndex], &arr1[AIndex] , &arr1[BIndex]);
00168     MultiplyConjPtr(&arr1[BIndex], &temp, &Twiddle[TwiddleIndex] );
00169 }
00170 
00171 
00172 
00173 void DoFFT(void) // This runs the actual math, after data is in FFTarray:
00174 {   // REVERSED: Now ScaleFFTby is used by the FFT and NOT by the IFT!! (must be done by calling program)
00175    int i, j, k;
00176    int skip=1;
00177    int groups = FFTsize ;
00178    int TwiddleIndex, IndexA, IndexB;
00179    // these three nested loops are the core of the FFT
00180 
00181    for (k=0;k<FFTlevel;k++)  // loop #1  for all the levels
00182    {
00183    /******** Now these are set differently:
00184       skip= (1<<k); //         (int)pow(2,k);
00185       groups= FFTsize/(2*skip); //  why  divided by 2 ?  because for a 16 element -
00186    *************/                    //  the first one is 8(groups) x 1(skip)
00187       groups /= 2 ; //  <<<< Here for groups
00188 
00189       // loop #2 --"group" loop -- XX/2 at first,  1 at the end
00190       for (j=0;j<groups;j++)    //= skip * 2)
00191       {
00192      TwiddleIndex=0;
00193      IndexA = j * skip * 2;
00194      IndexB = IndexA + skip;
00195 
00196           // and here is loop # 3 - twiddle loops for each group
00197      for (i=0;i<skip;i++)
00198      {
00199         ButterflyXfwd(IndexA++, IndexB++, TwiddleIndex, FFTarray);
00200     // Was: j * skip * 2 +i, j * skip * 2 + skip + i , TwiddleIndex, FFTarray);
00201         TwiddleIndex+= groups;
00202      }
00203       }
00204       skip *= 2 ; 
00205    }
00206 }
00207 
00208 
00209 void DoIFT(void) //  Identical to above, except uses ButterflyXinv
00210 {            // IFT must also (in calling program) apply the scale ScaleFFTby  <<< NOT
00211    int i, j, k;
00212    int skip=1;
00213    int groups = FFTsize ;
00214    int TwiddleIndex, IndexA, IndexB;
00215    // these three nested loops are the core of the FFT
00216 
00217    for (k=0;k<FFTlevel;k++)  // loop #1  for all the levels
00218    {
00219       groups /= 2 ; //  <<<< Here for groups
00220 
00221       // loop #2 --"group" loop -- XX/2 at first,  1 at the end
00222       for (j=0;j<groups;j++)    //= skip * 2)
00223       {
00224      TwiddleIndex=0;
00225      IndexA = j * skip * 2;
00226      IndexB = IndexA + skip;
00227 
00228           // and here is loop # 3 - twiddle loops for each group
00229      for (i=0;i<skip;i++)
00230      {
00231         ButterflyXinv(IndexA++, IndexB++, TwiddleIndex, FFTarray);
00232         TwiddleIndex+= groups;
00233      }
00234       }
00235       skip *= 2 ; 
00236    }
00237 }
00238 
00239 
00240 void Type2DoIFT(void) //  NEW!   NEW!
00241 {            // IFT must also (in calling program) apply the scale ScaleFFTby <<< NOT
00242    int i, j, k;
00243    int skip = FFTsize;   // BACKWARDS: =1;
00244    int groups = 1;   // not: FFTsize ;
00245    int TwiddleIndex, IndexA, IndexB;
00246    // these three nested loops are the core of the FFT
00247 
00248    for (k=0;k<FFTlevel;k++)  // loop #1  for all the levels
00249    {
00250       skip /= 2;  // <<<< HERE now
00251  // not:     groups /= 2 ; //  <<<< Here for groups
00252    // but, below:   groups *= 2;
00253 
00254       // BACKWARDS:  // loop #2 --"group" loop -- XX/2 at first,  1 at the end
00255       for (j=0;j<groups;j++)    //= skip * 2)
00256       {
00257      TwiddleIndex=0;
00258      IndexA = j * skip * 2;
00259      IndexB = IndexA + skip;
00260 
00261           // and here is loop # 3 - twiddle loops for each group
00262      for (i=0;i<skip;i++)
00263      {
00264         Type2ButterflyXinv(IndexA++, IndexB++, TwiddleIndex, FFTarray);
00265         TwiddleIndex+= groups;
00266      }
00267       }
00268      // BACKWARDS:  skip *= 2 ; /// <<<< And here!
00269    // but above:   skip /= 2;
00270       groups *= 2;  // <<< NOW HERE
00271    }
00272 }
00273 
00274 // USER LEVEL FUNCTIONS:
00275 
00276 void FFT(struct Complex *Input, int newlevel)       // Vector1[], int level)
00277 {
00278     int i;
00279 
00280     FFTInit(newlevel);
00281 
00282     for(i=0; i<FFTsize; i++)  // Shuffle the data:
00283     {
00284        FFTarray[shuffle[i]] = Scalec(Input[i], ScaleFFTby); // rather than Input[i] ;
00285     }
00286 
00287     DoFFT();   // <<< And actually do it!
00288 }
00289 
00290 void IFT(struct Complex *Input, int newlevel)       // Vector1[], int level)
00291 {
00292     int i;
00293 
00294     if(newlevel != FFTlevel)
00295 
00296     for(i=0; i<FFTsize; i++)  // Shuffle the data:
00297     {                     // AND SCALE since its the IFT:
00298        FFTarray[shuffle[i]] = Input[i] ; // NO LONGER: Scalec(Input[i], ScaleFFTby);
00299     }
00300 
00301     DoIFT();   // <<< And actually do it!
00302 }
00303 
00304 /* static void Type2IFT(struct Complex *Output, int newlevel)       // Vector1[], int level) */
00305 /* { */
00306 /*     int i; */
00307 
00308 /*     FFTInit(newlevel); */
00309 
00310 /*         // Input in fftarray, so... */
00311 /*     Type2DoIFT();   // <<< And actually do it! */
00312 
00313 /*     for(i=0; i<FFTsize; i++)  // Shuffle the data: */
00314 /*     {                     // AND SCALE since its the IFT: */
00315 /*        Output[shuffle[i]] = FFTarray[i] ; // No longer: Scalec(FFTarray[i], ScaleFFTby);  */
00316 /*     } */
00317 /* } */
00318 
00319 /* static void Type2IFTtoReal(float *Output, int newlevel)       // Vector1[], int level) */
00320 /* { */
00321 /*     int i; */
00322 
00323 /*     FFTInit(newlevel); */
00324 
00325 /*         // Input in fftarray, so... */
00326 /*     Type2DoIFT();   // <<< And actually do it! */
00327 
00328 /*     for(i=0; i<FFTsize; i++)  // Shuffle the data: */
00329 /*     {                     // AND SCALE since its the IFT: */
00330 /*        Output[shuffle[i]] = FFTarray[i].r ; // NO LONGER:   * ScaleFFTby; */
00331 /*     } */
00332 /* } */
00333 
00334 /*********** Set FFTlevel & init so just large enough for InputSize *******/
00335 void SetFFTsize(int InputSize)
00336 {
00337     int newFFTlevel = FFTlevel;
00338 
00339     while(InputSize > FFTsize)
00340     {
00341        newFFTlevel++;
00342        FFTsize *= 2;
00343     }
00344 
00345     while(2*InputSize <= FFTsize)
00346     {
00347        newFFTlevel--;
00348        FFTsize /= 2;
00349     }
00350     
00351     FFTInit(newFFTlevel);   
00352 }
00353 
00354 /************ FURTHER USER LEVEL FUNCTIONS ****************/
00355 
00356 void FFTofReal(float *Input, int InputSize)   // Enter size of array to be xfrmd
00357 {
00358     int i;
00359     SetFFTsize(InputSize);
00360 
00361     for(i=0; i<InputSize; i++)
00362     {
00363        FFTarray[shuffle[i]].r = Input[i]*ScaleFFTby; // YES NEEDED // NOT NEEDED, =1 for forward FFT: *ScaleFFTby;
00364        FFTarray[shuffle[i]].i = 0.F;
00365     }
00366 
00367     for(i=InputSize; i<FFTsize; i++)
00368     {
00369        FFTarray[shuffle[i]].r = FFTarray[shuffle[i]].i = 0.F;
00370     }
00371 
00372     DoFFT();
00373 }
00374 
00375 
00376 // For this version, FFTlevel/size must be set in advance & FFTinit() done:
00377 // Produces even (symetric) function over full range & produces cosine xfrm
00378 
00379 void FFTfullReal(float *Input, int InputSize, float scale)   // Enter size of array to be xfrmd
00380 {
00381     int i;
00382     struct Complex Ctemp;    
00383 // NOW A GLOBAL VAR:        int FFThalfsize = FFTsize/2;
00384     float inputscale = ((float)InputSize) /((float)FFThalfsize) ;  
00385     
00386     scale *= ScaleFFTby ; // Include this factor here, now.
00387 
00388     Ctemp.i = 0.F;
00389 
00390 // NO LONGER NEEDED:        if(FFTinverseMode)  // in case it got switched somehow!!
00391 //           FFTInit(FFTlevel, 0);
00392 
00393     for(i=0; i<FFThalfsize; i++)
00394     {
00395        Ctemp.r = scale*Input[((int) (((float)i) * inputscale))] ;
00396 
00397 // SHOULD BE:
00398        FFTarray[shuffle[i]] = FFTarray[shuffle[FFTsize-i]] = Ctemp;
00399     }
00400      // NEW:
00401     FFTarray[1].r = scale*Input[InputSize-1] ; // To make continuous!!
00402     FFTarray[1].i = 0.F ; // This is the FFThalfsize pt.
00403 
00404     DoFFT();
00405 }
00406 
00407 
00408     // Does NOT attempt to reduce the size of the fft array!!:
00409     // Should have run SetFFTsize() first!
00410 /* static void FFTofShortArray(struct Complex *Input, int InputSize) */
00411 /* { */
00412 /*     int i; */
00413 
00414 /*     for(i=0; i<InputSize; i++) */
00415 /*     { */
00416 /*        FFTarray[shuffle[i]] = Scalec(Input[i], ScaleFFTby);  */
00417 /*     } */
00418 
00419 /*     for(i=InputSize; i<FFTsize; i++) */
00420 /*     { */
00421 /*        FFTarray[shuffle[i]].r = FFTarray[shuffle[i]].i = 0.F; */
00422 /*     } */
00423 
00424 /*     DoFFT(); */
00425 /* } */
00426 
00427 /*****************************************************************************/
00428 
00429 
00430 /******************************************************************************
00431 *               European Southern Observatory
00432 *            VLTI MIDI Data Reduction Software
00433 *
00434 * Module name:  determineFFTsize
00435 * Input/Output: See function arguments to avoid duplication
00436 * Description:
00437 *
00438 *
00439 * History:
00440 * 01-Sep-03     (csabet) Integrated
00441 * 17-Jul-03     (jmeisner) Completed the code
00442 ******************************************************************************/
00443 int determineFFTsize (
00444     int    framesperscan)
00445 {
00446     int  result=1;
00447 
00448     while ((0.7F * ((float) result)) < ((float) framesperscan))
00449         result = 2 * result;
00450     return result;
00451 }
00452 /*****************************************************************************/
00453 

Generated on 5 Mar 2013 for MIDI Pipeline Reference Manual by  doxygen 1.6.1