src/fourier.c

Go to the documentation of this file.
00001 /*
00002    libit - Library for basic source and channel coding functions
00003    Copyright (C) 2005-2005 Vivien Chappelier, Herve Jegou
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public
00016    License along with this library; if not, write to the Free
00017    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00018 */
00019 
00020 /*
00021   Discrete Fourier transform
00022   Copyright (C) 2005 Vivien Chappelier.
00023 
00024   The current algorithm is O(nlogn) for any sizes. Power-of-two sizes use the
00025   FFT, while other sizes use DFT computed as a special case of z-transform.
00026   The z-transform itself done by convolution, which is done by FFT.
00027 
00028   This is certainly not the fastest FFT in the world, possible optimizations
00029   include using higher-radix FFTs and special cases for FFT of real data.
00030 
00031   Many of the tricks used here are well-documented in the following books,
00032   please refer to them for details on the algorithms:
00033   - "DSP Algorithms for Programmers"
00034     by Jorg Arndt
00035     [http://www.jjj.de/fxt/fxtbook.pdf] 
00036   - "Numerical Recipies in C"
00037     by W.H. Press, S.A. Teukolsky, W.T. Wetterling, B.P. Flannery
00038     [http://www.library.cornell.edu/nr/bookcpdf.html]
00039 
00040 */
00041 
00042 #include <it/types.h>
00043 #include <it/fourier.h>
00044 #include <it/io.h>
00045 #include <it/math.h>
00046 
00047 /* buffer size for which memory access latency is not limiting performance */
00048 #define CACHE_SIZE 128*1024 /* sane default, to be automatically tuned later */
00049 #define DFT_LAST   16   /* DFT of smaller size are done directly */
00050 
00051 static unsigned int cache_size = CACHE_SIZE;  /* tunable */
00052 
00053 /* FFT context, read-only once initialized */
00054 static int fft_init_done = 0;
00055 static int fft_log2size;
00056 static cvec dft_roots[DFT_LAST];
00057 static cvec fft_roots;
00058 static ivec fft_perm;
00059 
00060 /* return i such that 1 << i = n if n is a non-zero power of 2 */
00061 static inline int intlog2 (int n)
00062 {
00063   int  i;
00064 
00065   for (i = 0; n; i++, n >>= 1);
00066 
00067   return (i - 1);
00068 }
00069 
00070 /* initialize the FFT context */
00071 void fft_init (void)
00072 {
00073   int  size;
00074   int  i, k, m;
00075 
00076   if (fft_init_done)
00077     return;
00078 
00079   /* FFT data and precomputed roots must both fit in the cache */
00080   size = cache_size / sizeof (cplx) / 2;
00081   fft_log2size = intlog2 (size);
00082   fft_roots = cvec_new_unit_roots (size);
00083   cvec_push (fft_roots, cplx_1);  /* XXX: should not be needed */
00084 
00085   /* precompute the bit inversion permutation */
00086   fft_perm = ivec_new (size);
00087   fft_perm[0] = 0;
00088   fft_perm[size - 1] = size - 1;
00089   for (i = 1, k = 0; i < size - 1; i++) {
00090     m = size;
00091     do {
00092       m >>= 1;
00093       k ^= m;
00094     }
00095     while ((k & m) == 0);
00096     fft_perm[i] = k;
00097   }
00098 
00099   /* precompute the first few roots of unity for direct DFT */
00100   for (i = 2; i < DFT_LAST; i++)
00101     dft_roots[i] = cvec_new_unit_roots (i);
00102 
00103   fft_init_done = 1;
00104 }
00105 
00106 /* permute the elements of an array of complex numbers by inverting the bit */
00107 /* representation of the indexes */
00108 static inline void cplx_array_bitrev_permute (cplx * v, int n)
00109 {
00110   int  i, m, r;
00111 
00112   if (n <= 2)
00113     return;
00114 
00115   r = 0;
00116   for (i = 1; i < n - 1; i++) {
00117     m = n;
00118     do {
00119       m >>= 1;
00120       r ^= m;
00121     }
00122     while ((r & m) == 0);
00123     if (r > i)
00124       cplx_swap (v[i], v[r]);
00125   }
00126 }
00127 
00128 /* The Core FFT algorithm.
00129  * It is quite restrictive as the input must have a length which is a power of
00130  * two and less than half the cache size divided by the size of the complex
00131  * type. All other DFT algorithm are derived from this one.
00132  * No checks are made at this point, they are the responsibility of the
00133  * wrappers. The index permutation is done outside this function as well.
00134  */
00135 
00136 /* forward FFT by decimation in frequency */
00137 static void __fft_dif (cplx * v, int log2n)
00138 {
00139   cvec roots = fft_roots;
00140   int  log2f = fft_log2size;
00141   idx_t n, m, mh, s;
00142   idx_t k, l;
00143   idx_t log2m;
00144   cplx a, b;
00145   cplx *r;
00146 
00147   n = 1 << log2n;
00148 
00149   for (log2m = log2n; log2m > 0; log2m--) {
00150     m = 1 << log2m;
00151     mh = m >> 1;
00152     s = 1 << (log2f - log2m);
00153 
00154     r = &roots[1 << log2f];
00155     for (k = 0; k < mh; k++) {
00156       for (l = 0; l < n; l += m) {
00157   a = v[l + k];
00158   b = v[l + k + mh];
00159   v[l + k] = cadd (a, b);
00160   v[l + k + mh] = cmul (csub (a, b), *r);
00161       }
00162       r -= s;
00163     }
00164   }
00165 }
00166 
00167 /* backward FFT by decimation in time */
00168 static void __ifft_dit (cplx * v, int log2n)
00169 {
00170   cvec roots = fft_roots;
00171   int  log2f = fft_log2size;
00172   idx_t n, m, mh, s;
00173   idx_t k, l;
00174   idx_t log2m;
00175   cplx a, b;
00176   cplx *r;
00177 
00178   n = 1 << log2n;
00179 
00180   for (log2m = 1; log2m <= log2n; log2m++) {
00181     m = 1 << log2m;
00182     mh = m >> 1;
00183     s = 1 << (log2f - log2m);
00184 
00185     r = &roots[0];
00186     for (k = 0; k < mh; k++) {
00187       for (l = 0; l < n; l += m) {
00188   a = v[l + k];
00189   b = cmul (v[l + k + mh], *r);
00190   v[l + k] = cadd (a, b);
00191   v[l + k + mh] = csub (a, b);
00192       }
00193       r += s;
00194     }
00195   }
00196 }
00197 
00198 /* The Recursive FFT algorithm.
00199  * If the input vector fits in the cache, the Core FFT algorithm is called.
00200  * Otherwise, the MFA algorithm is applied on the input vector, considered as
00201  * a matrix with __fft_size rows. Each column is transformed efficiently
00202  * by the core FFT algorithm, and multiplied by the appropriate roots of unity.
00203  * The rows are then transformed by the Recursive FFT algorithm. Putting all
00204  * the coefficient back in order is done elsewhere as some FFT-based algorithms
00205  * don't need it.
00206  */
00207 
00208 static void _fft (cplx * v, int log2n)
00209 {
00210   int  log2f = fft_log2size;
00211   int  f = 1 << log2f;
00212   int  n = 1 << log2n;
00213   cvec tmp;
00214   int  i, j, k;
00215   int  r, log2r;
00216   double c;
00217   cplx *p;
00218   cplx e;
00219 
00220   if (log2n <= log2f) {
00221     /* fits in the cache */
00222     __fft_dif (v, log2n);
00223     return;
00224   }
00225 
00226   /* use the MFA algorithm considering an size x r matrix */
00227   log2r = log2n - log2f;
00228   r = (1 << log2r);
00229 
00230   /* transform the columns */
00231   tmp = cvec_new (f);
00232 
00233   for (j = 0; j < r; j++) {
00234 
00235     /* fetch a column */
00236     for (i = 0; i < f; i++)
00237       tmp[i] = v[j + r * i];
00238 
00239     /* transform it */
00240     __fft_dif (tmp, log2f);
00241 
00242     /* store, permute and multiply terms by e^(- 2*cplx_I*M_PI*i*j/n) */
00243     p = &v[j];
00244     *p = tmp[0];
00245     p += r;
00246 
00247     c = -2 * M_PI * j / n;
00248     for (i = 1; i < f - 1; i++) {
00249 
00250       k = fft_perm[i];
00251 
00252       e.r = cos (c * i);
00253       e.i = sin (c * i);
00254 
00255       *p = cmul (tmp[k], e);
00256       p += r;
00257     }
00258 
00259     e.r = cos (c * (f - 1));
00260     e.i = sin (c * (f - 1));
00261     *p = cmul (tmp[f - 1], e);
00262   }
00263 
00264   cvec_delete (tmp);
00265 
00266   /* transform the rows */
00267   p = v;
00268   for (j = 0; j < f; j++) {
00269     _fft (p, log2r);
00270     p += r;
00271   }
00272 }
00273 
00274 static void _ifft (cplx * v, int log2n)
00275 {
00276   int  log2f = fft_log2size;
00277   int  f = 1 << log2f;
00278   int  n = 1 << log2n;
00279   cvec tmp;
00280   int  i, j, k;
00281   int  r, log2r;
00282   double c;
00283   cplx *p;
00284   cplx e;
00285 
00286   if (log2n <= log2f) {
00287     /* fits in the cache */
00288     __ifft_dit (v, log2n);
00289     return;
00290   }
00291 
00292   /* use the MFA algorithm considering an size x r matrix */
00293   log2r = log2n - log2f;
00294   r = (1 << log2r);
00295 
00296   /* transform the rows */
00297   p = v;
00298   for (j = 0; j < f; j++) {
00299     _ifft (p, log2r);
00300     p += r;
00301   }
00302 
00303   /* transform the columns */
00304   tmp = cvec_new (f);
00305 
00306   for (j = 0; j < r; j++) {
00307 
00308     /* fetch, permute and multiply terms by e^(2*cplx_I*M_PI*i*j/n) */
00309     p = &v[j];
00310     tmp[0] = *p;
00311     p += r;
00312 
00313     c = 2 * M_PI * j / n;
00314     for (i = 1; i < f - 1; i++) {
00315 
00316       k = fft_perm[i];
00317 
00318       e.r = cos (c * i);
00319       e.i = sin (c * i);
00320 
00321       tmp[k] = cmul (*p, e);
00322       p += r;
00323     }
00324 
00325     e.r = cos (c * (f - 1));
00326     e.i = sin (c * (f - 1));
00327     tmp[f - 1] = cmul (*p, e);
00328 
00329     /* transform it */
00330     __ifft_dit (tmp, log2f);
00331 
00332     /* store a column */
00333     for (i = 0; i < f; i++)
00334       v[j + r * i] = tmp[i];
00335   }
00336 
00337   cvec_delete (tmp);
00338 }
00339 
00340 /* Put back the FFT coefficient in correct order */
00341 /* TODO: compute the permutation explicitly to get rid of recursivity */
00342 /* the transform on an index [ a b c d ] of f+f+f+<f bits is          */
00343 /*   f   f   f   <f          <f  f   f   f                            */
00344 /* [ a   b   c   d  ]  ->  [ d'  c   b   a  ]                         */
00345 /* with d' the bit reversed binary representation of d                */
00346 
00347 static void _fft_demangle (cplx * v, int log2n)
00348 {
00349   int  log2f = fft_log2size;
00350   int  f = 1 << log2f;
00351   int  n = 1 << log2n;
00352   int  i, j;
00353   int  r, log2r;
00354   cplx *p;
00355 
00356   if (log2n <= log2f) {
00357     cplx_array_bitrev_permute (v, n);
00358     return;
00359   }
00360 
00361   log2r = log2n - log2f;
00362   r = (1 << log2r);
00363 
00364   /* transpose the rows */
00365   if (log2r > log2f) {
00366     p = v;
00367     for (j = 0; j < f; j++) {
00368       _fft_demangle (p, log2r);
00369       cplx_array_bitrev_permute (p, r);
00370       p += r;
00371     }
00372   }
00373 
00374   cplx_array_bitrev_permute (v, n);
00375 
00376   p = v;
00377   for (i = 0; i < r; i++) {
00378     cplx_array_bitrev_permute (p, f);
00379     p += f;
00380   }
00381 }
00382 
00383 static void _ifft_mangle (cplx * v, int log2n)
00384 {
00385   int  log2f = fft_log2size;
00386   int  f = 1 << log2f;
00387   int  n = 1 << log2n;
00388   int  i, j;
00389   int  r, log2r;
00390   cplx *p;
00391 
00392   if (log2n <= log2f) {
00393     cplx_array_bitrev_permute (v, n);
00394     return;
00395   }
00396 
00397   log2r = log2n - log2f;
00398   r = (1 << log2r);
00399 
00400   /* transpose */
00401   p = v;
00402   for (i = 0; i < r; i++) {
00403     cplx_array_bitrev_permute (p, f);
00404     p += f;
00405   }
00406 
00407   cplx_array_bitrev_permute (v, n);
00408 
00409   /* transform the rows */
00410   if (log2r > log2f) {
00411     p = v;
00412     for (j = 0; j < f; j++) {
00413       cplx_array_bitrev_permute (p, r);
00414       _ifft_mangle (p, log2r);
00415       p += r;
00416     }
00417   }
00418 }
00419 
00420 /* Fast Fourier Transform */
00421 cvec it_fft (cvec v)
00422 {
00423   int  n, log2n;
00424   cvec cv;
00425 
00426   assert (cvec_length (v));
00427 
00428   n = cvec_length (v);
00429   log2n = intlog2 (n);
00430   assert ((1 << log2n) == n);
00431   fft_init ();
00432   cv = cvec_clone (v);
00433   _fft (cv, log2n);
00434   _fft_demangle (cv, log2n);
00435   return (cv);
00436 }
00437 
00438 /* Inverse Fast Fourier Transform */
00439 cvec it_ifft (cvec v)
00440 {
00441   int  n, log2n;
00442   cvec cv;
00443 
00444   assert (cvec_length (v));
00445 
00446   n = cvec_length (v);
00447   log2n = intlog2 (n);
00448   assert ((1 << log2n) == n);
00449   fft_init ();
00450   cv = cvec_clone (v);
00451   _ifft_mangle (cv, log2n);
00452   _ifft (cv, log2n);
00453   cvec_div_by_real (cv, n);
00454   return (cv);
00455 }
00456 
00457 /* convolution by FFT */
00458 cvec cvec_fft_conv (cvec a, cvec b)
00459 {
00460   cvec ta, tb;
00461   int  i, l, n;
00462   int  log2n;
00463 
00464   /* copy and zero pad input to 2^n */
00465   ta = cvec_clone (a);
00466   tb = cvec_clone (b);
00467   l = cvec_length (a);
00468   if (cvec_length (b) > l)
00469     l = cvec_length (b);
00470   log2n = intlog2 (l);
00471   if ((1 << log2n) != l)
00472     log2n++;
00473   log2n++;
00474   n = 1 << log2n;
00475 
00476   cvec_set_length (ta, n);
00477   cvec_set_length (tb, n);
00478 
00479   for (i = cvec_length (a); i < n; i++)
00480     ta[i] = cplx_0;
00481   for (i = cvec_length (b); i < n; i++)
00482     tb[i] = cplx_0;
00483 
00484   /* convolve by product in FFT domain */
00485   fft_init ();
00486   _fft (ta, log2n);
00487   _fft (tb, log2n);
00488   cvec_mul (ta, tb);
00489   cvec_delete (tb);
00490   _ifft (ta, log2n);
00491   cvec_div_by_real (ta, n);
00492   cvec_set_length (ta, cvec_length (a) + cvec_length (b) - 1);
00493   return ta;
00494 }
00495 
00496 /* correlation by FFT */
00497 cvec cvec_fft_corr (cvec a, cvec b)
00498 {
00499   cvec ta, tb;
00500   int  i, l, n;
00501   int  log2n;
00502 
00503   /* copy and zero pad input to 2^n */
00504   ta = cvec_clone (a);
00505   tb = cvec_clone (b);
00506   l = cvec_length (a);
00507   if (cvec_length (b) > l)
00508     l = cvec_length (b);
00509   log2n = intlog2 (l);
00510   if ((1 << log2n) != l)
00511     log2n++;
00512   log2n++;
00513   n = 1 << log2n;
00514 
00515   cvec_set_length (ta, n);
00516   cvec_set_length (tb, n);
00517 
00518   for (i = cvec_length (a); i < n; i++)
00519     ta[i] = cplx_0;
00520   for (i = cvec_length (b); i < n; i++)
00521     tb[i] = cplx_0;
00522 
00523   /* correlate by conjugate product in FFT domain */
00524   fft_init ();
00525   _fft (ta, log2n);
00526   _fft (tb, log2n);
00527   cvec_conj_mul (ta, tb);
00528   cvec_delete (tb);
00529   _ifft (ta, log2n);
00530   cvec_div_by_real (ta, n);
00531   cvec_set_length (ta, l);
00532   return ta;
00533 }
00534 
00535 /* autocorrelation by FFT */
00536 cvec cvec_fft_autocorr (cvec a)
00537 {
00538   cvec ta;
00539   int  i, l, n;
00540   int  log2n;
00541 
00542   /* copy and zero pad input to 2^n */
00543   ta = cvec_clone (a);
00544   l = cvec_length (a);
00545   log2n = intlog2 (l);
00546   if ((1 << log2n) != l)
00547     log2n++;
00548   log2n++;
00549   n = 1 << log2n;
00550 
00551   cvec_set_length (ta, n);
00552 
00553   for (i = cvec_length (a); i < n; i++)
00554     ta[i] = cplx_0;
00555 
00556   /* correlate by conjugate product in FFT domain */
00557   fft_init ();
00558   _fft (ta, log2n);
00559   cvec_abssqr (ta);
00560   _ifft (ta, log2n);
00561   cvec_div_by_real (ta, n);
00562   cvec_set_length (ta, l);
00563   return ta;
00564 }
00565 
00566 /* z-transform through FFT */
00567 cvec it_fzt (cvec v, cplx z)
00568 {
00569   int  i, l, n;
00570   int  log2n;
00571   cplx c, d;
00572   cvec av, bv, cv;
00573   double p;
00574   double rho;
00575   double theta;
00576   double crho;
00577   double s;
00578 
00579   assert (cvec_length (v));
00580   assert (cnorm (z) != 0);
00581 
00582   l = cvec_length (v);
00583 
00584   log2n = intlog2 (l);
00585   if ((1 << log2n) != l)
00586     log2n++;
00587   log2n++;
00588   n = 1 << log2n;
00589 
00590   av = cvec_new (l);
00591   bv = cvec_new_zeros (n);
00592   cv = cvec_new (n);
00593 
00594   /* copy and zero pad */
00595   for (i = 0; i < cvec_length (v); i++)
00596     cv[i] = v[i];
00597 
00598   for (i = cvec_length (v); i < n; i++)
00599     cv[i] = cplx_0;
00600 
00601   /* polar representation of z */
00602   rho = cnorm (z);
00603   theta = cang (z);
00604 
00605   /* elementwise multiply by z^{i^2/2} */
00606   bv[0] = cplx_1;
00607   s = 1.0 / n;
00608 
00609   for (i = 1; i < l; i++) {
00610     p = i * i / 2.0;
00611     crho = pow (rho, p);
00612     creal (c) = crho * cos (theta * p);
00613     cimag (c) = crho * sin (theta * p);
00614     d = cinv (c);
00615     bv[i] = d;
00616     bv[n - i] = d;    /* mirror needed for the convolution */
00617     av[i] = cscale (c, s);
00618     cv[i] = cmul (cv[i], c);
00619   }
00620 
00621   /* convolve in FFT domain by z^{-i^2/2} */
00622   fft_init ();
00623   _fft (cv, log2n);
00624   _fft (bv, log2n);
00625   cvec_mul (cv, bv);
00626   _ifft (cv, log2n);
00627   cvec_delete (bv);
00628 
00629   /* elementwise multiply by z^{i^2/2} */
00630   cv[0].r *= s;
00631   cv[0].i *= s;
00632   for (i = 1; i < l; i++)
00633     cv[i] = cmul (cv[i], av[i]);
00634 
00635   cvec_delete (av);
00636   cvec_set_length (cv, l);
00637 
00638   return (cv);
00639 }
00640 
00641 /* DFT through FFT */
00642 #define FDFT_FORW 0
00643 #define FDFT_BACK 1
00644 static cvec it_fdft (cvec v, int inv)
00645 {
00646   int  i, l, n;
00647   int  log2n;
00648   cplx c, d;
00649   cvec av, bv, cv;
00650   double p;
00651   double s;
00652 
00653   assert (cvec_length (v));
00654 
00655   l = cvec_length (v);
00656 
00657   log2n = intlog2 (l);
00658   if ((1 << log2n) != l)
00659     log2n++;
00660   log2n++;
00661   n = 1 << log2n;
00662 
00663   av = cvec_new (l);
00664   bv = cvec_new_zeros (n);
00665   cv = cvec_new (n);
00666 
00667   /* copy and zero pad */
00668   for (i = 0; i < cvec_length (v); i++)
00669     cv[i] = v[i];
00670 
00671   for (i = cvec_length (v); i < n; i++)
00672     cv[i] = cplx_0;
00673 
00674   /* elementwise multiply by z^{i^2/2} */
00675   bv[0] = cplx_1;
00676   if (inv)
00677     s = 1.0 / n / l;
00678   else
00679     s = 1.0 / n;
00680 
00681   for (i = 1; i < l; i++) {
00682     p = i * i / 2.0;
00683     creal (c) = creal (d) = cos (M_PI * i * i / l);
00684     if (inv) {
00685       cimag (c) = sin (M_PI * i * i / l);
00686       cimag (d) = -cimag (c);
00687     }
00688     else {
00689       cimag (c) = sin (-M_PI * i * i / l);
00690       cimag (d) = -cimag (c);
00691     }
00692     bv[i] = d;
00693     bv[n - i] = d;    /* mirror needed for the convolution */
00694     av[i] = cscale (c, s);
00695     cv[i] = cmul (cv[i], c);
00696   }
00697 
00698   /* convolve in FFT domain by z^{-i^2/2} */
00699   fft_init ();
00700   _fft (cv, log2n);
00701   _fft (bv, log2n);
00702   cvec_mul (cv, bv);
00703   _ifft (cv, log2n);
00704   cvec_delete (bv);
00705 
00706   /* elementwise multiply by z^{i^2/2} */
00707   cv[0].r *= s;
00708   cv[0].i *= s;
00709   for (i = 1; i < l; i++)
00710     cv[i] = cmul (cv[i], av[i]);
00711 
00712   cvec_delete (av);
00713   cvec_set_length (cv, l);
00714 
00715   return (cv);
00716 }
00717 
00718 /* Slow Discrete Fourier Transform */
00719 static cvec it_sdft (cvec v)
00720 {
00721   idx_t n, k, m;
00722   idx_t N;
00723   cvec cv;
00724   cvec roots;
00725 
00726   N = cvec_length (v);
00727   assert (N < DFT_LAST);
00728   cv = cvec_new (N);
00729 
00730   fft_init ();
00731   roots = dft_roots[N];
00732   for (k = 0; k < N; k++) {
00733     cv[k] = cplx_0;
00734     m = 0;
00735     for (n = 0; n < N; n++) {
00736       cv[k] = cadd (cv[k], cmul (v[n], roots[m]));
00737       m += N - k;
00738       m %= N;
00739     }
00740   }
00741   return cv;
00742 }
00743 
00744 /* Slow Inverse Discrete Fourier Transform */
00745 static cvec it_sidft (cvec v)
00746 {
00747   idx_t n, k, m;
00748   idx_t N;
00749   cvec cv;
00750   cvec roots;
00751 
00752   N = cvec_length (v);
00753   assert (N < DFT_LAST);
00754   cv = cvec_new (N);
00755 
00756   fft_init ();
00757   roots = dft_roots[N];
00758   for (n = 0; n < N; n++) {
00759     cv[n] = cplx_0;
00760     m = 0;
00761     for (k = 0; k < N; k++) {
00762       cv[n] = cadd (cv[n], cmul (v[k], roots[m]));
00763       m += n;
00764       m %= N;
00765     }
00766   }
00767   cvec_div_by_real (cv, N);
00768   return cv;
00769 }
00770 
00771 /* Discrete Fourier Transform */
00772 cvec it_dft (cvec v)
00773 {
00774   int  l;
00775   int  log2n;
00776 
00777   l = cvec_length (v);
00778 
00779   if (l == 0)
00780     return cvec_new (0);
00781 
00782   if (l == 1)
00783     return cvec_clone (v);
00784 
00785   log2n = intlog2 (l);
00786 
00787   if (l == (1 << log2n))
00788     return it_fft (v);
00789 
00790   if (l < DFT_LAST)
00791     return it_sdft (v);
00792 
00793   return it_fdft (v, FDFT_FORW);
00794 }
00795 
00796 /* Inverse Discrete Fourier Transform */
00797 cvec it_idft (cvec v)
00798 {
00799   int  l;
00800   int  log2n;
00801 
00802   l = cvec_length (v);
00803 
00804   if (l == 0)
00805     return cvec_new (0);
00806 
00807   if (l == 1)
00808     return cvec_clone (v);
00809 
00810   log2n = intlog2 (l);
00811 
00812   if (l == (1 << log2n))
00813     return it_ifft (v);
00814 
00815   if (l < DFT_LAST)
00816     return it_sidft (v);
00817 
00818   return it_fdft (v, FDFT_BACK);
00819 }
00820 
00821 /* Discrete Fourier Transform for real input data */
00822 cvec it_dft_real (vec v)
00823 {
00824   /* TODO: this is an ugly wrapper, optimized functions should be written */
00825   cvec cv = vec_to_cvec (v);
00826   cvec r = it_dft (cv);
00827   cvec_delete (cv);
00828   return r;
00829 }
00830 
00831 /* Inverse Discrete Fourier Transform for real input data */
00832 vec it_idft_real (cvec cv)
00833 {
00834   /* TODO: this is an ugly wrapper, optimized functions should be written */
00835   int  i, l;
00836   cvec r = it_idft (cv);
00837   vec  v;
00838 
00839   l = cvec_length (cv);
00840   v = vec_new (l);
00841 
00842   for (i = 0; i < l; i++)
00843     v[i] = creal (r[i]);
00844 
00845   cvec_delete (r);
00846   return v;
00847 }
00848 
00849 /*-------------- everything below will be deprecated in later releases ------*/
00850 #if 0
00851 /* do the real DFT in a clever way using the symmetries of the transform.  */
00852 /* the real vector is packed in a complex vector of half the length of the */
00853 /* real vector and the result of the transform is decoupled using a        */
00854 /* mathematical relation involving the roots of unity.                     */
00855 cvec __it_dft_real_fast (vec v)
00856 {
00857   cvec cv, cvt;
00858   cvec roots;
00859   idx_t k, l;
00860 
00861   l = vec_length (v);
00862   assert (l % 2 == 0);    /* require an even-sized vector */
00863 
00864   cv = cvec_new (l / 2);
00865 
00866   /* transform the vec into a cvec as cv[k] = v[2k] + i v[2k+1] */
00867   /* Note: this could be done by casting if we ensure the structure is packed */
00868   /*       there are gcc options for this, I don't know about VC     [Vivien] */
00869   for (k = 0; k < l / 2; k++) {
00870     creal (cv[k]) = v[2 * k];
00871     cimag (cv[k]) = v[2 * k + 1];
00872   }
00873 
00874   /* call the mighty DFT */
00875   cvt = it_dft (cv);
00876   cvec_delete (cv);
00877 
00878   /* compute the conjugate of roots of unity times i */
00879   roots = cvec_new_unit_roots (l);
00880   for (k = 0; k < l; k++) {
00881     double r, i;
00882     r = creal (roots[k]);
00883     i = cimag (roots[k]);
00884     creal (roots[k]) = i;
00885     cimag (roots[k]) = r;
00886   }
00887 
00888   /* separate the result, we use the fact that [c.f. Numerical Recipies in C] */
00889   /* vt = 1/2 * [ (cvt[k] + cvt[N-k]^*) - i (cvt[k] - cvt[N-k]^*) W_N^k^* ]   */
00890   cvec_set_length (cvt, l + 1); /* add one to put the low freq at the end */
00891   cvt[l / 2] = cvt[0];    /* copy the first element so that cvt[l/2] is defined */
00892   for (k = 0; k <= l / 2; k++) {
00893     cplx s = cconj (cvt[l / 2 - k]);  /* TODO insert cvt[0] at position N */
00894     cplx c = cvt[k];
00895 
00896     c = csub (cadd (c, s), cmul (csub (c, s), roots[k]));
00897 
00898     /* store in place */
00899     cvt[l - k] = cconj (c);
00900   }
00901   /* roots, bloody roots */
00902   cvec_delete (roots);
00903 
00904   /* now mirror the beginning */
00905   for (k = 0; k < l / 2; k++)
00906     cvt[k] = cconj (cvt[l - k]);
00907   cvec_set_length (cvt, l); /* forget about the last coeff */
00908 
00909   /* the 1/2 factor in the expression of vt */
00910   cvec_div_by_real (cvt, 2);
00911 
00912   return (cvt);
00913 }
00914 #endif

Hosted by
Copyright (C) 2005-2006 Hervé Jégou
Vivien Chappelier
Francois Cayre
libit logo courtesy of Jonathan Delhumeau