音频信号分析仪1

更新时间:2023-10-25 09:00:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

音频信号分析仪

摘要: 本音频信号分析仪由MSP430单片机和FPGA协同控制,通过AD转换,对音频信号进行采样,把连续信号离散化,然后通过FFT运算,在时域和频域对音频信号各个频率分量以及功率等指标进行分析和处理,然后通过高分辨率的LCD对信号的频谱进行显示。可实现5秒内至少更新一次测量数据,并具有数据存储、回放显示功能;测试表明本文介绍的音频信号分析仪测量准确、误差小、分辨力高,各项性能指标符合行业要求。

系统方案论证

1.1 采样方法比较与选择

方案一:采用FPGA对数据进行采集,利用外部12位AD转换器对数据进行转换后经过运算放大电路对信号进行放大后直接送入FPGA,然后由FPGA对数据进行处理。

方案二:利用MSP430单片机对数据进行采集,然后利用单片机内部自带的12位AD转换器进行转换后送入FPGA,然后由FPGA 对数据进行处理。

通过对两种方案的比较,我们发现两种方案各有优缺点,方案一的数据采集速度相对与方案二要快的多,但AD采样的精度又不如方案二,在我们的这个设计中,我们主要考虑了采样的精度,而且单片机的采样速率完全可以达到题目给我们的要求,所以我们选择了方案二

1.2 处理器的比较与选择

方案一:利用单片机来控制整个程序实现,但是让FPGA来完成所有的 运算,包括傅里叶变换,平方,开方运算。

方案二:直接采用单片机实现所有的功能,包括傅里叶变换,以及后期的数据处理。

由于快速傅立叶变换FFT算法设计大量的浮点运算,由于一个浮点占用四个字节,所以要占用大量的内存,同时浮点运算时间很慢,所以采用普通的单片机一般难以在一定的时间内完成运算,所以综合内存的大小以及运算速度我们选择方案一

1.3 失真度与周期性判别与测量方法比较与选择

利用傅立叶级数,所有的周期函数可以用其基本频率及整数倍频率的正弦波的级数来表示。设周期函数为u(t),则可表示为:

u(t)?A1sin?t?n????A?nsin(n?t??n) (2.6.1)

其中A1sin?t称为基波,A1sinn?t称为n次谐波。失真度(distrortion)是该谐波的矢量和与周期函数有效值之比,则失真度D为: D??An?2?2n2A??AN 21n?2? 对于普通的音频信号,频率分量一般较多,它不具有周期性。测量周期可以在时域测量也可以在频域测量,但是由于频域测量周期性要求某些频率点具有由规律的零点或接近零点出现,所以对于较为复杂的,频率分量较多且功率分布较均匀且低信号就无法正确的分析其周期性。

而在时域分析信号,我们可以先对信号进行处理,然后假定具有周期性,然后测出频率,把采样的信号进行周期均值法和定点分析法的分析后即可以判别出其周期性。

综上,我们选择信号在时域进行周期性分析和周期性测量。对于一般的音频信号,其时域变化是不规则的,所以没有周期性。而对于单频信号或者由多个具有最小公倍数的频率组合的多频信号具有周期性。这样我们可以在频域对信号的频谱进行定量分析,从而得出其周期性。而我们通过先假设信号是周期的,然后算出频率值,然后在用此频率对信号进行采样,采取连续两个周期的信号,对其值进行逐次比较和平均比较,若相差太远,则认为不是周期信号,若相差不远(约5%),则可以认为是周期信号。

二、系统总框图

2.1:总体设计

音频信号经过一个由运放和电阻组成的网络后,通过MSP430内部的AD转换器对信号进行AD转换,然后将数据送入FPGA存储器,当数据存储完成后,在FPGA系统时钟的控制下,对数据进行FFT变换,将结果存储、发送给单片机,由单片机来完成后期的数据处理和LCD显示。

信号输入信号放大AD转换LCD显示MSP430单片机F P G A数据处理数据处理

数据存储FFT变换数据存储 2.2硬件设计

信号输入电压为100mV~5V,为达到A/D转换器最佳的转换电压需要对待测量信号进行放大和阻抗变换。前级信号调理电路采用一级跟随器和同相放大电路,将信号输入电压分为5档,如图3.1所示,取R2?100? 则由

200?、470?、1k?、2k?。 放大倍数公式可求得R值分别为:100?、 本模块采用两片OP07构成一级跟随器和一级同相放大电路,主要用于实

