// // FFT library // // (one-dimensional complex and real FFTs for array // lengths of 2^n) // // Author: Toth Laszlo (tothl@inf.u-szeged.hu) // // Research Group on Artificial Intelligence // H-6720 Szeged, Aradi vertanuk tere 1, Hungary // // Last modified: 97.05.29 ///////////////////////////////////////////////////////// #include #include #include "pi.h" ///////////////////////////////////////////////////////// //Gives back "i" bit-reversed where "size" is the array //length //currently none of the routines call it long bitreverse(long i, long size){ long result,mask; result=0; for(;size>1;size>>=1){ mask=i&1; i>>=1; result<<=1; result|=mask; } /* __asm{ the same in assebly mov eax,i mov ecx,sizze mov ebx,0 l:shr eax,1 rcl ebx,1 shr ecx,1 cmp ecx,1 jnz l mov result,ebx }*/ return result; } //////////////////////////////////////////////////////// //Bit-reverser for the Bruun FFT //Parameters as of "bitreverse()" long bruun_reverse(long i, long sizze){ long result, add; result=0; add=sizze; while(1){ if(i!=0) { while((i&1)==0) { i>>=1; add>>=1;} i>>=1; add>>=1; result+=add; } else {result<<=1;result+=add; return result;} if(i!=0) { while((i&1)==0) { i>>=1; add>>=1;} i>>=1; add>>=1; result-=add; } else {result<<=1;result-=add; return result;} } } /*assembly version long bruun_reverse(long i, long sizze){ long result; result=0; __asm{ mov edx,sizze mov eax,i mov ebx,0 l: bsf cx,eax jz kesz1 inc cx shr edx,cl add ebx,edx shr eax,cl bsf cx,eax jz kesz2 inc cx shr edx,cl sub ebx,edx shr eax,cl jmp l kesz1: shl ebx,1 add ebx,edx jmp vege kesz2: shl ebx,1 sub ebx,edx vege: mov result,ebx } return result; }*/ ///////////////////////////////////////////////////////// // Decimation-in-freq radix-2 in-place butterfly // data: array of doubles: // re(0),im(0),re(1),im(1),...,re(size-1),im(size-1) // it means that size=array_length/2 !! // // suggested use: // intput in normal order // output in bit-reversed order // // Source: Rabiner-Gold: Theory and Application of DSP, // Prentice Hall,1978 void dif_butterfly(double *data,long size){ long angle,astep,dl; double xr,yr,xi,yi,wr,wi,dr,di,ang; double *l1, *l2, *end, *ol2; astep=1; end=data+size+size; for(dl=size;dl>1;dl>>=1,astep+=astep){ l1=data; l2=data+dl; for(;l2>1; end=data+size+size; for(dl=2;astep>0;dl+=dl,astep>>=1){ l1=data; l2=data+dl; for(;l2i){ //swap re=data[i+i];im=data[i+i+1]; data[i+i]=data[j+j];data[i+i+1]=data[j+j+1]; data[j+j]=re;data[j+j+1]=im; } }*/ l=size-1; m=size>>1; for (i=0,j=0; i>=1; } j+=k; } } ///////////////////////////////////////////////////////// // used by realfft // parameters as above // // Source: Brigham: The Fast Fourier Transform // Prentice Hall, ? void realize(double *data, long size){ double xr,yr,xi,yi,wr,wi,dr,di,ang,astep; double *l1, *l2; l1=data; l2=data+size+size-2; xr=*l1; xi=*(l1+1); *l1=xr+xi; *(l1+1)=xr-xi; l1+=2; astep=pi/size; for(ang=astep;l1<=l2;l1+=2,l2-=2,ang+=astep){ xr=(*l1+*l2)/2; yi=(-(*l1)+(*l2))/2; yr=(*(l1+1)+*(l2+1))/2; xi=(*(l1+1)-*(l2+1))/2; wr=cos(ang); wi=-sin(ang); dr=yr*wr-yi*wi; di=yr*wi+yi*wr; *l1=xr+dr; *(l1+1)=xi+di; *l2=xr-dr; *(l2+1)=-xi+di; } } ///////////////////////////////////////////////////////// // used by inverse realfft // parameters as above // // Source: Brigham: The Fast Fourier Transform // Prentice Hall, ? void unrealize(double *data, long size){ double xr,yr,xi,yi,wr,wi,dr,di,ang,astep; double *l1, *l2; l1=data; l2=data+size+size-2; xr=(*l1)/2; xi=(*(l1+1))/2; *l1=xr+xi; *(l1+1)=xr-xi; l1+=2; astep=pi/size; for(ang=astep;l1<=l2;l1+=2,l2-=2,ang+=astep){ xr=(*l1+*l2)/2; yi=-(-(*l1)+(*l2))/2; yr=(*(l1+1)+*(l2+1))/2; xi=(*(l1+1)-*(l2+1))/2; wr=cos(ang); wi=-sin(ang); dr=yr*wr-yi*wi; di=yr*wi+yi*wr; *l2=xr+dr; *(l1+1)=xi+di; *l1=xr-dr; *(l2+1)=-xi+di; } } ///////////////////////////////////////////////////////// // in-place Radix-2 FFT for complex values // data: array of doubles: // re(0),im(0),re(1),im(1),...,re(size-1),im(size-1) // it means that size=array_length/2 !! // // output is in similar order, normalized by array length // // Source: see the routines it calls ... void fft(double *data, long size){ double *l, *end; dif_butterfly(data,size); unshuffle(data,size); end=data+size+size; for(l=data;l>=1; dif_butterfly(data,size); unshuffle(data,size); realize(data,size); end=data+size+size; div=size+size; for(l=data;l>=1; unrealize(data,size); unshuffle(data,size); inverse_dit_butterfly(data,size); end=data+size+size; for(l=data;l>=1; dl=size; dl2=dl/2; for(;dl>1;dl>>=1,dl2>>=1){ l0=data; l3=data+dl; for(i=0;i1){ for(k=0;k1;dl>>=1,dl2>>=1){ l0=data+((dl*j)<<1); l1=l0+dl2;l2=l0+dl;l3=l1+dl; for(i=0;i>=1; dl2_o>>=1; kk<<=1; } //division with array length size<<=1; for(i=0;i>1;i>=1; dl=size; dl2=dl/2; //first filtering, when there're only two taps for(;dl>1;dl>>=1,dl2>>=1){ l0=data; l3=data+dl; for(i=0;i>1;i>=1; } j+=k; } /*----------------------*/ //length two butterflies i0=0; id=4; do{ for (; i02;k>>=1){ n2<<=1; n4=n2>>2; n8=n2>>3; e = 2*pi/(n2); i1=0; id=n2<<1; do{ for (; i12;k>>=1){ id=n2; n2>>=1; n4=n2>>2; n8=n2>>3; e = 2*pi/(n2); i1=0; do{ for (; i1>=1; } j+=k; } } ///////////////////////////////////////////////////////// // Sorensen in-place radix-2 FFT for real values // data: array of doubles: // re(0),re(1),re(2),...,re(size-1) // // output: // re(0),re(1),re(2),...,re(size/2),im(size/2-1),...,im(1) // normalized by array length // // Source: // Sorensen et al: Real-Valued Fast Fourier Transform Algorithms, // IEEE Trans. ASSP, ASSP-35, No. 6, June 1987 void realfft_radix2(double *data,long n){ double xt,a,e, t1, t2, cc, ss; long i, j, k, n1, n2, n3, n4, i1, i2, i3, i4; n4=n-1; //data shuffling for (i=0,j=0,n2=n/2; i>=1; } j+=k; } /* -------------------- */ for (i=0; i2;k>>=1){ n4 = n2; n2 = n4 << 1; n1 = n2 << 1; e = 2*pi/(n1); for (i=0; i