/Users/lyon/j4p/src/math/transforms/DFT.java

1    package math.transforms; 
2     
3     
4     
5    import sound.Oscillator; 
6     
7    import java.awt.*; 
8     
9    public class DFT extends Frame { 
10    
11       private double r_data[] = null; 
12       private double i_data[] = null; 
13    
14    
15       private String title = "FFT :"; 
16    
17       // if forward = true then perform a forward fft 
18       // else perform a backward fft; 
19       private boolean forward = true; 
20       private int nu; // number of bits needed to represent the index for r_data 
21       private static final float twoPI = (float) (2 * Math.PI); 
22    
23       public DFT(int N) { 
24           r_data = new double[N]; 
25           i_data = new double[N]; 
26       } 
27    
28       public DFT() { 
29       } 
30    
31    
32    
33       public void graphs(String t) { 
34           setTitle(t); 
35       } 
36    
37       public void setTitle(String t) { 
38           title = t; 
39       } 
40    
41   // swap Zi with Zj 
42       private void swapInt(int i, int j) { 
43           double tempr; 
44           int ti; 
45           int tj; 
46           ti = i - 1; 
47           tj = j - 1; 
48           tempr = r_data[tj]; 
49           r_data[tj] = r_data[ti]; 
50           r_data[ti] = tempr; 
51           tempr = i_data[tj]; 
52           i_data[tj] = i_data[ti]; 
53           i_data[ti] = tempr; 
54       } 
55    
56       public static double getMaxValue(double in[]) { 
57           double max; 
58           max = -0.99e30; 
59           for (int i = 0; i < in.length; i++) 
60               if (in[i] > max) 
61                   max = in[i]; 
62           return max; 
63    
64       } 
65    
66       private void normalizeAndTruncateInput(double in[]) { 
67           double data_max = getMaxValue(in); 
68           /* copy over normalized input */ 
69           for (int i = 0; i < r_data.length; i++) { 
70               r_data[i] = in[i]; 
71           } 
72       } 
73    
74       private void bitReverse2() { 
75           System.out.println("fft: bit reversal"); 
76           /* bit reversal */ 
77           int n = r_data.length; 
78           int j = 1; 
79    
80           int k; 
81    
82           for (int i = 1; i < n; i++) { 
83    
84               if (i < j) swapInt(i, j); 
85               k = n / 2; 
86               while (k >= 1 && k < j) { 
87    
88                   j = j - k; 
89                   k = k / 2; 
90               } 
91               j = j + k; 
92           } // for 
93       } 
94    
95       private int bitr(int j) { 
96           int ans = 0; 
97           for (int i = 0; i < nu; i++) { 
98               ans = (ans << 1) + (j & 1); 
99               j = j >> 1; 
100          } 
101          return ans; 
102      } 
103   
104      public void reverseFFT(double in_r[], double in_i[]) { 
105          forward = false; 
106          forwardFFT(in_r, in_i); 
107          forward = true; 
108          //centering(in_r); 
109      } 
110   
111      private void centering(double r[]) { 
112          int s = 1; 
113          for (int i = 0; i < r.length; i++) { 
114              s = -s; 
115              r[i] *= s; 
116          } 
117      } 
118   
119      public void forwardFFT(double in_r[], double in_i[]) { 
120          int id; 
121   
122          int localN; 
123          double wtemp, Wjk_r, Wjk_i, Wj_r, Wj_i; 
124          double theta, tempr, tempi; 
125          int ti, tj; 
126   
127          int numBits = log2(in_r.length); 
128          if (forward) { 
129              //centering(in_r); 
130          } 
131   
132   
133          // Truncate input data to a power of two 
134          int length = 1 << numBits; // length = 2**nu 
135          int n = length; 
136          int nby2; 
137   
138          // Copy passed references to variables to be used within 
139          // fft routines & utilities 
140          r_data = in_r; 
141          i_data = in_i; 
142   
143          bitReverse2(); 
144          for (int m = 1; m <= numBits; m++) { 
145              // localN = 2^m; 
146              localN = 1 << m; 
147   
148              nby2 = localN / 2; 
149              Wjk_r = 1; 
150              Wjk_i = 0; 
151   
152              theta = Math.PI / nby2; 
153   
154              // for recursive comptutation of sine and cosine 
155              Wj_r = Math.cos(theta); 
156              Wj_i = -Math.sin(theta); 
157              if (forward == false) { 
158                  Wj_i = -Wj_i; 
159              } 
160   
161   
162              for (int j = 0; j < nby2; j++) { 
163                  // This is the FFT innermost loop 
164                  // Any optimizations that can be made here will yield 
165                  // great rewards. 
166                  for (int k = j; k < n; k += localN) { 
167                      id = k + nby2; 
168                      tempr = Wjk_r * r_data[id] - Wjk_i * i_data[id]; 
169                      tempi = Wjk_r * i_data[id] + Wjk_i * r_data[id]; 
170   
171                      // Zid = Zi -C 
172                      r_data[id] = r_data[k] - tempr; 
173                      i_data[id] = i_data[k] - tempi; 
174                      r_data[k] += tempr; 
175                      i_data[k] += tempi; 
176                  } 
177   
178                  // (eq 6.23) and (eq 6.24) 
179   
180                  wtemp = Wjk_r; 
181   
182                  Wjk_r = Wj_r * Wjk_r - Wj_i * Wjk_i; 
183                  Wjk_i = Wj_r * Wjk_i + Wj_i * wtemp; 
184              } 
185          } 
186          // normalize output of fft. 
187          if (forward) 
188              for (int i = 0; i < r_data.length; i++) { 
189                  r_data[i] = r_data[i] / (double) n; 
190                  i_data[i] = i_data[i] / (double) n; 
191              } 
192          in_r = r_data; 
193          in_r = i_data; 
194      } 
195   
196      public static int log2(int n) { 
197          return (int) (Math.log(n) / Math.log(2.0)); 
198      } 
199   
200      public static double[] arrayCopy(double[] in) { 
201          int N = in.length; 
202          double out[] = new double[N]; 
203          for (int i = 0; i < N; i++) { 
204              out[i] = in[i]; 
205          } 
206          return out; 
207      } 
208   
209      public double[] dft(double v[]) { 
210          int N = v.length; 
211   
212          double t_img, t_real; 
213   
214          double twoPikOnN; 
215          double twoPijkOnN; 
216   
217          // how many bits do we need? 
218          N = log2(N); 
219          //Truncate input data to a power of two 
220          // length = 2**(number of bits). 
221          N = 1 << N; 
222   
223          double twoPiOnN = 2 * Math.PI / N; 
224          // We truncate to a power of two so that 
225          // we can compare execution times with the FFT. 
226          // DFT generally does not need to truncate its input. 
227   
228          r_data = new double[N]; 
229          i_data = new double[N]; 
230          double psd[] = new double[N]; 
231   
232   
233          System.out.println("Executing DFT on " + N + " points..."); 
234   
235          for (int k = 0; k < N; k++) { 
236   
237              twoPikOnN = twoPiOnN * k; 
238   
239   
240              for (int j = 0; j < N; j++) { 
241                  twoPijkOnN = twoPikOnN * j; 
242                  r_data[k] += v[j] * Math.cos(twoPijkOnN); 
243                  i_data[k] -= v[j] * Math.sin(twoPijkOnN); 
244              } 
245          } 
246          normalizeData(); 
247          return (getPowerSpectralDensity()); 
248      } 
249   
250      private void normalizeData() { 
251          int N = r_data.length; 
252          for (int k = 0; k < N; k++) { 
253              r_data[k] /= N; 
254              i_data[k] /= N; 
255          } 
256   
257      } 
258   
259      public double[] getReal() { 
260          return r_data; 
261      } 
262   
263      public double[] getImaginary() { 
264          return i_data; 
265      } 
266   
267   
268      public double[] getPowerSpectralDensity() { 
269          double[] psd = new double[r_data.length]; 
270          for (int k = 0; k < r_data.length; k++) { 
271              psd[k] = 
272                      r_data[k] * r_data[k] + 
273                      i_data[k] * i_data[k]; 
274   
275          } 
276          return psd; 
277      } 
278   
279      // assume that r_data and i_data are 
280      // set. Also assume that the real 
281      // value is to be returned 
282      public double[] ifft() { 
283          int i,  m, j, id; 
284          int N; // the radix 2 number of samples 
285          double wtemp, wr, wpr, wpi, wi, theta, tempr, tempi; 
286   
287          // length is the number of input samples 
288          int length = r_data.length; 
289   
290          // how many bits do we need? 
291          nu = (int) (Math.log(length) / Math.log(2.0)); 
292          //Truncate input data to a power of two 
293          length = 1 << nu; // length = 2**nu 
294   
295          int ti, tj; 
296   
297          int n = length; 
298   
299          for (m = 1; m <= nu; m++) { 
300   
301              // k = 2^m; 
302              N = 1 << m; 
303              theta = twoPI / N; 
304              // theta = - 2Pi/(2^m) 
305   
306              wr = 1.0; 
307              wi = 0.0; 
308              wpr = Math.cos(theta); 
309   
310              // ifft uses - sin(theta); 
311              wpi = -Math.sin(theta); 
312   
313   
314              for (j = 1; j <= N / 2; j++) { 
315                  for (i = j; i <= n; i = i + N) { 
316   
317                      id = i + N / 2; 
318                      tempr = wr * r_data[id - 1] - wi * i_data[id - 1]; 
319                      tempi = wr * i_data[id - 1] + wi * r_data[id - 1]; 
320   
321                      // Zid-1 = Zi-1 - C(tempr,tempi) 
322                      r_data[id - 1] = r_data[i - 1] - tempr; 
323                      i_data[id - 1] = i_data[i - 1] - tempi; 
324                      r_data[i - 1] += tempr; 
325                      i_data[i - 1] += tempi; 
326                  } 
327                  wtemp = wr; 
328                  // W = W * WP 
329                  // W = (wr + i wi) (wpr + i wpi) 
330                  // W = wr * wpr - wi * wpi + i (wi * wpr + wr * wpi) 
331                  wr = wr * wpr - wi * wpi; 
332                  wi = wi * wpr + wtemp * wpi; 
333              } 
334          } 
335          return (arrayCopy(r_data)); 
336      } 
337   
338   
339      // assume that r_data and i_data are 
340      // set. Also assume that the real 
341      // value is to be returned 
342      public double[] idft() { 
343          int N = r_data.length; 
344          double twoPiOnN = 2 * Math.PI / N; 
345   
346          double twoPikOnN; 
347          double twoPijkOnN; 
348   
349          double v[] = new double[N]; 
350   
351          System.out.println("Executing IDFT on " + N + " points..."); 
352   
353   
354          for (int k = 0; k < N; k++) { 
355              twoPikOnN = twoPiOnN * k; 
356              for (int j = 0; j < N; j++) { 
357                  twoPijkOnN = twoPikOnN * j; 
358                  v[k] += r_data[j] * Math.cos(twoPijkOnN) 
359                          - i_data[j] * Math.sin(twoPijkOnN); 
360   
361              } 
362          } 
363          return (v); 
364      } 
365   
366      public static void printArray(double[] v, String title) { 
367          System.out.println(title); 
368          for (int i = 0; i < v.length; i++) { 
369              System.out.println("v[" + i + "]=" + v[i]); 
370          } 
371      } 
372   
373   
374      public void printArrays(String title) { 
375          System.out.println(title); 
376          for (int i = 0; i < r_data.length; i++) { 
377              System.out.println("[" + i + "]=(" 
378                      + r_data[i] + "," + i_data[i] + ")"); 
379          } 
380   
381      } 
382   
383      public void printReal(String title) { 
384          System.out.println(title); 
385          for (int i = 0; i < r_data.length; i++) { 
386              System.out.println( 
387                      "r_data[" + i + "]=" 
388                      + r_data[i]); 
389          } 
390   
391      } 
392   
393      public static void main(String args[]) { 
394          Oscillator.testAudioDft(); 
395   
396      } 
397   
398      public static void testPSD() { 
399   
400   
401          DFT f = new DFT(); 
402   
403          int N = 8; 
404          int numBits = log2(N); 
405   
406          double x1[] = new double[N]; 
407          for (int j = 0; j < N; j++) 
408              x1[j] = j; 
409   
410   
411          double[] in_r = new double[N]; 
412          double[] in_i = new double[N]; 
413   
414          // copy test signal. 
415          in_r = arrayCopy(x1); 
416   
417          f.forwardFFT(in_r, in_i); 
418          f.printArrays("After the FFT"); 
419          double psd[] = f.getPowerSpectralDensity(); 
420          DFT.printArray(psd, "The psd"); 
421      } 
422   
423      public static void timeFFT() { 
424          int N = 2048; 
425          DFT f = new DFT(N); 
426          int numBits = log2(N); 
427   
428          double x1[] = new double[N]; 
429          for (int j = 0; j < N; j++) 
430              x1[j] = j; 
431   
432   
433          double[] in_r = new double[N]; 
434          double[] in_i = new double[N]; 
435   
436          double[] fftResult_r = new double[N]; 
437          double[] fftResult_i = new double[N]; 
438   
439          // copy test signal. 
440          in_r = arrayCopy(x1); 
441   
442   
443          f.forwardFFT(in_r, in_i); 
444   
445   
446          System.out.print("Time for " + N + "point fft"); 
447   
448   
449          // Copy to new array because IFFT will 
450          // destroy the FFT results. 
451          fftResult_r = arrayCopy(in_r); 
452          fftResult_i = arrayCopy(in_i); 
453   
454   
455          f.reverseFFT(in_r, in_i); 
456   
457          System.out.print("Time for " + N + "point ifft"); 
458   
459   
460   
461      } 
462   
463      public static void testFFT() { 
464          System.out.println("Starting 1D FFT test..."); 
465          DFT f = new DFT(); 
466   
467          int N = 8; 
468          int numBits = log2(N); 
469   
470          double x1[] = new double[N]; 
471          for (int j = 0; j < N; j++) 
472              x1[j] = j; 
473   
474   
475          double[] in_r = new double[N]; 
476          double[] in_i = new double[N]; 
477   
478          double[] fftResult_r = new double[N]; 
479          double[] fftResult_i = new double[N]; 
480   
481          // copy test signal. 
482          in_r = arrayCopy(x1); 
483   
484          f.forwardFFT(in_r, in_i); 
485   
486          // Copy to new array because IFFT will 
487          // destroy the FFT results. 
488          fftResult_r = arrayCopy(in_r); 
489          fftResult_i = arrayCopy(in_i); 
490   
491   
492          f.reverseFFT(in_r, in_i); 
493   
494          System.out.println("j\tx1[j]\tre[j]\tim[j]\tv[j]"); 
495          for (int i = 0; i < N; i++) { 
496              System.out.println( 
497                      i + "\t" + 
498                      x1[i] + "\t" + 
499                      fftResult_r[i] + "\t" + 
500                      fftResult_i[i] + "\t" + 
501                      in_r[i]); 
502          } 
503   
504      } 
505   
506      public static void print(double o[]){ 
507          for (int i=0; i < o.length; i++) 
508              System.out.println(o[i]); 
509      } 
510      public static void testDFT() { 
511   
512          int N = 8; 
513          DFT f = new DFT(N); 
514   
515          double v[]; 
516          double x1[] = new double[N]; 
517          for (int j = 0; j < N; j++) 
518              x1[j] = j; 
519   
520          // take dft 
521          f.dft(x1); 
522          v = f.idft(); 
523          System.out.println("j\tx1[j]\tre[j]\tim[j]\t v[j]"); 
524          for (int j = 0; j < N; j++) 
525              System.out.println( 
526                      j + "\t" + 
527                      x1[j] + "\t" + 
528                      f.r_data[j] + "\t" + 
529                      f.i_data[j] + "\t" + 
530                      v[j]); 
531   
532      } 
533   
534  } 
535