一、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<stdio.h>
#include<math.h>
#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<N;i++)
{
power=1;
m=0;
for(j=0;j<M;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<m)
{
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<N;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<j)
{
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<N;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<IndexNumber;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<N;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<N;k++)
{
x[k].Re=x[k].Re;
x[k].Im=-x[k].Im;
}
Dit2Fft(N,x);//直接调用FFT
for(k=0;k<N;k++)
{
x[k].Re=x[k].Re;
x[k].Im=-x[k].Im;
}
for(k=0;k<N;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<DATA_LEN/10;i++)//长度为DATA_LEN的学号
{
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<DATA_LEN&&j<(DATA_LEN-k);i++,j++)
{
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<DATA_LEN;i++)//FFT后再次输出
{
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<DATA_LEN;i++)//IFFT后再次输出
{
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<N;i++)
{
power=1;
m=0;
for(j=0;j
>=(M-1-j);//C语言 n>>=1 中的>>=意思是先将变量n的各个二进制位顺序右移1位,最高位补二进制0,然后将这个结果再复制给n。
if(tempp&0x01)//判断tempp最后一位是不是1
{
m=m+power;
}
power=power*2;
}
if(i<m)
{
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<N;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)
{
int LH,j,N1,i,k,n;
Complex T;
LH=N/2;
j=LH;
N1=N-2;
for(i=1;i<=N1;i++)
{
if(i
=k)
{
j=j-k;
k=k/2;
}
j=j+k;
}
for(n=0;n<N;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)
{
uint m=1;//指数函数值
uchar i;
for(i=0;i<IndexNumber;i++)
{
m=BaseNumber*m;
}
return m;
}
/******************************************************************************************
Pow函数结束:
******************************************************************************************/
/******************************************************************************************
函数说明:对数运算
参数说明:BaseNumber底数,AntiNumber真数
返回值:无符号整数
******************************************************************************************/
uint Log(uchar BaseNumber,uint AntiNumber)
{
uint m=0;//对数函数值
while(1)
{
AntiNumber=AntiNumber/BaseNumber;
if(AntiNumber)m++;
else break;
}
return m;
}
/******************************************************************************************
log函数结束:
******************************************************************************************/
/******************************************************************************************
函数说明:按时间抽取基二快速傅里叶算法
参数说明:N点数,等于2的M次方,*x序列的首地址
返回值:无
******************************************************************************************/
void Dit2Fft(uint N,Complex *x)
{
int i;
Complex temp;//临时复数变量
uint L,M=Log(2,N);//M级蝶形图
uint k,j;
uint StepLength;//k值步长
uint Bank ;//两点间的距离
const double pai=3.1415926;
double ps;
uint r;//旋转因子的幂
Complex W;//旋转因子
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)
{
Complex x_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函数结束:
******************************************************************************************/
/******************************************************************************************
函数说明:傅里叶反变换算法
参数说明:N点数,等于2的M次方,*x序列的首地址
返回值:无
1、求旋转因子的共轭,再乘1/N
2、x(n)=IFFT[x(k)]=1/N*{FFT[x*(k)]}*
******************************************************************************************/
void Ifft1(uint N,Complex *x)
{
int i;
Complex temp;//临时复数变量
uint L,M=Log(2,N);//M级蝶形图
uint k,j;
uint StepLength;//k值步长
uint Bank ;//两点间的距离
const double pai=3.1415926;
double ps;
uint r;//旋转因子的幂
Complex W;//旋转因子
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)
{
Complex x_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<N;k++)
{
x[k].Re=x[k].Re/N;
x[k].Im=x[k].Im/N;
}
}
void Ifft2(uint N,Complex *x)
{
uint k;
Invert_order(N,x);//位倒序输入
for(k=0;k<N;k++)
{
x[k].Re=x[k].Re;
x[k].Im=-x[k].Im;
}
Dit2Fft(N,x);
for(k=0;k<N;k++)
{
x[k].Re=x[k].Re;
x[k].Im=-x[k].Im;
}
for(k=0;k<N;k++)
{
x[k].Re=x[k].Re/N;
x[k].Im=x[k].Im/N;
}
}
/******************************************************************************************
Ifft函数结束:
******************************************************************************************/
#define DATA_LEN 1024
void main()
{
uint y[10]={0,1,2,3,4,5,6,7,8,9};//学号
uint N,M;
int i,j,k;
Complex x[DATA_LEN];
N=DATA_LEN;
M=Log(2,N);
printf("初始序列:\n");
for(i=0;i<DATA_LEN/10;i++)//长度为N的学号
{
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<DATA_LEN&&j<(DATA_LEN-k);i++,j++)
{
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<DATA_LEN;i++)//FFT后再次输出
{
printf("%lf %lfi",x[i].Re,x[i].Im);
printf("\n");
}
printf("\n");
Ifft1(N,x);//Ifft2(N,x);
printf("IFFT运算后的序列:\n");
for(i=0;i<DATA_LEN;i++)//IFFT后再次输出
{
printf("%lf %lfi",x[i].Re,x[i].Im);
printf("\n");
}
printf("\n");
}