信号处理实验实验报告 - 实验名称:音频频谱分析仪的设计与实现
- 实验目的:构建交互界面,具有播放声音功能,显示波形与频谱,并可测量声音时与参数
- 实验原理:
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)
|