您的位置:首页 > 编程语言 > MATLAB

MATLAB/guide实现数字信号处理——实例一

2020-03-05 20:29 2461 查看

电话按键声音模拟与分析

语音数字信号处理练习一,最近做的练习,希望对阅读的人有所帮助

1、实验内容

本次练习是使用matlab对声音信号的处理,来模拟电话按键在拨号时的按键音,对每个按键的声音信号再进行分析。最后得到按键声音信号的时域波形和频域波形。(效果图如图1所示)

关键字:MATLAB/Guide、语音信号处理、FFT、加窗、包络泛音

2、设计过程

2.1、设计理论与过程分析

发声的原理我们都很清楚,是由物体以一定频率的振动所产生,振动的频率不同则所听到的声音也有所不同。例如熟悉的音阶“do、re、mi…”便是在某一频率振动的声音。

在生活中,我们用心体会便会发现,电话的每个按钮的拨号音是各不相同的。很自然的可以想到每个按键在按下后会发出某一频率或者某一种混合频率的振动,从而是我们能感受到不同按键声。(这可能就是影视剧里面高手听电话音,辨别电话号码的能力来源吧)

查询资料得到了电话各个按键的声音频率到底是多少,我画了一个示意图,可以看下面的图。

可以看出,每个案件都是一个双频音,由两个频率成分组成。例如,按动“1”时发出的声音是由1209Hz和697Hz的声音叠加而成。


依据此原理,在设计过程中,我首先进行时域上的分析,先根据按动的按键产生特定的按键声,之后对时域成分进行FFT,从而完成频域分析。

在基本工作完成后,对发生在进行进阶修饰——包络泛音(ADSR)和时域上的加窗再频谱分析。

2.2、MATLAB/Guide中控件的排布

使用到的控件有:Push Botto和Axes.
控件排布方式为下图所示

控件排布完成后,检查控件是否是按照自己规划的顺序进行排列,尤其是在按键和坐标轴过多的情况下,避免混乱。

有一个小技巧,可以不用拖动控件去调整顺序,只需要把控件按照想要的形状排布,只够改动控件的“Tag”属性(如图4所示)去排列顺序。记得先保存,保存后可以刷新Editor中控件的Callback Fcn和create Fcn的排列,进而达到事后排列的目的。

“Tag”属性在我的理解是类似与“对象”的概念,是控件的名字。

2.3、Editor编辑器中基本代码编写

在控件按照顺序排列完成后,可以开始控件回调函数(callback fcn)的编写。

从自己制作过程中,我整理出了该练习程序编写的思路如下五点。

2.3.1. 给按键唯一编号

设置全局变量 Type,表示按键类型,每一个Push Button的callback function中添加如下代码。
global Type;
Type = 1;%第一个按钮设置编号1,一次类推
my_callback_fcn(handles);%设置编号后同意进行之后的操作

2.3.2. 给每个编号对应一个按键的频率成分

按下按钮后,Type值便确定。之后跳转到自己编写的回调函数,这里我设置的是“my_callback_fcn(handles)”。

我们取两个变量(F1,F2),在类型确定后赋值所需的频率值。可以使用switch…case语句或者if…else 语句获取频率值。

以第一个按键为例,程序语句如下:

switch(Type)
case(1)
F1 = 1209;F2 = 697;%对应第一个按钮发声的频率值
......

2.3.3. 根据频率成分得到信号时域曲线,绘制时域图

在2)中得到某个按钮对应的频率成分后,我们很容易的得到其声音曲线。Matlab代码如下:

Fs = 44100;                  %采样频率
T = 0.2;                     %采样时间
dt = 1/44100;                %采样时间间隔
N = T*Fs;                    %采样点数
t = linspace(0,T,N);       %采样时间序列
A1 = 1500*sin(2*pi*F1*t); %F1频率对应信号
A2 = 1500*sin(2*pi*F2*t); %F2频率对应信号
x = A1 + A2;                 %F1、F2叠加频率信号,即按键声音信号

x为得到的时域声音信号,绘图可以采用plot()函数进行绘图,横坐标t,纵坐标x。得到了时域图。

这一步能够得到如下图5红框中的结果

2.3.4. 发声

在相关资料上查询得知,matlab的波形声音播放函数可以使用wavplay()函数。但是可能只有在低版本的matlab中有这个函数,因我使用的matlab 2018b已经没有这个函数,所以我调用的是sound()这个函数,

sound(x,44100);%第一个参数为声音函数,第二个参数为采样点数

采样点数(第二个参数)决定了发声是否准确,我一开始时并没注意这一点,采用默认的采样点数,采样率过低,发声十分生硬,严重失真。后来提高了采样率后便改善了很多。

2.3.5. 对时域信号进行快速傅里叶变换(FFT)得到频率成分,绘制频谱图

这一步开始对时域图进行频谱分析。运用matlab中的fft()函数对信号进行快速傅里叶变换。代码如下

N1 = 1024*2;              %快速傅里叶变换采样点数
y = fft(x,N1);            %快速傅里叶变换,第一个参数为时域函数,第二个参数为FFT的点数。N1的值应为2的n次幂
y = abs(y)/(N1/2);        %取实数并进行幅值修正
f = linspace(0,Fs,N1);    %频率序列

Matlab函数中fft函数会根据第二个参数,进行选定点数的fft计算。运算完成后,生成的是一个用户指定点数的镜像的双边幅频谱,而我们只需要取其前部分那一半就能得到正频率部分的频谱图。因此程序中应取绝对值后,选定频率前半部分进行显示即可。

得到频域赋值为y,纵坐标频率范围为f,据此可以绘制出幅频特性图。

对范围内进行绘图得到图5中的最后一幅幅频图。可以看出该声音信号由两个频率成分组成。

到此程序基本上已经完成。 下面是进阶内容

2.4、包络泛音调整

到此程序基本完成,而更进一步,我们可以进行包络泛音ADSR和函数加窗操作,做进阶训练。

这一段我也解释不清楚,说是让声音更动听并减少机械音的操作,具体可以查询ADSR的资料阅读。(该图来自网络)

大体意思就是给声音信号加包络线,使其播放更加平滑。代码如下:

ADSR1 = linspace(0,max(x),2205);
ADSR2 = linspace(max(x),max(x)*3/5,2205);
ADSR3 = linspace(max(x)*3/5,max(x)*3/5,2205);
ADSR4 = linspace(max(x)*3/5,0,2205);
ADSR = [ADSR1,ADSR2,ADSR3,ADSR4];

sound(x.*ADSR,44100);

2.5、函数加窗操作

加窗操作是为了在后面FFT中减少截断误差,保证频谱赋值误差在可承受范围内。

我在本次实验中,给声音函数加上汉宁窗(hann),之后进行FFT,减少在信号截断中的失真。

x1 = x(1:0.1/dt);         %截取一段信号进行分析,选择0-0.1s的信号进行加窗处理
win = hann(length(x1));  %生成与截断信号相同长度的汉宁窗
win = win';                %排序进行转置
x_win = win.*x1*1.58;    %系数1.58为加窗后的增益调整值
%下面的FFT过程与3(5)中相同
N1 = 1024*2;
y = fft(x_win,N1);
y = abs(y)/(N1/2);
f = linspace(0,Fs,N1);

所有修饰加上后,得到的最终结果如图7所示

3、总结

注意取样点数的一致性,掌握好基本原理才是程序运行下去的依托。加窗是频谱分析中的常用操作,包络泛音是

  • 点赞
  • 收藏
  • 分享
  • 文章举报
陈阿达 发布了2 篇原创文章 · 获赞 1 · 访问量 49 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: