通过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即可。
#include
#include
#define uint unsigned int
#define uchar unsigned char
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;
}
通过两种方法进行倒序运算,第一个倒序运算子程序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函数结束: ******************************************************************************************/ /****************************************************************************************** 函数说明:指数运算 参数说明: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函数结束: ******************************************************************************************/ 先从第一级开始,逐级进行,共进行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函数结束: ******************************************************************************************/ 傅里叶反变换算法也有两种算法,第一种是求旋转因子的-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函数结束: ******************************************************************************************/ #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"); } 完整代码如下4、指数和对数运算
5、DIT-FFT的C语言程序
6、IFFT的C语言程序
7、main函数
/*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