您的位置:首页 > 编程语言

快速傅氏变换之旅(二) 七种FFT算法速度比较(含代码)

2012-04-01 17:37 295 查看
转载请标明是引用于 http://blog.csdn.net/chenyujing1234

例子代码:(编译工具:VS2005)

http://www.rayfile.com/zh-cn/files/76968e5e-7bde-11e1-8c13-0015c55db73d/

由于公司要做FFT算法,具体是做高尔夫球的弹道分析,至今还没把算法敲定。

今天网上看了算法,自己建立工程,进行了比较。

现在按算法速度从快到慢的顺序介绍:(先搭个框架,具体算法解释,请听下回分解)

1、

//*******************************************************************
// 将data[]中的元素进行快速傅立叶变换,当变换长度大于L2 cache,有较快的速度
BOOL FFT2(CMPL data[], size_t n)
//*******************************************************************
{
	unsigned long i;
	//------------------------------------
	if (n<4)
	{
		printf("too small transpos length\n");
		return FALSE;
	}	
	
	Init_OMAGE_ARRAY(n);
	if (g_w.arr==NULL)
	{
		printf("no enough memory\n");
		return FALSE;
	}
	reverseOrder(data,n,Log2(n)); //反序
    
	if (n<=MAX_IN_CACHE_TRANS_LEN)
	{
		fft_sub(data,n,2,n);
		return TRUE;
	}
	
	for (i=0;i<n;i+=MAX_IN_CACHE_TRANS_LEN)
	{
		fft_sub(data+i,MAX_IN_CACHE_TRANS_LEN,2,MAX_IN_CACHE_TRANS_LEN);
	}
	
	fft_sub(data,n,MAX_IN_CACHE_TRANS_LEN*2,n);
	return TRUE;
}




//*******************************************************************
// 将data[]中的元素进行快速傅立叶变换
BOOL FFT1(CMPL data[], size_t n)
//*******************************************************************
{
	unsigned long i,i1,i2,j1,j2,d;
	unsigned long groupBase,groupLen,omageBase;
	CMPL t,t1,t2;
	double *pW=NULL;
	char fileName[3209];
	if (n<4)
	{
		printf("too small transpos length\n");
		return FALSE;
	}	
	
	Init_OMAGE_ARRAY(n);
	if (g_w.arr==NULL)
	{
		printf("no enough memory\n");
		return FALSE;
	}
	
	reverseOrder(data,n,Log2(n)); //反序
    
	for (i=0;i<n;i+=2) // d: 翅间距=1, buffterfly group length =2, group number =n/2
	{
		t=data[i+1];
		CMPL_SUB(data[i+1],data[i],t);
		CMPL_ADD(data[i],  data[i],t);
	}
	
	#ifdef OUT_INTER_RESULT
			sprintf(fileName,"../test result/data1_%08d_FFT1.bin",2);
			dumpData(data,n,fileName);
	#endif

	for (i=0;i<n;i+=4)    // 翅间距=2, buffterfly group length =4 ,group number =n/4
	{
		t1=data[i+2];
		
		t2.Re=  data[i+3].Im;	//t2=(0,-1)*(data[i+3].Re,data[i+3].Im)
		t2.Im= -data[i+3].Re;

		CMPL_SUB(data[i+2],data[i],t1);
		CMPL_ADD(data[i],  data[i],t1);

		CMPL_SUB(data[i+3],data[i+1],t2);
		CMPL_ADD(data[i+1],data[i+1],t2);
	}
	#ifdef OUT_INTER_RESULT
			sprintf(fileName,"../test result/data1_%08d__FFT1.bin",4);
			dumpData(data,n,fileName);
	#endif

	// 翅间距>=4, buffterfly group length >=8 ,group number =n/group length
	for (groupLen=8;groupLen<=n;groupLen*=2 )
	{
 		d=groupLen/2;	//d: 翅间距
		omageBase=g_w.tabIndex[Log2(groupLen)-2].offset; 
		pW= (double *)(g_w.arr)+omageBase;	//omage array address
		for ( groupBase = 0; groupBase<n; groupBase+=groupLen)
		{
			DWORD r,t;
			i1=groupBase;				// butterfly 1 left-up index
			i2=groupBase+d/2;

			j1=i1+d;				// butterfly 1 left-down index	
			j2=i2+d;

			t1 =    data[j1];	 	//t1= e^(-2*PI*0 i) * data[j1]
			t2.Re=  data[j2].Im;	//t2= e^(-2*PI/4 i) * data[j2]
			t2.Im= -data[j2].Re;    // complex:(0,-1) * data[j2]

			CMPL_SUB(data[j1],data[i1],t1);
			CMPL_ADD(data[i1],data[i1],t1);
		    //-------------------------------
			
			CMPL_SUB(data[j2],data[i2],t2);
			CMPL_ADD(data[i2],data[i2],t2);	
			
			i1++;		i2++;
			j1++;		j2++;
			
			for (r=1; r<d/2; i1++,i2++,j1++,j2++,r++)
			{
           		t=groupLen/4-r;

				//w1.Re= pW[r];
				//w1.Im= -pW[t];
				//w2.Re= -pw[t];
				//w2.Im= -pw[r];
				
				t1.Re = ( pW[r]  * data[j1].Re +  pW[t] * data[j1].Im);
				t1.Im = ( -pW[t] * data[j1].Re + pW[r]  * data[j1].Im);
	
				t2.Re = ( -pW[t] * data[j2].Re +  pW[r]  * data[j2].Im);
				t2.Im = ( -pW[r]  * data[j2].Re -  pW[t] * data[j2].Im);
	
				CMPL_SUB(data[j1], data[i1], t1);
				CMPL_ADD(data[i1], data[i1], t1);

				CMPL_SUB(data[j2], data[i2], t2);
				CMPL_ADD(data[i2], data[i2], t2);
            }
		}
	#ifdef OUT_INTER_RESULT
		sprintf(fileName,"../test result/data1_%08d_FFT1.bin",groupLen);
		dumpData(data,n,fileName);
	
	#endif
	}
	return TRUE;

}


