双门限法语音端点检测(Python实现)

写在前面

花了几天时间写完了第一个视听觉信号处理的实验,其实还挺简单的,在这里分享一下。

本文介绍一下利用双门限法进行语音端点检测的方法,该方法主要利用了语音的短时能量短时过零率,关于这两个语音特征如何求解,前两篇文章已经介绍过了(短时能量短时过零率),这里就不详细介绍了。这篇文章的重点在双门限法的算法思想和实现过程。

先来解释一下什么叫端点检测

端点检测就是在一段包含语音的信号中,准确地确定语音的起始点和终止点,将语音段和非语音段区分开。我们知道,一段语音中,有静音部分和浊音部分,静音部分包括清音、噪音和无声(噪音可以归结到无声中),浊音部分和清音才是我们需要听的语音,因此,可以说只有这两部分才是对我们有用的语音。可以说,端点检测就是将这两部分区分出来。(注意,清音部分属于声音中的辅音,能量小,过零率高,一般是在浊音部分的前面)

算法介绍

算法简介

双门限法有三个阈值,前两个是语音能量的阈值,最后一个是语音过零率的阈值,至于为什么三个阈值却称为“双门限法”呢?我觉得这里的双门限不是指两个阈值,而是指,能量和过零率这两个时域特征。

至于为什么能用这两个特征来进行端点检测呢?最主要的原因就是:浊音的能量高于清音,清音的过零率高于无声部分。这样的话,我们就可以先利用能量,将浊音部分区分出来,再利用过零率,将清音也提取出来,就完成了端点检测。

算法步骤:

双门限法

  1. 第一步是取一个较高的短时能量作为阈值MH,利用这个阈值,我们就可以先分出语音中的浊音部分(如图,A1到A2区间)。本次实验的MH,我取的是所有帧的短时能量的平均数的一半(平均数我试过了,偏大,处理有问题)。
  2. 第二步是取一个较低的能量阈值ML,利用这个阈值,我们可以从A1,A2,向两端进行搜索,将较低能量段的语音部分也加入到语音段,进一步扩大语音段范围(如图所示,B1-B2之间还是语音段)。本次实验中,我首先计算语音前一段的静音部分的能量均值(前5帧),我将静音部分的能量均值和MH的平均数的一半作为ML。
  3. 第三步是利用短时过零率,短时过零率的阈值为Zs。由于语音的两端部分是辅音(也就是清音部分),也是语音中的一部分,但是辅音的能量与静音部分的能量一样低,但是过零率比静音部分高出很多。为了区分开二者,将利用短时能量区分完的语音段继续向两端进行搜索,短时过零率大于3倍Zs的部分,则认为是语音的清音部分。将该部分加入语言段,就是求得的语音段(如图C1-C2部分)。

至于为什么要这么设置这三个阈值,我只能告诉你,这是经验,或许你的比我设的更好

Python实现:

# 利用短时能量,短时过零率,使用双门限法进行端点检测
def endPointDetect(wave_data, energy, zeroCrossingRate) :
    sum = 0
    energyAverage = 0
    for en in energy :
        sum = sum + en
    energyAverage = sum / len(energy)

    sum = 0
    for en in energy[:5] :
        sum = sum + en
    ML = sum / 5                        
    MH = energyAverage / 4              #较高的能量阈值
    ML = (ML + MH) / 4    #较低的能量阈值
    sum = 0
    for zcr in zeroCrossingRate[:5] :
        sum = float(sum) + zcr             
    Zs = sum / 5                     #过零率阈值

    A = []
    B = []
    C = []

    # 首先利用较大能量阈值 MH 进行初步检测
    flag = 0
    for i in range(len(energy)):
        if len(A) == 0 and flag == 0 and energy[i] > MH :
            A.append(i)
            flag = 1
        elif flag == 0 and energy[i] > MH and i - 21 > A[len(A) - 1]:
            A.append(i)
            flag = 1
        elif flag == 0 and energy[i] > MH and i - 21 <= A[len(A) - 1]:
            A = A[:len(A) - 1]
            flag = 1

        if flag == 1 and energy[i] < MH :
            A.append(i)
            flag = 0
    print("较高能量阈值,计算后的浊音A:" + str(A))

    # 利用较小能量阈值 ML 进行第二步能量检测
    for j in range(len(A)) :
        i = A[j]
        if j % 2 == 1 :
            while i < len(energy) and energy[i] > ML :
                i = i + 1
            B.append(i)
        else :
            while i > 0 and energy[i] > ML :
                i = i - 1
            B.append(i)
    print("较低能量阈值,增加一段语言B:" + str(B))

    # 利用过零率进行最后一步检测
    for j in range(len(B)) :
        i = B[j]
        if j % 2 == 1 :
            while i < len(zeroCrossingRate) and zeroCrossingRate[i] >= 3 * Zs :
                i = i + 1
            C.append(i)
        else :
            while i > 0 and zeroCrossingRate[i] >= 3 * Zs :
                i = i - 1
            C.append(i)
    print("过零率阈值,最终语音分段C:" + str(C))
    return C

写在后面

具体的实现过程在这里,包括前两篇文章的能量和过零率的提取。

  • 22
    点赞
  • 194
    收藏
    觉得还不错? 一键收藏
  • 25
    评论
门限点检测是一种常用的信号处理算,用于检测信号中的边界点。以下是一段用Python实现门限点检测代码。 首先,我们需要导入必要的库: ```python import numpy as np import matplotlib.pyplot as plt ``` 然后,定义一个函数来实现门限点检测: ```python def double_threshold_detection(signal, low_threshold, high_threshold): low_indices = np.where(signal < low_threshold)[0] high_indices = np.where(signal > high_threshold)[0] start_indices = [low_indices[0]] end_indices = [] for i in range(1, len(low_indices)): if low_indices[i] - low_indices[i-1] > 1: start_indices.append(low_indices[i]) for i in range(0, len(high_indices)-1): if high_indices[i+1] - high_indices[i] > 1: end_indices.append(high_indices[i]) end_indices.append(high_indices[-1]) return start_indices, end_indices ``` 在这段代码中,我们指定了两个起始阈值:low_threshold和high_threshold。首先,我们使用np.where函数找到低于低阈值的索引和高于高阈值的索引。然后,我们根据低索引的连续性找到信号的起始位置,根据高索引的连续性找到信号的结束位置。最后,我们将起始位置和结束位置作为结果返回。 接下来,我们可以使用这段代码来检测一个示例信号的边界点: ```python # 定义一个示例信号 signal = np.array([1, 2, 3, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6, 5, 4, 3, 2]) # 调用门限点检测函数 start_indices, end_indices = double_threshold_detection(signal, 1, 4) # 绘制信号及检测结果 plt.plot(signal) plt.scatter(start_indices, [signal[i] for i in start_indices], color='r') plt.scatter(end_indices, [signal[i] for i in end_indices], color='g') plt.show() ``` 以上代码将绘制这段示例信号,并在检测到的起始位置处用红色圆点标记,结束位置处用绿色圆点标记。 这就是门限点检测Python代码实现
评论 25
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值