FFT的DSP实现一.设计目的1.加深对DFT算法原理和基本性质的理解;2.熟悉FFT的算法原理和FFT子程序的算法流程和应用;3.学习用FFT对连续信号和时域信号进行频谱分析的方法;4.学习DSP中FFT的设计和编程思想;5.学习使用CCS的波形观察器观察波形和频谱情况;二.设计内容用DSP汇编语言及C语言进行编程,实现FFT运算、对输入信号进行频谱分析。三.设计原理快速傅里叶变换FFT快速傅里叶变换(FFT)是一种高效实现离散傅里叶变换(DFT)的快速算法,是数字信号处理中最为重要的工具之一,它在声学,语音,电信和信号处理等领域有着广泛的应用。1离散傅里叶变换DFT对于长度为N的有限长序列x(n),它的离散傅里叶变换(DFT)为X(k)=0*)(nWnxN-nk(1)式中,WN=e-j*2π/N,称为旋转因子或蝶形因子。从DFT的定义可以看出,在x(n)为复数序列的情况下,对某个k值,直接按(1)式计算X(k)只需要N次复数乘法和(N-1)次复数加法。因此,对所有N个k值,共需要N2次复数乘法和N(N-1)次复数加法。对于一些相当大有N值(如1024点)来说,直接计算它的DFT所需要的计算量是很大的,因此DFT运算的应用受到了很大的限制。2快速傅里叶变换FFT旋转因子WN有如下的特性。对称性:WNk+N/2=-WNk周期性:WNn(N-k)=WNk(N-n)=WN-nk利用这些特性,既可以使DFT中有些项合并,减少了乘法积项,又可以将长序列的DFT分解成几个短序列的DFT。FFT就是利用了旋转因子的对称性和周期性来减少运算量的。FFT的算法是将长序列的DFT分解成短序列的DFT。例如:N为偶数时,先将N点的DFT分解为两个N/2点的DFT,使复数乘法减少一半:再将每个N/2点的DFT分解成N/4点的DFT,使复数乘又减少一半,继续进行分解可以大大减少计算量。最小变换的点数称为基数,对于基数为2的FFT算法,它的最小变换是2点DFT。一般而言,FFT算法分为按时间抽取的FFT(DITFFT)和按频率抽取的FFT(DIFFFT)两大类。DIFFFT算法是在时域内将每一级输入序列依次按奇/偶分成2个短序列进行计算。而DIFFFT算法是在频域内将每一级输入序列依次奇/偶分成2个短序列进行计算。两者的区别是旋转因子出现的位置不同,得算法是一样的。在DIFFFT算法中,旋转因子出现在输入端,而在DIFFFT算法中它出现在输入端。假定序列x(n)的点数N是2的幂,按照DIFFFT算法可将其分为偶序列和奇序列。偶序列:x(2r)=x1(r)奇序列:x(2r+1)=x2(r)其中:r=0,1,2,…,N/2-1则x(n)的DFT表示为111000NNNnknknkNNNnnnXkxnWxnWxnWn为偶数n为奇数/21/2121200221NNrkrkNNrrxrWxrW/21/21221200NNrkrkkNNNrrxrWWxrW/21/211/22/200NNrkkrkNNNrrxrWWxrW式中,x1(k)和x2(k)分别为x1(r)和x2(r)的N/2的DFT。由于对称性,WNk+N/2=-WNk。因此,N点DFT可分为两部分:前半部分:x(k)=x1(k)+WkNx2(k)(4)后半部分:x(N/2+k)=x1(k)-WkNx2(k)k=0,1,…,N/2-1(5)从式(4)和式(5)可以看出,只要求出0~N/2-1区间x1(k)和x2(k)的值,就可求出0~N-1区间x(k)的N点值。以同样的方式进行抽取,可以求得N/4点的DFT,重复抽取过程,就可以使N点的DFT用上组2点的DFT来计算,这样就可以大减少运算量。基2DIFFFT的蝶形运算如图(a)所示。设蝶形输入为X1(K)和X2((K),输出为x(k)和x(N/2+K),则有x(k)=x1(k)+WkNx2(k)(6)x(N/2+k)=x1(k)-WkNx2(k)(7)在基数为2的FFT中,设N=2M,共有M级运算,每级有N/2个2点FFT蝶形运算,因此,N点FFT总共有MN/2个蝶形运算。12kNXkWXk,0,1,.../21rkNCABA+BCA-BC图(a)基2DIFFFT的蝶形运算例如:基数为2的FFT,当N=8时,共需要3级,12个基2DITFFT的蝶形运算。其信号流程如图(b)所示。x(0)x(0)WN0x(4)x(1)-1WN0x(2)x(2)-1WN0WN2x(6)x(3)-1-1WN0x(1)x(4)-1WN0WN1x(5)x(5)-1-1WN0WN2x(3)x(6)-1-1WN0WN2WN3x(7)x(7)-1-1-1图(b)8点基2DIFFFT蝶形运算从图(b)可以看出,输入是经过比特反转的倒位序列,称为位码倒置,其排列顺序为x(0),x(4),x(2),x(6),x(1),x(5),x(3),x(7),输出是按自然顺序排列,其顺序为x(0),x(1),x(2),x(3),x(4),x(5),x(6),x(7).四.设计步骤(1)启动CCS,在CCS中建立一个C源文件和一个命令文件,并将这两个文件添加到工程,再编译并装载程序:阅读Dsp原理及应用中fft用dsp实现的有关程序。双击,启动CCS的仿真平台的配着选项。选择C5502Simulator。(3)启动ccs2后建立工程文件FFT.pjt(4)建立源文件FFT.c与链接文件FFT.cmd(5)将这两个文件加到FFT.pjt这个工程中。(6)创建out文件(7)加载out文件(8)加载数据(9)观察输入输出波形输入波形(时域)输出图形(频域)8改变信号的频率可以再做次实验。也可作512点或更多点的FFT.Cmd源文件代码:-f0-w-stack500-sysstack500-lrts55.libMEMORY{DARAM:o=0x100,l=0x7f00VECT:o=0x8000,l=0x100DARAM2:o=0x8100,l=0x7f00SARAM:o=0x10000,l=0x30000SDRAM:o=0x40000,l=0x3e0000}SECTIONS{.text:{}DARAM.vectors:{}VECT.trcinit:{}DARAM.gblinit:{}DARAM.frt:{}DARAM.cinit:{}DARAM.pinit:{}DARAM.sysinit:{}DARAM2.far:{}DARAM2.const:{}DARAM2.switch:{}DARAM2.sysmem:{}DARAM2.cio:{}DARAM2.MEM$obj:{}DARAM2.sysheap:{}DARAM2.sysstack:{}DARAM2.stack:{}DARAM2.input:{}DARAM2.fftcode:{}DARAM2}C文件源码:#includemath.h#definesample_1256#definesignal_1_f60#definesignal_2_f200#definesignal_sample_f512#definepi3.1415926intinput[sample_1];floatfwaver[sample_1],fwavei[sample_1],w[sample_1];floatsin_tab[sample_1];floatcos_tab[sample_1];voidinit_fft_tab();voidinput_data();voidfft(floatdatar[sample_1],floatdatai[sample_1]);voidmain(){inti;init_fft_tab();input_data();for(i=0;isample_1;i++){fwaver[i]=input[i];fwavei[i]=0.0f;w[i]=0.0f;}fft(fwaver,fwavei);while(1);}voidinit_fft_tab(){floatwt1;floatwt2;inti;for(i=0;isample_1;i++){wt1=2*pi*i*signal_1_f;wt1=wt1/signal_sample_f;wt2=2*pi*i*signal_2_f;wt2=wt2/signal_sample_f;input[i]=(cos(wt1)+cos(wt2))/2*32768;}}voidinput_data(){inti;for(i=0;isample_1;i++){sin_tab[i]=sin(2*pi*i/sample_1);cos_tab[i]=cos(2*pi*i/sample_1);}}voidfft(floatdatar[sample_1],floatdatai[sample_1]){intx0,x1,x2,x3,x4,x5,x6,x7,xx;inti,j,k,b,p,L;floatTR,TI,temp;for(i=0;isample_1;i++){x0=x1=x2=x3=x4=x5=x6=0;x0=i&0x01;x1=(i/2)&0x01;x2=(i/4)&0x01;x3=(i/8)&0x01;x4=(i/16)&0x01;x5=(i/32)&0x01;x6=(i/64)&0x01;x7=(i/128)&0x01;xx=x0*128+x1*64+x2*32+x3*16+x4*8+x5*4+x6*2+x7;datai[xx]=datar[i];}for(i=0;isample_1;i++){datar[i]=datai[i];datai[i]=0;}for(L=1;L=8;L++){b=1;i=L-1;while(i0){b=b*2;i--;}for(j=0;j=b-1;j++){p=1;i=8-L;while(i0){p=p*2;i--;}p=p*j;for(k=j;k256;k=k+2*b){TR=datar[k];TI=datai[k];temp=datar[k+b];datar[k]=datar[k]+datar[k+b]*cos_tab[p]+datai[k+b]*sin_tab[p];datai[k]=datai[k]-datar[k+b]*sin_tab[p]+datai[k+b]*cos_tab[p];datar[k+b]=TR-datar[k+b]*cos_tab[p]-datai[k+b]*sin_tab[p];datai[k+b]=TI+temp*sin_tab[p]-datai[k+b]*cos_tab[p];}}}for(i=0;isample_1/2;i++){w[i]=sqrt(datar[i]*datar[i]+datai[i]*datai[i]);}}六.设计感想通过这次DSP课程设计,加深对DFT算法原理和基本性质的理解,熟悉了FFT的算法原理和FFT子程序的算法流程和应用,掌握了DSP中FFT的设计和编程思想,以及用FFT对连续信号和时域信号进行频谱分析的方法,和使用CCS的波形观察器观察波形和频谱情况。这次课程设计,使我增长了知识,同时也增强了我动手解决问题的能力,锻炼我做事细心、用心、耐心的能力。同时也让我意识到平时的课程文化的学习固然非常重要,但是在与实际相联系的过程中还是有许多问题的,所以在以后的学习生活中,我要努力学习,培养自己独立思考的能力,要加强理论文化与实际操作的联系。积极参加各种设计活动,培养自己的综合能力,使自己得到全面的提高。参考文献DSP原理及应用邹彦主编