信號處理實驗實驗報告 - 實驗名稱:音頻頻譜分析儀的設計與實現
- 實驗目的:構建交互界面,具有播放聲音功能,顯示波形與頻譜,并可測量聲音時與參數
- 實驗原理:
MATLAB是一個數據分析與數據處理功能十分強大的工程應用軟件,其數據采集工具箱為數據的輸入和輸出提供了十分方便的函數與命令。本實驗要求基于聲卡和MATLAB實現音頻信號頻譜分析儀的設計與實現,功能包括音頻信號的輸入、 信號波形分析、信號頻譜分析 。 1.頻率周期檢測: 采用過零點的時間間隔即是周期,頻率為周期的倒數,求出多個時間差求平均值,采用平均值作為周期的估計值。 在一個周期內,求出信號的最小值和最大值差的一半,即y= ,第一個A值對應的最大值和最小值不是一個周期內得到的,因此除第一個A值以外的平均值作為估計值。 通過判斷與同頻信號過零點時刻,計算其時間差,然后換算成相應的相位差。 同樣以 的平均值作為估計值。 (1)峰值估計:利用下面的公式  (2)均值估計:  (3)均方值估計:  (4)方差估計:  
圖3.13 頻率、幅值和相位估計的流程圖 其中tin表示第n個過零點,yi為第i個采樣點的值,Fs為采樣頻率。 
式中, =Fs/N。但是上式計算效率低,故利用FFT快速計算,其原理是把重復的三角函數計算結果保存起來,以減少重復三角數的計算。 對于Y(k )如果 = 時,其取最大值, 為頻率估計值,其存在誤差,最大誤差 /2, 從原理上分析,混有噪聲時,用上述方法也可以得到周期和頻率。 為了直觀地表示信號的頻率特性,工程上常常將Fourier變換的結果用圖形的方式表示,即頻譜圖。 以頻率f為橫坐標,|Y(f)|為縱坐標,可以得到幅值譜; 以頻率f為橫坐標,arg Y(f)為縱坐標,可以得到相位譜; 以頻率f為橫坐標,Re Y(f)為縱坐標,可以得到實頻譜; 以頻率f為橫坐標,Im Y(f)為縱坐標,可以得到虛頻譜。 根據采樣定理,只有頻率不超過Fs/2的信號才能被正確采集,即Fourier變換的結果中頻率大于Fs/2的部分是不正確的部分,故不在頻譜圖中顯示。即橫坐標f ∈[0, Fs/2]。


