1.算法描述
1)DFT的运算量
3)C程序采用基--2按时间抽取的FFT算法
设输入序列长度为 (M为正整数),将该序列按时间顺序的奇偶
为简单起见,同时不失一般性,本实验采用三个余弦成分和一个支流偏置成分叠加所得的信号作为信号源。
3.MATLAB的FFT仿真和C的FFT实现
1)关于频谱的理论分析:
2)MATLAB的FFT仿真
MATLAB程序代码
>>FFT2(1,1,1,90,2,2,180,3,3,180,32)
>>FFT2(1,1,1,90,2,2,180,3,3,180,16)
>>FFT2(1,1,1,90,2,2,180,3,3,180,8)
>>FFT2(1,1,1,90,2,2,180,3,3,180,4)
原始信号如图:
图2、fs =32Hz
图3、fs =16Hz
图4、fs =8Hz
图5、fs =4Hz
注意到:
1、幅度谱,除却k=0外,图形呈轴对称分布;
2、相位谱,N为偶数时除却k=0和N/2外(N为奇数时,除却k=0外),图形呈中心对称分布。
理论上,由于复指数的周期性,长度为N(假设N为偶数,N为奇数时类似)的的DFT频谱分析,可把k=
下面取fs=8Hz和4Hz部分计算结果分析,其他情况可类似处理。
可看到:fs=8Hz时,由频谱结合物理意义计算的得到的余弦成分的幅值和初相位与原信号一致;fs=4
对此,可根据抽样定理解释。因为f1=1Hz,f2=2Hz, f3=3Hz,所以连续时间信号的截至频
直观的,可把混叠现象看作是幅度谱和相位谱中对称的右半部分图形,随着采样频率的减小而往左移动,当采样
改变信号波形
键入:
>> %改变信号的直流成分(由1变为2),原信号和频谱如下
FFT2(2,1,1,90,2,2,180,3,3,180,32)
变化趋势:幅度谱中k=0对应的幅度变为2N=64(原为32),其余处无明显变化,相位谱中,k=0,
键入:
>> %改变第三个余弦成分的幅值(由3改为4),原信号图和频谱图如下FFT2(2,1,1,90,2,
变化趋势:幅度谱中k=3对应的幅度变为64(4*32/2=64,原来这个值为3*32/2=48),
键入:
>> %改变第三个余弦成分的频率(由3Hz改为4Hz),原信号图和频谱如下
FFT2(2,1,1,90,2,2,180,4,4,180,32)
变化趋势:幅度谱中,k=4处幅度为N/2*4=64,k=3处幅度变为0,k=0,1,2处幅度不变;
键入:
>>%改变第三个余弦成分的初相位(由180改为270),原信号和频谱如下图
FFT2(2,1,1,90,2,2,180,4,4,270,32)
变化趋势:幅度谱波形无明显变化;相位谱中,k=4处相位值变为-90度,即270度。
由此可见,改变信号的波幅、频率和相位,幅度谱和相位谱将发生相应的变化,即恰合频谱的物理意义。
3)C语言实现FFT
C代码
/*此代码用于fft计算,采用基--2按时间抽取的FFT算法Decimation-in-Time(D
(Coolkey-Tukey)。为方便起见,同时不失一般性,把含有一个直流成分和三个正弦成分的信号作
#include
#include
/*圆周率*/
double pi=3.141592653589793;
int M,N;
/*定义复数*/
struct Complex_
{
double real;double img;
}*a,*b;
/*定义2的幂计算*/
int x_2(int a)
{
int i,r;
r=1;
r=r*2;
return(r);
}
/*定义码位倒读函数f(i)*/
int reverse(int i)
{
int ii,j;
ii=0;
for(j=M-1;j>=0;j--)
{
ii+=(int)(i/x_2(j))*x_2(M-1-j);/*先把i用二进制表示,然后码位倒
i-=(int)(i/x_2(j))*x_2(j);
}
return(ii);
}
/*定义复数乘法*/
struct Complex_ Multi(struct Complex_ a,struct Com
{
struct Complex_ c;
c.real=a.real*b.real-a.img*b.img;
c.img=a.real*b.img+a.img*b.real;
return(c);
}
/*定义复数幂运算*/
struct Complex_ W_K(struct Complex_ W,int k)
{
int i;
struct Complex_ x,y;
x=W;
if(k==0)
{
x.real=1;x.img=0;return(x);
}
else
{
for(i=1;i
{
y=Multi(x,W);
x=y;
}
return(x);
}
}
/*定义复数加法*/
struct Complex_ Add(struct Complex_ a,struct Compl
{
struct Complex_ c;
c.real=a.real+b.real;
c.img=a.img+b.img;
return(c);
}
/*离散序列的输入*/
void input()
{
int NN,i;
float f1,f2,f3,a0,a1,a2,a3,w1,w2,w3;
M=0;
/*在一秒钟内,采点数*/
printf("采点数:");
scanf("%d",&NN);
printf("\n");
/*信号的直流成分*/
printf("信号的直流成分:\n");
scanf("%f",&a0);
/*信号有三个余弦成分*/
/*余弦成分1*/
printf("第1个正弦成分的频率:\n");
scanf("%f",&f1);
printf("幅值:\n");
scanf("%f",&a1);
printf("初相位:\n");
scanf("%f",&w1);
/*余弦成分2*/
printf("第2个正弦成分的频率:\n");
scanf("%f",&f2);
printf("幅值:\n");
scanf("%f",&a2);
printf("初相位:\n");
scanf("%f",&w2);
/*余弦成分3*/
printf("第3个正弦成分的频率:\n");
scanf("%f",&f3);
printf("幅值:\n");
scanf("%f",&a3);
printf("初相位:\n");
scanf("%f",&w3);
for(i=0;x_2(i)
{
M=i+1;
}
N=x_2(M);/*N为不小于NN的最小的2的幂*/
a=(struct Complex_*)calloc(N,sizeof(struct Comple
b=(struct Complex_*)calloc(N,sizeof(struct Comple
/*把采样信号用码位倒读的方法存入计算机中*/
for(i=0;i
{
a[reverse(i)].real=a0+a1*cos(2*pi*f1*i/N+w1/180*
a[reverse(i)].img=0;
}
/*动态空间空闲处,补零*/
for(i=NN;i
{
a[reverse(i)].real=0;
a[reverse(i)].img=0;
}
}
/*主函数*/
void main()
{
int i,j,k,m,n,q,r;
FILE *fp;/*文件指针,指向存储fft结果的文件*/
struct Complex_ d,W,Wk,x,y;
j=0;
input();
m=1;
n=N;
for(i=0;i
{
n=n/2;
m=m*2;
q=x_2(i+1);/*q=2^(i+1)*/
W.real=cos(-2*pi/q);/*旋转因子实部*/
W.img=sin(-2*pi/q);/*旋转因子虚部*/
for(j=0;j
{
for(k=0;k
{
Wk=W_K(W,k);
b[j*m+k]=Add(a[j*m+k],Multi(Wk,a[j*m+k+m/2]));
}
for(k=m/2;k
{
Wk=W_K(W,k);
b[j*m+k]=Add(a[j*m+k-m/2],Multi(Wk,a[j*m+k]));
}
}
for(r=0;r
{
a[r]=b[r];
}
}
/*将结果写入文件e:\\keshe.txt*/
if((fp=fopen("e:\\keshe.txt","w+"))==NULL)
{
printf("Cannot open file strike any key exit!");
getch();
exit(1);
}
for(n=0;n
{
fprintf(fp,"%16.14f %16.14f\n",a[n].real,a[n].img
}
for(n=0;n
{
printf("%16.14f+%16.14fi\n",a[n].real,a[n].img);
}
free(a);/*释放内存空间*/
free(b);/*释放内存空间*/
}
改变采样频率
实验数据将由keshe.txt调入到MATLAB中,做出频谱图。
参数设置1
注意到两图的幅度谱图,很相似,而相位谱却相差很大。用C实现的FFT得到的相位谱也似乎没有什么对称性
表1
结合图17、18和表1,可以发现两个相位谱在k=0,1,2,3和31,30,29处一致,而在其他点
注:在先前编写的C程序中,把复数实部和虚部的数据类型设置为float时,相位谱的不对称更加严重,甚
参数设置2
可发现C实现下的FFT幅度谱图随采样频率变化的趋势与MATLAB仿真实验类似,而由于参数1实验相同
参数设置3
类似的,可发现幅度谱图随采样频率变化的趋势与MATLAB仿真实验类似。而C和MATLAB实现下,k
参数设置4
同MATLAB仿真结果一样出现混叠现象。
参数设置5
注意到幅度谱和相位谱都有很大区别,其中相位谱的区别是由两种不同的计算机语言规则造成的(正如之前提到
改变被采样信号波形
参数设置6
二者幅度谱相同,相位谱只在中间部分有差异(此差异对实际分析影响很小,且也无实际意义,可忽略),而在
参数设置7
二者幅度谱图相同,且较上一参数时发生的变化趋势与MATLAB仿真试验中一样;相位谱图在k=0,1,
参数设置8
二者幅度谱图相同,,且较上一参数时发生的变化趋势与MATLAB仿真试验中一样;相位谱图在k=0,1
至此,考察了序列长度和信号谐波成分对MATLAB的FFT仿真和C实现的FFT的影响,并结合了DFT
4.课程设计心得与自我评价
这个课程设计的主要部分是在暑假完成的,课程设计是关于FFT的计算机实现,要求掌握FFT算法,并分别
课程设计完成的过程中遇到许多问题:
首先是MATLAB的仿真。这时候问题不大,直接利用现成的内置函数。
其次是FFT的C实现。此处在代码的编写和程序的调试耗费了较多的时间,主要问题在于对算法的理解不够以
后来在C实现的FFT结果与MATLAB的仿真结果对比时,遇到较多问题:1、初相位为180度(或-1
这次课程设计运用了信号与系统、C语言、MATLAB语言的知识,使我加深了对DFT的物理意义的理解,
自我评价:比较满意。虽然觉得课程设计完成的没有太大的亮点,私下也以为这个题目较其他几个要简单些(这
参考文献:
1、【美】卡门(Kamen,E.W.)等.信号与系统基础.北京:科学出版社,2002
2、郑平安.程序设计基础(C语言版)第二版.北京:清华大学出版社,2006
3、【美】A.V.奥本海姆,R.W.谢弗.离散时间信号处理(第二版).西安:西安交通大学出版社,20
4、【加】Simon Haykin,【美】Barry Van Veen.信号与系统(第二版).北京:
5、丛玉良,王宏志.数字信号处理原理及其MATLAB实现.北京:电子工业出版社,2005
6、百度文库