MIDI Pipeline Reference Manual  2.8.3
fft.c
1 /******************************************************************************
2 *******************************************************************************
3 * European Southern Observatory
4 * VLTI MIDI Data Reduction Software
5 *
6 * Module name: fft.c
7 * Description: This is the new COMPILER INDEPENDENT fft module for NRTS etc.
8 *
9 * History:
10 * 03-Feb-03 (jmeisner) Created
11 * 03-Mar-03 (csabet) Added title, directives and included in the MIDI pipeline
12 *******************************************************************************
13 ******************************************************************************/
14 
15 /******************************************************************************
16 * Compiler directives
17 ******************************************************************************/
18 
19 /******************************************************************************
20 * Include files
21 ******************************************************************************/
22 #include <stdio.h>
23 #include <cpl.h>
24 #include <stdlib.h>
25 #include <math.h>
26 #include "complex_midi.h"
27 #include "compiler.h"
28 #include "fft.h"
29 
30 /**********************************************************
31 * Global Variables
32 **********************************************************/
33 // This number (power of 2) is the maximum array size supported:
34 // NOW IN FFT.H: #define MAXFFTSIZE 1024
35 // was called: BIGGER 256 #define BIGGER2 BIGGER/2
36 int FFTsize = 2; // (Formerly XX)
37 int FFThalfsize = 1; // (Formerly XX2)
38 int FFTlevel = 1; // FFTsize = 2^FFTlevel
39 int shuffle[MAXFFTSIZE];
40 
41 // New, array in which FFT is processed, and results delivered:
42 struct Complex *FFTarray ; // Changed to dynamic memory (csabet 11-Jan-2007)
43 
44 float ScaleFFTby; // Applies to entire fft
45  // REVERSED: Now ScaleFFTby is used by the FFT and NOT by the IFT!!
46  // Only used for IFT, ==1 if forward FT
47 
48 struct Complex Twiddle[MAXFFTSIZE/2]; // Now always set for forward xfrm
49 struct Complex Rotated;
50 // Now local to DoFFT: int skip,groups,TwiddleIndex;
51 
52 
53 
54 /*============================ C O D E A R E A ===========================*/
55 
56 // This function now returns all bit reversals
57 // First, the QC x86 inline assembly code:
58 
59 #ifdef QUICK_C /*---------------------------------------*/
60 
61 static int BitReverse(int x,int NumBits)
62 {
63  _asm
64  {
65  mov cx, NumBits;
66  mov dx, x;
67  sub ax, ax;
68 TOP:
69  rcr dx,1;
70  rcl ax,1;
71  loop TOP;
72  }
73 } // Ignore compiler warning about "no return value"
74 #else /*---------------------------------------*/
75 
76 static int BitReverse(int x, int NumBits)
77 {
78  int result = 0;
79  int i;
80  for(i=0; i<NumBits; i++)
81  {
82  result *= 2;
83  if(x&1)
84  result++;
85  x /= 2 ;
86  }
87  return result;
88 }
89 #endif /*---------------------------------------*/
90 
91 
92 // used to initialize the shuffled index
93 // and twiddle arrays:
94 void FFTInit(int level) // Now only runs when needed!! // no longer: , int inverse)
95 {
96  int i;
97  float angle=0.F, incr;
98 
99  if(level==FFTlevel) // If already correctly set...
100  return; // then nothing to do!!
101 
102  FFTlevel = level;
103 
104  FFTsize = 1 << level;
105  FFThalfsize = FFTsize/2 ;
106 
107  if(FFTsize>MAXFFTSIZE)
108  ERROR(-111) ; // not!: "requested FFT level exceeds max!");
109 
110 // NEW NORMALIZATION SCHEME, Constant division ONLY for INVERSE xfrm:
111 // Now, only USED by IFT, set regardless:
112 
113 // if(inverse) // REVERSED: Now ScaleFFTby is used by the FFT and NOT by the IFT!!
114 
115  ScaleFFTby = 1.F/((double) FFTsize) ;
116 
117 // else
118 // ScaleFFTby = 1.F;
119 
120 // Num2shuffle = 0;
121 
122  for (i=0; i<FFTsize; i++)
123  {
124  shuffle[i] = BitReverse(i, level);
125  }
126 
127  incr = -6.2831853F / ((float) FFTsize) ; // (1 << level) ;
128 
129 // NAH: if(inverse) incr = -incr ;
130 
131  for (i=0;i < FFThalfsize; i++) // this array needs only be 1/2 the array size
132  {
133  GetEtoJtimes(angle, &Twiddle[i]);
134  angle += incr;
135  }
136 }
137 
138  // FOR FORWARD XFRM:
139 static void ButterflyXfwd (int AIndex, int BIndex, int TwiddleIndex,
140  struct Complex arr1[])
141 // AIndex and BIndex are indices pointing to which elements
142 // are to be butterflied
143 {
144  MultiplyCptr(&Rotated, &arr1[BIndex], &Twiddle[TwiddleIndex] );
145  SubtractCptr( &arr1[BIndex] , &arr1[AIndex] , &Rotated);
146  AddCptr( &arr1[AIndex] , &arr1[AIndex] , &Rotated);
147 }
148  // FOR INVERSE XFRM:
149 static void ButterflyXinv (int AIndex, int BIndex, int TwiddleIndex,
150  struct Complex arr1[])
151 // AIndex and BIndex are indices pointing to which elements
152 // are to be butterflied
153 {
154  MultiplyConjPtr(&Rotated, &arr1[BIndex], &Twiddle[TwiddleIndex] );
155  SubtractCptr( &arr1[BIndex] , &arr1[AIndex] , &Rotated);
156  AddCptr( &arr1[AIndex] , &arr1[AIndex] , &Rotated);
157 }
158 
159  // For type2 algorithm:
160 static void Type2ButterflyXinv (int AIndex, int BIndex, int TwiddleIndex,
161  struct Complex arr1[])
162 // AIndex and BIndex are indices pointing to which elements
163 // are to be butterflied
164 {
165  struct Complex temp;
166  SubtractCptr(&temp, &arr1[AIndex], &arr1[BIndex]); // To become a index
167  AddCptr(&arr1[AIndex], &arr1[AIndex] , &arr1[BIndex]);
168  MultiplyConjPtr(&arr1[BIndex], &temp, &Twiddle[TwiddleIndex] );
169 }
170 
171 
172 
173 void DoFFT(void) // This runs the actual math, after data is in FFTarray:
174 { // REVERSED: Now ScaleFFTby is used by the FFT and NOT by the IFT!! (must be done by calling program)
175  int i, j, k;
176  int skip=1;
177  int groups = FFTsize ;
178  int TwiddleIndex, IndexA, IndexB;
179  // these three nested loops are the core of the FFT
180 
181  for (k=0;k<FFTlevel;k++) // loop #1 for all the levels
182  {
183  /******** Now these are set differently:
184  skip= (1<<k); // (int)pow(2,k);
185  groups= FFTsize/(2*skip); // why divided by 2 ? because for a 16 element -
186  *************/ // the first one is 8(groups) x 1(skip)
187  groups /= 2 ; // <<<< Here for groups
188 
189  // loop #2 --"group" loop -- XX/2 at first, 1 at the end
190  for (j=0;j<groups;j++) //= skip * 2)
191  {
192  TwiddleIndex=0;
193  IndexA = j * skip * 2;
194  IndexB = IndexA + skip;
195 
196  // and here is loop # 3 - twiddle loops for each group
197  for (i=0;i<skip;i++)
198  {
199  ButterflyXfwd(IndexA++, IndexB++, TwiddleIndex, FFTarray);
200  // Was: j * skip * 2 +i, j * skip * 2 + skip + i , TwiddleIndex, FFTarray);
201  TwiddleIndex+= groups;
202  }
203  }
204  skip *= 2 ;
205  }
206 }
207 
208 
209 void DoIFT(void) // Identical to above, except uses ButterflyXinv
210 { // IFT must also (in calling program) apply the scale ScaleFFTby <<< NOT
211  int i, j, k;
212  int skip=1;
213  int groups = FFTsize ;
214  int TwiddleIndex, IndexA, IndexB;
215  // these three nested loops are the core of the FFT
216 
217  for (k=0;k<FFTlevel;k++) // loop #1 for all the levels
218  {
219  groups /= 2 ; // <<<< Here for groups
220 
221  // loop #2 --"group" loop -- XX/2 at first, 1 at the end
222  for (j=0;j<groups;j++) //= skip * 2)
223  {
224  TwiddleIndex=0;
225  IndexA = j * skip * 2;
226  IndexB = IndexA + skip;
227 
228  // and here is loop # 3 - twiddle loops for each group
229  for (i=0;i<skip;i++)
230  {
231  ButterflyXinv(IndexA++, IndexB++, TwiddleIndex, FFTarray);
232  TwiddleIndex+= groups;
233  }
234  }
235  skip *= 2 ;
236  }
237 }
238 
239 
240 void Type2DoIFT(void) // NEW! NEW!
241 { // IFT must also (in calling program) apply the scale ScaleFFTby <<< NOT
242  int i, j, k;
243  int skip = FFTsize; // BACKWARDS: =1;
244  int groups = 1; // not: FFTsize ;
245  int TwiddleIndex, IndexA, IndexB;
246  // these three nested loops are the core of the FFT
247 
248  for (k=0;k<FFTlevel;k++) // loop #1 for all the levels
249  {
250  skip /= 2; // <<<< HERE now
251  // not: groups /= 2 ; // <<<< Here for groups
252  // but, below: groups *= 2;
253 
254  // BACKWARDS: // loop #2 --"group" loop -- XX/2 at first, 1 at the end
255  for (j=0;j<groups;j++) //= skip * 2)
256  {
257  TwiddleIndex=0;
258  IndexA = j * skip * 2;
259  IndexB = IndexA + skip;
260 
261  // and here is loop # 3 - twiddle loops for each group
262  for (i=0;i<skip;i++)
263  {
264  Type2ButterflyXinv(IndexA++, IndexB++, TwiddleIndex, FFTarray);
265  TwiddleIndex+= groups;
266  }
267  }
268  // BACKWARDS: skip *= 2 ; /// <<<< And here!
269  // but above: skip /= 2;
270  groups *= 2; // <<< NOW HERE
271  }
272 }
273 
274 // USER LEVEL FUNCTIONS:
275 
276 void FFT(struct Complex *Input, int newlevel) // Vector1[], int level)
277 {
278  int i;
279 
280  FFTInit(newlevel);
281 
282  for(i=0; i<FFTsize; i++) // Shuffle the data:
283  {
284  FFTarray[shuffle[i]] = Scalec(Input[i], ScaleFFTby); // rather than Input[i] ;
285  }
286 
287  DoFFT(); // <<< And actually do it!
288 }
289 
290 void IFT(struct Complex *Input, int newlevel) // Vector1[], int level)
291 {
292  int i;
293 
294  if(newlevel != FFTlevel)
295 
296  for(i=0; i<FFTsize; i++) // Shuffle the data:
297  { // AND SCALE since its the IFT:
298  FFTarray[shuffle[i]] = Input[i] ; // NO LONGER: Scalec(Input[i], ScaleFFTby);
299  }
300 
301  DoIFT(); // <<< And actually do it!
302 }
303 
304 /* static void Type2IFT(struct Complex *Output, int newlevel) // Vector1[], int level) */
305 /* { */
306 /* int i; */
307 
308 /* FFTInit(newlevel); */
309 
310 /* // Input in fftarray, so... */
311 /* Type2DoIFT(); // <<< And actually do it! */
312 
313 /* for(i=0; i<FFTsize; i++) // Shuffle the data: */
314 /* { // AND SCALE since its the IFT: */
315 /* Output[shuffle[i]] = FFTarray[i] ; // No longer: Scalec(FFTarray[i], ScaleFFTby); */
316 /* } */
317 /* } */
318 
319 /* static void Type2IFTtoReal(float *Output, int newlevel) // Vector1[], int level) */
320 /* { */
321 /* int i; */
322 
323 /* FFTInit(newlevel); */
324 
325 /* // Input in fftarray, so... */
326 /* Type2DoIFT(); // <<< And actually do it! */
327 
328 /* for(i=0; i<FFTsize; i++) // Shuffle the data: */
329 /* { // AND SCALE since its the IFT: */
330 /* Output[shuffle[i]] = FFTarray[i].r ; // NO LONGER: * ScaleFFTby; */
331 /* } */
332 /* } */
333 
334 /*********** Set FFTlevel & init so just large enough for InputSize *******/
335 void SetFFTsize(int InputSize)
336 {
337  int newFFTlevel = FFTlevel;
338 
339  while(InputSize > FFTsize)
340  {
341  newFFTlevel++;
342  FFTsize *= 2;
343  }
344 
345  while(2*InputSize <= FFTsize)
346  {
347  newFFTlevel--;
348  FFTsize /= 2;
349  }
350 
351  FFTInit(newFFTlevel);
352 }
353 
354 /************ FURTHER USER LEVEL FUNCTIONS ****************/
355 
356 void FFTofReal(float *Input, int InputSize) // Enter size of array to be xfrmd
357 {
358  int i;
359  SetFFTsize(InputSize);
360 
361  for(i=0; i<InputSize; i++)
362  {
363  FFTarray[shuffle[i]].r = Input[i]*ScaleFFTby; // YES NEEDED // NOT NEEDED, =1 for forward FFT: *ScaleFFTby;
364  FFTarray[shuffle[i]].i = 0.F;
365  }
366 
367  for(i=InputSize; i<FFTsize; i++)
368  {
369  FFTarray[shuffle[i]].r = FFTarray[shuffle[i]].i = 0.F;
370  }
371 
372  DoFFT();
373 }
374 
375 
376 // For this version, FFTlevel/size must be set in advance & FFTinit() done:
377 // Produces even (symetric) function over full range & produces cosine xfrm
378 
379 void FFTfullReal(float *Input, int InputSize, float scale) // Enter size of array to be xfrmd
380 {
381  int i;
382  struct Complex Ctemp;
383 // NOW A GLOBAL VAR: int FFThalfsize = FFTsize/2;
384  float inputscale = ((float)InputSize) /((float)FFThalfsize) ;
385 
386  scale *= ScaleFFTby ; // Include this factor here, now.
387 
388  Ctemp.i = 0.F;
389 
390 // NO LONGER NEEDED: if(FFTinverseMode) // in case it got switched somehow!!
391 // FFTInit(FFTlevel, 0);
392 
393  for(i=0; i<FFThalfsize; i++)
394  {
395  Ctemp.r = scale*Input[((int) (((float)i) * inputscale))] ;
396 
397 // SHOULD BE:
398  FFTarray[shuffle[i]] = FFTarray[shuffle[FFTsize-i]] = Ctemp;
399  }
400  // NEW:
401  FFTarray[1].r = scale*Input[InputSize-1] ; // To make continuous!!
402  FFTarray[1].i = 0.F ; // This is the FFThalfsize pt.
403 
404  DoFFT();
405 }
406 
407 
408  // Does NOT attempt to reduce the size of the fft array!!:
409  // Should have run SetFFTsize() first!
410 /* static void FFTofShortArray(struct Complex *Input, int InputSize) */
411 /* { */
412 /* int i; */
413 
414 /* for(i=0; i<InputSize; i++) */
415 /* { */
416 /* FFTarray[shuffle[i]] = Scalec(Input[i], ScaleFFTby); */
417 /* } */
418 
419 /* for(i=InputSize; i<FFTsize; i++) */
420 /* { */
421 /* FFTarray[shuffle[i]].r = FFTarray[shuffle[i]].i = 0.F; */
422 /* } */
423 
424 /* DoFFT(); */
425 /* } */
426 
427 /*****************************************************************************/
428 
429 
430 /******************************************************************************
431 * European Southern Observatory
432 * VLTI MIDI Data Reduction Software
433 *
434 * Module name: determineFFTsize
435 * Input/Output: See function arguments to avoid duplication
436 * Description:
437 *
438 *
439 * History:
440 * 01-Sep-03 (csabet) Integrated
441 * 17-Jul-03 (jmeisner) Completed the code
442 ******************************************************************************/
443 int determineFFTsize (
444  int framesperscan)
445 {
446  int result=1;
447 
448  while ((0.7F * ((float) result)) < ((float) framesperscan))
449  result = 2 * result;
450  return result;
451 }
452 /*****************************************************************************/
453