上篇(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

下篇将讲噪声的初始估计以及基于估计出来的噪声算先验信噪比和后验信噪比。

webRTC中语音降噪模块ANS细节详解(二)的更多相关文章

  1. webRTC中语音降噪模块ANS细节详解(三)

    上篇(webRTC中语音降噪模块ANS细节详解(二))讲了ANS的处理流程和语音在时域和频域的相互转换.本篇开始讲语音降噪的核心部分,首先讲噪声的初始估计以及基于估计出来的噪声算先验信噪比和后验信噪比 ...

  2. webRTC中语音降噪模块ANS细节详解(四)

    上篇(webRTC中语音降噪模块ANS细节详解(三))讲了噪声的初始估计方法以及怎么算先验SNR和后验SNR. 本篇开始讲基于带噪语音和特征的语音和噪声的概率计算方法和噪声估计更新以及基于维纳滤波的降 ...

  3. webRTC中语音降噪模块ANS细节详解(一)

    ANS(adaptive noise suppression) 是webRTC中音频相关的核心模块之一,为众多公司所使用.从2015年开始,我在几个产品中使用了webRTC的3A(AEC/ANS/AG ...

  4. python中argparse模块用法实例详解

    python中argparse模块用法实例详解 这篇文章主要介绍了python中argparse模块用法,以实例形式较为详细的分析了argparse模块解析命令行参数的使用技巧,需要的朋友可以参考下 ...

  5. Python中random模块生成随机数详解

    Python中random模块生成随机数详解 本文给大家汇总了一下在Python中random模块中最常用的生成随机数的方法,有需要的小伙伴可以参考下 Python中的random模块用于生成随机数. ...

  6. Java中堆内存和栈内存详解2

    Java中堆内存和栈内存详解   Java把内存分成两种,一种叫做栈内存,一种叫做堆内存 在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配.当在一段代码块中定义一个变量时,ja ...

  7. angular-ngSanitize模块-$sanitize服务详解

    本篇主要讲解angular中的$sanitize这个服务.此服务依赖于ngSanitize模块. 要学习这个服务,先要了解另一个指令: ng-bing-html. 顾名思义,ng-bind-html和 ...

  8. angular-ngSanitize模块-linky过滤器详解

    本篇主要讲解angular中的linky这个过滤器.此过滤器依赖于ngSanitize模块. linky能找出文本中的链接,然后把它转换成html链接.什么意思,就是说,一段文本里有一个链接,但是这个 ...

  9. View绘制详解(五),draw方法细节详解之View的滚动/滑动问题

    关于View绘制系列的文章已经完成了四篇了,前面四篇文章主要带小伙伴们熟悉一下View的体系的整体框架.View的测量以及布局等过程,从本篇博客开始,我们就来看看View的绘制过程.View的绘制涉及 ...

随机推荐

  1. Android Parsing between JSON and Kotlin Object with Google Gson Library

    Parsing between JSON and Kotlin Object with Google Gson Library dependencies { ... implementation 'c ...

  2. 性能测试必备命令(3)- lscpu

    性能测试必备的 Linux 命令系列,可以看下面链接的文章哦 https://www.cnblogs.com/poloyy/category/1819490.html 介绍 显示有关CPU架构的信息 ...

  3. Intel® QAT加速卡之编程demo框架

    QAT demo流程框架 示例一: 代码路径:qat1.5.l.1.13.0-19\quickassist\lookaside\access_layer\src\sample_code\functio ...

  4. Tars | 第0篇 腾讯犀牛鸟开源人才培养计划Tars实战笔记目录

    腾讯犀牛鸟开源人才培养计划Tars实战笔记目录 前言 在2021年夏,笔者参加了腾讯首届开源人才培养计划的Tars项目,负责Subset流量管理规则的Java语言JDK实现.其中写作几篇开源实战笔记, ...

  5. 一起学习PHP中GD库的使用(一)

    又到了一个大家非常熟悉的库了,对于图像图形的处理来说,GD 库是 PHPer 们绕不过去的一道坎.从很早很早的 CMS 或者 Discuz 时代,各类开源软件在安装的时候就会明确地指出 GD 库是它们 ...

  6. Nginx TP5环境配置

    Apache默认支持Pathinfo模式  Nginx不支持  需要手动配置  Apache默认支持Pathinfo模式  Nginx不支持  需要手动配置 server { #配置监听端口 list ...

  7. 记一次k8s pod频繁重启的优化之旅

    关键词:k8s.jvm.高可用 1.背景 最近有运维反馈某个微服务频繁重启,客户映像特别不好,需要我们尽快看一下. 听他说完我立马到监控平台去看这个服务的运行情况,确实重启了很多次.对于技术人员来说, ...

  8. Jmeter扩展组件开发(2) - 扩展开发第一个demo的实现

    maven工程src目录介绍 main:写代码 main/java:写Java代码 main/resources:写配置文件 test:写测试代码 test/java demo实现 创建Package ...

  9. Jmeter系列(14)- Setup与tearDown线程组

    与普通线程组区别 #Setup线程组:在普通线程组执⾏前触发 #tearDown线程组:在普通线程组执⾏后触发 线程组属性配置详情完全⼀致 使⽤策略建议 #Setup 线程组 – 压测执⾏准备阶段,准 ...

  10. Jmeter线程组设置

    添加线程组:右键测试计划->添加->Threads->线程组 左侧树形标签栏中,显示标签信息. 选中线程组,右侧内容栏中显示线程组的相关信息. 名称:可以给线程组设置一个个性化的命名 ...