一般而言,端点检测定义为从连续音频信号中检测出实际语音片段的起始点和终止点,从而提取出有效的语音片段,排除噪声等其他非语音信号的干扰,为后续语音处理系统提供可靠的语音信号;同时,语音端点检测去除了不必要的非语音片段,减少了后续语音处理系统的计算压力,有利于提高系统的响应速度。
对于语音处理,有必要简单了解一下简单的知识点,语音可粗略分为清音和浊音两大类:
- 浊音:在时域上呈现出明显的周期性,在频域上出现共振峰且能量大部分集中在较低频段内。
- 清音:相对于很大一类噪声没有明显的时域和频域特征,类似于白噪声。
一般情况下,语音信号是一种典型的非平稳信号,但是我们认为人说话是突然的,即:语音信号可假定为短时平稳的(10-30ms);因此在对语音信号进行分析时,需要将语音信号以10-30ms的间隔将连续的音频信号截取成一段一段来进行分析。
# 常见端点检测特征分类及处理过程
特征分类
时域特征:
- 短时能量:音信号的能量随着时间变化比较明显,一般清音部分的能量比浊音的能量小的多,所以在区分清音和浊音,有声段和无声段的应用中效果比较明显。
- 短时过零率:表示一帧语音中语音信号波形穿过横轴(零电平)的次数。它可以用来区分清音和浊音,这是因为语音信号中的高频段有高的过零率,低频段过零率较低
- 自相关函数、基频等
频域特征:
- 倒谱距离、 频率方差、谱熵等
一般算法处理过程
- 预处理:通常包括分帧和预滤波等。
- 分帧是指将语音信号分段(称为语音帧,各帧通常是有交叠的)
- 预滤波一般是指采用高通滤波器滤除低频噪声
- 特征提取
- 能量、过零、频谱这些常见的特征
- 端点判决:是指采用一种判决准则(如门限判决或模式分类等)来区分语音帧与非语音帧;
- 短时特征判别
- 模板匹配
- 后处理:是指对上述判决结果进行间断检测,得到最终的语音端点判决结果。
# 语音信号预处理原理
预加重
由于语音信号的平均功率谱受声门激励和口鼻辐射的影响,高频端大约在800Hz以上按6dB/倍频程跌落,而有效的语音信号能量一般集中在60~3400Hz频段,所以求语音信号频谱时,频率越高相应的成分越小,高频部分的频谱比低频部分的难求,为此要在预处理中进行预加重(Pre-emphasis)处理.
预加重的目的是提升高频部分,使信号的频谱变得平坦,保持在低频到高频的整个频带中,能用同样的信噪比求频谱,以便于频谱分析或声道参数分析.预加重可在语音信号数字化时在反混叠滤波器之前进行,这样不仅可以进行预加重,而且可以压缩信号的动态范围,有效地提高信噪比.但预加重一般是在语音信号数字化之后,在参数分析之前在计算机里用6dB/倍频程的提升高频特性的预加重数字滤波器来实现,一般:
滤波器的传递函数为:
反变换后在时域上的形式为:
其中 : 脉冲响应 u: 一般取接近于 1 的值
由于我们需要自己将预加重的程序实现,那么这种表达方法还不完整,接下去还需要简单推导,由以上时域表达形式,那么对于离散信号来说,只需要:
用单位样本输入的响应来表征,即用输入x[n]与单位响应h[n]作卷积
式中:* 表示卷积运算操作,下面操作与上面等效
利用卷积的运算规则,计算出响应表达式如下:
C++ 示例代码
/*
* 函数功能:一阶滤波器 H(Z) = 1-uZ^{-1}
* 离散卷积响应表示:
* y[n] = x[n] - ux[n-1]
* 参数说明:
* des:计算结果存放
* src: 原始音频采样
* u: 调节因子(一般接近于0)
* */
static void preEmphasis(audio_msgs::AudioData &des,const audio_msgs::AudioData &src,float u=_u){
for(int i=0;i<des.data_size;i++){
if(i==0){
des.data[i] = src.data[i];
}else{
des.data[i] = src.data[i] - src.data[i-1] * u;
}
}
}
分帧与加窗
对于一般的语音信号分析,这个环节必不可少。下面简单了解相关处理术语:
-
加窗分帧:这很容易理解,即使用一个窗口将音频信号分成一段一段的,可以连续分段,但一般推荐使用交叠分段方法,这是为了使帧与帧之间平滑过度。
-
帧移:前一帧与后一帧交叠部分,一般取 0~1/2
-
加窗函数:对语音处理来说,短时分析的方法是有效的解决途径。就是用一个长度有限的窗序列(w(m)}截取一段语音信号来进行分析,并让这个窗滑动以便分析任一时刻附近的信号,即加窗函数。容易理解,对于一段音频信号,其中包括不同的频率的采样值,若能够对其中的每个采样点进行权重处理,就相当于滤除一部分频率的信号,这样我们需要的信号就会更加明显,方便我们分析。常见的窗函数有:矩形窗和汉明窗等
解析:因为声音信号在10–30ms内具有短时平稳性,选择帧长在20–30ms,例如一帧里面有160个采样点,且通道数为1,采样率为8K:那么帧长就是:160×1/8000=20ms。帧移为10ms。
窗函数的定义
一般对于采样得到原始信号后,我们会将得到的信号与窗函数进行卷积运算,以便给每个采样点设置不同的权重,从而达到一定的滤波效果。具体实现形式如下:
其中:
:加窗语音信号 ; :为窗口函数
:原始音频信号 ; n: 窗口长度
比较常用的窗口函数分别为:
矩形窗
汉明窗
下面就汉民窗的数学定义用C++实现说明
C++ 示例代码
std::vector<SampleType> source;
source.reserve(size);
for (std::size_t n = 0; n < size; ++n)
{
source.push_back(
0.53836 - 0.46164 * std::cos(2.0 * M_PI * n / double(size - 1))
);
}
简单理解就是使用一个容器来存放对应的乘积结果,当使用时就可以直接访问容器的内容就好了。
# 特征提取
对于选取哪种特征来进行分析,不同的平台与不同的环境可以采取不同的策略。一般来说,对于嵌入式设备这种处理能力受到限制的平台,时域分析压力比较小。但就现在的趋势,拥有较强处理能力的嵌入式设备价格不再是太大的问题,所以将信号进行频域转换分析也是可行的。不过,能够做到在尽量少的运算得到尽量高的准确率肯定都是大家追求的。本文只对提取简单的特征作相应的分析,如能量与过零,其它比较繁琐特征的不做详细讨论。
短时能量
其中:
根据上方定义,为编程方便,暂时使用矩形窗口来实现分帧,且帧移为零。后续如果没有达到满意的实验效果再来添加处理方法不迟。为计算方便,我们使用对数形式减少数值的大小,统一取对数如下所示:
短时过零
其中sgn(x)为符号函数:
上面两个特征的定义相对简单,编程实现也比较容易。不过为了方便与统一说明,这里采用C++的信号处理库Aquila对函数实现进行简单说明,这里将要列举了能量的计算,对于过零也相对简单,可以自行设计。而对于频谱特征提取,这里不多说,若有兴趣了解的,可以使用Aquila库进行开发。
C++ 示例代码
/*
* 函数功能:统计对数能量
* 参数说明:
* 返回值:对数能量
* */
float FeatureSet::logEnergy()
{
float energy = 0.0;
std::vector<double>::iterator iter = m_data.begin();
for(int j=0;j<m_data.size();j++)
{
energy += ( ( iter[j]*iter[j] ));
}
return log(energy);
}
这里面传递进去的是一个信号对象,其里面具体运算过程实际上是取对存放在对象里面的信号值进行运算而已。
一般来说,当算法执行到特征提取这个步骤时才算是VAD检测算法的开始,如何才能判定是语音信号的端点呢?具体如何做?若根据开始提到的算法流程,只要再搜索相关资料,实现较为简单的双阈值判决算法并不会太难。接下来会在另一篇博文中具体描述如何使用ROS设计VAD检测的节点。