现系统阻抗变换和弱信号放大。由于AD转换芯片的模拟输入端口为容性负载,对输入信号会造成严重的波形失真,采用两级运放可以消除误差,同时达到阻抗匹配的目的。

2.3 功率谱测量

信号经过A/D转换以及滤波器处理后再进行FFT运算处理即得到信号频谱图,根据频谱即可求得各个0参数,所以FFT是运算的核心部分。

设x(n)为N点有限长序列,直接计算DFT,运算量较大。若N=2M,M为整数,按n的奇偶把x(n)分解为两个N/2点的子系列:x1(r)为偶系列、x2(2)为奇系列。

rkKrk则X(k)??x1(r)WN即一个N点DFT可以分/2?WN?x2(r)WN/2,

r?0r?0N?12N?12解为N/2个点的DFT运算。进行FFT运算必须对序列进行加窗处理,即

v(n)?x(n)w(n),加窗后的DFT是:

V(k)??v(n)en?0N?1?j2?nkN ,0?k?N?1 (2.4.1)

假设窗函数长度L小于或等于DFT长度N,为进行FFT运算,这里选择N为2的整数次幂。离散频率函数第k点对应模拟频率为:fk=k/NT,则数字域频率间隔???2?/N对应的模拟域谱线间距为:F=1/NT=fs/N即为频谱分辨率。

应用上面讨论的FFT算法计算x(n)的频谱,得到X(k)=XR(k)+jXI(k)写成极坐标形式:X(k)?|X(k)|ejarg[X(k)]式中,|X(k)|成为幅度谱,arg[X(k)]为相位谱。功率谱的定义为:PSD(k)?|X(k)|。

N2

四、软件设计

单片机程序主要用来对FFT的数据进行计算和相关参数的提取、存储和系统总体控制,包括LCD显示控制。FPGA部分采用了Altera公司的数字信号处理IP Core —FFT-V2.1.3实现FFT,考虑系统要求,一次进行512点实数数据的FFT转换,并对转换结果进行求模平方运算具体流程如下图:

五、系统测试

5.1 总功率测量 频率 幅度 测量测量 理论估算输时域频域值 误差 入总功总功信率(w) 率(w) 号 100Hz 1 Vpp 0.127 正0.129 0.125 1.2% 弦 1KH 1 Vpp 0.129 波 0.126 0.125 1.3% 音 40mVpp-5Vpp X 频40Hz-10KHz 0.783 0.761 《5% 信 X 号 1.803 1.777 《5% 结果分析: 我们用信号发生器产生一组正弦波信号,然后进行测量,发现误差在+-5%以内。我们以音频信号进行测量,由于其实际值无法测量,所以我们只能根据时域和频域以及估计其误差,都在5%以内。

5.2 单个频率分量测量 输入频率 幅度 最大最大次大功次大功信号 功率功率率频点 率频点频点 频点功率 功率 正弦波 500Hz 100mV 1.20m 0.04mW pp 500Hw 520Hz z 正弦波 5KHz 1Vpp 3.56mw 5KHz 120mw 5.02KHz 音频信20Hz- X 23mw 号 10K 880H600Hz 4.3mw z

结果分析:我们首先以理论上单一频率的正弦波为输入信号,在理想状况下,其频谱只在正弦波频率上有值,而由于有干扰,所以在其他频点也有很小的功率。

音频信号由于有多个频点,所以没有一定的规律性。由于音频信号波动较大,没有一定的规律,所以我们只好对音频信号进行定性的分析和测量。我们发现其数字和用MATLAB模拟的结果符合得很近。

五、结论

由于系统架构设计合理,功能电路实现较好,系统性能优良、稳定,较好地达到了题目要求的各项指标。本系统在40Hz~10KHz的频率范围内,可准确地测量信号中基波分量周期、各频率分量功率、失真度等;参数显示清晰,数据刷新时间小于5s;各项参数性能达到题目要求。

六、参考目录

[1] 丁玉美,高西全.数字信号处理.西安:西安电子科技大学出版社,2006 [2] 赵力.语音信号处理.北京:机械工业出版社,2003

[3] 康华光.电子技术基础模拟部分.北京:高等教育出版社,2005 [4] 张洪涛,万红,杨述斌.数字信号处理.武汉:华中科技大学出版社2003 [5] 高吉祥.全国大学生电子设计竞赛电子仪器仪表设计.北京:电子工业出版社,2007

