数字信号处理 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<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");
}
      
      
     
     
    
    
   
   

  • 6
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值