Edinburgh Speech Tools  2.1-release
fft.cc
Go to the documentation of this file.
1 /*************************************************************************/
2 /* */
3 /* Centre for Speech Technology Research */
4 /* University of Edinburgh, UK */
5 /* Copyright (c) 1994,1995,1996 */
6 /* All Rights Reserved. */
7 /* */
8 /* Permission is hereby granted, free of charge, to use and distribute */
9 /* this software and its documentation without restriction, including */
10 /* without limitation the rights to use, copy, modify, merge, publish, */
11 /* distribute, sublicense, and/or sell copies of this work, and to */
12 /* permit persons to whom this work is furnished to do so, subject to */
13 /* the following conditions: */
14 /* 1. The code must retain the above copyright notice, this list of */
15 /* conditions and the following disclaimer. */
16 /* 2. Any modifications must be clearly marked as such. */
17 /* 3. Original authors' names are not deleted. */
18 /* 4. The authors' names are not used to endorse or promote products */
19 /* derived from this software without specific prior written */
20 /* permission. */
21 /* */
22 /* THE UNIVERSITY OF EDINBURGH AND THE CONTRIBUTORS TO THIS WORK */
23 /* DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING */
24 /* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT */
25 /* SHALL THE UNIVERSITY OF EDINBURGH NOR THE CONTRIBUTORS BE LIABLE */
26 /* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES */
27 /* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN */
28 /* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, */
29 /* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF */
30 /* THIS SOFTWARE. */
31 /* */
32 /*************************************************************************/
33 /* Author : Simon King (taken from Tony Robinson) */
34 /* Date : July 1994 */
35 /*-----------------------------------------------------------------------*/
36 /* FFT functions */
37 /* */
38 /*=======================================================================*/
39 
40 #include <cmath>
41 //#include <iostream>
42 //#include <fstream>
43 #include "sigpr/EST_fft.h"
44 #include "EST_math.h"
45 #include "EST_error.h"
46 
47 #define PI8 0.392699081698724 /* PI / 8.0 */
48 #define RT2 1.4142135623731 /* sqrt(2.0) */
49 #define IRT2 0.707106781186548 /* 1.0/sqrt(2.0) */
50 
51 static void FR2TR(int, float*, float*);
52 static void FR4TR(int, int, float*, float*, float*, float*);
53 static void FORD1(int, float*);
54 static void FORD2(unsigned int, float*);
55 
56 /*
57 ** FAST(b,n)
58 ** This routine replaces the float vector b
59 ** of length n with its finite discrete fourier transform.
60 ** DC term is returned in b[0];
61 ** n/2th harmonic float part in b[1].
62 ** jth harmonic is returned as complex number stored as
63 ** b[2*j] + i b[2*j + 1]
64 ** (i.e., remaining coefficients are as a DPCOMPLEX vector).
65 **
66 */
67 
68 
69 static int slowFFTsub(EST_FVector &real, EST_FVector &imag, float f)
70 {
71  // f = -1 for FFT, 1 for IFFT
72  // would be nicer if we used a complex number class,
73  // but we don't, so it isn't
74 
75  // taken from the FORTRAN old chestnut
76  // in various sig proc books
77  // FORTRAN uses 1..n arrays, so subtract 1 all over the place
78 
79 
80  float u_real,u_imag;
81  float w_real,w_imag;
82  float t_real,t_imag;
83  float tmp_real,tmp_imag;
84 
85  int M,N;
86  int i,j,k,l;
87 
88  M = fastlog2(real.n());
89  N = (int)pow(float(2.0),(float)M);
90 
91  if (N != real.n())
92  {
93  EST_warning("Illegal FFT order %d", real.n());
94  return -1;
95  }
96 
97  for(l=1;l<=M;l++){
98 
99  int le = (int)pow(float(2.0),(float)(M+1-l));
100  int le1=le/2;
101 
102  u_real = 1.0;
103  u_imag = 0.0;
104 
105  w_real=cos(PI/le1);
106  w_imag=f * sin(PI/le1);
107 
108  for (j=1;j<=le1;j++)
109  {
110  for (i=j;i<=N-le1;i+=le)
111  {
112  int ip=i+le1;
113  t_real = real.a_no_check(i-1) + real.a_no_check(ip-1);
114  t_imag = imag.a_no_check(i-1) + imag.a_no_check(ip-1);
115 
116  tmp_real = real.a_no_check(i-1) - real.a_no_check(ip-1);
117  tmp_imag = imag.a_no_check(i-1) - imag.a_no_check(ip-1);
118 
119  real.a_no_check(ip-1) = tmp_real*u_real - tmp_imag*u_imag;
120  imag.a_no_check(ip-1) = tmp_real*u_imag + tmp_imag*u_real;
121 
122  real.a_no_check(i-1) = t_real;
123  imag.a_no_check(i-1) = t_imag;
124  }
125 
126  tmp_real = u_real*w_real - u_imag*w_imag;
127  tmp_imag = u_real*w_imag + u_imag*w_real;
128 
129  u_real=tmp_real;
130  u_imag=tmp_imag;
131 
132  }
133 
134  }
135 
136 
137  int NV2=N/2;
138  int NM1=N-1;
139  j=1;
140 
141 
142  for (i=1; i<=NM1;i++)
143  {
144  if (i < j)
145  {
146  t_real=real(j-1);
147  t_imag=imag(j-1);
148 
149  real[j-1] = real(i-1);
150  imag[j-1] = imag(i-1);
151 
152  real[i-1] = t_real;
153  imag[i-1] = t_imag;
154 
155  }
156 
157  k=NV2;
158 
159  while(k < j)
160  {
161  j=j-k;
162  k=k/2;
163  }
164 
165  j=j+k;
166 
167  }
168 
169  return 0;
170 }
171 
172 
173 int slowFFT(EST_FVector &real, EST_FVector &imag)
174 {
175  return slowFFTsub(real,imag,-1.0);
176 }
177 
178 
179 int slowIFFT(EST_FVector &real, EST_FVector &imag)
180 {
181  int N=real.n();
182  if (N <=0 )
183  return -1;
184 
185  if (slowFFTsub(real,imag,1.0) != 0)
186  return -1;
187 
188  for(int i=1;i<=N;i++){
189  real[i-1] /= (float)N;
190  imag[i-1] /= (float)N;
191  }
192 
193  return 0;
194 }
195 
196 
198 {
199  if (slowFFT(real, imag) != 0)
200  return -1;
201 
202  int i;
203  for(i=0;i<real.n();i++)
204  real[i] = imag[i] = (real(i)*real(i) + imag(i)*imag(i));
205 
206  return 0;
207 }
208 
210 {
211 
212  if (slowFFT(real,imag) != 0)
213  return -1;
214 
215  int i;
216  for(i=0;i<real.n();i++)
217  real[i] = imag[i] = sqrt((real(i)*real(i) + imag(i)*imag(i)));
218 
219  return 0;
220 }
221 
223 {
224 
225  if (fastFFT(real) == 0)
226  return -1;
227 
228  int i,j,k;
229  int n=real.n();
230  for(i=0,j=0, k=1;i<n;i+=2,j++,k+=2)
231  real.a_no_check(j)
232  = imag.a_no_check(j)
233  = sqrt((real.a_no_check(i)*real.a_no_check(i)
234  + real.a_no_check(k)*real.a_no_check(k)));
235 
236  return 0;
237 }
238 
239 // the following code is not by Simon King, as you can see
240 /*
241 ** Discrete Fourier analysis routine
242 ** from IEEE Programs for Digital Signal Processing
243 ** G. D. Bergland and M. T. Dolan, original authors
244 ** Translated from the FORTRAN with some changes by Paul Kube
245 **
246 ** Modified to return the power spectrum by Chuck Wooters
247 **
248 ** Modified again by Tony Robinson (ajr@eng.cam.ac.uk) Dec 92
249 **
250 ** Modified to use EST_FVector class Simon King (simonk@cstr.ed.ac.uk) Nov 96
251 **
252 */
253 
254 #define signum(i) (i < 0 ? -1 : i == 0 ? 0 : 1)
255 
256 int fastFFT(EST_FVector &invec)
257 {
258  // Tony Robinsons
259  /*float fn;*/
260  int i, in, nn, n2pow, n4pow;
261  /*int nthpo;*/
262 
263  // we could modify all the code to use vector classes ....
264  // ... or we could do this:
265 
266  // TO DO
267  // use FSimpleVector::copy_section here
268 
269  // quick fix
270  int n=invec.n(); // order
271 
272 #if 0
273  float *b = new float[n];
274  for(i=0; i<n; i++)
275  b[i] = invec(i);
276 #endif
277  float *b=invec.memory();
278 
279  n2pow = fastlog2(n);
280  if (n2pow <= 0) return 0;
281  /*nthpo = n;*/
282  /*fn = nthpo;*/
283  n4pow = n2pow / 2;
284 
285  /* radix 2 iteration required; do it now */
286  if (n2pow % 2)
287  {
288  nn = 2;
289  in = n / nn;
290  FR2TR(in, b, b + in );
291  }
292  else nn = 1;
293 
294  /* perform radix 4 iterations */
295  for(i = 1; i <= n4pow; i++) {
296  nn *= 4;
297  in = n / nn;
298  FR4TR(in, nn, b, b + in, b + 2 * in, b + 3 * in);
299  }
300 
301  /* perform inplace reordering */
302  FORD1(n2pow, b);
303  FORD2(n2pow, b);
304 
305  /* take conjugates */
306  for(i = 3; i < n; i += 2) b[i] = -b[i];
307 
308 #if 0
309  // copy back
310  for(i=0; i<n; i++)
311  invec[i] = b[i];
312 #endif
313 
314  return 1;
315 }
316 
317 /* radix 2 subroutine */
318 void FR2TR(int in, float *b0, float *b1)
319 {
320  int k;
321  float t;
322  for (k = 0; k < in; k++)
323  {
324  t = b0[k] + b1[k];
325  b1[k] = b0[k] - b1[k];
326  b0[k] = t;
327  }
328 }
329 
330 /* radix 4 subroutine */
331 void FR4TR(int in, int nn, float *b0, float *b1, float *b2, float* b3) {
332  float arg, piovn, th2;
333  float *b4 = b0, *b5 = b1, *b6 = b2, *b7 = b3;
334  float t0, t1, t2, t3, t4, t5, t6, t7;
335  float r1, r5, pr, pi;
336  float c1, c2, c3, s1, s2, s3;
337 
338  int j, k, jj, kk, jthet, jlast, ji, jl, jr, int4;
339  int L[16], L1, L2, L3, L4, L5, L6, L7, L8, L9, L10, L11, L12, L13, L14, L15;
340  int j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14;
341  int k0, kl;
342 
343  L[1] = nn / 4;
344  for(k = 2; k < 16; k++) { /* set up L's */
345  switch (signum(L[k-1] - 2)) {
346  case -1:
347  L[k-1]=2;
348  L[k]=2;
349  break;
350  case 0:
351  L[k]=2;
352  break;
353  case 1:
354  L[k]=L[k-1]/2;
355  }
356  }
357 
358  L15=L[1]; L14=L[2]; L13=L[3]; L12=L[4]; L11=L[5]; L10=L[6]; L9=L[7];
359  L8=L[8]; L7=L[9]; L6=L[10]; L5=L[11]; L4=L[12]; L3=L[13]; L2=L[14];
360  L1=L[15];
361 
362  piovn = PI / nn;
363  ji=3;
364  jl=2;
365  jr=2;
366 
367  for(j1=2;j1<=L1;j1+=2)
368  for(j2=j1;j2<=L2;j2+=L1)
369  for(j3=j2;j3<=L3;j3+=L2)
370  for(j4=j3;j4<=L4;j4+=L3)
371  for(j5=j4;j5<=L5;j5+=L4)
372  for(j6=j5;j6<=L6;j6+=L5)
373  for(j7=j6;j7<=L7;j7+=L6)
374  for(j8=j7;j8<=L8;j8+=L7)
375  for(j9=j8;j9<=L9;j9+=L8)
376  for(j10=j9;j10<=L10;j10+=L9)
377  for(j11=j10;j11<=L11;j11+=L10)
378  for(j12=j11;j12<=L12;j12+=L11)
379  for(j13=j12;j13<=L13;j13+=L12)
380  for(j14=j13;j14<=L14;j14+=L13)
381  for(jthet=j14;jthet<=L15;jthet+=L14)
382  {
383  th2 = jthet - 2;
384  if(th2<=0.0)
385  {
386  for(k=0;k<in;k++)
387  {
388  t0 = b0[k] + b2[k];
389  t1 = b1[k] + b3[k];
390  b2[k] = b0[k] - b2[k];
391  b3[k] = b1[k] - b3[k];
392  b0[k] = t0 + t1;
393  b1[k] = t0 - t1;
394  }
395  if(nn-4>0)
396  {
397  k0 = in*4 + 1;
398  kl = k0 + in - 1;
399  for (k=k0;k<=kl;k++)
400  {
401  kk = k-1;
402  pr = IRT2 * (b1[kk]-b3[kk]);
403  pi = IRT2 * (b1[kk]+b3[kk]);
404  b3[kk] = b2[kk] + pi;
405  b1[kk] = pi - b2[kk];
406  b2[kk] = b0[kk] - pr;
407  b0[kk] = b0[kk] + pr;
408  }
409  }
410  }
411  else
412  {
413  arg = th2*piovn;
414  c1 = cos(arg);
415  s1 = sin(arg);
416  c2 = c1*c1 - s1*s1;
417  s2 = c1*s1 + c1*s1;
418  c3 = c1*c2 - s1*s2;
419  s3 = c2*s1 + s2*c1;
420 
421  int4 = in*4;
422  j0=jr*int4 + 1;
423  k0=ji*int4 + 1;
424  jlast = j0+in-1;
425  for(j=j0;j<=jlast;j++)
426  {
427  k = k0 + j - j0;
428  kk = k-1; jj = j-1;
429  r1 = b1[jj]*c1 - b5[kk]*s1;
430  r5 = b1[jj]*s1 + b5[kk]*c1;
431  t2 = b2[jj]*c2 - b6[kk]*s2;
432  t6 = b2[jj]*s2 + b6[kk]*c2;
433  t3 = b3[jj]*c3 - b7[kk]*s3;
434  t7 = b3[jj]*s3 + b7[kk]*c3;
435  t0 = b0[jj] + t2;
436  t4 = b4[kk] + t6;
437  t2 = b0[jj] - t2;
438  t6 = b4[kk] - t6;
439  t1 = r1 + t3;
440  t5 = r5 + t7;
441  t3 = r1 - t3;
442  t7 = r5 - t7;
443  b0[jj] = t0 + t1;
444  b7[kk] = t4 + t5;
445  b6[kk] = t0 - t1;
446  b1[jj] = t5 - t4;
447  b2[jj] = t2 - t7;
448  b5[kk] = t6 + t3;
449  b4[kk] = t2 + t7;
450  b3[jj] = t3 - t6;
451  }
452  jr += 2;
453  ji -= 2;
454  if(ji-jl <= 0) {
455  ji = 2*jr - 1;
456  jl = jr;
457  }
458  }
459  }
460 }
461 
462 /* an inplace reordering subroutine */
463 void FORD1(int m, float *b) {
464  int j, k = 4, kl = 2, n = 0x1 << m;
465  float t;
466 
467  for(j = 4; j <= n; j += 2) {
468  if (k - j>0) {
469  t = b[j-1];
470  b[j - 1] = b[k - 1];
471  b[k - 1] = t;
472  }
473  k -= 2;
474  if (k - kl <= 0) {
475  k = 2*j;
476  kl = j;
477  }
478  }
479 }
480 
481 void FORD2(unsigned int m, float *b) {
482  float t;
483  const int n = 0x1<<m; /* 2^m */
484  unsigned int k;
485  float l[15];
486  #define l15 l[0]
487  #define l14 l[1]
488  #define l13 l[2]
489  #define l12 l[3]
490  #define l11 l[4]
491  #define l10 l[5]
492  #define l9 l[6]
493  #define l8 l[7]
494  #define l7 l[8]
495  #define l6 l[9]
496  #define l5 l[10]
497  #define l4 l[11]
498  #define l3 l[12]
499  #define l2 l[13]
500  #define l1 l[14]
501  l[0] = n;
502 
503  for (k=1;k<m;++k) {
504  l[k] = l[k-1]/2;
505  }
506  /* g++ 4.8 with -O3 and -Warray-bounds will generate a
507  false warning on the next loop:
508  */
509  for (k=m;k<15;++k) {
510  l[k] = 2;
511  }
512  int ij = 2;
513  for (int j1=2;j1<=l1;j1+=2) {
514  for (int j2=j1;j2<=l2;j2+=l1) {
515  for (int j3=j2;j3<=l3;j3+=l2) {
516  for (int j4=j3;j4<=l4;j4+=l3) {
517  for (int j5=j4;j5<=l5;j5+=l4) {
518  for (int j6=j5;j6<=l6;j6+=l5) {
519  for (int j7=j6;j7<=l7;j7+=l6) {
520  for (int j8=j7;j8<=l8;j8+=l7) {
521  for (int j9=j8;j9<=l9;j9+=l8) {
522  for (int j10=j9;j10<=l10;j10+=l9) {
523  for (int j11=j10;j11<=l11;j11+=l10) {
524  for (int j12=j11;j12<=l12;j12+=l11) {
525  for (int j13=j12;j13<=l13;j13+=l12) {
526  for (int j14=j13;j14<=l14;j14+=l13) {
527  for (int ji=j14;ji<=l15;ji+=l14) {
528  if (ij-ji < 0) {
529  t = b[ij-2];
530  b[ij-2] = b[ji-2];
531  b[ji-2] = t;
532  t = b[ij-1];
533  b[ij-1] = b[ji-1];
534  b[ji-1] = t;
535  }
536  ij += 2;
537  }}}}}}}}}}}}}}}
538  #undef l15
539  #undef l13
540  #undef l12
541  #undef l11
542  #undef l10
543  #undef l9
544  #undef l8
545  #undef l7
546  #undef l6
547  #undef l5
548  #undef l4
549  #undef l3
550  #undef l2
551  #undef l1
552  return;
553 }
554 
555 int fastlog2(int n) {
556  int num_bits, power = 0;
557 
558  if ((n < 2) || (n % 2 != 0)) return(0);
559  num_bits = sizeof(int) * 8; /* How big are ints on this machine? */
560 
561  while(power <= num_bits) {
562  n >>= 1;
563  power += 1;
564  if (n & 0x01) {
565  if (n > 1) return(0);
566  else return(power);
567  }
568  }
569  return(0);
570 }
#define l6
A vector class for floating point numbers. EST_FVector x should be used instead of float *x wherever ...
Definition: EST_FMatrix.h:119
#define l10
int slowFFT(EST_FVector &real, EST_FVector &imag)
Basic in-place FFT.
Definition: fft.cc:173
int fastlog2(int n)
Definition: fft.cc:555
#define l14
#define l5
#define l15
INLINE const T & a_no_check(ssize_t n) const
read-only const access operator: without bounds checking
Definition: EST_TVector.h:254
void power(EST_Wave &sig, EST_Track &a, float factor)
Definition: sigpr_utt.cc:422
#define l3
int fastFFT(EST_FVector &invec)
Fast FFT An optimised implementation by Tony Robinson to be used in preference to slowFFT...
Definition: fft.cc:256
#define l12
#define l4
#define l11
#define l7
int slowIFFT(EST_FVector &real, EST_FVector &imag)
Basic inverse in-place FFT.
Definition: fft.cc:179
#define l2
int power_spectrum_slow(EST_FVector &real, EST_FVector &imag)
Power spectrum using the slowFFT function.
Definition: fft.cc:209
#define IRT2
Definition: fft.cc:49
f
Definition: EST_item_aux.cc:48
#define l9
getString int
Definition: EST_item_aux.cc:50
void pr(LISP p)
Definition: slib.cc:1941
int energy_spectrum(EST_FVector &real, EST_FVector &imag)
Definition: fft.cc:197
#define PI
Definition: EST_Complex.h:48
const T * memory() const
Definition: EST_TVector.h:238
#define EST_warning
Definition: EST_error.h:106
#define l13
#define l1
#define l8
INLINE ssize_t n() const
number of items in vector.
Definition: EST_TVector.h:251
#define signum(i)
Definition: fft.cc:254
int power_spectrum(EST_FVector &real, EST_FVector &imag)
Power spectrum using the fastFFT function.
Definition: fft.cc:222