[6] 张巨洪.BASIC语言程序库.北京:清华大学出版社,1983

附件:

附1:元器件明细表: MSP430 OP07

EP2C35F672C8N 液晶320*240

附件2:FPGA系统总体电路图

附件2:部分主要程序清单:

/***************************************************************************************************************************************************/

//FPGA FFT运算芯片

//接口说明: P3.0~~P3.7 -->read_real_date (H7) ,P4.0~~P4.7 -->read_imag_date (H3) , P7.0~~P7.7-->wirte_date_to_FPGA (H6),

// (H4) P2.0-->w_date_clk_in ,P2.1-->r_date_clk_out ,P2.2-->reset_in //2008.7.31

/**************************************************************************************************************************************************/

#include #include

#define IO_INIT P2DIR=0XFF; P3DIR=0X00; P4DIR=0X00; P7DIR=0XFF

#define W_DATE_CLK_IN_FPGA_1 P2OUT|=BIT0 //w_date_clk_in为1

#define W_DATE_CLK_IN_FPGA_0 P2OUT&=~BIT0 //w_date_clk_in为0

#define R_DATE_CLK_OUT_FPGA_1 P2OUT|=BIT1 //r_date_clk_out为1

#define R_DATE_CLK_OUT_FPGA_0 P2OUT&=~BIT1 //r_date_clk_out为0

#define RESET_IN_1 P2OUT|=BIT2 //reset_in为1 #define RESET_IN_0 P2OUT&=~BIT2 //reset_in为0

#define DATE_IN_FPGA P7OUT #define REAL_DATE_IN_MSP430 P3IN #define IMAG_DATE_IN_MSP430 P4IN

#define CPU_F ((double)1000000)

#define delay_us(x) __delay_cycles((long)(CPU_F*(double)x/1000000.0)) #define delay_ms(x) __delay_cycles((long)(CPU_F*(double)x/1000.0))

void init_fft();

void r_fft_date_out();

void w_fft_date_in(unsigned int i); inline char my_abs(char x); int fft_date[512]={0}; char fft_exp=0;

void text_w_fft_date_in(unsigned int i); int main( void ) {

int i=0;

// Stop watchdog timer to prevent time out reset WDTCTL = WDTPW + WDTHOLD;

init_fft();

ADC12CTL0 = ADC12ON + REFON + REF2_5V + SHT0_6; // 设置 ADC12, 参考电压2.5V,采样周期25.6uS

ADC12CTL1 = SHP; // 内部定时采样 ADC12MCTL0 = INCH_3 + SREF_1; // 选择采样通道 A3, Vref+

ADC12IE = 0x01; // 使能 ADC12IFG.0 for (i = 0; i < 0x3600; i++); // 延时 ,使内部参考电压稳定

ADC12CTL0 |= ENC; // __enable_interrupt(); // text_w_fft_date_in(512); delay_ms(6000); r_fft_date_out(); while(1); }

void init_fft() {

P2DIR=0XFF; P3DIR=0X00; P4DIR=0X00; P7DIR=0XFF; W_DATE_CLK_IN_FPGA_0; R_DATE_CLK_OUT_FPGA_0; RESET_IN_1; delay_ms(1); RESET_IN_0; }

void r_fft_date_out() {

char real,imag; unsigned int i=0; float buff;

for(i=0;i<512;i++) {

R_DATE_CLK_OUT_FPGA_1; real=REAL_DATE_IN_MSP430; imag=IMAG_DATE_IN_MSP430; R_DATE_CLK_OUT_FPGA_0;

buff=pow(my_abs(real),2)+pow(my_abs(imag),2); fft_date[i]=sqrt(buff); }

R_DATE_CLK_OUT_FPGA_1;

fft_exp=REAL_DATE_IN_MSP430&0x3f; R_DATE_CLK_OUT_FPGA_0; }

使能转换 开中断

void w_fft_date_in(unsigned int i) {

unsigned int k; k=i;

while(k--) //读入实部 {

ADC12CTL0 |= ADC12SC; // 开始采样

__bis_SR_register(LPM0_bits); // 进入低功耗 LPM0 } k=i;

while(k--) //读入虚部 为全0 {

W_DATE_CLK_IN_FPGA_1; DATE_IN_FPGA=0;

W_DATE_CLK_IN_FPGA_0; }

W_DATE_CLK_IN_FPGA_1; //调整信号 W_DATE_CLK_IN_FPGA_0;

W_DATE_CLK_IN_FPGA_1; //调整信号 W_DATE_CLK_IN_FPGA_0; }

inline char my_abs(char x) {

if(x&0x80)

return (~x+1); else

return x; }

#pragma vector=ADC12_VECTOR __interrupt void ADC12ISR(void) {

W_DATE_CLK_IN_FPGA_1;

DATE_IN_FPGA = (unsigned char)((ADC12MEM0>>4)-0x80); W_DATE_CLK_IN_FPGA_0;

__bic_SR_register_on_exit(LPM0_bits); //退出低功耗 LPM0 }

void text_w_fft_date_in(unsigned int i) {

unsigned int k=0; k=i/2;

while(k--) //读入实部 {

DATE_IN_FPGA=100;

W_DATE_CLK_IN_FPGA_1; W_DATE_CLK_IN_FPGA_0; } k=i/2;

while(k--) //读入实部 {

DATE_IN_FPGA=0;

W_DATE_CLK_IN_FPGA_1; W_DATE_CLK_IN_FPGA_0; } k=i;

