FFT (高速フーリエ・コサイン・サイン変換) の概略と設計法
http://www.kurims.kyoto-u.ac.jp/~ooura/fftman/index.html
2.1.1 複素 FFT を間接的に用いる方法
http://www.kurims.kyoto-u.ac.jp/~ooura/fftman/ftmn2_1.html#sec2_1_1
第二の方法
長さ半分の複素FFTで実数のFFTを行う。
ソース
n=1<<30 でも使えるようにするため、参照元とnのスケーリングが異なる。
r_fft で a[n].r の値が存在するが、格納場所が無いので a[0].i に入れる。
r_carry で配列を超える繰越値は、配列の最後尾に入れる。
r_ifft 本来なら周波数間引きかな?でも作れないので wi の符号逆転で対応する。スケーリングが気になったが問題無いようだ。
これもメモリーのランダムアクセスになるのでかなり重いと思われる。使うなら相応のチューニングが必要かな?
/* 実数fft後処理 */ void *r_fft( int nx,ad_t a[] ) { double wr,wi,tmpr,tmpi,r; int m,n,mr,nr ; n = 1<< nx ; tmpr = a[0].r ; a[0].r = tmpr + a[0].i ; a[0].i = tmpr - a[0].i ; r = M_PI /(double)n; mr = n - 1 ; nr = 0 ; for( m = 1 ; m < n/2 ; m++ ) { nr = inc_rvbit(nx,nr); wi = cos(r*(double)m)*0.5; wr = sin(r*(double)m)*0.5+0.5; tmpr = wr * (a[nr].r - a[mr].r) - wi * (a[nr].i + a[mr].i); tmpi = wr * (a[nr].i + a[mr].i) + wi * (a[nr].r - a[mr].r); a[nr].r = a[nr].r - tmpr ; a[nr].i = a[nr].i - tmpi; a[mr].r = a[mr].r + tmpr ; a[mr].i = a[mr].i - tmpi; mr = n -1 - nr ; } } /* 実数ifft前処理 */ void *r_ifft( int nx,ad_t a[] ) { double wr,wi,tmpr,tmpi,r; int m,n,mr,nr ; n = 1<< nx ; tmpr = a[0].r ; a[0].r = (tmpr + a[0].i)*0.5 ; a[0].i = (tmpr - a[0].i)*0.5 ; r = M_PI /(double)n; mr = n - 1 ; nr = 0 ; for( m = 1 ; m < n/2 ; m++ ) { nr = inc_rvbit(nx,nr); wi = cos(r*(double)m)*0.5; wr = sin(r*(double)m)*0.5+0.5; tmpr = wr * (a[nr].r - a[mr].r) + wi * (a[nr].i + a[mr].i); tmpi = wr * (a[nr].i + a[mr].i) - wi * (a[nr].r - a[mr].r); a[nr].r = a[nr].r - tmpr ; a[nr].i = a[nr].i - tmpi; a[mr].r = a[mr].r + tmpr ; a[mr].i = a[mr].i - tmpi; mr = n -1 - nr ; } } /* 実数fft後処理+乗算+実数ifft前処理 */ /* c = a * b ; a=b=c OK */ void *r_mul( int nx,ad_t c[],ad_t a[],ad_t b[] ) { double wr,wi,tmpr,tmpi,r; ad_t anr,amr,bnr,bmr; int m,n,mr,nr ; n = 1<< nx ; anr.r = a[0].r + a[0].i ; anr.i = a[0].r - a[0].i ; anr.r *= b[0].r + b[0].i ; anr.i *= b[0].r - b[0].i ; c[0].r = (anr.r + anr.i)*0.5 ; c[0].i = (anr.r - anr.i)*0.5 ; anr = a[1]; bnr = b[1]; c[1].r = anr.r * bnr.r - anr.i * bnr.i ; c[1].i = anr.r * bnr.i + anr.i * bnr.r ; r = M_PI /(double)n; mr = n - 1 ; nr = 0 ; for( m = 1 ; m < n/2 ; m++ ) { nr = inc_rvbit(nx,nr); anr = a[nr]; amr = a[mr]; bnr = b[nr]; bmr = b[mr]; wi = cos(r*(double)m)*0.5; wr = sin(r*(double)m)*0.5+0.5; /* fft 後処理 a */ tmpr = wr * (anr.r - amr.r) - wi * (anr.i + amr.i); tmpi = wr * (anr.i + amr.i) + wi * (anr.r - amr.r); anr.r = anr.r - tmpr ; anr.i = anr.i - tmpi; amr.r = amr.r + tmpr ; amr.i = amr.i - tmpi; /* fft 後処理 b */ tmpr = wr * (bnr.r - bmr.r) - wi * (bnr.i + bmr.i); tmpi = wr * (bnr.i + bmr.i) + wi * (bnr.r - bmr.r); bnr.r = bnr.r - tmpr ; bnr.i = bnr.i - tmpi; bmr.r = bmr.r + tmpr ; bmr.i = bmr.i - tmpi; /* 乗算 */ tmpr = anr.r ; anr.r = tmpr * bnr.r - anr.i * bnr.i ; anr.i = tmpr * bnr.i + anr.i * bnr.r ; tmpr = amr.r ; amr.r = tmpr * bmr.r - amr.i * bmr.i ; amr.i = tmpr * bmr.i + amr.i * bmr.r ; /* ifft 前処理 */ tmpr = wr * (anr.r - amr.r) + wi * (anr.i + amr.i); tmpi = wr * (anr.i + amr.i) - wi * (anr.r - amr.r); c[nr].r = anr.r - tmpr ; c[nr].i = anr.i - tmpi; c[mr].r = amr.r + tmpr ; c[mr].i = amr.i - tmpi; mr = n -1 - nr ; } } /* スケーリングと繰越 n-2 -> 0 方向 */ void *r_carry(int nx,ad_t a[],int redex) { double *aa; double pn,tmp; int n , m; long car , t; aa = (double*)a; n = 1<<nx ; pn = 1.0/(double)n; car = 0 ; for(m=n*2-2;m>=0;m--){ tmp = aa[m]*pn + (double)car ; if( tmp >= 0.0 ){ t = (long)(tmp+0.5) ; car = t / redex ; aa[m] =(double)( t % redex ); }else{ t = (long)(tmp-0.5) ; car = t / redex - 1; aa[m] =(double)( t % redex + redex ); } } aa[n*2-1]=(double)car; } /* スケーリングと繰越 0 -> n-2 方向 */ void *r_carry_r(int nx,ad_t a[],int redex) { double *aa; double pn,tmp; int n , m; long car , t; aa = (double*)a; n = 1<<nx ; pn = 1.0/(double)n; car = 0 ; for(m=0;m<n*2-1;m++){ tmp = aa[m]*pn + (double)car ; if( tmp >= 0.0 ){ t = (long)(tmp+0.5) ; car = t / redex ; aa[m] =(double)( t % redex ); }else{ t = (long)(tmp-0.5) ; car = t / redex - 1; aa[m] =(double)( t % redex + redex ); } } aa[n*2-1]=(double)car; } |
実行例
input data n = 8 = 1<<3 0 a[ 0].r = 2.000000 a[ 0].i = 1.000000 b[ 0].r = 9.000000 b[ 0].i = 8.000000 1 a[ 1].r = 2.000000 a[ 1].i = 3.000000 b[ 1].r = 7.000000 b[ 1].i = 6.000000 2 a[ 2].r = 4.000000 a[ 2].i = 5.000000 b[ 2].r = 5.000000 b[ 2].i = 4.000000 3 a[ 3].r = 6.000000 a[ 3].i = 7.000000 b[ 3].r = 2.000000 b[ 3].i = 3.000000 4 a[ 4].r = 0.000000 a[ 4].i = 0.000000 b[ 4].r = 0.000000 b[ 4].i = 0.000000 5 a[ 5].r = 0.000000 a[ 5].i = 0.000000 b[ 5].r = 0.000000 b[ 5].i = 0.000000 6 a[ 6].r = 0.000000 a[ 6].i = 0.000000 b[ 6].r = 0.000000 b[ 6].i = 0.000000 7 a[ 7].r = 0.000000 a[ 7].i = 0.000000 b[ 7].r = 0.000000 b[ 7].i = 0.000000 fft(nx,a) fft(nx,b) 0 a[ 0].r = 14.000000 a[ 0].i = 16.000000 b[ 0].r = 23.000000 b[ 0].i = 21.000000 1 a[ 4].r = 11.242641 a[ 4].i = -11.485281 b[ 4].r = 22.899495 b[ 4].i = -1.242641 2 a[ 2].r = -6.000000 a[ 2].i = -0.000000 b[ 2].r = 7.000000 b[ 2].i = -1.000000 3 a[ 6].r = 6.899495 a[ 6].i = 2.171573 b[ 6].r = 7.828427 b[ 6].i = 4.514719 4 a[ 1].r = -2.000000 a[ 1].i = -4.000000 b[ 1].r = 5.000000 b[ 1].i = 3.000000 5 a[ 5].r = 2.757359 a[ 5].i = 5.485281 b[ 5].r = 3.100505 b[ 5].i = 7.242641 6 a[ 3].r = 2.000000 a[ 3].i = -8.000000 b[ 3].r = 1.000000 b[ 3].i = 9.000000 7 a[ 7].r = -12.899495 a[ 7].i = 7.828427 b[ 7].r = 2.171573 b[ 7].i = 21.485281 r_fft(nx,a) r_fft(nx,b) 0 a[ 0].r = 30.000000 a[ 0].i = -2.000000 b[ 0].r = 44.000000 b[ 0].i = 2.000000 1 a[ 4].r = -7.137071 a[ 4].i = -20.109358 b[ 4].r = 17.920298 b[ 4].i = -24.812274 2 a[ 2].r = -2.000000 a[ 2].i = 9.656854 b[ 2].r = 4.707107 b[ 2].i = -9.949747 3 a[ 6].r = 4.380086 a[ 6].i = -5.986423 b[ 6].r = 5.530124 b[ 6].i = -7.699802 4 a[ 1].r = -2.000000 a[ 1].i = -4.000000 b[ 1].r = 5.000000 b[ 1].i = 3.000000 5 a[ 5].r = 5.276769 a[ 5].i = -2.672715 b[ 5].r = 5.398808 b[ 5].i = -4.971880 6 a[ 3].r = -2.000000 a[ 3].i = 1.656854 b[ 3].r = 3.292893 b[ 3].i = 0.050253 7 a[ 7].r = 5.480217 a[ 7].i = -0.795649 b[ 7].r = 7.150769 b[ 7].i = -2.084352 ri_mul(nx,a,b) 0 a[ 0].r = 1320.000000 a[ 0].i = -4.000000 1 a[ 4].r = -626.857348 a[ 4].i = -183.278730 2 a[ 2].r = 86.669048 a[ 2].i = 65.355339 3 a[ 6].r = -21.871852 a[ 6].i = -66.831453 4 a[ 1].r = 2.000000 a[ 1].i = -26.000000 5 a[ 5].r = 15.199846 a[ 5].i = -40.664931 6 a[ 3].r = -6.669048 a[ 3].i = 5.355339 7 a[ 7].r = 37.529354 a[ 7].i = -17.112207 r_ifft(nx,a) 0 a[ 0].r = 658.000000 a[ 0].i = 662.000000 1 a[ 4].r = -74.970563 a[ 4].i = -351.646753 2 a[ 2].r = -18.000000 a[ 2].i = 38.000000 3 a[ 6].r = 34.357431 a[ 6].i = 29.480231 4 a[ 1].r = 2.000000 a[ 1].i = -26.000000 5 a[ 5].r = -41.029437 a[ 5].i = 55.646753 6 a[ 3].r = 98.000000 a[ 3].i = -22.000000 7 a[ 7].r = -514.357431 a[ 7].i = -185.480231 ifft(nx,a) 0 a[ 0].r = 144.000000 a[ 0].i = 200.000000 1 a[ 1].r = 320.000000 a[ 1].i = 496.000000 2 a[ 2].r = 720.000000 a[ 2].i = 984.000000 3 a[ 3].r = 1264.000000 a[ 3].i = 1608.000000 4 a[ 4].r = 1336.000000 a[ 4].i = 1104.000000 5 a[ 5].r = 872.000000 a[ 5].i = 648.000000 6 a[ 6].r = 440.000000 a[ 6].i = 256.000000 7 a[ 7].r = 168.000000 a[ 7].i = 0.000000 copy a -> b r_carry(nx,a,10) a[ 7].i = 2.000000 a[ 0].r = 0.000000 a[ 0].i = 9.000000 a[ 1].r = 7.000000 a[ 1].i = 2.000000 a[ 2].r = 4.000000 a[ 2].i = 0.000000 a[ 3].r = 9.000000 a[ 3].i = 9.000000 a[ 4].r = 1.000000 a[ 4].i = 9.000000 a[ 5].r = 7.000000 a[ 5].i = 6.000000 a[ 6].r = 8.000000 a[ 6].i = 4.000000 a[ 7].r = 1.000000 r_carry_r(nx,b,10) b[ 7].i = 2.000000 b[ 7].r = 4.000000 b[ 6].i = 8.000000 b[ 6].r = 4.000000 b[ 5].i = 3.000000 b[ 5].r = 4.000000 b[ 4].i = 6.000000 b[ 4].r = 8.000000 b[ 3].i = 8.000000 b[ 3].r = 1.000000 b[ 2].i = 2.000000 b[ 2].r = 6.000000 b[ 1].i = 6.000000 b[ 1].r = 2.000000 b[ 0].i = 6.000000 b[ 0].r = 8.000000 21234567*98765423=2097240991976841 76543212*32456789=2484346881266268 |
実行例2
fft(nx,a) fft(nx,b) r_mul(nx,a,b,a) 0 a[ 0].r = 658.000000 a[ 0].i = 662.000000 1 a[ 4].r = -74.970563 a[ 4].i = -351.646753 2 a[ 2].r = -18.000000 a[ 2].i = 38.000000 3 a[ 6].r = 34.357431 a[ 6].i = 29.480231 4 a[ 1].r = 2.000000 a[ 1].i = -26.000000 5 a[ 5].r = -41.029437 a[ 5].i = 55.646753 6 a[ 3].r = 98.000000 a[ 3].i = -22.000000 7 a[ 7].r = -514.357431 a[ 7].i = -185.480231 ifft(nx,a) r_carry(nx,a,10) a[ 7].i = 2.000000 a[ 0].r = 0.000000 a[ 0].i = 9.000000 a[ 1].r = 7.000000 a[ 1].i = 2.000000 a[ 2].r = 4.000000 a[ 2].i = 0.000000 a[ 3].r = 9.000000 a[ 3].i = 9.000000 a[ 4].r = 1.000000 a[ 4].i = 9.000000 a[ 5].r = 7.000000 a[ 5].i = 6.000000 a[ 6].r = 8.000000 a[ 6].i = 4.000000 a[ 7].r = 1.000000 21234567*98765423=2097240991976841 |
fft関連パーツが一応そろったので次からはチューニング。
0 件のコメント:
コメントを投稿