3.软件实现 3.1界面设计
MATLAB是Mathworks公司推出的数学软件,它将数值分析、矩阵计算、信号处理和图形显示结合在一起,为众多学科领域提供了一种简洁、高效的编程工具。它提供的GUIDE工具为可视化编程工具,使得软件的界面设计像VB一样方便。故本文采用MATLAB作为编程语言实现声音信号频谱分析仪,以下所讲的都是在MATLAB7.0环境中。
为了实现预期的功能,设计如图 3所示的界面。
图 3 频谱分析仪的界面设计
最上面的部分为标题区,用于显示软件标题等信息,不具人机交互功能。 再往下是信号输入区,包含3种输入方式,考虑到WAV文件可能是多声道,故提供了声道选择的界面,因为每次只能对单个声道进行分析。在信号发生器中加入了混迭选项,从而可以将产生的信号与原有的信号进行混迭。界面应该具有:只有当每个单选框被选中时才允许使用对应的输入框、按钮等;采样点数输入框在声卡与WAV文件的输入方式下作为输出,在信号发生器的输入方式下作为输入。
再往下是分析区。对于WAV文件及录音的信号,有时只对其中一部分信号进行分析,故提供了分析对象范围设定的界面。另外就是时域分析与频域分析的按钮,该软件的核心代码都在这两个按钮的回调函数中。
分析区下面是分析结果区,用于显示波形基本参数与统计量的计算结果。 分析结果区的下面是波形显示区,用于显示时域波形,在录音结束、打开WAV文件成功或者信号发生器生成波形时会更新显示。
右边为频谱图显示区,用于显示各种频谱的谱线,在点击频域分析后会更新显示。
3.2输入模块的实现
采样频率Fs与采样点数N是声音信号输入时共同需要作用的参数,故将其独立出来。下面为别介绍三种输入方式的实现。 3.2.1 声卡输入
这里声卡输入是指由麦克风录音得到的声音信号的输入,MATLAB提供了wavrecord函数,该函数能够实现读取麦克风录音信号。以下是“开始录音”按钮的回调函数内容。
%首先获得设定的Fs值
Fs=str2double(get(findobj('Tag','samplerate'),'String'));
%根据设定的录音时长进行录音,将其存入handles.y中
handles.y=wavrecord(str2double(get(handles.recordtime,'String'))*Fs, Fs,'int16'); %保存handles结构体,使得handles.y在别的函数中也能使用 guidata(hObject,handles); %在波形显示区绘出波形 plot(handles.time,handles.y); title('WAVE');
%将所采到的点的数量输出在“采样点数”中 ysize=size(handles.y)
set(handles.samplenum,'String',num2str(ysize(1))); 3.2.2 WAV文件输入
MATLAB提供了wavread函数,该函数能够方便的打开并读取WAV文件中的声音信息,并且同时读取所有声道。下面是“打开文件”按钮回调函数的部分代码。其它代码与声卡输入的类似。
%从WAV文件中读取的声音信息并临时存放到temp变量中 temp = wavread(get(findobj('Tag','filename'),'String')); %获得所选择的声道
channel=str2double(get(handles.channel,'String')); %将指定声道的信息存放到handles.y中 handles.y=temp(:,channel); 3.2.3 信号发生器
MATLAB有产生标准信号的函数,如sawtooth能够产生三角波或钜齿波,首先利用get函数获得波形soundtype,频率frequency,幅值amp和相位phase,然后是以下代码。
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
handles.y=y; %若没有勾选上“混迭”,则将生成的波形赋给handles.y else %否则将生成的波形与原有波形叠加 handles.y=handles.y+y; end
3.3分析模块
由于MATLAB的绘图功能很强大,所以图形显示模块不用单独开发,可直接调用plot、axis等函数实现图形显示功能,故图形显示也将在分析模块中给出。 3.3.1 时域分析
2.1.2节给出时域分析中的过零检测算法流程,故这里不给出过零检测的代码。MATLAB提供了mean,std函数,能够方便地计算均值、标准差。下面是过零检测之后的代码,其中T为过零检测得到的周期(向量),amp为过零检测得到的幅值(向量),n为过零点数。
freq=Fs/mean(T); %计算频率
set(handles.outt,'String',1/freq); %输出周期估计值
set(handles.outfreq,'String',num2str(freq)); %输出频繁估计值 %计算并输出幅值,以幅值均值作为其估计
set(handles.outamp,'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.outphase,'String',num2str(mean(phase))); %最大值与最小值的一半即为峰值
set(handles.outpeak,'String',(max(handles.y(from:to))-min(handles.y(from:to)))/2);%from,to即是界面中的“从第from点到第to点” %计算并输出均值
set(handles.outmean,'String',mean(handles.y(from:to))); %计算并输出均方值
set(handles.outmeansquare,'String',mean(handles.y(from:to).^2)); %计算半输出方差
set(handles.outs,'String',std(handles.y(from:to))^2);
3.3.2 频域分析
频域分析需要作Fourier变换,MATLAB提供了fft函数,能够方便地实现快速Fourier变换算法。以下代码省去了从界面中获得from、to、Fs的部分,也省去了绘图后设置横、纵坐标轴的名称的部分。
%首先提取出待分析的样本,将其存入sample中 sample=handles.y(from:to);
%生成离散化的频率点,以采样频率作为离散化的间隔 f=linspace(0,Fs/2,(to-from+1)/2);
%对样本作快速Fourier变换,变换结果存入Y中 Y=fft(sample,to-from+1);
[C,I]=max(abs(Y)); %获得幅值最大的点及其所对应的下标值I %则f(I)为最大的幅值所对应的频率,即信号频率的估计值 set(handles.foutt,'String',1/f(I)); %计算并输出周期的估计值 set(handles.foutfreq,'String',f(I)); %输出频率的估计值 Y=Y(1:(to-from+1)/2); %为与f对应,只取Y的前半部分 plot(handles.plot1,f,2*sqrt(Y.*conj(Y))); %绘制幅值谱曲线 plot(handles.plot2,f,angle(Y)); %绘制相位谱曲线 plot(handles.plot3,f,real(Y)); %绘制实频谱曲线 plot(handles.plot4,f,imag(Y)); %绘制虚频谱曲线 plot(handles.plot5,f,abs(Y).^2); %绘制功率谱曲线
4.运行实例与误差分析
为了分析软件的性能并比较时域分析与频域分析各自的优势,本章给出了两种分析方法的频率估计的比较,分析软件的在时域和频域的计算精度问题。
4.1频率估计
4.1.1 标准正弦信号的频率估计
用信号发生器生成标准正弦信号,然后分别进行时域分析与频域分析,得到的结果如图 4所示。从图中可以看出,时域分析的结果为f = 400.3702Hz,频域分析的结果为f = 417.959Hz,而标准信号的频率为400Hz,从而对于标准信号时域分析的精度远高于频域分析的精度。
图 4 标准正弦信号的频率估计
4.1.2 带噪声的正弦信号的频率估计
先成生幅值100的标准正弦信号,再将幅值50的白噪声信号与其混迭,对最终得到的信号进行时域分析与频域分析,结果如图 5所示,可以看出,时域分析的结