基于MCU的音频信号分析仪的解决方案

控制/MCU

1882人已加入

描述

  1 系统方案论证与比较

  1.1 摘要:本音频信号分析仪由32位MCU为主控制器,通过AD转换,对音频信号进行采样,把连续信号离散化,然后通过FFT快速傅氏变换运算,在时域和频域对音频信号各个频率分量以及功率等指标进行分析和处理,然后通过高分辨率的LCD对信号的频谱进行显示。该系统能够精确测量的音频信号频率范围为20Hz-10KHz,其幅度范围为5mVpp-5Vpp,分辨力分为20Hz和100Hz两档。测量功率精确度高达1%,并且能够准确的测量周期信号的周期,是理想的音频信号分析仪的解决方案。

  1.2 采样方法比较与选择

  方案一、用DDS芯片配合FIFO对信号进行采集,通过DDS集成芯片产生一个频率稳定度和精度相当高的信号作为FIFO的时钟,然后由FIFO对A/D转换的结果进行采集和存储,最后送MCU处理。

  方案二、直接由32位MCU的定时中断进行信号的采集,然后对信号分析。

  由于32位MCU -LPC2148是60M的单指令周期处理器,所以其定时精确度为16.7ns,已经远远可以实现我们的40.96KHz的采样率,而且控制方便成本便宜,所以我们选择由MCU直接采样。

  1.3 处理器的比较与选择

  由于快速傅立叶变换FFT算法设计大量的浮点运算,由于一个浮点占用四个字节,所以要占用大量的内存,同时浮点运算时间很慢,所以采用普通的8位MCU一般难以在一定的时间内完成运算,所以综合内存的大小以及运算速度,我们采用Philips 的32位的单片机LPC2148,它拥有32K的RAM,并且时钟频率高达60M,所以对于浮点运算不论是在速度上还是在内存上都能够很快的处理。

  1.4 周期性判别与测量方法比较与选择

  对于普通的音频信号,频率分量一般较多,它不具有周期性。测量周期可以在时域测量也可以在频域测量,但是由于频域测量周期性要求某些频率点具有由规律的零点或接近零点出现,所以对于较为复杂的,频率分量较多且功率分布较均匀且低信号就无法正确的分析其周期性。而在时域分析信号,我们可以先对信号进行处理,然后假定具有周期性,然后测出频率,把采样的信号进行周期均值法和定点分析法的分析后即可以判别出其周期性。

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

  1.5 系统总体设计

  音频信号经过一个由运放和电阻组成的50 Ohm阻抗匹配网络后,经由量程控制模块进行处理,若是一般的100mV-5V的电压,我们选择直通,也就是说信号没有衰减或者放大,但是若信号太小,12位的A/D转换器在2.5V参考电压的条件下的最小分辨力为1mV左右,所以如果选择直通的话其离散化处理的误差将会很大,所以若是采集到信号后发现其值太小,在20mV-250mV之间的话,我们可以将其认定为小信号,从而选择信号经过20倍增益的放大器后再进行A/D采样。

  mcu

  经过12位A/D转换器ADS7819转换后的数字信号经由32位MCU进行FFT变换和处理,分析其频谱特性和各个频率点的功率值,然后将这些值送由Atmega16进行显示。信号由32 位MCU分析后判断其周期性,然后由Atmegal6进行测量,然后进行显示。

  2 各单元电路设计

  2.1 前级阻抗匹配和放大电路设计

mcu 

  信号输入后通过R5,R6两个100Ohm的电阻和一个高精度仪表运放AD620实现跟随作用,由于理想运放的输入阻抗为无穷大,所以输入阻抗即为:R5//R6=50Ohm,阻抗匹配后的通过继电器控制是对信号直接送给AD转换还是放大20倍后再进行AD转换。

  在这道题目里,需要检测各频率分量及其功率,并且要测量正弦信号的失真度,这就要求在对小信号进行放大时,要尽可能少的引入信号的放大失真。正弦信号的理论计算失真度为零,对引入的信号失真非常灵敏,所以对信号的放大,运放的选择是个重点。

  我们选择的运放是TI公司的低噪声、低失真的仪表放大器INA217,其失真度在频率为1KHz,增益为20dB(100倍放大)时仅为0.004%,其内部原理图如图2-2所示。

mcu  
 

  其中放大器A1的输出电压计算公式为:OUT1=1+(R1/RG)*VIN+;同理, OUT2=1+(R2/RG)*VIN--;R3、R4、R5、R6及A3构成减法器,最后得到输出公式:VOUT=(VIN2-VIN1)*[1+(R1+R2)/RG];R1=R2=5K,取RG=526,从而放大倍数为20。

  2.2 AD转换及控制模块电路设计

