音頻信號分析儀(A題) 摘要: 本音頻信號分析儀由32位MCU為主控制器,通過AD轉換,對音頻信號進行采樣,把連續(xù)信號離散化,然后通過FFT快速傅氏變換運算,在時域和頻域對音頻信號各個頻率分量以及功率等指標進行分析和處理,然后通過高分辨率的LCD對信號的頻譜進行顯示。該系統(tǒng)能夠精確測量的音頻信號頻率范圍為20Hz-10KHz,其幅度范圍為5mVpp-5Vpp,分辨力分為20Hz和100Hz兩檔。測量功率精確度高達1%,并且能夠準確的測量周期信號的周期,是理想的音頻信號分析儀的解決方案。 關鍵詞: FFT MCU 頻譜 功率
目錄
1 系統(tǒng)方案論證與比較1.1 引言 1.2 采樣方法比較與選擇方案一、用DDS芯片配合FIFO對信號進行采集,通過DDS集成芯片產生一個頻率穩(wěn)定度和精度相當高的信號作為FIFO的時鐘,然后由FIFO對A/D轉換的結果進行采集和存儲,最后送MCU處理。 方案二、直接由32位MCU的定時中斷進行信號的采集,然后對信號分析。 由于32位MCU -LPC2148是60M的單指令周期處理器,所以其定時精確度為16.7ns,已經遠遠可以實現我們的40.96KHz的采樣率,而且控制方便成本便宜,所以我們選擇由MCU直接采樣。 1.3 處理器的比較與選擇由于快速傅立葉變換FFT算法設計大量的浮點運算,由于一個浮點占用四個字節(jié),所以要占用大量的內存,同時浮點運算時間很慢,所以采用普通的8位MCU一般難以在一定的時間內完成運算,所以綜合內存的大小以及運算速度,我們采用Philips 的32位的單片機LPC2148,它擁有32K的RAM,并且時鐘頻率高達60M,所以對于浮點運算不論是在速度上還是在內存上都能夠很快的處理。 1.4 周期性判別與測量方法比較與選擇對于普通的音頻信號,頻率分量一般較多,它不具有周期性。測量周期可以在時域測量也可以在頻域測量,但是由于頻域測量周期性要求某些頻率點具有由規(guī)律的零點或接近零點出現,所以對于較為復雜的,頻率分量較多且功率分布較均勻且低信號就無法正確的分析其周期性。 而在時域分析信號,我們可以先對信號進行處理,然后假定具有周期性,然后測出頻率,把采樣的信號進行周期均值法和定點分析法的分析后即可以判別出其周期性。 綜上,我們選擇信號在時域進行周期性分析和周期性測量。對于一般的音頻信號,其時域變化是不規(guī)則的,所以沒有周期性。而對于單頻信號或者由多個具有最小公倍數的頻率組合的多頻信號具有周期性。這樣我們可以在頻域對信號的頻譜進行定量分析,從而得出其周期性。而我們通過先假設信號是周期的,然后算出頻率值,然后在用此頻率對信號進行采樣,采取連續(xù)兩個周期的信號,對其值進行逐次比較和平均比較,若相差太遠,則認為不是周期信號,若相差不遠(約5%),則可以認為是周期信號。 1.5 系統(tǒng)總體設計音頻信號經過一個由運放和電阻組成的50 Ohm阻抗匹配網絡后,經由量程控制模塊進行處理,若是一般的100mV-5V的電壓,我們選擇直通,也就是說信號沒有衰減或者放大,但是若信號太小,12位的A/D轉換器在2.5V參考電壓的條件下的最小分辨力為1mV左右,所以如果選擇直通的話其離散化處理的誤差將會很大,所以若是采集到信號后發(fā)現其值太小,在20mV-250mV之間的話,我們可以將其認定為小信號,從而選擇信號經過20倍增益的放大器后再進行A/D采樣。 file:///C:/Users/chang/AppData/Local/Temp/msohtmlclip1/01/clip_image002.gif經過12位A/D轉換器ADS7819轉換后的數字信號經由32位MCU進行FFT變換和處理,分析其頻譜特性和各個頻率點的功率值,然后將這些值送由Atmega16進行顯示。信號由32 位MCU分析后判斷其周期性,然后由Atmegal6進行測量,然后進行顯示。
2 各單元電路設計2.1 前級阻抗匹配和放大電路設計file:///C:/Users/chang/AppData/Local/Temp/msohtmlclip1/01/clip_image004.jpg
信號輸入后通過R5,R6兩個100Ohm的電阻和一個高精度儀表運放AD620實現跟隨作用,由于理想運放的輸入阻抗為無窮大,所以輸入阻抗即為:R5//R6=50Ohm,阻抗匹配后的通過繼電器控制是對信號直接送給AD轉換還是放大20倍后再進行AD轉換。 在這道題目里,需要檢測各頻率分量及其功率,并且要測量正弦信號的失真度,這就要求在對小信號進行放大時,要盡可能少的引入信號的放大失真。正弦信號的理論計算失真度為零,對引入的信號失真非常靈敏,所以對信號的放大,運放的選擇是個重點。 我們選擇的運放是TI公司的低噪聲、低失真的儀表放大器INA217,其失真度在頻率為1KHz,增益為20dB(100倍放大)時僅為0.004%,其內部原理圖如圖2-2所示。 file:///C:/Users/chang/AppData/Local/Temp/msohtmlclip1/01/clip_image006.jpg
其中放大器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轉換及控制模塊電路設計file:///C:/Users/chang/AppData/Local/Temp/msohtmlclip1/01/clip_image008.jpg
采用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語言編程方便簡單.軟件流程圖如下: file:///C:/Users/chang/AppData/Local/Temp/msohtmlclip1/01/clip_image010.jpg 主流程圖 周期性分析和測量流程圖
4 系統(tǒng)測試4.1 總功率測量(室溫條件下)表4-1 總功率測量結果(室溫條件下) 結果分析: 由于實驗室提供的能夠模仿音頻信號的且能方便測量的信號只有正弦信號,所以我們用一款比較差點的信號發(fā)生器產生信號,然后進行測量,發(fā)現誤差不達,在+-5%以內。我們以音頻信號進行測量,由于其實際值無法測量,所以我們只能根據時域和頻域以及估計其誤差,都在5%以內。 4.2 單個頻率分量測量(室溫條件下)表4-2 單個頻率分量測量結果(室溫條件下) 結果分析:我們首先以理論上單一頻率的正弦波為輸入信號,在理想狀況下,其頻譜只在正弦波頻率上有值,而由于有干擾,所以在其他頻點也有很小的功率。 音頻信號由于有多個頻點,所以沒有一定的規(guī)律性。由于音頻信號波動較大,沒有一定的規(guī)律,且實驗室沒有專門配置測量儀器,所以我們只好以正弦波和三角波作為信號進行定量分析測量,以及對音頻信號進行定性的分析和測量。我們發(fā)現其數字和用電腦模擬的結果符合得很近。
5 結論由于系統(tǒng)架構設計合理,功能電路實現較好,系統(tǒng)性能優(yōu)良、穩(wěn)定,較好地達到了題目要求的各項指標。
參考文獻:[1] ALANV.OPPENHEIM.信號與系統(tǒng).西安:西安交通大學出版社,1997年 [2] 元秋奇.數字圖像處理學.北京:電子工業(yè)出版社,2000年 [3] 吳運昌.模擬電子線路基礎.廣州:華南理工大學出版社,2004年 [4] 閻石.數字電子技術基礎.北京:高等教育出版社,1997年 [5] 張曉麗等.數據結構與算法.北京:機械工業(yè)出版社,2002年 [6] 馬忠梅等. ARM&Linux嵌入式系統(tǒng)教程.北京:北京航空航天大學出版社,2004年 [7] 李建忠.單片機原理及應用.西安:西安電子科技大學,2002年
附錄:附1:元器件明細表:1、 LPC2148 2、 ATMEGA16 3、 AD620 4、 ADS7819 5、 液晶320*240 附2:儀器設備清單1、 低頻信號發(fā)生器 2、 數字萬用表 3、 失真度測量儀 4、 數字示波器 5、 穩(wěn)壓電源 附3:電路圖圖紙file:///C:/Users/chang/AppData/Local/Temp/msohtmlclip1/01/clip_image012.jpg 電源系統(tǒng) file:///C:/Users/chang/AppData/Local/Temp/msohtmlclip1/01/clip_image014.jpg 前級放大和AD轉換 file:///C:/Users/chang/AppData/Local/Temp/msohtmlclip1/01/clip_image016.jpg Atmega16控制板 附4:程序清單/*///////////////////////////////////////////////////////////////////////////////////////////////// FFT轉換函數,dataR:實部,datai:虛部, ////////////////////////////////////////////////////////////////////////////////////////////////*/ voidFFT(float *dataR,float *dataI,int n) { inti,L,j,k,b,p,xx,qq; intx[11]={0}; floatTR,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; } for(i=0;i<count[n];i++) {dataR=dataI; dataI=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=sqrt(dataR*dataR+dataI*dataI); w=w/count[n-1]; } w[0]=w[0]/2; } ///////////////////////////回放數據///////////////////////// voidviewdata(void) { unsignedint 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,0,15); print3510(Im*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,0,15); print3510(Im*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); } //下翻頁 } } } ////////////////////////////失真度計算/////////////////////// voiddistortion(void) { LCD_ClearScreen(); LCD_WriteChineseString(font6,3,10,20); unsignedint 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=Re*Re;Re=Re/2;} ////////////////////總功率///////////////////////////////// Fp=0; for(i=1;i<SampleNum/2;i++)Fp+=Re; 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;} //返回 } } } /////////////////按鍵掃描////////////////////////////// unsignedchar 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; } return0xFF; } //////////////////排序處理////////////////////////////// voidsort(float *a,float *b,int n) //a為待排序的量,b為起位置 { inti,j,temp; for(i=0;i<n;i++)b=i+1; for(j=0;j<=n-1;j++) { for(i=0;i<n-j;i++) if(a<a[i+1]) { temp=a; a=a[i+1]; a[i+1]=temp; temp=b; b=b[i+1]; b[i+1]=temp; } } } //////////////////////顯示/////////////////// voidp3510(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); }
|