2、

void fft(int n, double xRe[], double xIm[],
                double yRe[], double yIm[])
{
    int   sofarRadix[maxFactorCount], 
          actualRadix[maxFactorCount], 
          remainRadix[maxFactorCount];
    int   nFactor;
    int   count;

    pi = 4*atan(1);    

    transTableSetup(sofarRadix, actualRadix, remainRadix, &nFactor, &n);
    permute(n, nFactor, actualRadix, remainRadix, xRe, xIm, yRe, yIm);

    for (count=1; count<=nFactor; count++)
      twiddleTransf(sofarRadix[count], actualRadix[count], remainRadix[count], 
                    yRe, yIm);
}   /* fft */




3、

void four1(double data[], int nn, int isign)
{
    int n,j,i,m,mmax,istep;
    double tempr,tempi,theta,wpr,wpi,wr,wi,wtemp;
    n = 2 * nn;
    j = 1;
    for (i = 1; i<=n; i=i+2)
    {
        if(j > i)
        {
            tempr = data[j];
            tempi = data[j + 1];
            data[j] = data[i];
            data[j + 1] = data[i + 1];
            data[i] = tempr;
            data[i + 1] = tempi;
        }
        m = n / 2;
        while (m >= 2 && j > m)
        {
            j = j - m;
            m = m / 2;
        }
        j = j + m;
    }
    mmax = 2;
    while(n > mmax)
    {
        istep = 2 * mmax;
        theta = 6.28318530717959 / (isign * mmax);
        wpr = -2.0 * sin(0.5 * theta)*sin(0.5 * theta);
        wpi = sin(theta);
        wr = 1.0;
        wi = 0.0;
        for(m = 1; m<=mmax; m=m+2)
        {
            for (i = m; i<=n; i=i+istep)
            {
                j = i + mmax;
                tempr=double(wr)*data[j]-double(wi)*data[j+1];
                tempi=double(wr)*data[j+1]+double(wi)*data[j];
                data[j] = data[i] - tempr;
                data[j + 1] = data[i + 1] - tempi;
                data[i] = data[i] + tempr;
                data[i + 1] = data[i + 1] + tempi;
            }
            wtemp = wr;
            wr = wr * wpr - wi * wpi + wr;
            wi = wi * wpr + wtemp * wpi + wi;
        }
        mmax = istep;
    }
}


4、

void fft(COMPLEX in[],COMPLEX out[], COMPLEX omega[],int n)
{
	int s,k,m,l,nv,t,j;
	COMPLEX podd,ret;

	k = (int)(log(n) / log(2) + 0.5);
	nv = n;
	m = 1;
	for ( l = k-1 ; l >= 0 ; l-- )
	{
		for ( t = 0 ; t < m * nv ; t+=nv )
			for ( j = 0 ; j < nv/2 ; j++ )
			{
				s = (t+j) / (int)pow(2,l);
				s = reverse(s,k);

				ret = omega[s];
				mul(&ret,&in[t+j+nv/2],&podd);
				sub(&in[t+j],&podd,&in[t+j+nv/2]);
				add(&in[t+j],&podd,&in[t+j]);
			}
		m *= 2;
		nv /= 2;
	}

	for ( t = 0 ; t < n ; t++ )
	{
		s = reverse(t,k);
		out[t] = in[s];
	}
}


5、

void cdft(int n, int isgn, double *a)
{
    void cftfsub(int n, double *a);
    void cftbsub(int n, double *a);
    
    if (isgn >= 0) {
        cftfsub(n, a);
    } else {
        cftbsub(n, a);
    }
}




