语音端点检测之双门限法(python版)

1.短时能量


1.1 短时能量
设第 n 帧语音信号 x n ( m ) 的短时能量用 E n 表示,则其计算公式如下:

En 是一个度量语音信号幅度值变化的函数,但它有一个缺陷,即它对高电平非常敏感

(因为它计算时用的是信号的平方)。

补充:短时能量的作用

1、短时能量可以区分清音和浊音,因为浊音的能量要比清音的大得多;
清音:释义是轻柔的声音;发音时声带不振动的音,如p、t、k (pa, te , ke)
浊音:将发音时声带振动的音称为浊音,如b、d、g (ba, de, ge)
2、对声音段和无声段进行判定;
3、对声母和韵母分界;
4、连字的分界等。


2.短时过零率

短时过零率表示一帧语音中语音信号波形穿过横轴(零电平)的次数。

        对于连续语音信号,过零即意味着时域波形通过时间轴;

        而对于离散信号,如果相邻的取样值改变符号则称为过零。

因此,过零率就是样本改变符号的次数。

 


3. 双门限法

在双门限算法中,短时能量检测可以较好地区分出浊音和静音。(前面说过)

对于清音,由于其能量较小,在短时能量检测中会因为低于能量门限而被误判为静音;

短时过零率则可以从语音中区分出静音和清音。将两种检测结合起来,就可以检测出语音段(清音和浊音)及静音段。

在基于短时能量和过零率的双门限端点检测算法中首先为短时能量和过零率分别确定两个门限,一个为较低的门限,对信号的变化比较敏感,另一个是较高的门限。当低门限被超过时,很有可能是由于很小的噪声所引起的,未必是语音的开始,当高门限被超过并且在接下来的时间段内一直超过低门限时,则意味着语音信号的开始。


4.双门限法实现步骤

1)计算信号的短时能量和短时平均过零率;

2)根据语音能量的轮廓选取一个较高的门限 T2,语音信号的能量包络大部分都在此门限之上,这样可以进行一次初判。

语音起止点位于该门限与短时能量包络交点 N3 N4 所对应的时间间隔之外;

3)根据背景噪声的能量确定一个较低的门限 T1,并从初判起点往左,从初判终点往

右搜索,分别找到能零比曲线第一次与门限 T1,相交的 2 个点 N2 N5,于是 N2  N5 段就是 用双门限方法所判定的语音段;

4)以短时平均过零率为准,从 N2 点往左和 N5 往右搜索,找到短时平均过零率低于

某阈值 T3 的两点 N1 N6,这便是语音段的起止点。

注意:门限值要通过多次实验来确定,门限都是由背景噪声特性确定的。语音起始段的

复杂度特征与结束时的有差异,起始时幅度变化比较大,结束时,幅度变化比较缓慢。在进

行起止点判决前,通常都要采集若干帧背景噪声并计算其短时能量和短时平均过零率,作为

选择 M1 M2 的依据

 

 

from speechlib import *
(fs, data) = wavfile.read('C4_1_y.wav')#fs 采样频率
data1 = data/np.max(np.abs(data))                # 幅值归一化

N = len(data1)
wlen = 200 #分帧长度
inc = 80#:帧移
IS = 0.1
overlap = wlen - inc
NIS = int((IS * fs - wlen) // inc + 1) # 无声段的帧数,用来计算阈值
fn = (N - wlen) // inc + 1 #总帧数

frameTime = FrameTimeC(fn, wlen, inc, fs) #计算分帧后,每一帧对应的时间。
time = [i / fs for i in range(N)]

voiceseg, vsl, SF, NF, amp, zcr = vad_TwoThr(data1, wlen, inc, NIS)
#双门限法函数
#名称:vad_TwoThr
#功能:用双门限法进行端点检测。
#调用格式:[voiceseg,vsl,SF,NF,amp,zcr]=vad_TwoThr(x,wlen,inc,NIS)
#说明:输入参数 x 是输入的语音数据;wlen 是帧长;inc 是帧移;
# NIS 是无声段的帧数,用来计算阈值。输出参数 voiceseg 是一个数据结构,记录了语音端点的信息;
# vsl 是 voiceseg的长度;SF 是语音帧标志(SF=1 表示该帧是语音段);
# NF 是噪声/无声帧标志(NF=1 表示该帧是噪声/无声段);amp 是返回的短时能量,zcr 是返回的短时过零率。
plt.subplot(3, 1, 1)
plt.plot(time, data1)
plt.title('双门限法的端点检测')
plt.ylabel('幅值')
plt.xlabel('时间/s')

plt.subplot(3, 1, 2)
plt.plot(frameTime, amp)#amp 是返回的短时能量
plt.title('短时能量')
plt.ylabel('幅值')
plt.xlabel('时间/s')

plt.subplot(3, 1, 3)
plt.plot(frameTime, zcr)#zcr 是返回的短时过零率
plt.title('短时过零率')
plt.ylabel('幅值')
plt.xlabel('时间/s')

for i in range(vsl):
    nx1=voiceseg[i]['start']
    nx2=voiceseg[i]['end']
    plt.subplot(3, 1, 1)
    plt.axvline(frameTime[nx1], np.min(data1), np.max(data1), color='blue', linestyle='--')
    plt.axvline(frameTime[nx2], np.min(data1), np.max(data1), color='red', linestyle='-')
    plt.legend(['波形', '起点', '终点'])

    plt.subplot(3, 1, 2)
    plt.axvline(frameTime[nx1], np.min(amp), np.max(amp), color='blue', linestyle='--')
    plt.axvline(frameTime[nx2], np.min(amp), np.max(amp), color='red', linestyle='-')
    plt.legend(['短时能量', '起点', '终点'])

    plt.subplot(3, 1, 3)
    plt.axvline(frameTime[nx1], np.min(zcr), np.max(zcr), color='blue', linestyle='--')
    plt.axvline(frameTime[nx2], np.min(zcr), np.max(zcr), color='red', linestyle='-')
    plt.legend(['短时过零率', '起点', '终点'])

plt.show()

5.代码解释补充:

matplotlib.pyplot.axvline()

此函数在绘图轴上添加垂直线

用法:

matplotlib.pyplot.axvline(x=0, ymin=0, ymax=1, **kwargs)

参数:
x:数据坐标中的x位置以放置垂直线
ymin:y轴上的垂直线起始位置,它将取0到1之间的值,0是轴的底部,1是轴的顶部
ymax:y轴上的垂直线结束位置,它将取0到1之间的值,0是轴的底部,1是轴的顶部
**kwargs:其他可选参数可更改线的属性,例如
改变颜色,线宽等

https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.axvline.html 函数官网解释

6.运行结果

 

 

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值