基于Matlab编写的语音端点检测
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
基于Matlab编写的语音端点检测
专业:
班级:
姓名:
指导教师:
2011 年6月18 日
一、实验目的
1.学会MATLAB的使用,掌握MATLAB的程序设计方法;
3.掌握语音处理的基本概念、基本理论和基本方法;
4.掌握基于MATLAB编程实现带噪语音信号端点检测;
5.学会用MATLAB对信号进行分析和处理。
二、实验内容简介:
(1)采集一段语音信号,采样率为8KHZ,量化精度为16比特线性码;
(2)分析帧长30ms(或10ms~50ms);
(3)利用公式分别计算这段语音信号的短时能量、短时平均幅度、短时过零率曲线;
(4)利用(3)中的结果画出短时零能比曲线;(零能比: 即同一时间段内的过零率和能量的比值)
(5)根据上述结果判断找出其中的一帧浊音信号和一帧清音信号,分别计算他们的短时自相关函数和平均幅度差函数;
(6)调整能量门限,设置参数。
实现语音端点的检测。
三,实验心得
这次的实验,,给我最大的收获就是培养了独立思考和动手的能力,还有就是实验的灵活性,总得来说就是在独立与创新这二个环节,我更加掌握MATLAB 的程序设计方法,进一步的了解了掌握基于MATLAB编程实现带噪语音信号端点检测的原理,这充分锻炼了我们独立的动手能力和独立的解决所遇到的问题,让我对这门课程又有了新的理解。
四.课程设计原理
端点检测是语音信号处理过程中非常重要的一步,它的准确性直接影响到语音信号处理的速度和结果,因此端点检测方法的研究一直是语音信号处理中的热点。
本设计使用传统的短时能量和过零率相结合的语音端点检测算法利用短时过
零率来检测清音.用短时能量来检测浊音,两者相配合便实现了信号信噪比较大情况下的端点检测。
算法对于输入信号的检测过程可分为短时能量检测和短时过零率检测两个部分。
算法以短时能量检测为主,短时过零率检测为辅。
根据语音的统计特性,可以把语音段分为清音、浊音以及静音(包括背景噪声)三种。
在本算法中,短时能量检测可以较好地区分出浊音和静音。
对于清音,由于其能量较小,在短时能量检测中会因为低于能量门限而被误判为静音;短时过零率则可以从语音中区分出静音和清音。
将两种检测结合起来,就可以检测出语音段(清音和浊音)及静音段
1、短时能量计算
定义n 时刻某语音信号的短时平均能量n E 为:
∑∑--=+∞-∞=-=-=
n N n m m n m n w m x m n w m x E )1(22)]()([)]()([
式中N 为窗长,可见短时平均能量为为一帧样点值的甲醛平方和。
特殊地,当窗函数为矩形窗时,有
∑--==
n N n m n m x E )1(2)(
2、短时过零率
过零就是指信号通过零值。
过零率就是每秒内信号值通过零值的次数。
对于离散时间序列,过零则是指序列取样值改变符号,过零率则是每个样本的改变符号的次数。
对于语音信号,则是指在一帧语音中语音信号波形穿过横轴(零电平)的次数。
可以用相邻两个取样改变符号的次数来计算。
如果窗的起点是n=0,短时过零率Z 为
波形穿过横轴(零电平)的次数
短时过零可以看作信号频率的简单度量
浊音的短时平均幅度最大,无声的短时平均幅度最小,清音的短时过零率最大,无声居中,浊音的短时过零率最小。
3、短时自相关函数
∑-=--=1
00))1(())((21N n w w n S Sgn n S Sgn Z ∑--=+=1
0)
()()(k N n w w w k n s n s k R ⎩⎨⎧<-≥=0
,10,1)sgn(x x x
1、是偶函数;
2、s(n)是周期的,那么R(k)也是周期的;
3、可用于基音周期估计和线性预测分析
4、判断语音信号的起点和终点
利用短时平均幅度和短时过零率可以判断语音信号的起点和终点。
语音端点检测方法可采用测试信号的短时能量或短时对数能量、联合过零率等特征参数,并采用双门限判定法来检测语音端点,即利用过零率检测清音,用短时能量检测浊音,两者配合。
首先为短时能量和过零率分别确定两个门限,一个是较低的门限数值较小,对信号的变化比较敏感,很容易超过;另一个是比较高的门限,数值较大。
低门限被超过未必是语音的开始,有可能是很短的噪声引起的,高门限被超过并且接下来的自定义时间段内的语音超
首先,可根据浊语音情况下短时平均幅度M的概率密度函数P(M/V)确定一个阈值参数MH, MH的值定得比较高。
当一帧输入信号的M值超过MH 时,就可以十分肯定该帧语音信号不是无声,而有相当大的可能性是浊音由N1’向前和N2’向后继续用短时过零率Z进行搜索。
根据无声情况下短时过零率Z的均值,设置一个参数Z0,如果由N1’向前搜索时Z始终大于Z0的3倍,则认为这些信号仍属于语音段,直至Z突然下降到低于3Z0值时,这时可以确定语音的精确起点(为了保证可靠,由N1’向前搜索时间不超过25ms)。
对终点做同样的处理。
采取这一算法的原因在于,N1’以前可能是一段清辅音段(如f,s),它的能量相当弱,依靠能量不可能把他们与无声段区别开,而他们的过零率明显高于无声,因而能用这个参数来精确的判断二者的分割点,也就是语音真正的起点。
四、实验步骤:
(1)用cooledit录了一段音,是我自己说的。
采样率为8KHZ,量化精度为16比特线性码。
(2)利用滤波器对信号进行带通滤波,这样可除去大部分共振峰的影响(3)利用公式分别编程计算这段语音信号的短时能量、短时平均幅度、短时过零率,然后分别画出它们的曲线;
(4)然后画出短时零能比曲线。
(5)根据上述结果判断找出其中的一帧浊音信号和一帧清音信号。
判断依据是,浊音:短时能量大、短时平均幅度大、短时过零率低;清音:短时能量小、
短时平均幅度小、短时过零率高。
浊音,取13270--13510个点,清音,取
12120--12360个点。
分别计算他们的短时自相关函数和平均幅度差函数;
(6)调整能量门限,设置参数,实现语音端点的检测。
五、实验结论分析:
(1)从图中明显可以看出,浊音信号的具有明显的周期性,其自相关函数和平均幅度差函数也表现出周期性。
清音信号稍微差一点,但不是很明显,主要是由于清音信号的位置找的不是很好。
(2)浊音:短时能量大、短时平均幅度大、短时过零率低;清音:短时能量小、短时平均幅度小、短时过零率高。
(3)门限值的选取对语音检测结果有很大影响。
(4)仅仅根据能量判断是比较粗糙的,还需根据过零率进行判断。
因为清音和噪声的短时平均过零率比背景噪声的平均过零率要高出好几倍。
附源代码:
N=240
[Y]=wavread('lailigen.wav',[1 18000]);
L=length(Y)
LL=length(Y)/N figure(1)
set(1,'Position',[10,35,350,650])
Em=zeros(1,(LL-1)*240);
for ii=1:(LL-1)*240,
temp=Y(ii:ii+240);
Em(ii)=sum(temp.*temp);
end
subplot(4,1,1)
jj=[1:(LL-1)*240];
plot(jj, Em,'b');
title('¶ÌʱÄÜÁ¿')
grid
Mn=zeros(1,(LL-1)*240);
for ii=1:(LL-1)*240,
temp=Y(ii:ii+240);
Mn(ii)=sum(abs(temp))/N;
end
figure(1)
subplot(4,1,2)
jj=[1:(LL-1)*240];
plot(jj, Mn,'b');
title('¶Ìʱƽ¾ù·ù¶È')
grid
Zn=zeros(1,(LL-1)*240);
for ii=2:(LL-1)*240,
temp1=sign(Y(ii:ii+240));
temp=sign(Y(ii-1:ii+240-1));
Zn(ii)=sum(abs(temp1-temp));
end
figure(1)
subplot(4,1,3)
jj=[1:(LL-1)*240];
plot(jj, Zn,'b');
title('¶Ìʱ¹ýÁãÂÊ')
grid
figure(1)
subplot(4,1,4)
jj=[1:(LL-1)*240];
plot(jj, Zn./Em,'b');
title('ÁãÄܱÈÇúÏß')
grid
temp=Y(13271:13510);%
Rn1=zeros(1,240);
for nn=[1:240],
for ii=[1:240-nn],
Rn1(nn) =Rn1(nn)+ temp(ii)*temp(nn+ii);
end
end
figure(2)
set(2,'Position',[400,35,350,650])
subplot(4,1,1)
jj=[1:240];
plot(jj, Rn1,'b');
title('×ÇÒô¶Ìʱ×ÔÏà¹Øº¯Êý')
grid
Yn1=zeros(1,240);
for nn=[1:240],
for ii=[1:240-nn],
Yn1(nn) =Yn1(nn)+ abs(temp(ii)-temp(nn+ii));
end
end
figure(2)
subplot(4,1,2)
jj=[1:240];
plot(jj, Yn1,'b');
title('×ÇÒô¶Ìʱƽ¾ù·ù¶È²î')
grid
temp=Y(12121:12360);
Rn2=zeros(1,240);
for nn=[1:240],
for ii=[1:240-nn],
Rn2(nn) =Rn2(nn)+ temp(ii)*temp(nn+ii);
end
end
figure(2)
subplot(4,1,3)
jj=[1:240];
plot(jj, Rn2,'b');
title('ÇåÒô¶Ìʱ×ÔÏà¹Ø')
grid
Yn2=zeros(1,240);
for nn=[1:240],
for ii=[1:240-nn],
Yn2(nn) =Yn2(nn)+ abs(temp(ii)-temp(nn+ii));
end
end
figure(2)
subplot(4,1,4)
jj=[1:240];
plot(jj, Yn2,'b');
title('ÇåÒô¶Ìʱƽ¾ù·ù¶È²î')
grid
[x,fs,nbits]=wavread('lailigen.wav');
x = x / max(abs(x));
FrameLen = 256;
inc =90;
amp1 = 10;
amp2 = 2;
zcr1 = 10;
zcr2 = 5;
minsilence = 6;
minlen = 15;
status = 0;
count = 0;
silence = 0;
amp=Em;
zcr=Mn;
amp1 = min(amp1, max(amp)/4);
amp2 = min(amp2, max(amp)/8);
for n=1:length(zcr)
goto = 0;
switch status
case {0,1}
if amp(n) > amp1
x1 = max(n-count-1,1);
status = 2;
silence = 0;
count = count + 1;
elseif amp(n) > amp2 || zcr(n) > zcr2
status = 1;
count = count + 1;
else
status = 0;
count = 0;
end
case 2,
if amp(n) > amp2 ||zcr(n) > zcr2
count = count + 1;
else
silence = silence+1;
if silence < minsilence
count = count + 1;
elseif count < minlen
status = 0;
silence = 0;
count = 0;
else
status = 3;
end
end
case 3,
break;
end
end
count = count-silence/2;
x2 = x1 + count -1;
figure(3)
subplot(3,1,1)
plot(x)
axis([1 length(x) -1 1])
ylabel('Speech');
line([x1*inc x1*inc], [-1 1], 'Color', 'red');
line([x2*inc x2*inc], [-1 1], 'Color', 'red'); subplot(3,1,2)
plot(amp);
axis([1 length(amp) 0 max(amp)])
ylabel('Energy');
line([x1 x1], [min(amp),max(amp)], 'Color', 'red'); line([x2 x2], [min(amp),max(amp)], 'Color', 'red'); subplot(3,1,3)
plot(zcr);
axis([1 length(zcr) 0 max(zcr)])
ylabel('ZCR');
line([x1 x1], [min(zcr),max(zcr)], 'Color', 'red'); line([x2 x2], [min(zcr),max(zcr)], 'Color', 'red');。