void cftfsub(int n, double *a)
{
    void bitrv2(int n, double *a);
    void bitrv216(double *a);
    void bitrv208(double *a);
    void cftmdl1(int n, double *a);
    void cftrec4(int n, double *a);
    void cftleaf(int n, int isplt, double *a);
    void cftfx41(int n, double *a);
    void cftf161(double *a);
    void cftf081(double *a);
    void cftf040(double *a);
    void cftx020(double *a);
#ifdef USE_CDFT_THREADS
    void cftrec4_th(int n, double *a);
#endif /* USE_CDFT_THREADS */
    
    if (n > 8) {
        if (n > 32) {
            cftmdl1(n, a);
#ifdef USE_CDFT_THREADS
            if (n > CDFT_THREADS_BEGIN_N) {
                cftrec4_th(n, a);
            } else 
#endif /* USE_CDFT_THREADS */
            if (n > 512) {
                cftrec4(n, a);
            } else if (n > 128) {
                cftleaf(n, 1, a);
            } else {
                cftfx41(n, a);
            }
            bitrv2(n, a);
        } else if (n == 32) {
            cftf161(a);
            bitrv216(a);
        } else {
            cftf081(a);
            bitrv208(a);
        }
    } else if (n == 8) {
        cftf040(a);
    } else if (n == 4) {
        cftx020(a);
    }
}

void cftbsub(int n, double *a)
{
    void bitrv2conj(int n, double *a);
    void bitrv216neg(double *a);
    void bitrv208neg(double *a);
    void cftb1st(int n, double *a);
    void cftrec4(int n, double *a);
    void cftleaf(int n, int isplt, double *a);
    void cftfx41(int n, double *a);
    void cftf161(double *a);
    void cftf081(double *a);
    void cftb040(double *a);
    void cftx020(double *a);
#ifdef USE_CDFT_THREADS
    void cftrec4_th(int n, double *a);
#endif /* USE_CDFT_THREADS */
    
    if (n > 8) {
        if (n > 32) {
            cftb1st(n, a);
#ifdef USE_CDFT_THREADS
            if (n > CDFT_THREADS_BEGIN_N) {
                cftrec4_th(n, a);
            } else 
#endif /* USE_CDFT_THREADS */
            if (n > 512) {
                cftrec4(n, a);
            } else if (n > 128) {
                cftleaf(n, 1, a);
            } else {
                cftfx41(n, a);
            }
            bitrv2conj(n, a);
        } else if (n == 32) {
            cftf161(a);
            bitrv216neg(a);
        } else {
            cftf081(a);
            bitrv208neg(a);
        }
    } else if (n == 8) {
        cftb040(a);
    } else if (n == 4) {
        cftx020(a);
    }
}


6、

//*************************************************************************
// *
// * 函数名称:
// *   FFT()
// *
// * 参数:
// *   complex<double> * TD- 指向时域数组的指针
// *   complex<double> * FD- 指向频域数组的指针
// *   r-2的幂数,即迭代次数
// *
// * 返回值:
// *   无。
// *
// * 说明:
// *   该函数用来实现快速付立叶变换。
// *
// ************************************************************************/
void FFT(	complex<double> *TD,  complex<double> *FD, 
			complex<double> *X1,  complex<double> *X2,
			complex<double> *Omega,	  int r)
{
	// 付立叶变换点数
	long count;

	// 循环变量
	int i,j,k;

	// 中间变量
	int bfsize,p;

	// 角度
	double angle;

	complex<double> *X;

	// 计算付立叶变换点数
	count = 1 << r;

	// 分配运算所需存储器
	//Omega  = new complex<double>[count / 2];
	//X1 = new complex<double>[count];
	//X2 = new complex<double>[count];

	// 计算加权系数
	for(i = 0; i < count / 2; i++)
	{
		angle = -i * 3.1415926 * 2 / count;
		Omega[i] = complex<double>(cos(angle), sin(angle));
	}

	// 将时域点写入X1
	memcpy(X1, TD, sizeof(complex<double>) * count);

	// 采用蝶形算法进行快速付立叶变换
	for(k = 0; k < r; k++)
	{
		for(j = 0; j < 1 << k; j++)
		{
			bfsize = 1 << (r-k);
			for(i = 0; i < bfsize / 2; i++)
			{
				p = j * bfsize;
				X2[i + p] = X1[i + p] + X1[i + p + bfsize / 2];
				X2[i + p + bfsize / 2] = (X1[i + p] - X1[i + p + bfsize / 2]) * Omega[i * (1<<k)];
			}
		}
		X  = X1;
		X1 = X2;
		X2 = X;
	}

	// 重新排序
	for(j = 0; j < count; j++)
	{
		p = 0;
		for(i = 0; i < r; i++)
		{
			if (j&(1<<i))
			{
				p+=1<<(r-i-1);
			}
		}
		FD[j]=X1[p];
	}

	// 释放内存
	//delete Omega;
	//delete X1;
	//delete X2;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: