数字信号处理 DIT-FFT和IFFT的 C语言程序实现

一、MATLAB的FFT、IFFT方法

通过MATLAB,来检验输入序列的FFT、IFFT,判断C语言程序的正确性

matlab的FFT IFFT方法

说明:以下资源来源于《数字信号处理的MATLAB实现》万永革主编

一.调用方法

X=FFT(x);

X=FFT(x,N);

x=IFFT(X);

x=IFFT(X,N)

 

用MATLAB进行谱分析时注意:

(1)函数FFT返回值的数据结构具有对称性。

例:

N=8;

n=0:N-1;

xn=[4 3 2 6 7 8 9 0];

Xk=fft(xn)

Xn=ifft(Xk)

Xk与xn的维数相同,共有8个元素。Xk的第一个数对应于直流分量,即频率值为0。

(2)做FFT分析时,幅值大小与FFT选择的点数有关,但不影响分析结果。在IFFT时已经做了处理。要得到真实的振幅值的大小,只要将得到的变换后结果乘以2除以N即可。

二、C语言程序实现DIT-FFT和IFFT

1、宏定义

#include

#include

#define uint unsigned int

#define uchar unsigned char

2、复数定义和运算

typedef struct Complex//复数结构体

{

       doubleRe;

       doubleIm;

}Complex;

Complex Mul(Complex a,Complex b)//复数相乘

{

       Complexc;

       c.Re=a.Re*b.Re-a.Im*b.Im;

       c.Im=a.Re*b.Im+a.Im*b.Re;

       returnc;

}

Complex Plus(Complex a,Complex b)//复数相加

{

       Complexc;

       c.Re=a.Re+b.Re;

       c.Im=a.Im+b.Im;

       returnc;

}

Complex Sub(Complex a,Complex b)//复数相减

{

       Complexc;

       c.Re=a.Re-b.Re;

       c.Im=a.Im-b.Im;

       returnc;

}

3、倒序运算

通过两种方法进行倒序运算,第一个倒序运算子程序Invert_order(uint N,Complex *x,uchar M)是对数组中的每一个数,进行二进制的移位运算,求出数组的倒序;第二个倒序运算子程序Invert_order(uint N,Complex *x)是按照教材上的内容进行编写的,主要是对倒序规律进行分析,直接将数组中的数进行交换。此报告中的程序采用了第二种方法。

/******************************************************************************************

函数说明:倒序运算

参数说明:N点数,等于2的M次方,*x序列的首地址

返回值:无

******************************************************************************************/

/*void Invert_order(uint N,Complex *x,ucharM)

{

       uintpower,i,j,m,tempp;//m是i的倒位序数

       Complextemp;//是临时变量

       for(i=0;i

       {

              power=1;

              m=0;

              for(j=0;j

              {

                     tempp=i;

                     tempp>>=(M-1-j);//C语言 n>>=1 中的>>=意思是先将变量n的各个二进制位顺序右移1位,最高位补二进制0,然后将这个结果再复制给n。

                     if(tempp&0x01)//判断tempp最后一位是不是1

                     {

                            m=m+power;

                     }

                     power=power*2;

              }

              if(i

              {

                     temp.Im=x[i].Im;

                     temp.Re=x[i].Re;

                     x[i].Re=x[m].Re;

                     x[i].Im=x[m].Im;

                     x[m].Im=temp.Im;

                  x[m].Re=temp.Re;

              }

              for(n=0;n

              {

              if(x[n].Re<-10000000)

              {

                     x[n].Re=0;

              }

              if(x[n].Im<-10000000)

              {

                     x[n].Im=0;

              }

       }

}*/

void Invert_order(uint N,Complex *x)

