Rosetta
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
kiss_fft.cc
Go to the documentation of this file.
1 // -*- mode:c++;tab-width:2;indent-tabs-mode:t;show-trailing-whitespace:t;rm-trailing-spaces:t -*-
2 // vi: set ts=2 noet:
3 //
4 // (c) Copyright Rosetta Commons Member Institutions.
5 // (c) This file is part of the Rosetta software suite and is made available under license.
6 // (c) The Rosetta software is developed by the contributing members of the Rosetta Commons.
7 // (c) For more information, see http://www.rosettacommons.org. Questions about this can be
8 // (c) addressed to University of Washington UW TechTransfer, email: license@u.washington.edu.
9 
10 /// @file
11 /// @brief
12 /// @author Frank DiMaio
13 
14 
15 // implementation loosely based on Kiss-FFT's fast fourier transform
16 // for licensing info see external/kiss_fft_v1_2_8/COPYING
17 
19 #include <cstdlib> //g++ 4.3.2 requires for exit()
20 //#include <string.h> //g++ 4.3.2 requires for memcpy()
21 // tracer
22 #include <iostream>
23 
24 
25 namespace numeric {
26 namespace fourier {
27 
28 
29 // replace the global variables with classes that protect access to buffer data
30 kiss_fft_cpx* get_scratch_buff( size_t nbuf ) {
31  static kiss_fft_cpx *scratchbuf=NULL;
32  static size_t nscratchbuf=0;
33  if ( nscratchbuf < nbuf ) {
34  delete [] scratchbuf;
35  scratchbuf = new kiss_fft_cpx[ nbuf ];
36  nscratchbuf = nbuf;
37  }
38  // free memory
39  // amw: do not check <= 0 as it is a size_t, eq is sufficient
40  if ( nbuf == 0 ) {
41  delete [] scratchbuf;
42  scratchbuf = NULL;
43  nscratchbuf = 0;
44  }
45  return (scratchbuf);
46 }
47 kiss_fft_cpx* get_tmp_buff( size_t nbuf ) {
48  static kiss_fft_cpx *tmpbuf=NULL;
49  static size_t ntmpbuf=0;
50  if ( ntmpbuf < nbuf ) {
51  delete [] tmpbuf;
52  tmpbuf = new kiss_fft_cpx[ nbuf ];
53  ntmpbuf = nbuf;
54  }
55  // free memory
56  if ( nbuf == 0 ) {
57  delete [] tmpbuf;
58  tmpbuf = NULL;
59  ntmpbuf = 0;
60  }
61  return (tmpbuf);
62 }
63 
64 ///////////////////////////////////////
65 // 1d c->c fft
66 ///////////////////////////////////////
67 void kf_bfly2(
68  kiss_fft_cpx * Fout,
69  const size_t fstride,
70  const kiss_fft_cfg st,
71  int m ) {
72  kiss_fft_cpx * Fout2;
73  kiss_fft_cpx * tw1 = st->twiddles();
74  kiss_fft_cpx t;
75  Fout2 = Fout + m;
76  do{
77  t = (*Fout2) * (*tw1);
78  tw1 += fstride;
79  *Fout2 = (*Fout) - (t);
80  *Fout += t;
81  ++Fout2;
82  ++Fout;
83  }while (--m);
84 }
85 
86 void kf_bfly4(
87  kiss_fft_cpx * Fout,
88  const size_t fstride,
89  const kiss_fft_cfg st,
90  const size_t m ) {
91  kiss_fft_cpx *tw1,*tw2,*tw3;
92  kiss_fft_cpx scratch[6];
93  size_t k=m;
94  const size_t m2=2*m;
95  const size_t m3=3*m;
96 
97  tw3 = tw2 = tw1 = st->twiddles();
98 
99  do {
100  scratch[0] = Fout[m] * (*tw1);
101  scratch[1] = Fout[m2] * (*tw2);
102  scratch[2] = Fout[m3] * (*tw3);
103 
104  scratch[5] = (*Fout) - scratch[1];
105  *Fout += scratch[1];
106  scratch[3] = scratch[0] + scratch[2];
107  scratch[4] = scratch[0] - scratch[2];
108  Fout[m2] = (*Fout) - scratch[3];
109  tw1 += fstride;
110  tw2 += fstride*2;
111  tw3 += fstride*3;
112  *Fout += scratch[3];
113 
114  if ( st->inverse() ) {
115  Fout[m] = kiss_fft_cpx( scratch[5].real() - scratch[4].imag() , scratch[5].imag() + scratch[4].real());
116  Fout[m3] = kiss_fft_cpx( scratch[5].real() + scratch[4].imag() , scratch[5].imag() - scratch[4].real());
117  } else {
118  Fout[m] = kiss_fft_cpx( scratch[5].real() + scratch[4].imag() , scratch[5].imag() - scratch[4].real());
119  Fout[m3] = kiss_fft_cpx( scratch[5].real() - scratch[4].imag() , scratch[5].imag() + scratch[4].real());
120  }
121  ++Fout;
122  }while(--k);
123 }
124 
125 void kf_bfly3(
126  kiss_fft_cpx * Fout,
127  const size_t fstride,
128  const kiss_fft_cfg st,
129  size_t m
130 ) {
131  size_t k=m;
132  const size_t m2 = 2*m;
133  kiss_fft_cpx *tw1,*tw2;
134  kiss_fft_cpx scratch[5];
135  kiss_fft_cpx epi3;
136  epi3 = st->twiddles()[fstride*m];
137 
138  tw1=tw2=st->twiddles();
139 
140  do{
141  scratch[1] = Fout[m] * (*tw1);
142  scratch[2] = Fout[m2] * (*tw2);
143 
144  scratch[3] = scratch[1]+scratch[2];
145  scratch[0] = scratch[1]-scratch[2];
146  tw1 += fstride;
147  tw2 += fstride*2;
148 
149  Fout[m] = kiss_fft_cpx( Fout->real() - (scratch[3].real()/2) , Fout->imag() - (scratch[3].imag()/2) );
150  scratch[0] *= epi3.imag();
151  *Fout += scratch[3];
152 
153  Fout[m2] = kiss_fft_cpx( Fout[m].real() + scratch[0].imag() , Fout[m].imag() - scratch[0].real());
154  Fout[m] = kiss_fft_cpx( Fout[m].real() - scratch[0].imag() , Fout[m].imag() + scratch[0].real());
155 
156  ++Fout;
157  }while(--k);
158 }
159 
160 void kf_bfly5(
161  kiss_fft_cpx * Fout,
162  const size_t fstride,
163  const kiss_fft_cfg st,
164  int m ) {
165  kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4;
166  int u;
167  kiss_fft_cpx scratch[13];
168  kiss_fft_cpx * twiddles = st->twiddles();
169  kiss_fft_cpx *tw;
170  kiss_fft_cpx ya,yb;
171  ya = twiddles[fstride*m];
172  yb = twiddles[fstride*2*m];
173 
174  Fout0=Fout;
175  Fout1=Fout0+m;
176  Fout2=Fout0+2*m;
177  Fout3=Fout0+3*m;
178  Fout4=Fout0+4*m;
179 
180  tw=st->twiddles();
181  for ( u=0; u<m; ++u ) {
182  scratch[0] = *Fout0;
183 
184  scratch[1] = *Fout1 * tw[u*fstride];
185  scratch[2] = *Fout2 * tw[2*u*fstride];
186  scratch[3] = *Fout3 * tw[3*u*fstride];
187  scratch[4] = *Fout4 * tw[4*u*fstride];
188 
189  scratch[7] = scratch[1]+scratch[4];
190  scratch[10] = scratch[1]-scratch[4];
191  scratch[8] = scratch[2]+scratch[3];
192  scratch[9] = scratch[2]-scratch[3];
193 
194  *Fout0 = kiss_fft_cpx( Fout0->real() + scratch[7].real() + scratch[8].real(),
195  Fout0->imag() + scratch[7].imag() + scratch[8].imag() );
196 
197  scratch[5] = kiss_fft_cpx( scratch[0].real() + scratch[7].real()*ya.real() + scratch[8].real()*yb.real() ,
198  scratch[0].imag() + scratch[7].imag()*ya.real() + scratch[8].imag()*yb.real() );
199 
200  scratch[6] = kiss_fft_cpx( (scratch[10].imag()*ya.imag()) + (scratch[9].imag()*yb.imag()) ,
201  -(scratch[10].real()*ya.imag()) - (scratch[9].real()*yb.imag()));
202 
203  *Fout1 = scratch[5]-scratch[6];
204  *Fout4 = scratch[5]+scratch[6];
205 
206  scratch[11] = kiss_fft_cpx( scratch[0].real() + (scratch[7].real()*yb.real()) + (scratch[8].real()*ya.real()),
207  scratch[0].imag() + (scratch[7].imag()*yb.real()) + (scratch[8].imag()*ya.real()));
208  scratch[12] = kiss_fft_cpx( -(scratch[10].imag()*yb.imag()) + (scratch[9].imag()*ya.imag()),
209  (scratch[10].real()*yb.imag()) - (scratch[9].real()*ya.imag()));
210 
211  *Fout2 = scratch[11]+scratch[12];
212  *Fout3 = scratch[11]-scratch[12];
213 
214  ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4;
215  }
216 }
217 
218 // perform the butterfly for one stage of a mixed radix FFT
220  kiss_fft_cpx * Fout,
221  const size_t fstride,
222  const kiss_fft_cfg st,
223  int m,
224  int p
225 ) {
226  int u, q1, q;
227  kiss_fft_cpx * twiddles = st->twiddles();
228  kiss_fft_cpx t;
229  int Norig = st->nfft();
230 
231  //CHECKBUF(scratchbuf,nscratchbuf,p);
232  kiss_fft_cpx *scratchbuf = get_scratch_buff(p);
233 
234  for ( u = 0; u < m; ++u ) {
235  int k = u;
236  for ( q1 = 0 ; q1 < p; ++q1 ) {
237  scratchbuf[ q1 ] = Fout[ k ];
238  k += m;
239  }
240 
241  k = u;
242  for ( q1 = 0 ; q1 < p ; ++q1 ) {
243  int twidx = 0;
244  Fout[ k ] = scratchbuf[ 0 ];
245  for ( q = 1; q < p; ++q ) {
246  twidx += fstride * k;
247  if ( twidx >= Norig ) twidx -= Norig;
248  t = scratchbuf[ q ] * twiddles[ twidx ];
249  Fout[ k ] += t;
250  }
251  k += m;
252  }
253  }
254 }
255 
256 void kf_work(
257  kiss_fft_cpx * Fout,
258  const kiss_fft_cpx * f,
259  const size_t fstride,
260  int in_stride,
261  int * factors,
262  const kiss_fft_cfg st
263 ) {
264  kiss_fft_cpx * Fout_beg=Fout;
265  const int p = *factors++; /* the radix */
266  const int m = *factors++; /* stage's fft length/p */
267  const kiss_fft_cpx * Fout_end = Fout + p*m;
268 
269  if ( m==1 ) {
270  do{
271  *Fout = *f;
272  f += fstride*in_stride;
273  }while(++Fout != Fout_end );
274  } else {
275  do{
276  // recursive call:
277  // DFT of size m*p performed by doing
278  // p instances of smaller DFTs of size m,
279  // each one takes a decimated version of the input
280  kf_work( Fout , f, fstride*p, in_stride, factors,st);
281  f += fstride*in_stride;
282  }while( (Fout += m) != Fout_end );
283  }
284 
285  Fout=Fout_beg;
286 
287  // recombine the p smaller DFTs
288  switch (p) {
289  case 2 : kf_bfly2(Fout,fstride,st,m); break;
290  case 3 : kf_bfly3(Fout,fstride,st,m); break;
291  case 4 : kf_bfly4(Fout,fstride,st,m); break;
292  case 5 : kf_bfly5(Fout,fstride,st,m); break;
293  default : kf_bfly_generic(Fout,fstride,st,m,p); break;
294  }
295 }
296 
297 void kiss_fft_stride(kiss_fft_cfg st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int in_stride) {
298  if ( fin == fout ) {
299  //CHECKBUF(tmpbuf,ntmpbuf,st->nfft);
300  kiss_fft_cpx *tmpbuf = get_tmp_buff(st->nfft());
301  kf_work(tmpbuf,fin,1,in_stride, st->factors(),st);
302  //memcpy(fout,tmpbuf,sizeof(kiss_fft_cpx)*st->nfft());
303  for ( int i=0; i<st->nfft(); ++i ) fout[i]=tmpbuf[i];
304  } else {
305  kf_work( fout, fin, 1,in_stride, st->factors(),st );
306  }
307 }
308 
309 void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout) {
310  kiss_fft_stride(cfg,fin,fout,1);
311 }
312 
315  const kiss_fft_scalar *rin,
316  const kiss_fft_scalar *iin,
317  kiss_fft_scalar *rout,
318  kiss_fft_scalar *iout,
319  int fin_stride,
320  int fout_stride) {
321  // input buffer timedata is stored row-wise
322  int k, ncfft;
323  kiss_fft_cpx *tmpbuf = get_tmp_buff(st->nfft());
324 
325  ncfft = st->substate()->nfft();
326  for ( k = 0; k < ncfft; ++k ) {
327  st->tmpbuf()[k] = kiss_fft_cpx( rin[k*fin_stride],iin[k*fin_stride] );
328  }
329  kiss_fft (st->substate(), st->tmpbuf(), tmpbuf);
330  for ( k = 0; k < ncfft; ++k ) {
331  rout[k*fout_stride] = tmpbuf[k].real();
332  iout[k*fout_stride] = tmpbuf[k].imag();
333  }
334 }
335 
336 
337 // not really necessary to call, but if someone is doing in-place ffts, they may want to free the
338 // buffers from CHECKBUF
339 void kiss_fft_cleanup(void) {
340  get_scratch_buff(0);
341  get_tmp_buff(0);
342 }
343 
345  while ( 1 ) {
346  int m=n;
347  while ( (m%2) == 0 ) m/=2;
348  while ( (m%3) == 0 ) m/=3;
349  while ( (m%5) == 0 ) m/=5;
350  if ( m<=1 ) {
351  break; // n is completely factorable by twos, threes, and fives
352  }
353  n++;
354  }
355  return n;
356 }
357 
358 
359 ///////////////////////////////////////
360 /// real fft
361 ///////////////////////////////////////
362 void kiss_fftr(kiss_fftr_cfg st, const kiss_fft_scalar *timedata, kiss_fft_cpx *freqdata) {
363  // input buffer timedata is stored row-wise
364  int k,ncfft;
365  kiss_fft_cpx fpnk,fpk,f1k,f2k,tw,tdc;
366 
367  if ( st->substate()->inverse() ) {
368  std::cerr << "kiss fft usage error: improper alloc\n";
369  exit(1);
370  }
371 
372  ncfft = st->substate()->nfft();
373 
374  // perform the parallel fft of two real signals packed in real,imag
375  kiss_fft( st->substate() , (const kiss_fft_cpx*)timedata, st->tmpbuf() );
376  // The real part of the DC element of the frequency spectrum in st->tmpbuf
377  // contains the sum of the even-numbered elements of the input time sequence
378  // The imag part is the sum of the odd-numbered elements
379  //
380  // The sum of tdc.r and tdc.i is the sum of the input time sequence.
381  // yielding DC of input time sequence
382  // The difference of tdc.r - tdc.i is the sum of the input (dot product) [1,-1,1,-1...
383  // yielding Nyquist bin of input time sequence
384  tdc = kiss_fft_cpx( st->tmpbuf()[0].real() , st->tmpbuf()[0].imag() );
385  freqdata[0] = kiss_fft_cpx( tdc.real() + tdc.imag() , 0 );
386  freqdata[ncfft] = kiss_fft_cpx( tdc.real() - tdc.imag() , 0 );
387 
388  //std::cout << ((kiss_fft_cpx*)timedata)[0] << " " << ((kiss_fft_cpx*)timedata)[1] << std::endl;
389  //std::cout << st->tmpbuf()[0] << " " << st->tmpbuf()[1] << std::endl;
390 
391  for ( k=1; k <= ncfft/2 ; ++k ) {
392  fpk = st->tmpbuf()[k];
393  fpnk = kiss_fft_cpx( st->tmpbuf()[ncfft-k].real(), -st->tmpbuf()[ncfft-k].imag());
394 
395  f1k = fpk + fpnk;
396  f2k = fpk - fpnk;
397  tw = f2k * st->super_twiddles()[k-1];
398 
399  freqdata[k] = kiss_fft_cpx( (f1k.real() + tw.real())/2.0 , (f1k.imag() + tw.imag())/2.0 );
400  freqdata[ncfft-k] = kiss_fft_cpx( (f1k.real() - tw.real())/2.0 , (tw.imag() - f1k.imag())/2.0);
401  }
402 }
403 
404 void kiss_fftri(kiss_fftr_cfg st, const kiss_fft_cpx *freqdata, kiss_fft_scalar *timedata) {
405  // input buffer timedata is stored row-wise
406  int k, ncfft;
407 
408  if ( st->substate()->inverse() == 0 ) {
409  std::cerr << "kiss fft usage error: improper alloc\n";
410  exit (1);
411  }
412 
413  ncfft = st->substate()->nfft();
414 
415  st->tmpbuf()[0] = kiss_fft_cpx( freqdata[0].real() + freqdata[ncfft].real() ,
416  freqdata[0].real() - freqdata[ncfft].real() );
417 
418  for ( k = 1; k <= ncfft / 2; ++k ) {
419  kiss_fft_cpx fk, fnkc, fek, fok, tmp;
420  fk = freqdata[k];
421  fnkc = kiss_fft_cpx( freqdata[ncfft - k].real() , -freqdata[ncfft - k].imag() );
422 
423  fek = fk + fnkc;
424  tmp = fk - fnkc;
425  fok = tmp * st->super_twiddles()[k-1];
426  st->tmpbuf()[k] = fek + fok;
427  st->tmpbuf()[ncfft - k] = fek - fok;
428 
429  st->tmpbuf()[ncfft - k] = kiss_fft_cpx( st->tmpbuf()[ncfft - k].real() ,
430  -st->tmpbuf()[ncfft - k].imag() );
431  }
432  kiss_fft (st->substate(), st->tmpbuf(), (kiss_fft_cpx *) timedata);
433 }
434 
435 ///////////////////////////////////////
436 /// dct-II
437 ///////////////////////////////////////
438 void kiss_dct(kiss_dct_cfg st, const kiss_fft_scalar *timedata, kiss_fft_scalar *freqdata) {
439  // input buffer timedata is stored row-wise
440  int k,ncfft;
441  kiss_fft_cpx f1k,f2k;
442 
443  if ( st->substate()->inverse() ) {
444  std::cerr << "kiss fft usage error: improper alloc\n";
445  exit(1);
446  }
447 
448  ncfft = st->substate()->nfft();
449 
450  // pack data
451  // ind = [(1:2:n) (n:-2:2)];
452  // a = a(ind);
453  kiss_fft_cpx *tmpbuf = get_tmp_buff(ncfft);
454  for ( k = 0; k < ncfft/2; ++k ) {
455  tmpbuf[k] = kiss_fft_cpx(timedata[2*k],0.0);
456  }
457  for ( k = ncfft/2; k<ncfft; ++k ) {
458  tmpbuf[k] = kiss_fft_cpx(timedata[2*(ncfft-k)-1],0.0);
459  }
460 
461  // fft
462  kiss_fft( st->substate() , tmpbuf, st->tmpbuf() );
463 
464  // twiddle
465  for ( k=0; k<ncfft ; ++k ) {
466  f1k = st->super_twiddles()[k];
467  f2k = st->tmpbuf()[k];
468  freqdata[k] = 2*(f1k.real()*f2k.real() - f1k.imag()*f2k.imag());
469  }
470 }
471 
472 ///////////////////////////////////////
473 /// idct-II (dct-iii)
474 ///////////////////////////////////////
475 void kiss_idct(kiss_dct_cfg st, const kiss_fft_scalar *freqdata, kiss_fft_scalar *timedata) {
476  // input buffer timedata is stored row-wise
477  int k,ncfft;
478  kiss_fft_cpx f1k,f2k;
479  kiss_fft_scalar x0 = freqdata[0];
480 
481  if ( !st->substate()->inverse() ) {
482  std::cerr << "kiss fft usage error: improper alloc\n";
483  exit(1);
484  }
485 
486  ncfft = st->substate()->nfft();
487 
488  // twiddle
489  kiss_fft_cpx *tmpbuf = get_tmp_buff(ncfft);
490  for ( k=0; k<ncfft ; ++k ) {
491  f1k = st->super_twiddles()[k];
492  f2k = kiss_fft_cpx(freqdata[k],0.0);
493  tmpbuf[k] = f1k*f2k;
494  }
495 
496  // fft
497  kiss_fft( st->substate() , tmpbuf, st->tmpbuf() );
498 
499  // unpack data
500  // tmp(1:2:n)=(1:n/2);
501  // tmp(2:2:n)=(n:-1:n/2+1);
502  // ind=tmp
503  for ( k = 0; k < ncfft/2; ++k ) {
504  timedata[2*k] = 2*st->tmpbuf()[k].real() - x0;
505  }
506  for ( k = ncfft/2; k<ncfft; ++k ) {
507  timedata[2*(ncfft-k)-1] = 2*st->tmpbuf()[k].real() - x0;
508  }
509 }
510 
511 
512 ///////////////////////////////////////
513 /// multidim fft
514 ///////////////////////////////////////
515 // This works by tackling one dimension at a time.
516 //
517 // In effect,
518 // Each stage starts out by reshaping the matrix into a DixSi 2d matrix.
519 // A Di-sized fft is taken of each column, transposing the matrix as it goes.
520 //
521 // Here's a 3-d example:
522 // Take a 2x3x4 matrix, laid out in memory as a contiguous buffer
523 // [ [ [ a b c d ] [ e f g h ] [ i j k l ] ]
524 // [ [ m n o p ] [ q r s t ] [ u v w x ] ] ]
525 //
526 // Stage 0 ( D=2): treat the buffer as a 2x12 matrix
527 // [ [a b ... k l]
528 // [m n ... w x] ]
529 //
530 // FFT each column with size 2.
531 // Transpose the matrix at the same time using kiss_fft_stride.
532 //
533 // [ [ a+m a-m ]
534 // [ b+n b-n]
535 // ...
536 // [ k+w k-w ]
537 // [ l+x l-x ] ]
538 //
539 // Note fft([x y]) == [x+y x-y]
540 //
541 // Stage 1 ( D=3) treats the buffer (the output of stage D=2) as an 3x8 matrix,
542 // [ [ a+m a-m b+n b-n c+o c-o d+p d-p ]
543 // [ e+q e-q f+r f-r g+s g-s h+t h-t ]
544 // [ i+u i-u j+v j-v k+w k-w l+x l-x ] ]
545 //
546 // And perform FFTs (size=3) on each of the columns as above, transposing
547 // the matrix as it goes. The output of stage 1 is
548 // (Legend: ap = [ a+m e+q i+u ]
549 // am = [ a-m e-q i-u ] )
550 //
551 // [ [ sum(ap) fft(ap)[0] fft(ap)[1] ]
552 // [ sum(am) fft(am)[0] fft(am)[1] ]
553 // [ sum(bp) fft(bp)[0] fft(bp)[1] ]
554 // [ sum(bm) fft(bm)[0] fft(bm)[1] ]
555 // [ sum(cp) fft(cp)[0] fft(cp)[1] ]
556 // [ sum(cm) fft(cm)[0] fft(cm)[1] ]
557 // [ sum(dp) fft(dp)[0] fft(dp)[1] ]
558 // [ sum(dm) fft(dm)[0] fft(dm)[1] ] ]
559 //
560 // Stage 2 ( D=4) treats this buffer as a 4*6 matrix,
561 // [ [ sum(ap) fft(ap)[0] fft(ap)[1] sum(am) fft(am)[0] fft(am)[1] ]
562 // [ sum(bp) fft(bp)[0] fft(bp)[1] sum(bm) fft(bm)[0] fft(bm)[1] ]
563 // [ sum(cp) fft(cp)[0] fft(cp)[1] sum(cm) fft(cm)[0] fft(cm)[1] ]
564 // [ sum(dp) fft(dp)[0] fft(dp)[1] sum(dm) fft(dm)[0] fft(dm)[1] ] ]
565 //
566 // Then FFTs each column, transposing as it goes.
567 //
568 // The resulting matrix is the 3d FFT of the 2x3x4 input matrix.
569 //
570 // Note as a sanity check that the first element of the final
571 // stage's output (DC term) is
572 // sum( [ sum(ap) sum(bp) sum(cp) sum(dp) ] )
573 // , i.e. the summation of all 24 input elements.
575  int i,k;
576  const kiss_fft_cpx * bufin=fin;
577  kiss_fft_cpx * bufout;
578 
579  // arrange it so the last bufout == fout
580  if ( st->ndims() & 1 ) {
581  bufout = fout;
582  if ( fin==fout ) {
583  //memcpy( st->tmpbuf(), fin, sizeof(kiss_fft_cpx) * st->dimprod() );
584  for ( int i=0; i<st->dimprod(); ++i ) st->tmpbuf()[i]=fin[i];
585  bufin = st->tmpbuf();
586  }
587  } else {
588  bufout = st->tmpbuf();
589  }
590 
591  for ( k=0; k < st->ndims(); ++k ) {
592  int curdim = st->dims()[k];
593  int stride = st->dimprod() / curdim;
594 
595  for ( i=0 ; i<stride ; ++i ) {
596  kiss_fft_stride( st->states(k), bufin+i , bufout+i*curdim, stride );
597  }
598 
599  // toggle back and forth between the two buffers
600  if ( bufout == st->tmpbuf() ) {
601  bufout = fout;
602  bufin = st->tmpbuf();
603  } else {
604  bufout = st->tmpbuf();
605  bufin = fout;
606  }
607  }
608 }
609 
610 
611 ///////////////////////////////////////
612 // Multidim real FFT
613 ///////////////////////////////////////
614 void kiss_fftndr(kiss_fftndr_cfg st, const kiss_fft_scalar *timedata, kiss_fft_cpx *freqdata) {
615  int k1,k2;
616  int dimReal = st->dimReal();
617  int dimOther = st->dimOther();
618  int nrbins = dimReal/2+1;
619 
620  kiss_fft_cpx * tmp1 = (kiss_fft_cpx*)st->tmpbuf();
621  kiss_fft_cpx * tmp2 = tmp1 + std::max(nrbins,dimOther);
622 
623  // timedata is N0 x N1 x ... x Nk real
624  // take a real chunk of data, fft it and place the output at correct intervals
625  for ( k1=0; k1<dimOther; ++k1 ) {
626  kiss_fftr( st->cfg_r(), timedata + k1*dimReal , tmp1 ); // tmp1 now holds nrbins complex points
627  for ( k2=0; k2<nrbins; ++k2 ) {
628  tmp2[ k2*dimOther+k1 ] = tmp1[k2];
629  }
630  }
631 
632  for ( k2=0; k2<nrbins; ++k2 ) {
633  kiss_fftnd(st->cfg_nd(), tmp2+k2*dimOther, tmp1); // tmp1 now holds dimOther complex points
634  for ( k1=0; k1<dimOther; ++k1 ) {
635  freqdata[ k1*(nrbins) + k2] = tmp1[k1];
636  }
637  }
638 }
639 
640 void kiss_fftndri(kiss_fftndr_cfg st, const kiss_fft_cpx *freqdata, kiss_fft_scalar *timedata) {
641  int k1,k2;
642  int dimReal = st->dimReal();
643  int dimOther = st->dimOther();
644  int nrbins = dimReal/2+1;
645  kiss_fft_cpx * tmp1 = (kiss_fft_cpx*)st->tmpbuf();
646  kiss_fft_cpx * tmp2 = tmp1 + std::max(nrbins,dimOther);
647 
648  for ( k2=0; k2<nrbins; ++k2 ) {
649  for ( k1=0; k1<dimOther; ++k1 ) {
650  tmp1[k1] = freqdata[ k1*(nrbins) + k2 ];
651  }
652  kiss_fftnd(st->cfg_nd(), tmp1, tmp2+k2*dimOther);
653  }
654 
655  for ( k1=0; k1<dimOther; ++k1 ) {
656  for ( k2=0; k2<nrbins; ++k2 ) {
657  tmp1[k2] = tmp2[ k2*dimOther+k1 ];
658  }
659  kiss_fftri( st->cfg_r(),tmp1,timedata + k1*dimReal);
660  }
661 }
662 
663 }
664 }
ocstream cerr(std::cerr)
Wrapper around std::cerr.
Definition: ocstream.hh:290
void kiss_fftr(kiss_fftr_cfg st, const kiss_fft_scalar *timedata, kiss_fft_cpx *freqdata)
real fft
Definition: kiss_fft.cc:362
class kiss_fftnd_state * kiss_fftnd_cfg
void kiss_idct(kiss_dct_cfg st, const kiss_fft_scalar *freqdata, kiss_fft_scalar *timedata)
idct-II (dct-iii)
Definition: kiss_fft.cc:475
int kiss_fft_next_fast_size(int n)
Definition: kiss_fft.cc:344
#define kiss_fft_scalar
void kf_work(kiss_fft_cpx *Fout, const kiss_fft_cpx *f, const size_t fstride, int in_stride, int *factors, const kiss_fft_cfg st)
Definition: kiss_fft.cc:256
void kiss_fft_split(kiss_fftsplit_cfg st, const kiss_fft_scalar *rin, const kiss_fft_scalar *iin, kiss_fft_scalar *rout, kiss_fft_scalar *iout, int fin_stride, int fout_stride)
Definition: kiss_fft.cc:313
class kiss_fftsplit_state * kiss_fftsplit_cfg
void kf_bfly_generic(kiss_fft_cpx *Fout, const size_t fstride, const kiss_fft_cfg st, int m, int p)
Definition: kiss_fft.cc:219
void kf_bfly2(kiss_fft_cpx *Fout, const size_t fstride, const kiss_fft_cfg st, int m)
Definition: kiss_fft.cc:67
void kiss_fft(kiss_fft_cfg cfg, const kiss_fft_cpx *fin, kiss_fft_cpx *fout)
Definition: kiss_fft.cc:309
void kiss_dct(kiss_dct_cfg st, const kiss_fft_scalar *timedata, kiss_fft_scalar *freqdata)
dct-II
Definition: kiss_fft.cc:438
void kf_bfly4(kiss_fft_cpx *Fout, const size_t fstride, const kiss_fft_cfg st, const size_t m)
Definition: kiss_fft.cc:86
tuple p
Definition: docking.py:9
void kiss_fftri(kiss_fftr_cfg st, const kiss_fft_cpx *freqdata, kiss_fft_scalar *timedata)
Definition: kiss_fft.cc:404
class kiss_fftr_state * kiss_fftr_cfg
kiss_fft_cpx * get_scratch_buff(size_t nbuf)
Definition: kiss_fft.cc:30
void kiss_fftndr(kiss_fftndr_cfg st, const kiss_fft_scalar *timedata, kiss_fft_cpx *freqdata)
Definition: kiss_fft.cc:614
void kiss_fft_stride(kiss_fft_cfg st, const kiss_fft_cpx *fin, kiss_fft_cpx *fout, int in_stride)
Definition: kiss_fft.cc:297
kiss_fft_cpx * get_tmp_buff(size_t nbuf)
Definition: kiss_fft.cc:47
class kiss_dct_state * kiss_dct_cfg
void kiss_fft_cleanup(void)
Definition: kiss_fft.cc:339
void kiss_fftndri(kiss_fftndr_cfg st, const kiss_fft_cpx *freqdata, kiss_fft_scalar *timedata)
Definition: kiss_fft.cc:640
void kf_bfly3(kiss_fft_cpx *Fout, const size_t fstride, const kiss_fft_cfg st, size_t m)
Definition: kiss_fft.cc:125
BooleanOptionKey const exit("options:exit")
Definition: OptionKeys.hh:51
void kf_bfly5(kiss_fft_cpx *Fout, const size_t fstride, const kiss_fft_cfg st, int m)
Definition: kiss_fft.cc:160
std::complex< kiss_fft_scalar > kiss_fft_cpx
static T max(T x, T y)
Definition: Svm.cc:19
class kiss_fftndr_state * kiss_fftndr_cfg
class kiss_fft_state * kiss_fft_cfg
void kiss_fftnd(kiss_fftnd_cfg st, const kiss_fft_cpx *fin, kiss_fft_cpx *fout)
multidim fft
Definition: kiss_fft.cc:574