設計音頻信號頻譜分析儀,功能包括: - 信號輸入:實現從聲卡、WAV文件、標準信號發生器輸入信號。
- 信號波形分析:包括幅值、頻率、周期的估計,以及統計量峰值、均值、均方值和方差的計算;
- 信號頻譜的分析、頻率、周期的估計,圖形顯示幅度譜、相位譜、實頻譜、虛頻譜和功率譜。
五、實驗步驟與結果(附程序和結果圖片): (1)程序: - function soundcard_Callback(hObject, eventdata, handles); %guide自動生成聲卡函數
- set(findobj('Tag','recordtime'),'enable','on'); %set函數用于設定屬性,使能TAG名為recordtime的選項卡。
- h=findobj('Tag','wenben_filename');
- set(h,'enable','off');% %關閉Tag名為wenben_filename的選項卡
- h=findobj('Tag','freq');
- set(h,'enable','off'); %關閉Tag名為wenben_filename的選項卡
- h=findobj('Tag','fu_du'); %關閉Tag名為fu_du的選項卡,off為關閉,即該選項卡不起 作用,只有聲卡起作用
- set(h,'enable','off');
- h=findobj('Tag','phrase');
- set(h,'enable','off');
- %上述程序實現聲卡輸入功能,只將Tag名為recordtime、startrecord的選項卡使能打開,而其他選項卡都是off狀態,例如set(findobj('Tag','recordtime'),'enable','on')語句是將Tag名為recordtime的選項卡打開,on代表打開,off為關閉。
- set(handles.edit10,'enable','off');
- set(handles.openfile,'enable','off');
- set(handles.wavemaker,'enable','off');
- set(handles.wavetype,'enable','off');
- set(handles.add,'enable','off');
- set(handles.startrecord,'enable','on');
- function startrecord_Callback(hObject, eventdata, handles)
- %以下為開始錄音程序,audiorecorder函數可以實現得到麥克風聲音,函數功能與wavrecord函數功能相同,但是MATLAB2017中沒有wavrecord,只有audiorecorder
- Fs=30000;
- Y=audiorecorder(Fs,24,1);
- recordblocking(Y,2);
- handles.y = getaudiodata(Y);
- ysize=size(handles.y);
- set(handles.samplenum,'String',num2str(ysize(1)));
- plot(handles.axes4,handles.y);
- guidata(hObject,handles);
復制代碼(2)實驗結果 
通過編寫函數實現了聲卡錄音并且對聲音進行時域和頻域分析。 2. WAV文件輸入: - %同理以下實現的是WAV文件輸入,只將'Tag'為'filename'的選項卡打開,而其他選項卡的狀態均關閉,實現WAV文件輸入handles.'recordtime'等同于findobj('Tag','recordtime')的功能,都是找到'Tag'為'recordtime'的選項卡。h=findobj('Tag','recordtime');set(h,'enable','off')兩個語句的功能和語句set(findobj('Tag','recordtime'),'enable','off')的功能相同
- h=findobj('Tag','filename');
- set(h,'enable','on');
- h=findobj('Tag','freq');
- set(h,'enable','off');
- h=findobj('Tag','amp');
- set(h,'enable','off');
- h=findobj('Tag','phase');
- set(h,'enable','off');
- set(findobj('Tag','recordtime'),'enable','off');
- set(handles.edit10,'enable','on');
- set(handles.openfile,'enable','on');
- set(handles.wavemaker,'enable','off');
- set(handles.wavetype,'enable','off');
- set(handles.add,'enable','off');
- set(handles.startrecord,'enable','off');
- %以下程序實現打開文件功能
- function openfile_Callback(hObject, eventdata, handles)
- [temp,Fs]=audioread(get(findobj('Tag','filename'),'String'));%WAV文件中讀取的信息臨時保存到temp中
- handles.y=temp(:,2);
- guidata(hObject,handles)%在波形顯示區顯示波形
- plot(handles.axes4,handles.y);
- title('WAVE');
- ysize=size(handles.y)%將所采集到的數據點數輸出在采樣點數中
- set(handles.samplenum,'String',num2str(ysize(1)));
- %同理此程序實現的是WAV文件輸入,只將'Tag'為'filename'的選項卡打開,而其他選項卡的狀態均關閉,實現WAV文件輸入handles.'recordtime'等同于findobj('Tag','recordtime')的功能,都是找到'Tag'為'recordtime'的選項卡。h=findobj('Tag','recordtime');set(h,'enable','off')兩個語句的功能和語句set(findobj('Tag','recordtime'),'enable','off')的功能相同
復制代碼
可以對WAV類型的文件自動打開、播放以及時頻域分析等功能。 - %以下程序是實現輸入頻率、幅度等信息的程序,打開'Tag'為'freq'、'amp'、'phase'、wavemaker、add的選項卡,即生成波形按鈕可使用,而且可以輸入頻率、相位和幅度。同時關閉錄音時間(recordtime)、文件輸入(openfile)輸入功能
- h=findobj('Tag','filename');
- set(h,'enable','off');
- h=findobj('Tag','freq');
- set(h,'enable','on');
- h=findobj('Tag','amp');
- set(h,'enable','on');
- h=findobj('Tag','phase');
- set(h,'enable','on');
- set(findobj('Tag','recordtime'),'enable','off');
- set(handles.edit10,'enable','off');
- set(handles.openfile,'enable','off');
- set(handles.wavemaker,'enable','on');
- set(handles.wavetype,'enable','on');
- set(handles.add,'enable','on');
- set(handles.startrecord,'enable','off');
- %下面的程序實現的是波形生成的功能
- function wavemaker_Callback(hObject, eventdata, handles)
- Fs=str2double(get(findobj('Tag','samplerate'),'String'));得到采樣頻率
- N=str2double(get(findobj('Tag','samplenum'),'String'));得到采樣點數
- x=linspace(0,N/Fs,N);
- soundtype=get(handles.wavetype,'Value');得到wavetype選項卡的值給soundtype
- frequency=str2double(get(handles.freq,'String'));
- amp=str2double(get(handles.amp,'String'));
- phase=str2double(get(handles.phase,'String'));
- %根據soundtype值不同選擇不同的波形類型,soundtype范圍為1到5,分別對應五種波形,
- 超出范圍報錯
- switch soundtype
- case 1
- y=amp*sin(2*pi*x*frequency+phase);
- case 2
- y=amp*sign(sin(2*pi*x*frequency+phase));
- case 3
- y=amp*sawtooth(2*pi*x*frequency+phase,0.5);
- case 4
- y=amp*sawtooth(2*pi*x*frequency+phase);
- case 5
- y=amp*(2*rand(size(x))-1);
- otherwise
- errordlg('Illegal wave type','Choose errer');
- End
- if get(handles.add,'Value')==0.0%得到add(混疊)的值,如果為0(沒有選混疊),則不混疊
- handles.y=y;
- Else %否則混疊
- handles.y=handles.y+y;
- end
- plot(handles.axes4,handles.y) %畫出波形
- guidata(hObject,handles);
- title('WAVE');
- axis([0 N -str2double(get(handles.amp,'String')) str2double(get(handles.amp,'String'))]);
- %標記坐標軸范圍和標題
復制代碼

三角波 
方波 
白噪聲 
正弦波


正弦波混疊
信號發生器信號輸入實現了正弦波、方波、三角波、白噪聲以及鋸齒波的產生,并可以實現混疊、時頻域分析等功能,但是在時域分析分析時,由于其是利用多個采樣點,利用計算公式來進行時頻域分析,采樣點不能完全逼近實際波形,因此會造成一定誤差。 Fs=str2double(get(findobj('Tag','samplerate'),'String')); %得到'Tag'為'samplerate'的名稱并轉換為數字即得到輸入頻率的數值。 N=str2double(get(findobj('Tag','samplenum'),'String')); %得到'Tag'為'samplenum'的名稱并轉換為數字即得到采樣點數。 T=[];amp=[];ti=[]; n=1; ymax=max([handles.y(1) handles.y(2)]); %將y(2),y(1)的最大值給ymax ymin=min([handles.y(1) handles.y(2)]); %將y(2),y(1)的最小值給ymin from=str2double(get(handles.point1,'String')); %得到point1方框的數值, 即分析起始點 to=str2double(get(handles.pointlast,'String')); %得到pointlast方框的數值,即分析終止點 if from<1|to-from<5; msgbox('error'); return; End %如果起始點小于1或者分析間隔小于5報錯,提示'error' for i=from+2:to-1; if handles.y(i-1)<0 & handles.y(i-2)<0 & handles.y(i)>=0 & 0 if handles.y(i)==0handles.y(i+1)> ti(n)=i; else ti(n)=i-handles.y(i)/(handles.y(i)-handles.y(i-1)); end amp(n)=(ymax-ymin)/2;得到幅度 ymax=0; ymin=0; n=n+1; else if ymax<handles.y(i) ymax=handles.y(i); end if ymin>handles.y(i) ymin=handles.y(i); end end end n=n-1; for i=1:n-1 T(i)=ti(i+1)-ti(i); End %利用過零點時間間隔求周期, freq = Fs/mean(T); %周期均值的的倒數得到頻率 set(handles.wenben_zhouqi,'String',1/freq); %分別在相應位置顯示周期、頻率、均值 set(handles.wenben_pinlv,'String',num2str(freq)); set(handles.wenben_fudu,'String',num2str(mean(amp(2:n-1))));%以幅度均值作為幅度的估計值 phase=2*pi*(1-(ti(1:n-1)-1)./T+floor((ti(1:n-1)-1)./T));%將待分析信號的過零點與標準信號的過零點比較,得到相位 set(handles.wenben_xiangwei,'String',num2str(mean(phase))); %利用同頻信號零點取均值得到相位 set(handles.wenben_fengzhi,'String',(max(handles.y(from:to))-min(handles.y(from:to)))/2); %利用 得到峰值
set(handles.wenben_junzhi,'String',mean(handles.y(from:to))); %得到均值 set(handles.wenben_junfangzhi,'String',mean(handles.y(from:to).^2));%得到均方值 %得到均方值并在Tag名為wenben_junfangzhi顯示,mean(handles.y(from:to)取所有點的均值 set(handles.wenben_fangcha,'String',std(handles.y(from:to))^2); %得到方差,并在Tag名為wenben_fangcha顯示 
三角波時域分析 
矩形波時域分析
- function freqanalysis_Callback(hObject, eventdata, handles)
- Fs=str2double(get(findobj('Tag','samplerate'),'String'));
- N=str2double(get(findobj('Tag','samplenum'),'String'));
- if handles.wavetype==0
- msgbox('No wave!');如果wavetype=0,顯示no wave
- return;
- end
- from=str2double(get(handles.point1,'String'));%得到point1方框的數值, 即分析起始點
- to=str2double(get(handles.pointlast,'String'));%得到pointlast方框的數值,即分析終止點
- sample=handles.y(from:to); %得到波形采樣點矩陣
- f=linspace(0,Fs/2,(to-from+1)/2); %在[0,(to-from+1)/2]之間取Fs/2個點
- Y=fft(sample,to-from+1); %to-from+1點FFT算法
- [C,I]=max(abs(Y)); %得到頻譜最大值
- set(handles.freqzhouqi,'String',1/f(I)) ;%得到周期并顯示
- set(handles.freqpinlv,'String',f(I)); %得到頻率并顯示
- Y=Y(1:(to-from+1)/2);
- plot(handles.axes5,f,2*sqrt(Y.*conj(Y)));%分別繪制實頻譜、虛頻譜、相位譜、幅度譜、功率譜
- plot(handles.axes6,f,angle(Y));
- plot(handles.axes7,f,real(Y));
- plot(handles.axes8,f,imag(Y));
- plot(handles.axes9,f,abs(Y).^2);
- xlabel(handles.axes5,'freq(Hz)'); %標記坐標軸
- xlabel(handles.axes6,'freq(Hz)');
- xlabel(handles.axes7,'freq(Hz)');
- xlabel(handles.axes8,'freq(Hz)');
- xlabel(handles.axes9,'freq(Hz)');
- ylabel(handles.axes5,'amp');
- ylabel(handles.axes6,'phase');
- ylabel(handles.axes7,'real');
- ylabel(handles.axes8,'imag');
- ylabel(handles.axes9,'power');
復制代碼

輸入分析點數起始點小于1報錯 
正弦波時頻域分析結果 
通過實驗結果分析,我們可以看出,交互界面基本上實現了頻域和時域分析的功能,而且實現了自動報錯功能,時域分析結果周期、頻率、幅度誤差較小,可能是由于采樣點數或者在取值時量化誤差造成的,在誤差允許范圍內實現了時域分析。但是相位有較大的誤差,通過過零點檢測相位可能由于采集過零點時刻誤差較大,造成相位估計值誤差較大。頻域分析周期以及頻率雖然有一定誤差,但是誤差很小。誤差可能由于MATLAB利用離散點來逼近波形,不可能完全和實際一樣。 本次實驗完成了音頻頻譜分析儀的設計與實現,基本上滿足了題目要求,并且為分析儀增加了錯誤輸入提醒、自動查找文件等新功能。 通過本次實驗,學習使用了MATLABguide交互界面的設計方法,掌握了guide交互界面設計的基本流程、guide交互界面函數的編寫,重新認識了MATLAB的強大功能,MATLAB不僅提供了基本的函數,幫助我們實現設計功能,而且根據我們設計的界面,自動生成了模板,極大的方便了我們的設計工作。 本次實驗相對前六次實驗難度加大,在前幾次實驗的基礎上,依然感覺無從下手,通過借閱圖書、上網查閱資料終于完成了本次實驗,通過本次實驗接觸了交互界面的設計方法,同時也認識到MATLAB強大的功能,提供了友好的交互界面設計。在本次試驗中遇到了很多的問題,比如基本函數的調用格式,在使用findobj函數時報錯,提示輸入參數不足,通過上網查找資料、請教同學,才發現調用格式出錯。還有根據教材使用wavrecord函數時,提示未定義該函數,在命令窗口help wavrecord,發現MATLAB不提供該函數,上網查找發現MATLAB2013以后刪除了該函數。 總之,通過本次實驗,初步認識了交互界面的設計方法,同時認識到MATLAB強大的功能,在設計過程中遇到了很多問題,通過查找資料解決問題,提高了查找資料、解決問題的能力。通過信號處理七次實驗掌握了MATLAB的使用方法以及強大功能,激發了自己學習MATLAB的熱情,必將為今后的學習打下良好的基礎。
完整的Word格式文檔51黑下載地址:
實驗七音頻頻譜分析儀的設計與實現2.docx
(658.31 KB, 下載次數: 44)
2018-1-18 13:50 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|