while(k--) //读入虚部 为全0 {

DATE_IN_FPGA=0;

W_DATE_CLK_IN_FPGA_1; W_DATE_CLK_IN_FPGA_0; }

W_DATE_CLK_IN_FPGA_1; //调整信号 W_DATE_CLK_IN_FPGA_0;

W_DATE_CLK_IN_FPGA_1; //调整信号 W_DATE_CLK_IN_FPGA_0;

W_DATE_CLK_IN_FPGA_1; //调整信号 W_DATE_CLK_IN_FPGA_0;

W_DATE_CLK_IN_FPGA_1; //调整信号 W_DATE_CLK_IN_FPGA_0;

}/***************************************************************************************************************************************************/

//FPGA FFT运算芯片

//接口说明: P3.0~~P3.7 -->read_real_date (H7) ,P4.0~~P4.7 -->read_imag_date (H3) , P7.0~~P7.7-->wirte_date_to_FPGA (H6), // (H4) P2.0-->w_date_clk_in ,P2.1-->r_date_clk_out ,P2.2-->reset_in //2008.7.31

/**************************************************************************************************************************************************/

#include #include

#define IO_INIT P2DIR=0XFF; P3DIR=0X00; P4DIR=0X00; P7DIR=0XFF

#define W_DATE_CLK_IN_FPGA_1 P2OUT|=BIT0 //w_date_clk_in为

1

#define W_DATE_CLK_IN_FPGA_0 P2OUT&=~BIT0 //w_date_clk_in为0

#define R_DATE_CLK_OUT_FPGA_1 P2OUT|=BIT1 //r_date_clk_out为1

#define R_DATE_CLK_OUT_FPGA_0 P2OUT&=~BIT1 //r_date_clk_out为0

#define RESET_IN_1 P2OUT|=BIT2 //reset_in为1 #define RESET_IN_0 P2OUT&=~BIT2 //reset_in为0

#define DATE_IN_FPGA P7OUT #define REAL_DATE_IN_MSP430 P3IN #define IMAG_DATE_IN_MSP430 P4IN

#define CPU_F ((double)1000000)

#define delay_us(x) __delay_cycles((long)(CPU_F*(double)x/1000000.0)) #define delay_ms(x) __delay_cycles((long)(CPU_F*(double)x/1000.0))

void init_fft();

void r_fft_date_out();

void w_fft_date_in(unsigned int i); inline char my_abs(char x); int fft_date[512]={0}; char fft_exp=0;

void text_w_fft_date_in(unsigned int i); int main( void ) {

int i=0;

// Stop watchdog timer to prevent time out reset WDTCTL = WDTPW + WDTHOLD; init_fft();

ADC12CTL0 = ADC12ON + REFON + REF2_5V + SHT0_6; // 设置 ADC12, 参考电压2.5V,采样周期25.6uS

ADC12CTL1 = SHP; // 内部定时采样 ADC12MCTL0 = INCH_3 + SREF_1; // 选择采样通道 A3, Vref+

ADC12IE = 0x01; // 使能 ADC12IFG.0 for (i = 0; i < 0x3600; i++); // 延时 ,使内部参考电压稳定

ADC12CTL0 |= ENC; // 使能转换 __enable_interrupt(); // 开中断 text_w_fft_date_in(512);

delay_ms(6000); r_fft_date_out(); while(1); }

