wjchen

Never lose a holy curiosity.

单通道语音增强之谱减法与维纳滤波

31 Oct 2019 » 语音


本文代码位于GitHub

1. 概述

单通道语音增强比较传统的方法是谱减法和维纳滤波, 在平稳噪声的条件下,能够获得较理想的去噪效果。 《语音增强–理论与实践》[@loizou2007speech]里面各有一章详细分析了这两种模型。

假设麦克风采集到的带噪语音序列为$y[n]$,并且噪声都是加性噪声。则带噪语音序列为无噪语音序列与噪声序列的和。 原始语音信号与噪声均可视为随机信号。

常用的语音增强方法都是在频域,需要对带噪信号$y[n]$进行分帧、加窗、短时傅里叶变换(STFT)后,得到每一帧的频域信号,其中X,Y,D分别是干净语音、带噪信号和噪声的频域信号。

语音增强的目标是对实际信号$X(\omega_{k})$的幅度和相位进行估计。但是因为相位不易估计、而且研究表明相位对去噪效果影响比较小[@wang1982unimportance],所以大部分方法都只对幅度谱进行增强,而相位则沿用带噪信号的相位。

换句话说,语音增强就是要找出一个频域的实函数$H_{\omega_{k}}$, 并且将这个函数与带噪信号相乘,得到干净语音的估计。这个实函数称作抑制增益(Suppression Gain)。

下面是单通道语音增强系统主要步骤的示意图,系统目标就是估计抑制增益,而抑制增益依赖于两个核心步骤:语音检测VAD和噪声估计模块。只有准确估计噪声谱$D(\omega_{k})$,才有可能准确估计抑制增益。 详细的VAD和噪声估计方法不在这篇文章里面详述,具体可以看参考文献。 一种简单的想法是先估计出VAD,如过判断此帧没有语音,则更新噪声谱,否则就沿用上一帧的噪声谱。

Fig.1 - 单通道语音增强统计模型流程图


综上,语音增强的典型流程就是:

  1. 对带噪语音y[n]分帧, 每一帧进行DFT得到$Y(\omega_{k})$。

  2. 利用$Y(\omega_{k})$进行VAD检测和噪声估计。

  3. 计算抑制增益$H_{k}$。

  4. 抑制增益$H_{k}$与带噪信号谱相乘,得到纯净语音谱$\hat{X}(\omega_{k})$。

  5. 对$\hat{X}(\omega_{k})$进行IDFT,得到纯净语音序列的估计$x[n]$。

噪声估计模块可以估计噪声功率,也可以估计信噪比,避免信号幅度变化带来的误差。 定义后验信噪比:

定义先验信噪比:

2. 谱减法 Spectral Subtraction

谱减法是最直观的去噪声思想,就是带噪信号减去噪声的频谱,就等于干净信号的频谱。估计信号频谱的表达式如下,其中$\hat{D}(\omega_{k})$应是噪声估计模块得到的噪声频谱。

传统的语音增强算法都不恢复准确的相位,而是沿用测量信号$Y(\omega_{k})$的相位,所以实际谱减法的公式为幅度谱相减:

其中$\hat{D}(\omega_{k})$是估计的噪声幅值。 最终增益函数为

从幅度谱角度做谱减,是架设了测量信号和噪声的相位一样,引入了较大失真。 从功率谱角度做谱减,是更常用的方法。

假设语音信号与噪声不相关,于是得到估计的信号功率谱是测量信号功率谱减去估计的噪声功率谱。

因此抑制增益函数即为:

用后验信噪比表示:

用先验信噪比表示:

	def spec_sub_gain(parameters=None):
		ksi = parameters['ksi']
		gain = np.sqrt( ksi / (1+ ksi)) # gain function
		return gain

3.1 维纳滤波 Wiener Filtering

维纳滤波的思想也很直接,就是将带噪信号经过线性滤波器变换来逼近原信号,并求均方误差最小时的线性滤波器参数。 维纳滤波可以是在时域推导,也可以在频域推导。如第一部分所介绍,语音增强系统通常在频域处理信号,所以下面只讨论频域维纳滤波。

Fig.2 - 线性滤波器进行语音增强


频域上,估计信号即为线性滤波器与输入信号的乘积。可见这个滤波器$H(\omega_{k})$正是我们要求的抑制增益函数。维纳滤波语音增强的目标就是寻找系数为实数的线性滤波器,使得滤波偶信号与原干净语音信号之间的均方误差最小。

均方误差为:

这是一个优化问题,目标是求使得均方误差最小的参数$H$

展开均方误差:

对$H(\omega_{k})$求极值:

得到极值点:

求共轭后得到$H(\omega_{k})$:

$P_{xy}$是互功率,X与D不相关, $E\left[X(\omega_{k})D(\omega_{k})^*\right]=0$, 那么

带噪信号功率$P_{yy}$也可以展开为语音信号和噪声功率之和。

用先验信噪比表示

用后验信噪比表示:

	def wiener_gain(parameters=None):
		ksi = parameters['ksi']
		gain = ksi / (1+ ksi) # gain function
		return gain

参考文献

[1] P. C. Loizou, Speech enhancement: theory and practice. CRC press, 2007.

[2] D.Wang and J. Lim, The unimportance of phase in speech enhancement,” IEEE Transactions on Acoustics, Speech, and Signal Processing, vol. 30, no. 4, pp. 679-681, 1982.