上篇(webRTC中语音降噪模块ANS细节详解(一))讲了维纳滤波的基本原理。本篇先给出webRTC中ANS的基本处理过程,然后讲其中两步(即时域转频域和频域转时域)中的一些处理细节。
ANS的基本处理过程如下图1:
图1
从图1可以看出,处理过程主要分6步,具体如下:
1) 把输入的带噪信号从时域转到频域,主要包括分帧、加窗和短时傅里叶变换(STFT)等
2) 做初始噪声估计,基于估计出的噪声算先验信噪比和后验信噪比
3) 计算分类特征,这些特征包括似然比检验(LRT)、频谱平坦度和频谱差异。根据这些特征确定语音/噪声概率,从而判定当前信号是语音还是噪声。
4) 根据算出来的语音/噪声概率去更新噪声估计
5) 基于维纳滤波去噪
6) 把去噪后的信号从频域转换回时域,主要包括短时傅里叶逆变换(ISTFT)、加窗和重叠相加等。
我用于理解和调试的版本是以前的C版本,里面又分为浮点和定点两种实现方式。对于算法理解来说,最好看浮点实现的版本,因为它能和算法原理中的数学表达式很好的联系起来。定点实现中有很多诸如定标等工程实现上的技巧,跟数学表达式很难直接联系。部署时如有load等制约因素,最好用定点的实现,因为通常定点实现的load比浮点实现的小不少。ANS支持8k/16k/32k HZ等三种采样率。对于语音来说,最常用的是16k HZ的,本文以及后续的均设定采用率为16k HZ。语音信号处理时以帧为单位,ANS中一帧为10 ms,可以算出一帧是160个采样点。语音信号处理又通常在频域下进行的,因此先要把时域信号变成频域信号,处理后再把频域信号变回时域信号。时域信号变频域信号在ANS降噪处理过程的开始部分,频域信号变时域信号在ANS降噪处理过程的结束部分,但它们是相对称的,且它们与降噪处理算法无关,因此把它们放在一起讲。下面讲讲时频互转中的一些细节。
先看从时域信号变成频域信号。主要步骤是分帧、加窗和做短时傅里叶变换(STFT)。分帧上面说过,10 ms一帧,每帧160个采样点。加窗的目的是避免频谱泄漏。有多种窗函数,常见的有矩形窗、三角窗、汉宁(hanning)窗和海明(hamming)窗等。语音处理中常用的是汉宁窗和海明窗。ANS中用的是汉宁窗和矩形窗混在一起的混合窗。做STFT要求点数是2的N次方,现在每帧160个点,大于160的最近的2的N次方是256,所以STFT一次处理256个点(这也是代码中256(#define ANAL_BLOCKL_MAX 256)的由来)。现在每帧160个点,需要补成256个点。一种做法是在160个点后面补零补成256个点。ANS用了一种更好的方法。用上一帧的尾部的96个点来补从而形成256个点。这样从时域信号变成频域信号的处理流程如下图2:
图2
因为对256点做STFT,所以加窗的点数也是256。ANS用的是窗是汉宁和矩形混合窗。汉宁窗函数是w(n) = 0.5 * (1 + cos(2*pi*n / (N-1))),范围是(0,1),波形如下图3。
图3
这个混合窗是把192(96*2)点的汉宁窗在顶点处插入64点的幅值为1的矩形窗,从而形成256(256 = 192 + 64)点的混合窗,波形如下图4。
图4
至于为什么要这么做,后面讲频域转换到时域时再说。256个点的值与相应的窗函数相乘,得到要送进STFT处理的值。STFT处理后得到256个频点的值,这些值除了第0点和第N/2点(N=256,即第128点)点是实数外,其余点都是复数,且关于第N/2点共轭对称。因为共轭对称,一个点知道了,它的对称点就可以求出来。所以STFT处理后有(N/2 + 1)个点的值。这里N=256,STFT的输出是129个点的值。这也是代码中129(#define HALF_ANAL_BLOCKL 129)的由来。得到129个频点的值后还要算每个频点的幅度谱和能量等,用于后面降噪算法,具体处理如下面代码,已给出详细的注释,就不细说了。
在频域做完降噪处理后需要把信号从频域变回时域,即信号的重建或者合成,主要步骤是做短时傅里叶反变换(ISTFT)、加窗和重叠相加(overlap add, OLA)等,处理流程如下图5。
图5
先做ISTFT(短时傅里叶反变换),得到256点的实数值。这256点包括上一帧的尾部的96点,即有重叠。该怎么拼接保证声音连贯呢?上面讲从时域到频域变换时用的窗是汉宁矩形混合窗,汉宁窗前半部分(头部96点)类似于做正弦操作,后半部分(尾部96点)类似于做余弦操作。重叠部分是在上一帧的尾部,加窗做的是类余弦操作,在当前帧是头部,加窗做的是类正弦操作。信号重建叠加时一般要求能量或者幅值不变,能量是幅值的平方。那些重叠的点(假设幅值为m)在上一帧中加窗时做了类余弦操作,加窗后幅值变成了m*cosθ,在当前帧中加窗时做了类正弦操作,加窗后幅值变成了m*sinθ,能量和为m2*cos2θ + m2*sin2θ, 正好等于m2(原信号的能量),这说明只要把重叠部分相加就可以保证语音信号的连贯了。这就解释了代码中把ISTFT后的值再做一次加窗操作并把重叠部分相加的原因。具体代码见下图6。
图6
至于矩形窗部分,幅值为1,即加窗后信号幅值不变,因而不需要做处理,直接填上就可以了。需要注意的是图6中还有一个能量缩放因子factor。它在前200帧默认为1,后续帧按如下逻辑关系得到。
图7给出了做完ISTFT后数据拼接的示意图。做完ISTFT后有256点数据,当前帧的头部96点数据与上一帧的尾部96点数据相加,中间64点数据不变,当前帧尾部96点数据与下一帧的头部96点数据相加,这样就能很好的拼接处连贯的语音数据了。
图7
下篇将讲噪声的初始估计以及基于估计出来的噪声算先验信噪比和后验信噪比。
本文摘自 :https://www.cnblogs.com/