《MATLAB语音信号分析与合成(第二版)》:第6章 语音端点的检测(1)
《MATLAB语音信号分析与合成(第二版)》:第6章 语音端点的检测(1)
- 前言
- 1. 数据与函数路径设置
- 2. MATLAB仿真一:语音信号双门限端点检测
- 3. MATLAB仿真二:语音信号改进双门限端点检测一
- 4. MATLAB仿真三:语音信号改进双门限端点检测二
- 5. MATLAB仿真四:语音信号改进双门限端点检测三
- 6. MATLAB仿真五:语音信号相关法端点检测一
- 7. MATLAB仿真六:语音信号相关法端点检测二
- 8. MATLAB仿真七:语音信号相关法端点检测三
- 9. MATLAB仿真八:语音信号相关法端点检测四
- 10. MATLAB仿真九:语音信号相关法端点检测五
- 11. MATLAB仿真十:语音信号方差法端点检测一
- 12. MATLAB仿真十一:语音信号方差法端点检测二
- 13. MATLAB仿真十二:语音信号方差法端点检测三
- 14. MATLAB仿真十三:语音信号方差法端点检测四
- 小结
前言
《MATLAB语音信号分析与合成(第二版)》是中科院声学所的大佬宋知用老师数十年经验积累下的呕心之作,对于语音信号处理相关感兴趣的同学,日后希望在语音信号分析、处理与合成相关领域进行一定研究的话,可以以此进行入门。
语音信号处理是数字信号处理的一个重要分支。本书含有许多数字信号处理的方法和 MATLAB函数。 全书共10章。第1-4章介绍语音信号处理的一些基本分析方法和手段,以及相应的MATLAB函数;第5-9章介绍语音信号预处理和特征的提取,包括消除趋势项和基本的减噪方法,以及端点检测、基音的提取和共 振峰的提取,并利用语音信号处理的基本方法,给出了多种提取方法和相应的 MATLAB程序;第10章结合 各种参数的检测介绍了语音信号的合成、语音信号的变速和变调处理,还介绍了时域基音同步叠加( TD PSOLA)的语音合成,并给出了相应的MATLAB程序。附录A中给出了调试复杂程序的方法和思路。 本书可作为从事语音信号处理的本科高年级学生、研究生或科研工程技术人员的辅助读物,也可作为从 事信号处理研究与应用的科研工程技术人员的参考用书。
我的研究生导师的主攻方向就是语音信号处理相关,虽然自己研究生期间的大论文方向是数字图像处理,但所谓语音图像不分家,自己在老师的研究生主讲课小波变换上虽然划水,但在后期导师的语音信号处理的课程设计和工程应用上自己在语音上还算入了一点小门道,在结课测试中拿到了小组第一,导师还特地发了三百大洋的伙食经费以资鼓励。
这次重新捡起语音识别,正好入手了宋老师的这本书,算是自己重新复习一遍吧,主要以介绍各章节中源码为主,这是本书的第六章的前13个仿真应用实例,话不多说,开始!
1. 数据与函数路径设置
书中经常会调用的一些函数(自编函数或取自其他应用工具箱中的函数)已集中在basic_tbx工具箱中,在运行本书的程序前请把该工具箱设置(用set path设置)在工作路径下;
当要运行EMD处理时,要把emd工具箱设置在工作路径下;
当要运行主体延伸基音检测时,要把Pitch_ztlib工具箱设置在工作路径下;
当要进行时域基音同步叠加语音合成时,要把psola_lib工具箱设置在工作路径下;
当要应用本书提供的语音数据时,最好把speech_signal设置在工作路径下。
本书的所有函数和程序都在MATLAB R2009a版本下调试通过。(我用的是MATLAB2015b,有些函数已经更新,所以我会进行修改,以便调试通过)
路径设置的方法如下:
打开MATLAB,点击“主页”,找到设置路径
将上述文件夹路径全部添加到MATLAB搜索路径中
添加完毕,保存,开始仿真。
2. MATLAB仿真一:语音信号双门限端点检测
%% pr6_1_1 clear all; clc; close all;filedir=[]; % 指定文件路径filename='bluesky1.wav'; % 指定文件名fle=[filedir filename] % 构成路径和文件名的字符串% [x,fs]=wavread(fle); % 读入数据文件[x,fs]=audioread(fle); % 读入数据文件x=x/max(abs(x)); % 幅度归一化N=length(x);% 取信号长度time=(0:N-1)/fs; % 计算时间pos = get(gcf,'Position');% 作图set(gcf,'Position',[pos(1), pos(2)-100,pos(3),(pos(4)-200)]);plot(time,x,'k'); title('男声“蓝天,白云,碧绿的大海”的端点检测');ylabel('幅值'); axis([0 max(time) -1 1]); grid;xlabel('时间/s');wlen=200; inc=80; % 分帧参数IS=0.1; overlap=wlen-inc; % 设置ISNIS=fix((IS*fs-wlen)/inc +1); % 计算NISfn=fix((N-wlen)/inc)+1; % 求帧数frameTime=frame2time(fn, wlen, inc, fs);% 计算每帧对应的时间[voiceseg,vsl,SF,NF]=vad_ezm1(x,wlen,inc,NIS); % 端点检测for k=1 : vsl % 画出起止点位置 nx1=voiceseg(k).begin; nx2=voiceseg(k).end; nxl=voiceseg(k).duration; fprintf('%4d %4d %4d %4d\n',k,nx1,nx2,nxl); line([frameTime(nx1) frameTime(nx1)],[-1.5 1.5],'color','k','LineStyle','-'); line([frameTime(nx2) frameTime(nx2)],[-1.5 1.5],'color','k','LineStyle','--');end
function [voiceseg,vsl,SF,NF]=vad_ezm1(x,wlen,inc,NIS)x=x(:); % 把x转换成列数组maxsilence = 15; % 初始化minlen = 5; status = 0;count = 0;silence = 0;y=enframe(x,wlen,inc)'; % 分帧fn=size(y,2); % 帧数amp=sum(y.^2); % 求取短时平均能量zcr=zc2(y,fn); % 计算短时平均过零率ampth=mean(amp(1:NIS)); % 计算初始无话段区间能量和过零率的平均值 zcrth=mean(zcr(1:NIS));amp2=2*ampth; amp1=4*ampth; % 设置能量和过零率的阈值zcr2=2*zcrth;%开始端点检测xn=1;for n=1:fn switch status case {0,1} % 0 = 静音, 1 = 可能开始 if amp(n) > amp1 % 确信进入语音段 x1(xn) = max(n-count(xn)-1,1); status = 2; silence(xn) = 0; count(xn) = count(xn) + 1; elseif amp(n) > amp2 | ... % 可能处于语音段 zcr(n) > zcr2 status = 1; count(xn) = count(xn) + 1; else % 静音状态 status = 0; count(xn) = 0; x1(xn)=0; x2(xn)=0; end case 2, % 2 = 语音段 if amp(n) > amp2 & ... % 保持在语音段 zcr(n) > zcr2 count(xn) = count(xn) + 1; silence(xn) = 0; else % 语音将结束 silence(xn) = silence(xn)+1; if silence(xn) < maxsilence % 静音还不够长,语音尚未结束 count(xn) = count(xn) + 1; elseif count(xn) < minlen % 语音长度太短,认为是静音或噪声 status = 0; silence(xn) = 0; count(xn) = 0; else % 语音结束 status = 3; x2(xn)=x1(xn)+count(xn); end end case 3, % 语音结束,为下一个语音准备 status = 0; xn=xn+1; count(xn) = 0; silence(xn)=0; x1(xn)=0; x2(xn)=0; endend el=length(x1); if x1(el)==0, el=el-1; end% 获得x1的实际长度if x2(el)==0% 如果x2最后一个值为0,对它设置为fn fprintf('Error: Not find endding point!\n'); x2(el)=fn;endSF=zeros(1,fn); % 按x1和x2,对SF和NF赋值NF=ones(1,fn);for i=1 : el SF(x1(i):x2(i))=1; NF(x1(i):x2(i))=0;endspeechIndex=find(SF==1); % 计算voicesegvoiceseg=findSegment(speechIndex);vsl=length(voiceseg);
3. MATLAB仿真二:语音信号改进双门限端点检测一
%% pr6_2_1 clear all; clc; close all;filedir=[]; % 指定文件路径filename='bluesky1.wav'; % 指定文件名fle=[filedir filename] % 构成路径和文件名的字符串% [xx,fs]=wavread(fle); % 读入数据文件[xx,fs]=audioread(fle); % 读入数据文件xx=xx/max(abs(xx));% 幅度归一化N=length(xx); % 取信号长度time=(0:N-1)/fs; % 计算时间刻度x=Gnoisegen(xx,20);% 把白噪声叠加到信号上wlen=200; inc=80; % 设置帧长和帧移IS=0.25; overlap=wlen-inc;% 设置前导无话段长度NIS=fix((IS*fs-wlen)/inc +1); % 计算前导无话段帧数fn=fix((N-wlen)/inc)+1; % 求出总帧数frameTime=frame2time(fn, wlen, inc, fs);% 计算每帧对应的时间[voiceseg,vsl,SF,NF]=vad_ezr(x,wlen,inc,NIS); % 端点检测% 作图subplot 211; plot(time,xx,'k'); hold ontitle('纯语音男声“蓝天,白云,碧绿的大海”波形');ylabel('幅值'); axis([0 max(time) -1 1]); xlabel('(a)');for k=1 : vsl nx1=voiceseg(k).begin; nx2=voiceseg(k).end; fprintf('%4d %4d %4d\n',k,nx1,nx2); line([frameTime(nx1) frameTime(nx1)],[-1.5 1.5],'color','k','LineStyle','-'); line([frameTime(nx2) frameTime(nx2)],[-1.5 1.5],'color','k','LineStyle','--');endsubplot 212; plot(time,x,'k');title('加噪语音波形(信噪比20dB)');ylabel('幅值'); axis([0 max(time) -1 1]);xlabel(['时间/s' 10 '(b)']);
function [voiceseg,vsl,SF,NF]=vad_ezr(x,wlen,inc,NIS)x=x(:); % 把x转成列数组maxsilence = 15; % 初始化 minlen = 5; status = 0;count = 0;silence = 0;%计算短时能量y=enframe(x,wlen,inc)'; % 分帧fn=size(y,2); % 帧数amp=sum(y.^2); % 求取短时平均能量zcr=zc2(y,fn); % 计算短时平均过零率 ampth=mean(amp(1:NIS)); % 计算初始无话段区间能量和过零率的平均值zcrth=mean(zcr(1:NIS));amp2=2*ampth; amp1=4*ampth; % 设置能量和过零率的值 zcr2=0.8*zcrth;%开始端点检测xn=1;for n=1:fn fprintf('%4d %5.4f %5.4f ',n,amp(n),zcr(n)); switch status case {0,1} % 0 = 静音, 1 = 可能开始 if amp(n) > amp1 % 确信进入语音段 x1(xn) = max(n-count(xn)-1,1); status = 2; silence(xn) = 0; count(xn) = count(xn) + 1; elseif amp(n) > amp2 | ... % 可能处于语音段 zcr(n) < zcr2 status = 1; count(xn) = count(xn) + 1; else % 静音状态 status = 0; count(xn) = 0; x1(xn)=0; x2(xn)=0; end case 2, % 2 = 语音段 if amp(n) > amp2 | ... % 保持在语音段 zcr(n) < zcr2 count(xn) = count(xn) + 1; else % 语音将结束 silence(xn) = silence(xn)+1; if silence(xn) < maxsilence % 静音还不够长,尚未结束 count(xn) = count(xn) + 1; elseif count(xn) < minlen % 语音长度太短,认为是噪声 status = 0; silence(xn) = 0; count(xn) = 0; else % 语音结束 status = 3; x2(xn)=x1(xn)+count(xn); end end case 3, % 语音结束,为下一个语音准备 status = 0; xn=xn+1; count(xn) = 0; silence(xn)=0; x1(xn)=0; x2(xn)=0; end fprintf('%4d \n',status);end el=length(x1);if x1(el)==0, el=el-1; end% 获得x1的实际长度if x2(el)==0% 如果x2最后一个值为0,对它设置为fn fprintf('Error: Not find endding point!\n'); x2(el)=fn;endSF=zeros(1,fn); % 按x1和x2,对SF和NF赋值NF=ones(1,fn);for i=1 : el SF(x1(i):x2(i))=1; NF(x1(i):x2(i))=0;endspeechIndex=find(SF==1); % 计算voicesegvoiceseg=findSegment(speechIndex);vsl=length(voiceseg);
4. MATLAB仿真三:语音信号改进双门限端点检测二
%% pr6_2_2 clear all; clc; close all;filedir=[]; % 指定文件路径filename='bluesky1.wav'; % 指定文件名fle=[filedir filename] % 构成路径和文件名的字符串% [xx,fs]=wavread(fle); % 读入数据文件[xx,fs]=audioread(fle); % 读入数据文件xx=xx/max(abs(xx));% 幅度归一化N=length(xx); % 取信号长度time=(0:N-1)/fs; % 计算时间刻度SNR=10; % 信噪比x=Gnoisegen(xx,SNR); % 把白噪声叠加到信号上wlen=200; inc=80; % 设置帧长和帧移IS=0.25; overlap=wlen-inc;% 设置前导无话段长度NIS=fix((IS*fs-wlen)/inc +1); % 计算前导无话段帧数y=enframe(x,wlen,inc)'; % 分帧fn=size(y,2); % 帧数amp=sum(y.^2); % 求取短时平均能量zcr=zc2(y,fn); % 计算短时平均过零率 ampm = multimidfilter(amp,5); % 中值滤波平滑处理zcrm = multimidfilter(zcr,5); ampth=mean(ampm(1:NIS)); % 计算初始无话段区间能量和过零率的平均值 zcrth=mean(zcrm(1:NIS));amp2=1.1*ampth; amp1=1.3*ampth; % 设置能量和过零率的阈值zcr2=0.9*zcrth;frameTime=frame2time(fn, wlen, inc, fs);% 计算各帧对应的时间[voiceseg,vsl,SF,NF]=vad_param2D_revr(ampm,zcrm,amp2,amp1,zcr2);% 端点检测% 作图subplot 211; plot(time,xx,'k');title('纯语音男声“蓝天,白云,碧绿的大海”波形');ylabel('幅值'); axis([0 max(time) -1 1]); for k=1 : vsl nx1=voiceseg(k).begin; nx2=voiceseg(k).end; fprintf('%4d %4d %4d\n',k,nx1,nx2); line([frameTime(nx1) frameTime(nx1)],[-1.5 1.5],'color','k','LineStyle','-'); line([frameTime(nx2) frameTime(nx2)],[-1.5 1.5],'color','k','LineStyle','--');endsubplot 212; plot(time,x,'k');title(['加噪语音波形(信噪比' num2str(SNR) 'dB)']);ylabel('幅值'); axis([0 max(time) -1 1]);xlabel('时间/s');
function [voiceseg,vsl,SF,NF]=vad_param2D_revr(dst1,dst2,T1,T2,T3,T4)fn=length(dst1); % 取帧数maxsilence = 8; % 初始化 minlen = 5; status = 0;count = 0;silence = 0;%开始端点检测xn=1;for n=1:fn switch status case {0,1} % 0 = 静音, 1 = 可能开始 if dst1(n) > T2 | ... % 确信进入语音段 ( nargin==6 & dst2(n) < T4 ) x1(xn) = max(n-count(xn)-1,1); status = 2; silence(xn) = 0; count(xn) = count(xn) + 1; elseif dst1(n) > T1 | ... % 可能处于语音段 dst2(n) < T3 status = 1; count(xn) = count(xn) + 1; else % 静音状态 status = 0; count(xn) = 0; x1(xn)=0; x2(xn)=0; end case 2, % 2 = 语音段 if dst1(n) > T1 | ... % 保持在语音段 dst2(n) < T3 count(xn) = count(xn) + 1; silence(xn) = 0; else % 语音将结束 silence(xn) = silence(xn)+1; if silence(xn) < maxsilence % 静音还不够长,尚未结束 count(xn) = count(xn) + 1; elseif count(xn) < minlen % 语音长度太短,认为是噪声 status = 0; silence(xn) = 0; count(xn) = 0; else % 语音结束 status = 3; x2(xn)=x1(xn)+count(xn); end end case 3, % 语音结束,为下一个语音准备 status = 0; xn=xn+1; count(xn) = 0; silence(xn)=0; x1(xn)=0; x2(xn)=0; endend el=length(x1);if x1(el)==0, el=el-1; end% 获得x1的实际长度if x2(el)==0% 如果x2最后一个值为0,对它设置为fn fprintf('Error: Not find endding point!\n'); x2(el)=fn;endSF=zeros(1,fn); % 按x1和x2,对SF和NF赋值NF=ones(1,fn);for i=1 : el SF(x1(i):x2(i))=1; NF(x1(i):x2(i))=0;endspeechIndex=find(SF==1); % 计算voicesegvoiceseg=findSegment(speechIndex);vsl=length(voiceseg);
5. MATLAB仿真四:语音信号改进双门限端点检测三
%% pr6_2_3 clear all; clc; close all;filedir=[]; % 指定文件路径filename='bluesky1.wav'; % 指定文件名fle=[filedir filename] % 构成路径和文件名的字符串% [xx,fs]=wavread(fle); % 读入数据文件[xx,fs]=audioread(fle); % 读入数据文件x=xx/max(abs(xx)); % 幅度归一化N=length(xx); % 取信号长度time=(0:N-1)/fs; % 计算时间刻度wlen=200; inc=80; % 设置帧长和帧移IS=0.25; overlap=wlen-inc;% 设置前导无话段长度NIS=fix((IS*fs-wlen)/inc +1); % 计算前导无话段帧数y=enframe(x,wlen,inc)'; % 分帧etemp=sum(y.^2); % 求取短时平均能量etemp=etemp/max(etemp); % 能量幅值归一化fn=size(y,2); % 帧数T1=0.002; % 设置阈值T2=0.01;frameTime=frame2time(fn, wlen, inc, fs);% 计算各帧对应的时间[voiceseg,vsl,SF,NF]=vad_param1D(etemp,T1,T2);% 用一个参数端点检测% 作图subplot 211; plot(time,x,'k'); hold ontitle('纯语音男声“蓝天,白云,碧绿的大海”波形');ylabel('幅值'); axis([0 max(time) -1 1]); for k=1 : vsl nx1=voiceseg(k).begin; nx2=voiceseg(k).end; fprintf('%4d %4d %4d\n',k,nx1,nx2); line([frameTime(nx1) frameTime(nx1)],[-1 1],'color','k','LineStyle','-'); line([frameTime(nx2) frameTime(nx2)],[-1 1],'color','k','LineStyle','--');endsubplot 212; plot(frameTime,etemp,'k');title('语音短时能量图');ylabel('幅值'); axis([0 max(time) 0 1]);xlabel('时间/s');line([0 max(time)],[T1 T1],'color','k','LineStyle','-');line([0 max(time)],[T2 T2],'color','k','LineStyle','--');
function [voiceseg,vsl,SF,NF]=vad_param1D(dst1,T1,T2)fn=size(dst1,2); % 取得帧数maxsilence = 8; % 初始化 minlen = 5; status = 0;count = 0;silence = 0;%开始端点检测xn=1;for n=2:fn switch status case {0,1} % 0 = 静音, 1 = 可能开始 if dst1(n) > T2 % 确信进入语音段 x1(xn) = max(n-count(xn)-1,1); status = 2; silence(xn) = 0; count(xn) = count(xn) + 1; elseif dst1(n) > T1 % 可能处于语音段% zcr(n) < zcr2 status = 1; count(xn) = count(xn) + 1; else % 静音状态 status = 0; count(xn) = 0; x1(xn)=0; x2(xn)=0; end case 2, % 2 = 语音段 if dst1(n) > T1 % 保持在语音段 count(xn) = count(xn) + 1; silence(xn) = 0; else % 语音将结束 silence(xn) = silence(xn)+1; if silence(xn) < maxsilence % 静音还不够长,尚未结束 count(xn) = count(xn) + 1; elseif count(xn) < minlen % 语音长度太短,认为是噪声 status = 0; silence(xn) = 0; count(xn) = 0; else % 语音结束 status = 3; x2(xn)=x1(xn)+count(xn); end end case 3, % 语音结束,为下一个语音准备 status = 0; xn=xn+1; count(xn) = 0; silence(xn)=0; x1(xn)=0; x2(xn)=0; endend el=length(x1);if x1(el)==0, el=el-1; end% 获得x1的实际长度if el==0, return; endif x2(el)==0% 如果x2最后一个值为0,对它设置为fn fprintf('Error: Not find endding point!\n'); x2(el)=fn;endSF=zeros(1,fn); % 按x1和x2,对SF和NF赋值NF=ones(1,fn);for i=1 : el SF(x1(i):x2(i))=1; NF(x1(i):x2(i))=0;endspeechIndex=find(SF==1); % 计算voicesegvoiceseg=findSegment(speechIndex);vsl=length(voiceseg);
6. MATLAB仿真五:语音信号相关法端点检测一
%% pr6_3_1 clear all; clc; close all;run Set_I % 基本设置run PART_I % 读入数据,分帧等准备for k=2 : fn% 计算自相关函数 u=y(:,k); ru=xcorr(u); Ru(k)=max(ru);endRum=multimidfilter(Ru,10);% 平滑处理Rum=Rum/max(Rum); % 归一化thredth=max(Rum(1:NIS)); % 计算阈值T1=1.1*thredth;T2=1.3*thredth;[voiceseg,vsl,SF,NF]=vad_param1D(Rum,T1,T2);% 自相关函数的端点检测% 作图subplot 311; plot(time,x,'k');title('纯语音波形');ylabel('幅值'); axis([0 max(time) -1 1]);subplot 312; plot(time,signal,'k');title(['加噪语音波形(信噪比' num2str(SNR) 'dB)']);ylabel('幅值'); axis([0 max(time) -1 1]);subplot 313; plot(frameTime,Rum,'k');title('短时自相关函数'); axis([0 max(time) 0 1.2]);xlabel('时间/s'); ylabel('幅值'); line([0,frameTime(fn)], [T1 T1], 'color','k','LineStyle','--');line([0,frameTime(fn)], [T2 T2], 'color','k','LineStyle','-');for k=1 : vsl % 标出语音端点 nx1=voiceseg(k).begin; nx2=voiceseg(k).end; fprintf('%4d %4d %4d\n',k,nx1,nx2); subplot 311; line([frameTime(nx1) frameTime(nx1)],[-1 1],'color','k','LineStyle','-'); line([frameTime(nx2) frameTime(nx2)],[-1 1],'color','k','LineStyle','--');end
%Set_I.m% Set_IIS=0.25; % 设置前导无话段长度wlen=200; % 设置帧长为25msinc=80; % 求帧移filedir=[]; % 设置文件路径filename='bluesky1.wav'; % 设置文件名称fle=[filedir filename] % 构成文件路径和名称SNR=10; % 设置信噪比
% PART_I.m% PART_I% [xx,fs]=wavread(fle); % 读入数据[xx,fs]=audioread(fle); % 读入数据xx=xx-mean(xx); % 消除直流分量x=xx/max(abs(xx)); % 幅值归一化N=length(x);% 取信号长度time=(0:N-1)/fs; % 设置时间signal=Gnoisegen(x,SNR); % 叠加噪声wnd=hamming(wlen); % 设置窗函数overlap=wlen-inc; % 求重叠区长度NIS=fix((IS*fs-wlen)/inc +1); % 求前导无话段帧数y=enframe(signal,wnd,inc)'; % 分帧fn=size(y,2); % 求帧数frameTime=frame2time(fn, wlen, inc, fs);% 计算各帧对应的时间
7. MATLAB仿真六:语音信号相关法端点检测二
%% pr6_3_2 clear all; clc; close all;run Set_I % 基本设置run PART_I % 读入数据,分帧等准备for k=2 : fn% 计算互相关函数 u1=y(:,k-1); u2=y(:,k); ru=xcorr(u1,u2); Ru(k)=max(ru);endRum=multimidfilter(Ru,10);% 平滑处理Rum=Rum/max(Rum); % 归一化thredth=max(Rum(2:NIS)); % 计算阈值T1=1.1*thredth;T2=1.3*thredth;[voiceseg,vsl,SF,NF]=vad_param1D(Rum,T1,T2);% 互相关函数的端点检测% 作图subplot 311; plot(time,x,'k');title('纯语音波形');ylabel('幅值'); axis([0 max(time) -1 1]);subplot 312; plot(time,signal,'k');title(['加噪语音波形(信噪比' num2str(SNR) 'dB)']);ylabel('幅值'); axis([0 max(time) -1 1]);subplot 313; plot(frameTime,Rum,'k');title('短时自相关函数'); axis([0 max(time) 0 1.2]);xlabel('时间/s'); ylabel('幅值'); line([0,frameTime(fn)], [T1 T1], 'color','k','LineStyle','--');line([0,frameTime(fn)], [T2 T2], 'color','k','LineStyle','-');for k=1 : vsl % 标出语音端点 nx1=voiceseg(k).begin; nx2=voiceseg(k).end; fprintf('%4d %4d %4d\n',k,nx1,nx2); subplot 311; line([frameTime(nx1) frameTime(nx1)],[-1 1],'color','k','LineStyle','-'); line([frameTime(nx2) frameTime(nx2)],[-1 1],'color','k','LineStyle','--');end
8. MATLAB仿真七:语音信号相关法端点检测三
%% pr6_3_3 clear all; clc; close all;run Set_I % 基本设置run PART_I % 读入数据,分帧等准备[n,Wn]=buttord(300/(fs/2),600/(fs/2),3,20); % 计算滤波器阶数和带宽[bs,as]=butter(n,Wn); % 求取数字滤波器系数for k=1 : fn u=y(:,k); % 取一帧数据 ru=xcorr(u); % 计算自相关函数 rnu=ru/max(ru);% 归一化 rpu=filter(bs,as,rnu);% 数字滤波 Ru(k)=max(rpu);% 寻找最大值endRum=multimidfilter(Ru,10);% 平滑处理thredth=max(Rum(1:NIS)); % 设置阈值T1=1.2*thredth;T2=1.5*thredth;[voiceseg,vsl,SF,NF]=vad_param1D(Rum,T1,T2); % 单参数双门限端点检测% 作图subplot 311; plot(time,x,'k');title('纯语音波形');ylabel('幅值'); axis([0 max(time) -1 1]);subplot 312; plot(time,signal,'k');title(['加噪语音波形(信噪比' num2str(SNR) 'dB)']);ylabel('幅值'); axis([0 max(time) -1 1]);subplot 313; plot(frameTime,Rum,'k');title('短时归一化自相关函数'); grid; ylim([0 1.2]);xlabel('时间/s'); ylabel('幅值'); line([0,frameTime(fn)], [T1 T1], 'color','k','LineStyle','--');line([0,frameTime(fn)], [T2 T2], 'color','k','LineStyle','-');% 标出语音端点for k=1 : vsl nx1=voiceseg(k).begin; nx2=voiceseg(k).end; fprintf('%4d %4d %4d\n',k,nx1,nx2); subplot 311; line([frameTime(nx1) frameTime(nx1)],[-1 1],'color','k','LineStyle','-'); line([frameTime(nx2) frameTime(nx2)],[-1 1],'color','k','LineStyle','--'); subplot 313; line([frameTime(nx1) frameTime(nx1)],[0 1.2],'color','k','LineStyle','-'); line([frameTime(nx2) frameTime(nx2)],[0 1.2],'color','k','LineStyle','--');end
9. MATLAB仿真八:语音信号相关法端点检测四
%% pr6_3_4 clear all; clc; close all;run Set_I % 基本设置run PART_I % 读入数据,分帧等准备for k=1 : fn u=y(:,k); % 取一帧数据 ru=xcorr(u); % 计算自相关函数 ru0=ru(wlen); % 取主峰值 ru1=max(ru(wlen+17:wlen+133)); % 取第一个副峰值 R1(k)=ru0/ru1; % 计算主副峰比值endRum=multimidfilter(R1,20);% 平滑处理Rum=Rum/max(Rum); % 数值归一化alphath=mean(Rum(1:NIS)); % 设置阈值T1=0.95*alphath; T2=0.75*alphath;[voiceseg,vsl,SF,NF]=vad_param1D_revr(Rum,T1,T2);% 单参数双门限反向端点检测% 作图subplot 311; plot(time,x,'k');title('纯语音波形');ylabel('幅值'); axis([0 max(time) -1 1]);subplot 312; plot(time,signal,'k');title(['加噪语音波形(信噪比' num2str(SNR) 'dB)']);ylabel('幅值'); axis([0 max(time) -1 1]);subplot 313; plot(frameTime,Rum,'k');title('短时自相关函数主副峰值比'); axis([0 max(time) 0 1.2]);xlabel('时间/s'); ylabel('幅值'); line([0,frameTime(fn)], [T1 T1], 'color','k','LineStyle','--');line([0,frameTime(fn)], [T2 T2], 'color','k','LineStyle','-');% 标出语音端点for k=1 : vsl nx1=voiceseg(k).begin; nx2=voiceseg(k).end; fprintf('%4d %4d %4d\n',k,nx1,nx2); subplot 311; line([frameTime(nx1) frameTime(nx1)],[-1 1],'color','k','LineStyle','-'); line([frameTime(nx2) frameTime(nx2)],[-1 1],'color','k','LineStyle','--'); subplot 313; line([frameTime(nx1) frameTime(nx1)],[0 1.2],'color','k','LineStyle','-'); line([frameTime(nx2) frameTime(nx2)],[0 1.2],'color','k','LineStyle','--');end
function [voiceseg,vsl,SF,NF]=vad_param1D_revr(dst1,T1,T2)fn=length(dst1); % 取得帧数maxsilence = 8; % 初始化 minlen = 5; status = 0;count = 0;silence = 0;%开始端点检测xn=1;for n=2:fn switch status case {0,1} % 0 = 静音, 1 = 可能开始 if dst1(n) < T2 % 确信进入语音段 x1(xn) = max(n-count(xn)-1,1); status = 2; silence(xn) = 0; count(xn) = count(xn) + 1; elseif dst1(n) < T1 % 可能处于语音段 status = 1; count(xn) = count(xn) + 1; else % 静音状态 status = 0; count(xn) = 0; x1(xn)=0; x2(xn)=0; end case 2, % 2 = 语音段 if dst1(n) < T1 % 保持在语音段 count(xn) = count(xn) + 1; silence(xn) = 0; else % 语音将结束 silence(xn) = silence(xn)+1; if silence(xn) < maxsilence % 静音还不够长,尚未结束 count(xn) = count(xn) + 1; elseif count(xn) < minlen % 语音长度太短,认为是噪声 status = 0; silence(xn) = 0; count(xn) = 0; else % 语音结束 status = 3; x2(xn)=x1(xn)+count(xn); end end case 3, % 语音结束,为下一个语音准备 status = 0; xn=xn+1; count(xn) = 0; silence(xn)=0; x1(xn)=0; x2(xn)=0; endend el=length(x1);if x1(el)==0, el=el-1; end% 获得x1的实际长度if el==0, return; endif x2(el)==0% 如果x2最后一个值为0,对它设置为fn fprintf('Error: Not find endding point!\n'); x2(el)=fn;endSF=zeros(1,fn); % 按x1和x2,对SF和NF赋值NF=ones(1,fn);for i=1 : el SF(x1(i):x2(i))=1; NF(x1(i):x2(i))=0;endspeechIndex=find(SF==1); % 计算voicesegvoiceseg=findSegment(speechIndex);vsl=length(voiceseg);
10. MATLAB仿真九:语音信号相关法端点检测五
%% pr6_3_5 clear all; clc; close all;run Set_I % 基本设置run PART_I % 读入数据,分帧等准备Rw=zeros(2*wlen-1,1); % Rw初始化for k=1 : NIS % 按式(6-3-6)计算Rw u=y(:,k); % 取一帧数据 ru=xcorr(u); % 计算自相关函数 Rw=Rw+ru;endRw=Rw/NIS;Rw2=sum(Rw.*Rw); % 计算式(6-3-5)中分母内Rw的部分for k=1 : fn u=y(:,k); % 取一帧数据 ru=xcorr(u); % 计算自相关函数 Cm=sum(ru.*Rw);% 计算式(6-3-5)中分子部分 Cru=sum(ru.*ru); % 计算式(6-3-5)中分母内Ry的部分 Ru(k)=Cm/sqrt(Rw2*Cru); % 计算式(6-3-5)每帧的自相关函数余弦夹角endRum=multimidfilter(Ru,10);% 平滑处理alphath=mean(Rum(1:NIS)); % 设置阈值T2=0.8*alphath; T1=0.9*alphath;[voiceseg,vsl,SF,NF]=vad_param1D_revr(Rum,T1,T2); % 单参数双门限反向端点检测% 作图subplot 311; plot(time,x,'k');title('纯语音波形');ylabel('幅值'); axis([0 max(time) -1 1]);subplot 312; plot(time,signal,'k');title(['加噪语音波形(信噪比' num2str(SNR) 'dB)']);ylabel('幅值'); axis([0 max(time) -1 1]);subplot 313; plot(frameTime,Rum,'k');title('短时自相关函数余弦夹角值'); axis([0 max(time) 0 1]);xlabel('时间/s'); ylabel('幅值'); line([0,frameTime(fn)], [T1 T1], 'color','k','LineStyle','--');line([0,frameTime(fn)], [T2 T2], 'color','k','LineStyle','-');for k=1 : vsl % 标出语音端点 nx1=voiceseg(k).begin; nx2=voiceseg(k).end; fprintf('%4d %4d %4d\n',k,nx1,nx2); subplot 311; line([frameTime(nx1) frameTime(nx1)],[-1 1],'color','k','LineStyle','-'); line([frameTime(nx2) frameTime(nx2)],[-1 1],'color','k','LineStyle','--'); subplot 313; line([frameTime(nx1) frameTime(nx1)],[0 1.2],'color','k','LineStyle','-'); line([frameTime(nx2) frameTime(nx2)],[0 1.2],'color','k','LineStyle','--');end
11. MATLAB仿真十:语音信号方差法端点检测一
%% pr6_4_1 clear all; clc; close all;run Set_I % 基本设置run PART_I % 读入数据,分帧等准备Y=fft(y); % FFT变换N2=wlen/2+1;% 取正频率部分n2=1:N2;Y_abs=abs(Y(n2,:));% 取幅值for k=1:fn % 计算每帧的频带方差 Dvar(k)=var(Y_abs(:,k))+eps;enddth=mean(Dvar(1:NIS)); % 求取阈值T1=1.5*dth;T2=3*dth;[voiceseg,vsl,SF,NF]=vad_param1D(Dvar,T1,T2);% 频域方差双门限的端点检测% 作图subplot 311; plot(time,x,'k');title('纯语音波形');ylabel('幅值'); axis([0 max(time) -1 1]);subplot 312; plot(time,signal,'k');title('加噪语音波形(信噪比10dB)');ylabel('幅值'); axis([0 max(time) -1 1]);subplot 313; plot(frameTime,Dvar,'k');title('短时频带方差值'); grid; ylim([0 1.2*max(Dvar)]);xlabel('时间/s'); ylabel('幅值'); line([0,frameTime(fn)], [T1 T1], 'color','k','LineStyle','--');line([0,frameTime(fn)], [T2 T2], 'color','k','LineStyle','-');for k=1 : vsl % 标出语音端点 nx1=voiceseg(k).begin; nx2=voiceseg(k).end; fprintf('%4d %4d %4d\n',k,nx1,nx2); subplot 311; line([frameTime(nx1) frameTime(nx1)],[-1 1],'color','k','LineStyle','-'); line([frameTime(nx2) frameTime(nx2)],[-1 1],'color','k','LineStyle','--'); subplot 313; line([frameTime(nx1) frameTime(nx1)],[0 1.2*max(Dvar)],'color','k','LineStyle','-'); line([frameTime(nx2) frameTime(nx2)],[0 1.2*max(Dvar)],'color','k','LineStyle','--');end
12. MATLAB仿真十一:语音信号方差法端点检测二
%% pr6_4_2 clear all; clc; close all;run Set_I % 基本设置run PART_I % 读入数据,分帧等准备Y=fft(y); % FFT变换N2=wlen/2+1;% 取正频率部分n2=1:N2;Y_abs=abs(Y(n2,:));% 取幅值M=fix(N2/4);% 计算子带数for k=1 : fn for i=1 : M % 每个子带中有4条谱线 j=(i-1)*4+1; SY(i,k)=Y_abs(j,k)+Y_abs(j+1,k)+Y_abs(j+2,k)+Y_abs(j+3,k); end Dvar(k)=var(SY(:,k)); % 计算每帧子带分离的频带方差endDvarm=multimidfilter(Dvar,10); % 平滑处理dth=mean(Dvarm(1:(NIS))); % 阈值计算T1=1.5*dth;T2=3*dth;[voiceseg,vsl,SF,NF]=vad_param1D(Dvarm,T1,T2);% 频域方差双门限的端点检测% 作图subplot 311; plot(time,x,'k');title('纯语音波形');ylabel('幅值'); axis([0 max(time) -1 1]);subplot 312; plot(time,signal,'k');title('加噪语音波形(信噪比10dB)');ylabel('幅值'); axis([0 max(time) -1 1]);subplot 313; plot(frameTime,Dvar,'k');title('短时均匀子带分离的频带方差值'); grid; ylim([0 1.2*max(Dvar)]);xlabel('时间/s'); ylabel('幅值'); line([0,frameTime(fn)], [T1 T1], 'color','k','LineStyle','--');line([0,frameTime(fn)], [T2 T2], 'color','k','LineStyle','-');for k=1 : vsl % 标出语音端点 nx1=voiceseg(k).begin; nx2=voiceseg(k).end; fprintf('%4d %4d %4d\n',k,nx1,nx2); subplot 311; line([frameTime(nx1) frameTime(nx1)],[-1 1],'color','k','LineStyle','-'); line([frameTime(nx2) frameTime(nx2)],[-1 1],'color','k','LineStyle','--'); subplot 313; line([frameTime(nx1) frameTime(nx1)],[0 1.2*max(Dvar)],'color','k','LineStyle','-'); line([frameTime(nx2) frameTime(nx2)],[0 1.2*max(Dvar)],'color','k','LineStyle','--');end
13. MATLAB仿真十二:语音信号方差法端点检测三
%% pr6_4_3 clear all; clc; close all;run Set_I % 基本设置run PART_I % 读入数据,分帧等准备% BARK子带参数表Fk=[50 20 100; 150 100 200; 250 200 300; 350 300 400; 450 400 510; 570 510 630; 700 630 770;... 840 770 920; 1000 920 1080; 1170 1080 1270; 1370 1270 1480; 1600 1480 1720; 1850 1720 2000;... 2150 2000 2320; 2500 2320 2700; 2900 2700 3150; 3400 3150 3700; 4000 3700 4400;... 4800 4400 5300; 5800 5300 6400; 7000 6400 7700; 8500 7700 9500; 10500 9500 12000;... 13500 12000 15500; 18775 15500 22050];% 插值fs2=fix(fs/2); y=y';for i=1:fn sourfft(i,:)=fft(y(i,:),wlen); % FFT变换 sourfft1(i,:)=abs(sourfft(i,1:wlen/2)); % 取正频率幅值 sourre(i,:)=resample(sourfft1(i,:),fs2,wlen/2); % 谱线内插end% 计算BARK滤波器个数for k=1 : 25 if Fk(k,3)>fs2 break endendnum=k-1;for i=1 : fn Sr=sourre(i,:);% 取一帧谱值 for k=1 : num m1=Fk(k,2); m2=Fk(k,3); % 求出BARK滤波器的上下截止频率 Srt=Sr(m1:m2); % 取来相应的谱线 Dst(k)=var(Srt); % 求笫k个BARK滤波器中的方差值 end Dvar(i)=mean(Dst); % 求各个BARK滤波器中方差值的平均值endDvarm=multimidfilter(Dvar,10); % 平滑处理dth=mean(Dvarm(1:(NIS))); % 阈值计算T1=1.5*dth;T2=3*dth;[voiceseg,vsl,SF,NF]=vad_param1D(Dvarm,T1,T2); % BARK子带的频带方差双门限的端点检测% 作图subplot 311; plot(time,x,'k');title('纯语音波形');ylabel('幅值'); axis([0 max(time) -1 1]);subplot 312; plot(time,signal,'k');title('加噪语音波形(信噪比10dB)');ylabel('幅值'); axis([0 max(time) -1 1]);subplot 313; plot(frameTime,Dvar,'k');title('短时BARK子带分离的频带方差值'); axis([0 max(time) 0 1.2*max(Dvar)]);xlabel('时间/s'); ylabel('幅值'); line([0,frameTime(fn)], [T1 T1], 'color','k','LineStyle','--');line([0,frameTime(fn)], [T2 T2], 'color','k','LineStyle','-');for k=1 : vsl % 标出语音端点 nx1=voiceseg(k).begin; nx2=voiceseg(k).end; fprintf('%4d %4d %4d\n',k,nx1,nx2); subplot 311; line([frameTime(nx1) frameTime(nx1)],[-1 1],'color','k','LineStyle','-'); line([frameTime(nx2) frameTime(nx2)],[-1 1],'color','k','LineStyle','--'); subplot 313; line([frameTime(nx1) frameTime(nx1)],[0 1.2*max(Dvar)],'color','k','LineStyle','-'); line([frameTime(nx2) frameTime(nx2)],[0 1.2*max(Dvar)],'color','k','LineStyle','--');end
14. MATLAB仿真十三:语音信号方差法端点检测四
%% pr6_4_4 clear all; clc; close all;run Set_I % 基本设置run PART_I % 读入数据,分帧等准备h=waitbar(0,'Running...'); % 设置运行程序进度条图,初始化set(h,'name','端点检测 - 0%'); % 设置本图的名称"端点检测"for i=1 : fn u=y(:,i);% 取第i帧数据 v=wavlet_barkms(u,'db2',fs); % 利用小波包分解获取17个BARK子带数据 num=size(v,1); for k=1 : num Srt=v(k,:); % 取得第k个BARK子带中的数据 Dst(k)=var(Srt); % 求第k个BARK子带中的方差值 end Dvar(i)=mean(Dst); % 对17个BARK子带计算方差平均 waitbar(i/fn,h) % 显示运行的百分比,用红条表示% 显示本图的名称"端点检测",并显示运行的百分比数,用数字表示 set(h,'name',['端点检测 - ' sprintf('%2.1f',i/fn*100) '%'])endclose(h) % 关闭程序进度条图Dvarm=multimidfilter(Dvar,10); % 平滑处理Dvarm=Dvarm/max(Dvarm); % 幅值归一化dth=mean(Dvarm(1:(NIS))); % 阈值计算T1=1.5*dth;T2=2.5*dth;[voiceseg,vsl,SF,NF]=vad_param1D(Dvarm,T1,T2);% 小波包BARK子带时域方差双门限的端点检测% 作图subplot 311; plot(time,x,'k');title('纯语音波形');ylabel('幅值'); axis([0 max(time) -1 1]);subplot 312; plot(time,signal,'k');title('加噪语音波形(信噪比10dB)');ylabel('幅值'); axis([0 max(time) -1 1]);subplot 313; plot(frameTime,Dvarm,'k');title('小波包短时BARK子带方差值'); axis([0 max(time) 0 1.2*max(Dvarm)]);xlabel('时间/s'); ylabel('幅值'); line([0,frameTime(fn)], [T1 T1], 'color','k','LineStyle','--');line([0,frameTime(fn)], [T2 T2], 'color','k','LineStyle','-');for k=1 : vsl % 标出语音端点 nx1=voiceseg(k).begin; nx2=voiceseg(k).end; fprintf('%4d %4d %4d\n',k,nx1,nx2); subplot 311; line([frameTime(nx1) frameTime(nx1)],[-1 1],'color','k','LineStyle','-'); line([frameTime(nx2) frameTime(nx2)],[-1 1],'color','k','LineStyle','--'); subplot 313; line([frameTime(nx1) frameTime(nx1)],[0 1.2*max(Dvarm)],'color','k','LineStyle','-'); line([frameTime(nx2) frameTime(nx2)],[0 1.2*max(Dvarm)],'color','k','LineStyle','--');end
function y=multimidfilter(x,m)a=x;for k=1 : m b=medfilt1(a, 5); a=b;endy=b;
小结
语音信号的端点检测即检测出有效语音段,排除非有效语音的干扰,从而实现更好的语音识别效果。本章从最基础的双门限检测,到双门限检测法的改进方法,相关法、方差法、谱距离法、谱熵法、能零比方法、能熵比方法、小波变换方法、EMD分解方法,最后对低信噪比时的语音信号也进行了一定的讨论与研究。
语音信号的端点检测属于语音信号进入下一步语音识别的基础,对本章内容感兴趣或者想充分学习了解的,建议去研习书中第六章节的内容。后期会对其中一些知识点在自己理解的基础上进行讨论补充,欢迎大家一起学习交流。
关于宋老师:宋知用——默默传授MATLAB与信号处理知识的老人家
本系列文章列表如下:
《MATLAB语音信号分析与合成(第二版)》:第2章 语音信号的时域、频域特性和短时分析技术
《MATLAB语音信号分析与合成(第二版)》:第3章 语音信号在其他变换域中的分析技术和特性
《MATLAB语音信号分析与合成(第二版)》:第4章 语音信号的线性预测分析
《MATLAB语音信号分析与合成(第二版)》:第5章 带噪语音和预处理
《MATLAB语音信号分析与合成(第二版)》:第6章 语音端点的检测(1)
《MATLAB语音信号分析与合成(第二版)》:第6章 语音端点的检测(2)
《MATLAB语音信号分析与合成(第二版)》:第7章 语音信号的减噪
《MATLAB语音信号分析与合成(第二版)》:第8章 基音周期的估算方法
《MATLAB语音信号分析与合成(第二版)》:第9章 共振峰的估算方法
《MATLAB语音信号分析与合成(第二版)》:第10章 语音信号的合成算法