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