第一节 回声消除原理

  1. 声学回声消除主要用来解决双端通信中回声干扰的问题。如下图所示,A、B两段正在进行远程语音通话,B端语音被麦克风采集后转换成电信号,经过网络传输到达A端,由A端扬声器播放出来,如果在A端没有做AEC处理,那么这个声音就会被A端的麦克风采集传回到B段,从而干扰正常的语音通信。
  1. AEC目前已经形成了以自适应滤波处理联合回声后处理为主的技术方案。其中,自适应滤波器用来模拟和追踪真实的“回声路径”,并由收敛出的“回声路径”(实际为滤波器系数)估算出回声信号,再从近端纯净语音和回声的混合信号中减去估计的回声。
  2. 如下图所示是AEC技术的基本原理结构图,d(n)是麦克风采集到的第n个样点值,一般包括回声信号y(n)和近端语音v(n)。为了更好的解释问题,在这里先忽略近端语音v(n),即假设d(n)=y(n)。y(n)可以看做是远端信号输入向量x(n)与真实的回声路径w(n)线性卷积的结果。y'(n)是对y(n)的估计,w'(n)是对真实回声路径w(n)的模拟,e(n)是估计的回声与真实回声之间的误差,同时e(n)又被用作自适应滤波器的反馈,参与w'(n)的更新迭代。在理想情况下,随着迭代次数的增加,w'(n)的值会越来越接近真实的回声路径w(n),e(n)会趋近于0.但是在实际应用中,由于扬声器和麦克风等影响,回声路径会表现出一定的非线性特征,而AEC的滤波器往往都是线性的自适应滤波器,故这导致AEC的线性滤波之后仍然残留一定的回声,这一部分可以使用非线性处理技术(Nonlinear Processing, NLP)进一步抑制。关于真实回声、估计回声和误差的计算公式如下所示:

y(n)=x(n)*w(n)

y'(n)=x(n)*w'(n)

e(n)=d(n)-y'(n)

此外,当近端有说话人存在的时候,远端和近端很容易形成双讲(即远端和近端同时有人说话),这时近端的会话会作为能量很大的干扰进入滤波器的期望输出中,从而造成自适应滤波器发散,无法正常收敛。所以AEC还需要一个双讲检测技术(Double Talk Detection,DTD),当检测到双讲存在的时候,就冻结滤波器系数更新,防止滤波器系数发散。

  1. 自适应滤波器
  • (1)LMS(最小均方)算法

LMS算法是一种随机梯度下降算法,随着迭代次数增加,更新出的权重值无法精确收敛于维纳解,会以随机游走的方式在维纳解附近徘徊。它最大的优点是计算复杂度低,但是收敛速度慢。故有人提出了归一化最小均方算法(NLMS)。(2)NLMS算法由本节的式(3.1)可以发现,当x(n)较大的时候,会引起梯度放大,而x(n)较小的时候,算法收敛速度就会变慢。为了解决这一问题,可以对输入向量x(n)的平方欧式范数进行归一化,这就得到了NLMS算法,即

(3)分块频域自适应滤波器(PBFDAF)算法在实际应用场景中,回声路径时长可达几百毫秒,在16kHz采样率下,就需要上千阶滤波器,而NLMS滤波器的算法复杂度会随着滤波器的阶数呈线性增长。为了克服这一问题,提出了分块频域自适应滤波器(Partitioned Block Frequency Domain Adaptive Filter,PBFDAF)滤波器,它利用FFT可快速实现卷积运算的特点,在频域进行滤波器更新,同时用逐块更新来代替逐点更新,从而大大降低了计算复杂度。

第二节 WebRTC回声消除算法

  • 延迟估计

当远端信号到达近端的时候,会被AEC模块复制作为参考信号,接着从近端扬声器播放出来,再被近端麦克风采集送入AEC处理。整个过程的总延迟为T=T1+T2+T3(T1为从AEC模块传往近端的时间,T2为近端扬声器到麦克风的时间,T3为近端麦克风到AEC模块的时间。)当延迟增大时,就需要更长的线性滤波器来应付这个延迟,而更长的线性滤波器带来的是浪费、低效能,但是如果我们提前知道了这个延迟,就可以从缓存的参考信号中直接选中跟当前近端信号相匹配的那一帧,而不需要过长的滤波器系数。为了估计近端数据相对于远端数据的延迟,需要在缓存中缓存一定时长的远端数据(时长应尽可能 覆盖到可能出现的最大延迟)。然后用AEC当前取到的一帧近端数据跟远端缓存的每一帧进行匹配,找到相似度最高的那一帧远端数据,两者时间索引的差值就是估计出来的延迟。所以延迟估计算法的核心就是如何衡量近端数据和远端数据的相似度。WebRTC里面的算法具有计算复杂度低、准确度高的优点。它的计算步骤如下:

设1表示有说话声音,0表示无说话声音(静音或说话声音很弱),参考端(远端)信号x(t)和接收端信号(近端)信号y(t)理论上有以下几种组合方式:(0,0)(1,0)(0,1)(1,1)。WebRTC假设除了(0,0)(1,1)都不会发生。假设在时间间隔p、频带q(即将第p个时间间隔信号进行fft变换,取其第q个频点),输入信号x加窗后的功率谱为Xw(p,q),对每个频带中的功率谱设定一个门限Xw(p,q)_threshold,那么:

  • 如果 Xw(p,q)  >= Xw(p,q)_threshold  ,   则Xw(p,q) =1;
  • 如果 Xw(p,q) <    Xw(p,q)_threshold  ,   则Xw(p,q) =0。

同理,对于信号y(t),加窗信号功率谱Yw(p,q)和门限Yw(p,q)_threshold:

  • 如果 Yw(p,q) >= Yw(p,q)_threshold   ,   则Yw(p,q) =1;
  • 如果 Yw(p,q) < Yw(p,q)_threshold ,        则Yw(p,q) =0。

WebRTC中将当前参与运算的128点远端信号和128点近端信号做128点FFT,获得一个65点振幅谱的数据块(对称,抛弃后面63个),然后选取第12个频点到第43个频点(应该是去掉甚低频和高频,减少对于时延估计的影响)一共32个子带。这样每个特定的子带的Xw(p,q)(Yw(p,q)同理)都可以用一个比特来表示,总共需要32个比特,这样只需要用一个32位数据类型就可以表示完一个时间间隔里面的情况。webrtc对参考信号定义了75个32位的数组存放历史远端参考信号(binary_far_history),对近端信号定义了16个32位的数组来存放历史数据(binary_near_history,数组中的每一个元素实际都是一个时间间隔的情况),最新的数据都存在下标为0的元素中。每次比较的时候,就是将binary_near_history[15]与binary_far_history中的每一个32位数据分别按位异或,得到了75个32位比特数据结果。统计32位结果中的1的个数存放于bit_counts中,接下来对bit_counts进行平滑防止延时突变,得到mean_bit_count。如果mean_bit_count越小,则表明进度按数据与该帧远端数据越吻合,理论上可能这就是越接近两者的真实时延,但是为了可靠,还是将其存放为value_best_candidate,然后对这一数值进行边界保护,即如果该数值接近预设的最差时延,则认为该数值不可靠,就不更新时延值,如果可靠,则进一步使用一阶马尔科夫模型更新最终的实验结果last_delay。

  • 自适应滤波

WebRTC中AEC使用的是PBFDAF。在早期算法中,FilterFar函数实现远端频域滤波,ScaleErrorSignal函数对误差信号做归一化处理,FilterAdaptation函数用来更新滤波器。算法使用滤波器阶数为768阶,在频域分为12块,计算滤波器更新量使用的步长因子mu有两个标准:采样率为8kHz的时候,mu=0.6;当采样率为16kHz或32kHz的时候,mu=0.5。特别需要说明的是,FilterAdaptation函数根据之前计算的归一化处理后的ef,计算滤波器权重的频域该变量,先存在fft变量中,将该变量先变换到时域,后64点置零,然后在变换到频域,这样做是为了保证线性卷积结果的正确性,最后在频域更新wfBuf。

  • 非线性处理(NLP)

NLP是抑制线性滤波之后误差信号中残留的回声。那么如何衡量误差信号中残留回声的大小呢?WebRTC利用信号之间的频域相干性c(0≤c≤1)。首先计算近端信号d(n)和误差信号e(n)之间的频域相干性cde,可以简单将cde当做残留回声在误差信号中的占有比例。假设现行阶段正常运行,cde越接近于1,说明近端信号和误差信号相似性越高,月不需要对误差信号做控制;相反,cde越小,越需要对误差信号做抑制。同时会计算近端信号d(n)和远端信号x(n)之间的频域相干性cxd,令c’xd=1-cxd,c’xd越大,说明回声残留越小,越不需要做抑制;反之越需要做抑制。由cxd和c’xd进一步处理,计算出每个频域带响应的抑制因子sγ(k)。将抑制因子与误差信号对应的频带相乘,从而实现对残留回声的抑制。此外,NLP在抑制回声段的时候也会将噪声一同抑制,而近端语音段的噪声得到保留,这种噪声的时有时无会带来听感上的不舒适,为了降低这种影响,往往会在NLP后面加上白噪声。