{

       intLH,j,N1,i,k,n;

       ComplexT;

       LH=N/2;

       j=LH;

       N1=N-2;

       for(i=1;i<=N1;i++)

       {

              if(i

              {

                     T.Im=x[i].Im;

                     T.Re=x[i].Re;

                     x[i].Re=x[j].Re;

                     x[i].Im=x[j].Im;

                     x[j].Im=T.Im;

                  x[j].Re=T.Re;

              }

              k=LH;

              while(j>=k)

              {

                     j=j-k;

                     k=k/2;

              }

              j=j+k;

       }

       for(n=0;n

       {

              if(x[n].Re<-10000000)

              {

                     x[n].Re=0;

              }

              if(x[n].Im<-10000000)

              {

                     x[n].Im=0;

              }

       }

}

/******************************************************************************************

Invert_order函数结束:

******************************************************************************************/

4、指数和对数运算

/******************************************************************************************

函数说明:指数运算

参数说明:BaseNumber底数,IndexNumber指数

返回值:无符号整数

******************************************************************************************/

uint Pow(uchar BaseNumber,uint IndexNumber)

{

       uintm=1;//指数函数值

       uchari;

       for(i=0;i

       {

              m=BaseNumber*m;

       }

       returnm;

}

/******************************************************************************************

Pow函数结束:

******************************************************************************************/

 

/******************************************************************************************

函数说明:对数运算

参数说明:BaseNumber底数,AntiNumber真数

返回值:无符号整数

******************************************************************************************/

 

uint Log(uchar BaseNumber,uint AntiNumber)

{

       uintm=0;//对数函数值

       while(1)

       {

              AntiNumber=AntiNumber/BaseNumber;

              if(AntiNumber)m++;

              elsebreak;

       }

       returnm;

}

/******************************************************************************************

log函数结束:

******************************************************************************************/

5、DIT-FFT的C语言程序

先从第一级开始,逐级进行,共进行M级运算。然后在进行第L级运算时,求出每一级的旋转因子。最后一层循环,求出每个旋转因子对应的所有蝶形。

/******************************************************************************************

函数说明:按时间抽取基二快速傅里叶算法

参数说明:N点数,等于2的M次方,*x序列的首地址

返回值:无

******************************************************************************************/

void Dit2Fft(uint N,Complex *x)

{

       inti;

       Complextemp;//临时复数变量

       uintL,M=Log(2,N);//M级蝶形图

       uintk,j;

       uintStepLength;//k值步长

       uintBank ;//两点间的距离

       constdouble pai=3.1415926;

       doubleps;

       uintr;//旋转因子的幂

       ComplexW;//旋转因子

       for(L=1;L<=M;L++)//从第一级开始,逐级进行,共进行M级运算

       {

              StepLength=Pow(2,L);

              Bank=StepLength/2;

              for(j=0;j<=Bank-1;j++)//求出每一级的旋转因子

              {

                     r=Pow(2,M-L)*j;

                     ps=2*pai/N*r;

                     W.Re=cos(ps);

                     W.Im=-sin(ps);

                     for(k=j;k<=N-1;k=k+StepLength)//求出每个旋转因子对应的所有蝶形

                     {

                            Complexx_temp;

                            x_temp=Mul(W,x[k+Bank]);

                            temp=Plus(x[k],x_temp);

                            x[k+Bank]=Sub(x[k],x_temp);

                            x[k].Re=temp.Re;

                            x[k].Im=temp.Im;

                     }

              }

       }

}

/******************************************************************************************

Dit2Fft函数结束:

******************************************************************************************/

6、IFFT的C语言程序

傅里叶反变换算法也有两种算法,第一种是求旋转因子的-kn,再乘1/N。

第二种是直接调用FFT程序,先将X(k)取共轭,然后直接调用FFT子程序,最后对FFT结果取共轭并乘以1/N。即

此报告中的程序采用了第一种方法。

/******************************************************************************************

函数说明:傅里叶反变换算法

参数说明:N点数,等于2的M次方,*x序列的首地址

返回值:无

1、求旋转因子的-kn,再乘1/N

2、x(n)=IFFT[x(k)]=1/N*{FFT[x*(k)]}*

******************************************************************************************/

void Ifft1(uint N,Complex *x)//1、求旋转因子的-kn,再乘1/N

{

       inti;

       Complextemp;//临时复数变量

       uintL,M=Log(2,N);//M级蝶形图

       uintk,j;

       uintStepLength;//k值步长

       uintBank ;//两点间的距离

       constdouble pai=3.1415926;

       doubleps;

       uintr;//旋转因子的幂

       ComplexW;//旋转因子

       Invert_order(N,x);//位倒序输入

       for(L=1;L<=M;L++)

       {

              StepLength=Pow(2,L);

              Bank=StepLength/2;

              for(j=0;j<=Bank-1;j++)

              {

                     r=Pow(2,M-L)*j;

                     ps=2*pai/N*r;

                     W.Re=cos(ps);

                     W.Im=sin(ps);//改变旋转因子

                     for(k=j;k<=N-1;k=k+StepLength)

                     {

                            Complexx_temp;

                            x_temp=Mul(W,x[k+Bank]);

                            temp=Plus(x[k],x_temp);

                            x[k+Bank]=Sub(x[k],x_temp);

                            x[k].Re=temp.Re;

                            x[k].Im=temp.Im;

                     }

              }

       }

       for(k=0;k

       {

              x[k].Re=x[k].Re/N;

              x[k].Im=x[k].Im/N;

       }

}

 

void Ifft2(uint N,Complex *x)//2、x(n)=IFFT[x(k)]=1/N*{FFT[x*(k)]}*

{

       uintk;

       Invert_order(N,x);//位倒序输入

       for(k=0;k

       {

              x[k].Re=x[k].Re;

              x[k].Im=-x[k].Im;

       }

       Dit2Fft(N,x);//直接调用FFT

       for(k=0;k

       {

              x[k].Re=x[k].Re;

              x[k].Im=-x[k].Im;

       }

       for(k=0;k

       {

              x[k].Re=x[k].Re/N;

              x[k].Im=x[k].Im/N;

       }

}

/******************************************************************************************

Ifft函数结束:

******************************************************************************************/

7、main函数

#define DATA_LEN 1024//设定数据长度为1024

void main()

{

       uinty[10]={0,1,2,3,4,5,6,7,8,9};//学号

       uintN,M;

       inti,j,k;

       Complexx[DATA_LEN];

       N=DATA_LEN;

       M=Log(2,N);

       printf("初始序列:\n");

       for(i=0;i

       {

              for(j=0,k=0;j<10;j++,k=j+i*10)

              {

              x[k].Im=0;

              x[k].Re=y[j];

              printf("%lf%lfi\n",x[k].Re,x[k].Im);

              }

       }

       for(i=k,j=0;i

       {

              x[i].Im=0;

              x[i].Re=y[j];

              printf("%lf%lfi\n",x[i].Re,x[i].Im);

       }

       printf("\n");

       Invert_order(N,x);//倒序第一种算法Invert_order(N,x,M);(使用需将子程序块注释更换)

       Dit2Fft(N,x);

       printf("FFT运算后的序列:\n");

       for(i=0;i

       {

              printf("%lf%lfi",x[i].Re,x[i].Im);

              printf("\n");

       }

       printf("\n");

       Ifft1(N,x);//IFFT的第二种算法Ifft2(N,x);

       printf("IFFT运算后的序列:\n");

       for(i=0;i

       {

              printf("%lf%lfi",x[i].Re,x[i].Im);

              printf("\n");

       }

       printf("\n");

}

完整代码如下

/*matlab的FFT IFFT方法
说明:以下资源来源于《数字信号处理的MATLAB实现》万永革主编
一.调用方法
X=FFT(x);
X=FFT(x,N);
x=IFFT(X);
x=IFFT(X,N)

用MATLAB进行谱分析时注意:
(1)函数FFT返回值的数据结构具有对称性。
例:
N=8;
n=0:N-1;
xn=[4 3 2 6 7 8 9 0];
Xk=fft(xn)
Xn=ifft(Xk)
Xk与xn的维数相同,共有8个元素。Xk的第一个数对应于直流分量,即频率值为0。
(2)做FFT分析时,幅值大小与FFT选择的点数有关,但不影响分析结果。在IFFT时已经做了处理。要得到真实的振幅值的大小,只要将得到的变换后结果乘以2除以N即可。
*/
#include
#include
#define uint unsigned int
#define uchar unsigned char

typedef struct Complex//复数结构体
{
	double Re;
	double Im;
}Complex;

Complex Mul(Complex a,Complex b)//复数相乘
{
	Complex c;
	c.Re=a.Re*b.Re-a.Im*b.Im;
	c.Im=a.Re*b.Im+a.Im*b.Re;
	return c;
}

Complex Plus(Complex a,Complex b)//复数相加
{
	Complex c;
	c.Re=a.Re+b.Re;
	c.Im=a.Im+b.Im;
	return c;
}

Complex Sub(Complex a,Complex b)//复数相减
{
	Complex c;
	c.Re=a.Re-b.Re;
	c.Im=a.Im-b.Im;
	return c;
}

/******************************************************************************************

函数说明:倒序运算

参数说明:N点数,等于2的M次方,*x序列的首地址

返回值:无

******************************************************************************************/
/*void Invert_order(uint N,Complex *x,uchar M)
{
	uint power,i,j,m,tempp;//m是i的倒位序数
	Complex temp;//是临时变量
	for(i=0;i=(M-1-j);//C语言 n>>=1 中的>>=意思是先将变量n的各个二进制位顺序右移1位,最高位补二进制0,然后将这个结果再复制给n。
			if(tempp&0x01)//判断tempp最后一位是不是1
			{
				m=m+power;
			}
			power=power*2;
		}
		if(i

你可能感兴趣的:(C语言)