mcu  

  采用12位AD转换器ADS7819进行转换,将转换的数据送32位控制器进行处理。

  2.3 功率谱测量

  功率谱测量主要通过对音频信号进行离散化处理,通过FFT运算,求出信号各个离散频率点的功率值,然后得到离散化的功率谱。

  由于题目要求频率分辨力为100Hz和20Hz两个档,这说明在进行FFT运算前必须通过调整采样频率(fK)和采样的点数(N),使其基波频率f为100Hz和20Hz。

  根据频率分辨率与采样频率和采样点数的关系:f=fk/N;可以得知, fk=N*f;又根据采样定理,采样频率fk必须不小于信号频率fm的2倍,即:fk》=2fm;

  题目要求的最大频率为10KHz,所以采样频率必须大于20KHz,考虑到FFT运算在2的次数的点数时的效率较高,所以我们在20Hz档时选择40.96KHz采样率,采集2048个点,而在100档时我们选择51.2KHz采样率,采集512个点。通过FFT 分析出不同的频率点对应的功率后,就可以画出其功率谱,并可以在频域计算其总功率。

  3 软件设计

  主控制芯片为LPC2148,测量周期为Atmega16实现,由于处理器速度较快,所以采用c语言编程方便简单。软件流程图如下:

 mcu 


  4 系统测试

  4.1 总功率测量(室温条件下)

  mcu

  结果分析: 由于实验室提供的能够模仿音频信号的且能方便测量的信号只有正弦信号,所以我们用一款比较差点的信号发生器产生信号,然后进行测量,发现误差不达,在+-5%以内。我们以音频信号进行测量,由于其实际值无法测量,所以我们只能根据时域和频域以及估计其误差,都在5%以内。

  4.2 单个频率分量测量(室温条件下)
 

mcu

  

  结果分析:我们首先以理论上单一频率的正弦波为输入信号,在理想状况下,其频谱只在正弦波频率上有值,而由于有干扰,所以在其他频点也有很小的功率。音频信号由于有多个频点,所以没有一定的规律性。由于音频信号波动较大,没有一定的规律,且实验室没有专门配置测量仪器,所以我们只好以正弦波和三角波作为信号进行定量分析测量,以及对音频信号进行定性的分析和测量。我们发现其数字和用电脑模拟的结果符合得很近。

  5 结论

  由于系统架构设计合理,功能电路实现较好,系统性能优良、稳定,较好地达到了题目要求的各项指标。

  附录:

  附1:电路图图纸

  
