音频信号的FFT分析
一、实验目的: (2)
二、实验内容: (2)
三、实验程序功能与结构说明: (2)
四、实验流程图: (3)
五、实验步骤: (4)
1、实验演示: (4)
2、实验的调试: (4)
六、实验主要程序: (5)
1、主函数: (5)
2、中断程序: (12)
3、异步串口初始化程序: (12)
4、AD初始化: (13)
七、实验结果: (15)
1、SEEDDEC2812单元的D3灯由闪烁变成常暗。 (15)
2、可以看到失真比较大的FFT波形,如下图所示: (15)
1)、失真信号及频域图: (15)
2)、期信号时域和频域曲线图: (15)
八、实验心得: (16)
一、实验目的:
1、熟悉CCS集成开发环
2、熟悉SEED-DTK实验环境
3、加深对DFT算法原理和基本性质的理解
4、学习用FFT对连续信号和时域信号地频谱分析的方法
5、熟悉FFT的算法原理和FFT子程序的算法流程和应用
6、了解DSP处理FFT算法的特殊寻址方式
二、实验内容:
1、DSP的初始化
2、A/D采样
3、FFT的位倒序程序
4、FFT的蝶形运算程序
5、求功率谱的程序
6、串口发送与接收
三、实验程序功能与结构说明:
在数字滤波器实验中,主要包含以下文件:
1、DTK_BPD_FFT.c:这是实验的主程序,包含了包含定时器中断程序、AD中断程序、
FFT参数的初始化,完成与SEED-MMI5402的系统的异步通讯、信号采集与FFT计算。
2、DSP28_Sci.c:包含量了异步串口初始化程序。
3、DSP28_Adc.c:包含了AD初始化。
4、DSP28_Defaultlsr.c:包含了异步串口接收中断服务程序。
5、Cfft32c.asm、cfft32i.asm、rfft32br.asm、rfft32m.asm、rfft32s.asm、rfft32w.asm:TI
源代码。
6、SRAM.cmd:声明了系统的存贮器配置与程序各段的链接关系。
7、DTK_BPD_FFT.out:DSP上可执行的程序,即实验程序。
四、实验流程图:
五、实验步骤:
1、实验演示:
在脱机(不接CCS)的情况下,可以首先进行实验的演示。在实验选项的菜单下,选择FFT实验一项。先择不使用CCS,确定后,LCD显示屏将显示“程序装载中,请稍侯”,并且用状态条显示程序装载进度,等待装载程序后,SEEDDEC2812单元的D3灯由闪烁变暗。LCD 显示屏将显示“FFT实验装载成功”。一段时间后,可以看到在LCD上显示FFT前的原始信号与实验后的功率谱图,如下图(a与b)所示:
2、实验的调试:
1)、将DSP仿真器与计算机连接好:
2)、将DSP仿真器的JTAG插关与SEED-DEC2812单元的J1相连接
3)、启动计算机,当计算机启动后,打开SEED-DTK BPD的电源。观察SEEK-DTK_IO单元的+5V、+3.3V、+15V、-15V的电源指示灯是否均亮,若有不亮的,请断开电源,检查电源。
4)、在实验选项的菜单下,选择定时器实验一项,选择使用CCS。
5)、打开CCS,进入CCS的操作环境。
6)、装入DTK_BPD_FFT.wks调试环境。
7)、进行调度,通过Probe Points来观察FFT的结果。
六、实验主要程序:
1、主函数:
void main(void)
{
/*初始化系统*/
InitSysCtrl();
/*关中断*/
DINT;
IER = 0x0000;
IFR = 0x0000;
/*初始化PIE中断*/
InitPieCtrl();
/*初始化PIE中断矢量表*/
InitPieVectTable();
/*初始化SCIA寄存器*/
InitSci();
//初始化cputimer
InitCpuTimers();
for(i= 0; i<0x104;i++)
{
uart[i] = 0x5555;
uarts[i] = 0x5555;
}
for(i=0;i<32;i++)
{
sys_statbuff[i]=0;//系统标志buff清0
}
CommandSave=0;
/*设置中断服务程序入口地址*/
EALLOW; // This is needed to write to EALLOW protected registers PieVectTable.TXAINT = &SCITXINTA_ISR;
PieVectTable.RXAINT = &SCIRXINTA_ISR;
PieVectTable.TINT2 = &ISRTimer2;
PieVectTable.ADCINT = &ad;
EDIS; // This is needed to disable write to EALLOW protected registers
//
/*开中断*/
IER |= M_INT9;//SCI中断
IER |= M_INT1;//ADC中断
EINT; // Enable Global interrupt INTM
ERTM; // Enable Global realtime interrupt DBGM
LED1_ON;
*LED3=0;
/*实验主控程序*/
psend = (PuartForDec5416)(&uarts[0]);
precieve = (PuartForDec5416)(&uart[0]);
padset = (PAdConfig)(&adset[0]);
/*通知主机,系统准备好*/
psend->Length = FRAMLONGTH;
psend->Type = UARTCOMMAND;
psend->Data[0] = INITOVER;
psend->Mutul = UARTCONT;
uart_send();
for(;;)
{
if(CommandSave==FFTDATASEND)
{
CommandSave=0;
/*不满buffer的数据*/
if(datasendlength <= 256)
{
for(i = 0;i { psend->Data[i] = Ad_data[i+sendcount*256]; } psend->Length = datasendlength; psend->Type = UARTDATA; psend->Mutul = UARTCONT; uart_send(); } else { /*满buffer数据*/ for(k = 0; k<256;k++) { psend->Data[k] = Ad_data[k+sendcount*256]; } psend->Length = 256; psend->Type = UARTDATA; psend->Mutul = UARTMUTL; uart_send(); datasendlength= datasendlength - 256; sendcount++; } } uart_s =uart_recive(); /* 返回值0:接受完成 */ /* 1:数据未准备好*/ /* 3: 较验出错*/ if(uart_s==1) { continue; } /*数据较验出错*/ if(uart_s == 3) { for(i= 0; i<0x104;i++) { uart[i] = 0x5555; } /*通知主机程序通讯出错,准备重发*/ psend->Length = FRAMLONGTH; psend->Type = UARTCOMMAND; psend->Data[0] = RECIEVEERROR; psend->Mutul = UARTCONT; uart_send(); continue; } /*接收完成*/ if(uart_s ==0) { /*不是命令帧*/ if(precieve->Type != UARTCOMMAND) { /*无效命令*/ psend->Length = FRAMLONGTH; psend->Type = UARTCOMMAND; psend->Data[0] = COMMANDNODO; psend->Mutul = UARTCONT; uart_send(); precieve->Type = UARTCOMMAND; continue; } } /*接收从主机的数据*/ precieve = (PuartForDec5416)(&uart[0]); switch(precieve->Data[0]) { /*FFT设置*/ case FFTSET: for(i=0;i<3;i++) { adset[i] = precieve->Data[i+1]; } /*设置数据发送长度*/ datasendlong = padset->SampleLong; datasendlength= 3*datasendlong/2; precieve->Data[0] = 0; break; /*启动AD采样和fft计算*/ case FFTSTART: convcount=0; adconvover=0; sendcount=0; convfirstN=1000; /*AD采样率*/ switch( padset->SampleRate) { case ADSAMPL8K: //0xd //采样率为8k DINT; /*设置CPU*/ ConfigCpuTimer(&CpuTimer2, 150, 125); StartCpuTimer2(); /*开中断*/ IER |= M_INT14; EINT; InitAdc(); break; case ADSAMPL44K: // 0x23 //采样率为44k DINT; /*设置CPU*/ ConfigCpuTimer(&CpuTimer2, 150, 22); StartCpuTimer2(); /*开中断*/ IER |= M_INT14; EINT; InitAdc(); break; case ADSAMPL96K://0x1d //采样率为96k DINT; /*设置CPU*/ ConfigCpuTimer(&CpuTimer2, 150, 10); StartCpuTimer2(); /*开中断*/ IER |= M_INT14; EINT; InitAdc96k(); break; default: break; } for(;;) { if (adconvover==1) break; } /*AD采样结束*/ /*fft转换*/ /* Initialize FFT module */ switch(datasendlong) { case 128: fft128.ipcbptr=ipcb; fft128.init(&fft128); for(i=0;i { ipcb[i] = Ad_data[i]; Ad_data[i]=(Ad_data[i]>>4)-0x555;//偏移量1v。 ipcb[i] = (ipcb[i]>>4)-0x555; } RFFT32_brev(ipcb,ipcb,FFTN128); fft128.calc(&fft128); fft128.split(&fft128); break; case 256: fft256.ipcbptr=ipcb; fft256.init(&fft256); for(i=0;i { ipcb[i] = Ad_data[i]; Ad_data[i]=(Ad_data[i]>>4)-0x555;//偏移量1v。 ipcb[i] = (ipcb[i]>>4)-0x555; } RFFT32_brev(ipcb,ipcb,FFTN256); fft256.calc(&fft256); fft256.split(&fft256); break; case 512: fft512.ipcbptr=ipcb; fft512.init(&fft512); for(i=0;i { ipcb[i] = Ad_data[i]; Ad_data[i]=(Ad_data[i]>>4)-0x555;//偏移量1v。 ipcb[i] = (ipcb[i]>>4)-0x555; } RFFT32_brev(ipcb,ipcb,FFTN512); fft512.calc(&fft512); fft512.split(&fft512); break; default: break; } /*求模*/ m=0; for(i=0;i { p=ipcb[i]; q=ipcb[i+1]; n=p*p+q*q; n=sqrt(n); mod[m]=n; m++; } r= datasendlong; for(i=0;i { Ad_data[r]=mod[i]; r++; } //FFT计算完毕 psend->Length = 1; psend->Type = UARTCOMMAND; psend->Data[0] = FFTOVER; psend->Mutul = UARTCONT; uart_send(); precieve->Data[0] = 0; break; /*FFT数据传送*/ case FFTDATASEND: precieve->Data[0] = 0; CommandSave=FFTDATASEND; break; case RECIEVEERROR: datasendlength = datasendlength + 256; sendcount--; precieve->Data[0] = 0; CommandSave=FFTDATASEND; break; /*系统复位*/ case SYSRESET: sys_reset(); default: break; } } } 2、中断程序: interrupt void ad(void) { IFR=0x0000; PieCtrl.PIEACK.all=0xffff; if(convfirstN==0) { Ad_data[convcount] = AdcRegs.RESULT1; if(Ad_data[convcount]==0) { convcount--; } convcount++; if (convcount==(padset->SampleLong)) { convcount=0; adconvover=1;//接满标志 DINT; /*停止计数*/ StopCpuTimer2(); /*关中断*/ IER &= 0xdfff; EINT; } } else convfirstN--; } 3、异步串口初始化程序: void InitSci(void) { *UART_MODE = 0x44; EALLOW; GpioMuxRegs.GPFMUX.all = 0x0030; EDIS; /* loopback 8 bit data */ SciaRegs.SCICCR.all = 0x07; SciaRegs.SCICTL1.all = 0x03; SciaRegs.SCICTL2.all = 0x02; SciaRegs.SCIHBAUD = 0x00; SciaRegs.SCILBAUD = 0xF3; SciaRegs.SCICTL1.all = 0x23; PieCtrl.PIEIER9.bit.INTx1 = 1; } 4、AD初始化: void InitAdc(void) { AdcRegs.ADCTRL1.bit.RESET=1; AdcRegs.ADCTRL2.bit.RST_SEQ1=1; AdcRegs.MAX_CONV.bit.MAX_CONV=15; NOP; AdcRegs.ADCTRL1.bit.RESET=0; AdcRegs.ADCTRL1.bit.SUSMOD=3; AdcRegs.ADCTRL1.bit.ACQ_PS=0; AdcRegs.ADCTRL1.bit.CPS=0; AdcRegs.ADCTRL1.bit.CONT_RUN=0; AdcRegs.ADCTRL1.bit.SEQ_CASC=1; AdcRegs.MAX_CONV.bit.MAX_CONV=15; AdcRegs.CHSELSEQ1.bit.CONV00=14;//硬件连接到了ADCINB6 AdcRegs.CHSELSEQ1.bit.CONV01=1; AdcRegs.CHSELSEQ1.bit.CONV02=2; AdcRegs.CHSELSEQ1.bit.CONV03=3; AdcRegs.CHSELSEQ2.bit.CONV04=4; AdcRegs.CHSELSEQ2.bit.CONV05=5; AdcRegs.CHSELSEQ2.bit.CONV06=6; AdcRegs.CHSELSEQ2.bit.CONV07=7; AdcRegs.CHSELSEQ3.bit.CONV08=8; AdcRegs.CHSELSEQ3.bit.CONV09=9; AdcRegs.CHSELSEQ3.bit.CONV10=10; AdcRegs.CHSELSEQ3.bit.CONV11=11; AdcRegs.CHSELSEQ4.bit.CONV12=12; AdcRegs.CHSELSEQ4.bit.CONV13=13; AdcRegs.CHSELSEQ4.bit.CONV14=14; AdcRegs.CHSELSEQ4.bit.CONV15=15; AdcRegs.ADCTRL3.bit.ADCBGRFDN=3; AdcRegs.ADCTRL3.bit.ADCPWDN=1; AdcRegs.ADCTRL3.bit.ADCCLKPS=8; AdcRegs.ADCTRL3.bit.SMODE_SEL=1; AdcRegs.ADC_ST_FLAG.bit.INT_SEQ1_CLR=1; AdcRegs.ADC_ST_FLAG.bit.INT_SEQ2_CLR=1; AdcRegs.ADCTRL2.bit.EVB_SOC_SEQ=0; AdcRegs.ADCTRL2.bit.RST_SEQ1=0; AdcRegs.ADCTRL2.bit.INT_ENA_SEQ1=1; AdcRegs.ADCTRL2.bit.INT_MOD_SEQ1=0; AdcRegs.ADCTRL2.bit.EVA_SOC_SEQ1=0; AdcRegs.ADCTRL2.bit.EXT_SOC_SEQ1=0; AdcRegs.ADCTRL2.bit.RST_SEQ2=0; AdcRegs.ADCTRL2.bit.SOC_SEQ2=0; AdcRegs.ADCTRL2.bit.INT_ENA_SEQ2=0; AdcRegs.ADCTRL2.bit.INT_MOD_SEQ2=0; AdcRegs.ADCTRL2.bit.EVB_SOC_SEQ2=0; } 七、实验结果: 1、SEEDDEC2812单元的D3灯由闪烁变成常暗。 2、可以看到失真比较大的FFT波形,如下图所示:1)、失真信号及频域图: 2)、周期信号时域和频域曲线图: 含有随机噪声的周期信号 频域圈 八、实验心得: 熟悉了在CCS集成开发环境下,新建工程,并且运行,在此过程中,可以通过观察内存中的位变化来查看实验结果,除此之外还可以通过在计算机上查看与实验箱平台相同步的波形查看器,可以清楚地看到它的FFT波形,虽然不是很准确。 加深了对DFT算法及FFT算法的了解,快速傅氏变换(FFT)是离散傅氏变换的快速算法,它是根据离散傅氏变换的奇、偶、虚、实等特性,对离散傅立叶变换的算法进行改进获得的。它对傅氏变换的理论并没有新的发现,但是对于在计算机系统或者说数字系统中应用离散傅立叶变换,可以说是进了一大步。 设x(n)为N项的复数序列,由DFT变换,任一X(m)的计算都需要N次复数乘法和N-1次复数加法,而一次复数乘法等于四次实数乘法和两次实数加法,一次复数加法等于两次实数加法,即使把一次复数乘法和一次复数加法定义成一次“运算”(四次实数乘法和四次实数加法),那么求出N项复数序列的X(m),即N点DFT变换大约就需要N2次运算。当N=1024点甚至更多的时候,需要N2=1048576次运算,在FFT中,利用WN的周期性和对称性,把一个N项序列(设N=2k,k为正整数),分为两个N/2项的子序列,每个N/2点DFT变换需要(N/2)2次运算,再用N次运算把两个N/2点的DFT变换组合成一个N点的DFT变换。这样变换以后,总的运算次数就变成N+2(N/2)2=N+N2/2。继续上面的例子,N=1024时,总的运算次数就变成了525312次,节省了大约50%的运算量。而如果我们将这种“一分为二”的思想不断进行下去,直到分成两两一组的DFT运算单元,那么N点的DFT变换就只需要Nlog2N次的运算,N在1024点时,运算量仅有10240次,是先前的直接算法的1%,点数越多,运算量的节约就越大,这就是FFT的优越性;FFT算法的输出X(K)为自然顺序,但为了适应原位计算,其输入序列不是按x(n)的自然顺序排序,这种经过M-1次奇偶抽选后的排序为序列的倒序。因此,在运算之前应先对序列x(n)进行倒序。倒序的规律就是把顺序数的二进制位倒置,即可得到倒序值。倒序数是在M位二进制数最高位加一,逢2向右进位。对于FFT,M位二进制数最高位的权值为N/2,且从左到右二进制位的权值依次为你N/4,N/8,···,2,1。因此,最高位加一相当于十进制运算J+N/2。(J表示当前倒序数的十进制数值)。