webRTC中语音降噪模块ANS细节详解(二)
上篇(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细节详解(二)的更多相关文章
- webRTC中语音降噪模块ANS细节详解(三)
上篇(webRTC中语音降噪模块ANS细节详解(二))讲了ANS的处理流程和语音在时域和频域的相互转换.本篇开始讲语音降噪的核心部分,首先讲噪声的初始估计以及基于估计出来的噪声算先验信噪比和后验信噪比 ...
- webRTC中语音降噪模块ANS细节详解(四)
上篇(webRTC中语音降噪模块ANS细节详解(三))讲了噪声的初始估计方法以及怎么算先验SNR和后验SNR. 本篇开始讲基于带噪语音和特征的语音和噪声的概率计算方法和噪声估计更新以及基于维纳滤波的降 ...
- webRTC中语音降噪模块ANS细节详解(一)
ANS(adaptive noise suppression) 是webRTC中音频相关的核心模块之一,为众多公司所使用.从2015年开始,我在几个产品中使用了webRTC的3A(AEC/ANS/AG ...
- python中argparse模块用法实例详解
python中argparse模块用法实例详解 这篇文章主要介绍了python中argparse模块用法,以实例形式较为详细的分析了argparse模块解析命令行参数的使用技巧,需要的朋友可以参考下 ...
- Python中random模块生成随机数详解
Python中random模块生成随机数详解 本文给大家汇总了一下在Python中random模块中最常用的生成随机数的方法,有需要的小伙伴可以参考下 Python中的random模块用于生成随机数. ...
- Java中堆内存和栈内存详解2
Java中堆内存和栈内存详解 Java把内存分成两种,一种叫做栈内存,一种叫做堆内存 在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配.当在一段代码块中定义一个变量时,ja ...
- angular-ngSanitize模块-$sanitize服务详解
本篇主要讲解angular中的$sanitize这个服务.此服务依赖于ngSanitize模块. 要学习这个服务,先要了解另一个指令: ng-bing-html. 顾名思义,ng-bind-html和 ...
- angular-ngSanitize模块-linky过滤器详解
本篇主要讲解angular中的linky这个过滤器.此过滤器依赖于ngSanitize模块. linky能找出文本中的链接,然后把它转换成html链接.什么意思,就是说,一段文本里有一个链接,但是这个 ...
- View绘制详解(五),draw方法细节详解之View的滚动/滑动问题
关于View绘制系列的文章已经完成了四篇了,前面四篇文章主要带小伙伴们熟悉一下View的体系的整体框架.View的测量以及布局等过程,从本篇博客开始,我们就来看看View的绘制过程.View的绘制涉及 ...
随机推荐
- Windows内核-7-IRP和派遣函数
Windows内核-7-IRP和派遣函数 IRP以及派遣函数是Windows中非常重要的概念.IRP 是I/O Request Pocket的简称,意思是I/O操作的请求包,Windows中所有Use ...
- AWS扩容EC2实例根空间
文章原文 aws 端操作 先在EC2 实例中选中磁盘 然后打开跟设备 修改大小后保存 ec2 端操作 lsblk 查看当前设备的磁盘编号 df -T -H 查看扩容前的空间大小并确定磁盘格式 grow ...
- zabbix 批量安装+自动注册
环境介绍 zabbix版本Zabbix 4.2.6 zabbix server:10.0.10.234 zabbix-agent:16台 Linux 7.x设备 自动发现 自动发现的好处:快速发现 ...
- ELK 收集 Tomcat日志以及修改Tomcat日志格式
ELK 收集 Tomcat日志以及修改Tomcat日志格式 Tomcat日志 想要收集tomcat 日志 首先我们要对tomcat的日志有足够的了解 tomca日志分类 简单的说tomcat logs ...
- Activiti 学习(四)—— Activiti 结合实际业务
流程实例 流程实例(ProcessInstance)代表流程定义的执行实例.一个流程实例包括了所有的运行节点.我们可以利用这个对象来了解当前流程实例的进度等信息.例如:用户或程序按照流程定义内容发起一 ...
- 洛谷P1308——单词统计
https://www.luogu.org/problem/show?pid=1308 题目描述 一般的文本编辑器都有查找单词的功能,该功能可以快速定位特定单词在文章中的位置,有的还能统计出特定单词在 ...
- 【OI】计算分子量 Molar mass UVa 1586 题解
题目:(由于UVa注册不了,还是用vjudge) https://vjudge.net/problem/UVA-1586 详细说明放在了注释里面.原创. 破题点在于对于一个元素的组合(元素+个数),只 ...
- Jmeter系列(6)- 分析源码,创建登录、浏览商品接口请求
前言简介 接口的压力测试有个二八原则:线上80%的用户量在一天24小时20%(即4.8个小时)的时间里可以平稳运行,这个接口就算是通过压力测试了 源码分析 登录 浏览商品 创建请求 登录 浏览菜单 C ...
- Spring Cloud Hystrix 学习(三)请求合并
什么是请求合并?我们先来看两张图: 上方的两张图中,第二张可以看出服务端只执行了一次响应,这就是请求合并.客户端新增的请求合并模块,内部存在一个等待的时间窗口,将一定时间段内满足条件的请求进行合并,以 ...
- ci框架 查询构造器类
$this->db->get() 该方法执行 SELECT 语句并返回查询结果,可以得到一个表的所有数据: $query = $this->db->get('mytable') ...