mcu

  
mcu

  
mcu


  附2:程序清单

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

  FFT转换函数,dataR:实部,datai:虚部,

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

  void FFT(float *dataR,float *dataI,int n)

  {

  int i,L,j,k,b,p,xx,qq;

  int x[11]={0};

  float TR,TI,temp;

  float QQ;

  //////////////////////////////////位倒置////////////////////////////////////////////////////

  for(i=0;i《count[n];i++)

  { xx=0;

  for(j=0;j《n;j++)

  x[j]=0;

  for(j=0;j《n;j++)

  {x[j]=(i/count[j])&0x01;}

  for(j=0;j《n;j++)

  {xx=xx+x[j]*count[n-j-1];}

  dataI[xx]=dataR[i];

  }

  for(i=0;i《count[n];i++)

  { dataR[i]=dataI[i];

  dataI[i]=0;

  }

  ////////////////////////////////////蝶形运算////////////////////////////////////////

  for(L=1;L《=n;L++)

  {

  b=1; i=L-1;

  while(i》0)

  { b=b*2;

  i--;

  }

  for(j=0;j《=b-1;j++)

  { p=1; i=n-L;

  while(i》0)

  { p=p*2; i--;}

  p=p*j;

  for(k=j;k《count[n];k=k+2*b)

  {

  TR=dataR[k];

  TI=dataI[k];

  temp=dataR[k+b];

  QQ=2*pi*p/count[n];

  qq=p*count[11-n];

  dataR[k]=dataR[k]+dataR[k+b]*cos_tab[qq]+dataI[k+b]*sin_tab[qq];

  dataI[k]=dataI[k]-dataR[k+b]*sin_tab[qq]+dataI[k+b]*cos_tab[qq];

  dataR[k+b]=TR-dataR[k+b]*cos_tab[qq]-dataI[k+b]*sin_tab[qq]; //查表运算

  dataI[k+b]=TI+temp*sin_tab[qq]-dataI[k+b]*cos_tab[qq];

  }

  }

  }

  for(i=0;i《count[n];i++)

  {

  w[i]=sqrt(dataR[i]*dataR[i]+dataI[i]*dataI[i]);

  w[i]=w[i]/count[n-1];

  }

  w[0]=w[0]/2;

  }

  ///////////////////////////回放数据/////////////////////////

  void viewdata(void)

  {

  unsigned int key,page,i;

  page=0;

  LCD_PenColor=0x1F; //红色

  LCD_WriteChineseString(font5,2,40,0);

  LCD_PenColor=0xFC; //蓝色

  while(1){

  key=getkey();

  if(key!=0xFF)

  {

  if(key==4) {SystemState=fft_mode;return;} //返回

  if(key==2) {

  LCD_ClearScreen();

  LCD_WriteChineseString(font3,2,10,0);LCD_WriteChineseString(font4,2,60,0);

  i=page*4+1;

  p3510(Re[i],0,15); print3510(Im[i]*mode,50,15);

  p3510(Re[i+1],0,26); print3510(Im[i+1]*mode,50,25);

  p3510(Re[i+2],0,38); print3510(Im[i+2]*mode,50,35);

  p3510(Re[i+3],0,50); print3510(Im[i+3]*mode,50,50);

  if(page》0) page--;

  delay_nms(8000000);

  } //上翻页

  if(key==1) {

  LCD_ClearScreen();

  LCD_WriteChineseString(font3,2,10,0);LCD_WriteChineseString(font4,2,60,0);

  i=page*4+1;

  p3510(Re[i],0,15); print3510(Im[i]*mode,50,15);

  p3510(Re[i+1],0,26); print3510(Im[i+1]*mode,50,25);

  p3510(Re[i+2],0,38); print3510(Im[i+2]*mode,50,35);

  p3510(Re[i+3],0,50); print3510(Im[i+3]*mode,50,50);

  page++;if(page》=SampleNum/4) page=0;

  delay_nms(8000000);

  } //下翻页

  }

  }

  }

  ////////////////////////////失真度计算///////////////////////

  void distortion(void)

  {

  LCD_ClearScreen();

  LCD_WriteChineseString(font6,3,10,20);

  unsigned int key;

  int fr;

  while(1)

  {

  ////////////获取频率////////////////////

  log_2_N=11;SampleNum=SampleTab[log_2_N];

  reset_timer(0);

  init_timer0(40960);

  New_Flag=0;

  enable_timer(0);

  ////////////////////等待采样完成///////////////////////////

  while(!FFT_Flag);

  disable_timer(0); //关定时器0

  //////////////////////FFT运算/////////////////////////////////

  FFT(Re,Im,log_2_N);

  ////////////////频域功率////////////////////////////////////

  for(i=1;i《SampleNum/2;i++) {Re[i]=Re[i]*Re[i];Re[i]=Re[i]/2;}

  ////////////////////总功率/////////////////////////////////

  Fp=0;

  for(i=1;i《SampleNum/2;i++) Fp+=Re[i];

  sort(&Re[1],&Im[1],SampleNum/2-1);

  fr=1000000/fre;

  if(Tflag) {LCD_WriteChineseString(font7,1,50,20);LCD_WriteEnglishString(“ ”,0,38);print3510(fr,10,38);LCD_WriteEnglishString(“US”,58,38);}

  else

  {LCD_WriteEnglishString(“ ”,0,38);LCD_WriteChineseString(font8,1,50,20);}

  ////////////////////按键扫描/////////////////////////////

  key=getkey();

  if(key!=0xFF)

  {

  if(key==1) {SystemState=fft_mode;mode=20;break;} //返回

  if(key==2) {SystemState=fft_mode;mode=100;break;} //返回

  }

  }

  }

  /////////////////按键扫描//////////////////////////////

  unsigned char getkey(void)

  {

  if(IO1PIN_bit.P1_21==0) {

  delay_nms(200000);

  if(IO1PIN_bit.P1_21==0) return 1;

  }

  if(IO1PIN_bit.P1_22==0) {

  delay_nms(2000000);

  if(IO1PIN_bit.P1_22==0) return 2;

  }

  if(IO1PIN_bit.P1_23==0) {

  delay_nms(2000000);

  if(IO1PIN_bit.P1_23==0) return 3;

  }

  if(IO1PIN_bit.P1_24==0) {

  delay_nms(2000000);

  if(IO1PIN_bit.P1_24==0) return 4;

  }

  return 0xFF;

  }

  //////////////////排序处理//////////////////////////////

  void sort(float *a,float *b,int n) //a为待排序的量,b为起位置

  {

  int i,j,temp;

  for(i=0;i《n;i++) b[i]=i+1;

  for(j=0;j《=n-1;j++)

  {

  for (i=0;i《n-j;i++)

  if (a[i]《a[i+1])

  {

  temp=a[i];

  a[i]=a[i+1];

  a[i+1]=temp;

  temp=b[i];

  b[i]=b[i+1];

  b[i+1]=temp;

  }

  }

  }

  //////////////////////显示///////////////////

  void p3510(int v,int x,int y)

  {

  int x0;

  x0=v*157;

  x0=x0/100000000;

  LCD_WriteEnglishChar(x0+‘0’,x,y);

  x0=v*157;

  x0=x0/100;

  x0+=1000000;

  print3510(x0,x+6,y);

  LCD_WriteEnglishChar(‘。’,x+6,y);

  }

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
评论(0)
发评论
cajeptw 2014-05-29
0 回复 举报
学习了 收起回复

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分