void init_fft() {

P2DIR=0XFF; P3DIR=0X00; P4DIR=0X00; P7DIR=0XFF; W_DATE_CLK_IN_FPGA_0; R_DATE_CLK_OUT_FPGA_0; RESET_IN_1; delay_ms(1); RESET_IN_0; }

void r_fft_date_out() {

char real,imag; unsigned int i=0; float buff;

for(i=0;i<512;i++) {

R_DATE_CLK_OUT_FPGA_1; real=REAL_DATE_IN_MSP430; imag=IMAG_DATE_IN_MSP430; R_DATE_CLK_OUT_FPGA_0;

buff=pow(my_abs(real),2)+pow(my_abs(imag),2); fft_date[i]=sqrt(buff); }

R_DATE_CLK_OUT_FPGA_1;

fft_exp=REAL_DATE_IN_MSP430&0x3f; R_DATE_CLK_OUT_FPGA_0; }

void w_fft_date_in(unsigned int i) {

unsigned int k; k=i;

while(k--) //读入实部 {

ADC12CTL0 |= ADC12SC; // 开始采样

__bis_SR_register(LPM0_bits); // 进入低功耗 LPM0 } k=i;

while(k--) //读入虚部 为全0

{

W_DATE_CLK_IN_FPGA_1; DATE_IN_FPGA=0;

W_DATE_CLK_IN_FPGA_0; }

W_DATE_CLK_IN_FPGA_1; //调整信号 W_DATE_CLK_IN_FPGA_0;

W_DATE_CLK_IN_FPGA_1; //调整信号 W_DATE_CLK_IN_FPGA_0; }

inline char my_abs(char x) {

if(x&0x80)

return (~x+1); else

return x; }

#pragma vector=ADC12_VECTOR __interrupt void ADC12ISR(void) {

W_DATE_CLK_IN_FPGA_1;

DATE_IN_FPGA = (unsigned char)((ADC12MEM0>>4)-0x80); W_DATE_CLK_IN_FPGA_0;

__bic_SR_register_on_exit(LPM0_bits); //退出低功耗 LPM0 }

void text_w_fft_date_in(unsigned int i) {

unsigned int k=0; k=i/2;

while(k--) //读入实部 {

DATE_IN_FPGA=100;

W_DATE_CLK_IN_FPGA_1; W_DATE_CLK_IN_FPGA_0; } k=i/2;

while(k--) //读入实部 {

DATE_IN_FPGA=0;

W_DATE_CLK_IN_FPGA_1; W_DATE_CLK_IN_FPGA_0; } k=i;

while(k--) //读入虚部 为全0 {

DATE_IN_FPGA=0;

W_DATE_CLK_IN_FPGA_1; W_DATE_CLK_IN_FPGA_0; }

W_DATE_CLK_IN_FPGA_1; //调整信号 W_DATE_CLK_IN_FPGA_0;

W_DATE_CLK_IN_FPGA_1; //调整信号 W_DATE_CLK_IN_FPGA_0;

W_DATE_CLK_IN_FPGA_1; //调整信号 W_DATE_CLK_IN_FPGA_0;

W_DATE_CLK_IN_FPGA_1; //调整信号 W_DATE_CLK_IN_FPGA_0;

}/***************************************************************************************************************************************************/

//FPGA FFT运算芯片

//接口说明: P3.0~~P3.7 -->read_real_date (H7) ,P4.0~~P4.7 -->read_imag_date (H3) , P7.0~~P7.7-->wirte_date_to_FPGA (H6), // (H4) P2.0-->w_date_clk_in ,P2.1-->r_date_clk_out ,P2.2-->reset_in //2008.7.31

/**************************************************************************************************************************************************/

#include #include

#define IO_INIT P2DIR=0XFF; P3DIR=0X00; P4DIR=0X00; P7DIR=0XFF

#define W_DATE_CLK_IN_FPGA_1 P2OUT|=BIT0 //w_date_clk_in为1

#define W_DATE_CLK_IN_FPGA_0 P2OUT&=~BIT0 //w_date_clk_in为0

#define R_DATE_CLK_OUT_FPGA_1 P2OUT|=BIT1 //r_date_clk_out为1

#define R_DATE_CLK_OUT_FPGA_0 P2OUT&=~BIT1 //r_date_clk_out为0

#define RESET_IN_1 P2OUT|=BIT2 //reset_in为1 #define RESET_IN_0 P2OUT&=~BIT2 //reset_in为0

本文来源:https://www.bwwdw.com/article/82z2.html

Top