声学回声消除(Acoustic Echo Cancellation)原理与实现

  回声就是声音信号通过一系列反射以后,又听到了本身讲话的声音,这就是回声。一些回声是必要的,好比剧院里的音乐回声以及延迟时间较短的房间回声;而大多数回声会形成负面影响,好比在有线或者无线通讯时重复听到本身讲话的声音(回想那些年咱们开黑打游戏时,若是其中有我的开了外放,他的声音就会回荡来回荡去)。所以消除回声的负面影响对通讯系统是十分必要的。html

  针对回声消除(Acoustic Echo Cancellation,AEC )问题,现现在最流行的算法就是基于自适应滤波的回声消除算法。本文从回声信号的两种分类以及 AEC 的基本原理出发,介绍几种经典的 AEC 算法并对其性能进行阐释。react

回声分类

  在通讯系统中,回声主要分为两类:电路回声声学回声git

电路回声

  电路回声一般产生于有线通话中,为了下降电话中心局与电话用户之间电话线的价格,用户间线的链接采用两线制;而电话中心局之间链接采用四线制(上面两条线路用于发送给用户端信号,下面两条线路用于接收用户端信号)。问题就出来了,形成电路回声的根本缘由是转换混合器的二线-四线阻抗不能彻底匹配(使用的不一样型号的电线或者负载线圈没有被使用的缘由),致使混合器 接收线路 上的语音信号流失到了 发送线路 ,产生了回声信号,使得另外一端的用户在接收信号的同时听到了本身的声音。github

电路回声产生原理web

  在现现在的数字通讯网络中,转换混合器与数模转换器融为一体,但不管是模拟电子线路仍是数字电子线路,二-四线的转换都会形成阻抗不匹配问题,从而致使其产生电路回声,影响现代通讯质量。因为电路回声的线性以及稳定性,用一个简单的线性叠加器就能够实现电路回声消除。首先将产生的回声信号在数值上取反,线性地叠加在回声信号上,将产生的回声信号抵消,实现电路回声的初步消除。然而因为技术缺陷,线性叠加器不能完整地将回声信号抹去,所以须要添加一个非线性处理器,其实质是一个阻挡信号的开关,将残余的回声信号通过非线性处理以后,就能够实现电路回声的消除,或者获得噪声很小的静音信号。因为电路回声信号是线性且稳定的,因此比较容易将其消除,而本文主要研究的是如何消除非线性的声学回声。算法

电路回声消除的基本原理浏览器

声学回声

  在麦克风与扬声器互相做用影响的双工通讯系统中极易产生声学回声。以下图所示网络

远端讲话者A-->麦克风A-->电话A-->电话B---->扬声器B--->麦克风B-->电话B-->电话A-->扬声器A--->麦克风A--->.........就这样无限循环,函数

详细讲解:远端讲话者A的话语被麦克风采集并传入至通讯设备,通过无线或有线传输以后达到近端的通讯设备,并经过近端 B 的扬声器播放,这个声音又会被近端 B 的麦克风拾取至其通讯设备造成声学回声,经传输又返回了远端 A 的通讯设备,并经过远端 A 的扬声器播放出来,从而远端讲话者就听到了本身的回声。oop

声学回声产生原理

声学回声信号根据传输途径的差异能够分别直接回声信号和间接回声信号。

直接回声:近端扬声器B将语音信号播放出来后,近端麦克风B直接将其采集后获得的回声。

  直接回声不受环境的印象,与扬声器到麦克风的距离及位置有很大的关系,所以直接回声是一种线性信号

间接回声:近端扬声器B将语音信号播放出来后,语音信号通过复杂多变的墙面反射后由近端麦克风B将其拾取。

  间接回声的大小与房间环境、物品摆放以及墙面吸引系数等等因素有关,所以间接回声是一种非线性信号

回声消除技术主要用于在免提电话、电话会议系统等情形中。

AEC的基本原理

  现在解决 AEC 问题最经常使用的方法,就是

使用不一样的自适应滤波算法调整滤波器的权值向量,估计一个近似的回声路径来逼近真实回声路径,从而获得估计的回声信号,并在纯净语音和回声的混合信号中除去此信号来实现回声的消除。

 AEC的基本原理

  $x(n)$为远端输入信号,通过未知的回声路径$w(n)$获得$y(n)=x(n)*w(n)$,再加上观测噪声$v(n)$即为指望信号$d(n)= y(n) + v(n)$。x(n)经过自适应滤波器$\hat{w}(n)$获得估计的回声信号,并与指望信号$d(n)$相减获得偏差信号$e(n)$,即$e(n)=d(n)-\hat{w}^T(n)x(n)$,偏差信号的值越小说明自适应滤波算法所估计的回声路径就越接近实际的回声路径。

  滤波器采用特定的自适应算法不停地调整权值向量,使估计的回声路径$\hat{w}(n)$逐渐趋近于真实回声路径$w(n)$。显然,在 AEC 问题中,自适应滤波器的选择对回声消除的性能好坏起着十分关键的做用。

自适应滤波器的基本原理

  自适应滤波器是一个对输入信号进行处理并不停学习,直到其达到指望值的器件。自适应滤波器在输入信号非平稳条件下,也能够根据环境不断调节滤波器权值向量,使算法达到特定的收敛条件,从而实现自适应滤波过程。

  自适应滤波器按输入信号类型可分为模拟滤波器和离散滤波器,本文中使用的是离散滤波器中的数字滤波器数字滤波器按结构可划分为输入不只与过去和当前的输入有关、还与过去的输出有关的无限冲激响应滤波器(IIR),以及输出与有限个过去和当前的输入有关的有限冲激响应滤波器(FIR))为了使得自适应滤波器具备更强的稳定性,而且具备足够的滤波器系数能够用来调整以达到特定的收敛准则,通常选取横向的 FIR 滤波器进行来进行回声的消除

 横向FIR滤波器结构框图

  $x(n)$是远端输入信号,$\hat{w}_i(n)$是滤波器系数,其中$i=0,1,...,L-1$,$L$为滤波器的长度,$n$为采样点数,$\hat{w}(n)$为滤波器的权值向量且$\hat{w}(n)=[\hat{w}_0(n),\hat{w}_1(n),...,\hat{w}_{L-1}(n)]^T$,根据偏差信号$e(n)=d(n)-\hat{w}^T(n)x(n)$的值以及不一样算法的收敛准则调整滤波器的权值向量。

  然而自适应滤波算法的选择从根本上决定了回声消除的效果是否良好,接下来将介绍几种解决 AEC 问题的经典自适应滤波算法。

回声消除经常使用算法

LSM算法

  经过上面AEC的基本原理咱们知道了偏差信号$e(n)$等于指望信号减去滤波器输出信号:

$$e(n)=d(n)-\hat{w}^T(n)x(n)$$

对上式两端先平方,而后再求其数学指望,可将$e(n)$的MSE表示为:

$$\xi=E[e^2(n)]=E[d^2(n)]-2P^T\hat{w}(n)+\hat{w}^T(n)R\hat{w}(n)$$

其中,$P=E[d(n)x(n)]$为$d(n)$与输入信号$x(n)$的负相关矩阵,$R=E[x(n)x^T(n)]$为$x(n)$的自相关矩阵。

  对偏差信号求导而且使导数值置零,求解获得使得偏差最小的“最优权重” $\hat{w}_{opt}(n)=\frac{P}{R}$,R 和 P 的估计分别为$\hat{R}(n) 和$\hat{P}(n)$,利用各自的瞬时估计值将其分别表示为:$\hat{R}(n)=x(x)x^T(n)$;$\hat{P}(n)=d(n)x(n)$ 。另外,用$\hat{g}_w(n)$表示偏差信号对权值向量导数的估计值,利用下式方法求解最优权值向量的维纳解:

 获得:$\hat{g}_w(n)=-2e(n)x(n)$ ,算法取瞬时平方偏差做为目标函数,那么$\hat{g}_w(n)$为其真实梯度,由于:

所以获得 LMS 算法的权值向量更新公式:

$$\hat{w}(n+1)=\hat{w}(n)+2\mu e(n)x(n)$$

式中,$\mu$为固定步长因子,$\mu$的大小很大程度上决定了算法的收敛与稳态性能。LMS 算法复杂性低,可是它的收敛速度慢。为改善 LMS 这个不足之处,科研人员提出一系列改进算法,NLMS 算法就是其中一种

NLMS算法

NSAF算法

MATLAB代码实现

当须要同时进行语音通讯(或全双工传输)时,回声消除对于音频电话会议很是重要。在回声消除中,测得的麦克风信号包含两个信号:

  • 近端语音信号$v(n)$ 

  • 远端回声信号$\hat{d}(n)$

目的是从麦克风信号中去除远端回声信号,从而仅发送近端语音信号。本示例包含一些声音片断,所以您可能如今要调整计算机的音量。

房间脉冲响应

首先,您须要对扬声器所在的扬声器到麦克风的信号路径的声学建模。使用长有限冲激响应滤波器来描述房间的特征。下面的代码生成一个随机的脉冲响应,该响应与会议室的显示相同。假设系统采样率为16000 Hz。

fs = 16000;
M = fs / 2 + 1; 
frameSize = 2048; 

[B,A] = cheby2(4,20,[0.1 0.7]); 
impulseResponseGenerator = dsp.IIRFilter(' Numerator ',[zeros(1,6)B],... 
    'Denominator',A); 

FVT = fvtool(impulseResponseGenerator);  %分析过滤器 
FVT.Color = [1 1 1];

roomImpulseResponse = impulseResponseGenerator( ...
        (log(0.99*rand(1,M)+0.01).*sign(randn(1,M)).*exp(-0.002*(1:M)))');
roomImpulseResponse = roomImpulseResponse/norm(roomImpulseResponse)*4;
room = dsp.FIRFilter('Numerator', roomImpulseResponse');

fig = figure;
plot(0:1/fs:0.5, roomImpulseResponse);
xlabel('Time (s)');
ylabel('Amplitude');
title('Room Impulse Response');
fig.Color = [1 1 1];

 

近端语音信号

电话会议系统的用户一般位于系统麦克风附近。这是麦克风上男性讲话的声音。

load nearspeech

player          = audioDeviceWriter('SupportVariableSizeInput', true, ...
                                    'BufferSize', 512, 'SampleRate', fs);
nearSpeechSrc   = dsp.SignalSource('Signal',v,'SamplesPerFrame',frameSize);
nearSpeechScope = dsp.TimeScope('SampleRate', fs, ...
                    'TimeSpan', 35, 'TimeSpanOverrunAction', 'Scroll', ...
                    'YLimits', [-1.5 1.5], ...
                    'BufferLength', length(v), ...
                    'Title', 'Near-End Speech Signal', ...
                    'ShowGrid', true);

% Stream processing loop
while(~isDone(nearSpeechSrc))
    % Extract the speech samples from the input signal
    nearSpeech = nearSpeechSrc();
    % Send the speech samples to the output audio device
    player(nearSpeech);
    % Plot the signal
    nearSpeechScope(nearSpeech);
end
release(nearSpeechScope);

 

远端语音信号

在电话会议系统中,语音从扬声器中传播出去,在房间里弹跳,而后被系统的麦克风拾取。聆听在没有近端语音的状况下在麦克风处拾起语音时的声音。

load farspeech
farSpeechSrc    = dsp.SignalSource('Signal',x,'SamplesPerFrame',frameSize);
farSpeechSink   = dsp.SignalSink;
farSpeechScope  = dsp.TimeScope('SampleRate', fs, ...
                    'TimeSpan', 35, 'TimeSpanOverrunAction', 'Scroll', ...
                    'YLimits', [-0.5 0.5], ...
                    'BufferLength', length(x), ...
                    'Title', 'Far-End Speech Signal', ...
                    'ShowGrid', true);

% Stream processing loop
while(~isDone(farSpeechSrc))
    % Extract the speech samples from the input signal
    farSpeech = farSpeechSrc();
    % Add the room effect to the far-end speech signal
    farSpeechEcho = room(farSpeech);
    % Send the speech samples to the output audio device
    player(farSpeechEcho);
    % Plot the signal
    farSpeechScope(farSpeech);
    % Log the signal for further processing
    farSpeechSink(farSpeechEcho);
end
release(farSpeechScope);

 

 

麦克风信号

麦克风处的信号既包含近端语音,也包含在整个房间中回声的远端语音。回声消除器的目的是消除远端语音,从而仅将近端语音发送回远端听众。

reset(nearSpeechSrc);
farSpeechEchoSrc = dsp.SignalSource('Signal', farSpeechSink.Buffer, ...
                    'SamplesPerFrame', frameSize);
micSink         = dsp.SignalSink;
micScope        = dsp.TimeScope('SampleRate', fs,...
                    'TimeSpan', 35, 'TimeSpanOverrunAction', 'Scroll',...
                    'YLimits', [-1 1], ...
                    'BufferLength', length(x), ...
                    'Title', 'Microphone Signal', ...
                    'ShowGrid', true);

% Stream processing loop
while(~isDone(farSpeechEchoSrc))
    % Microphone signal = echoed far-end + near-end + noise
    micSignal = farSpeechEchoSrc() + nearSpeechSrc() + ...
                0.001*randn(frameSize,1);
    % Send the speech samples to the output audio device
    player(micSignal);
    % Plot the signal
    micScope(micSignal);
    % Log the signal
    micSink(micSignal);
end
release(micScope);

频域自适应滤波器(FDAF)

该示例中的算法是频域自适应滤波器(FDAF)当待识别系统的脉冲响应较长时,此算法很是有用。FDAF使用快速卷积技术来计算输出信号和过滤器更新。该计算可在MATLAB®中快速执行。经过频点步长归一化,它还具备快速收敛性能。为滤波器选择一些初始参数,并查看远端语音在偏差信号中的消除程度。

% Construct the Frequency-Domain Adaptive Filter
echoCanceller    = dsp.FrequencyDomainAdaptiveFilter('Length', 2048, ...
                    'StepSize', 0.025, ...
                    'InitialPower', 0.01, ...
                    'AveragingFactor', 0.98, ...
                    'Method', 'Unconstrained FDAF');

AECScope1   = dsp.TimeScope(4, fs, ...
                'LayoutDimensions', [4,1], ...
                'TimeSpan', 35, 'TimeSpanOverrunAction', 'Scroll', ...
                'BufferLength', length(x));

AECScope1.ActiveDisplay = 1;
AECScope1.ShowGrid      = true;
AECScope1.YLimits       = [-1.5 1.5];
AECScope1.Title         = 'Near-End Speech Signal';

AECScope1.ActiveDisplay = 2;
AECScope1.ShowGrid      = true;
AECScope1.YLimits       = [-1.5 1.5];
AECScope1.Title         = 'Microphone Signal';

AECScope1.ActiveDisplay = 3;
AECScope1.ShowGrid      = true;
AECScope1.YLimits       = [-1.5 1.5];
AECScope1.Title         = 'Output of Acoustic Echo Canceller mu=0.025';

AECScope1.ActiveDisplay = 4;
AECScope1.ShowGrid      = true;
AECScope1.YLimits       = [0 50];
AECScope1.YLabel        = 'ERLE (dB)';
AECScope1.Title         = 'Echo Return Loss Enhancement mu=0.025';

% Near-end speech signal
release(nearSpeechSrc);
nearSpeechSrc.SamplesPerFrame = frameSize;

% Far-end speech signal
release(farSpeechSrc);
farSpeechSrc.SamplesPerFrame = frameSize;

% Far-end speech signal echoed by the room
release(farSpeechEchoSrc);
farSpeechEchoSrc.SamplesPerFrame = frameSize;

回波回波加强(ERLE)

因为您能够访问近端和远端语音信号,所以能够计算回声回波损耗加强(ERLE),这是对回声衰减量的平滑度量(以dB为单位)。从图中能够看出,在收敛周期结束时您得到了大约35 dB的ERLE。

diffAverager = dsp.FIRFilter('Numerator', ones(1,1024));
farEchoAverager = clone(diffAverager);
setfilter(FVT,diffAverager);

micSrc = dsp.SignalSource('Signal', micSink.Buffer, ...
    'SamplesPerFrame', frameSize);

% Stream processing loop - adaptive filter step size = 0.025
while(~isDone(nearSpeechSrc))
    nearSpeech = nearSpeechSrc();
    farSpeech = farSpeechSrc();
    farSpeechEcho = farSpeechEchoSrc();
    micSignal = micSrc();
    % Apply FDAF
    [y,e] = echoCanceller(farSpeech, micSignal);
    % Send the speech samples to the output audio device
    player(e);
    % Compute ERLE
    erle = diffAverager((e-nearSpeech).^2)./ farEchoAverager(farSpeechEcho.^2);
    erledB = -10*log10(erle);
    % Plot near-end, far-end, microphone, AEC output and ERLE
    AECScope1(nearSpeech, micSignal, e, erledB);
end
release(AECScope1);

不一样步长值的影响

为了得到更快的收敛速度,能够尝试使用更大的步长值。可是,这种增长会产生另外一种效果:当近端扬声器讲话时,自适应滤波器“调整不当”。聆听您选择的步长比之前大60%时会发生什么。

% Change the step size value in FDAF
reset(echoCanceller);
echoCanceller.StepSize = 0.04;

AECScope2 = clone(AECScope1);
AECScope2.ActiveDisplay = 3;
AECScope2.Title = 'Output of Acoustic Echo Canceller mu=0.04';
AECScope2.ActiveDisplay = 4;
AECScope2.Title = 'Echo Return Loss Enhancement mu=0.04';

reset(nearSpeechSrc);
reset(farSpeechSrc);
reset(farSpeechEchoSrc);
reset(micSrc);
reset(diffAverager);
reset(farEchoAverager);

% Stream processing loop - adaptive filter step size = 0.04
while(~isDone(nearSpeechSrc))
    nearSpeech = nearSpeechSrc();
    farSpeech = farSpeechSrc();
    farSpeechEcho = farSpeechEchoSrc();
    micSignal = micSrc();
    % Apply FDAF
    [y,e] = echoCanceller(farSpeech, micSignal);
    % Send the speech samples to the output audio device
    player(e);
    % Compute ERLE
    erle = diffAverager((e-nearSpeech).^2)./ farEchoAverager(farSpeechEcho.^2);
    erledB = -10*log10(erle);
    % Plot near-end, far-end, microphone, AEC output and ERLE
    AECScope2(nearSpeech, micSignal, e, erledB);
end

release(nearSpeechSrc);
release(farSpeechSrc);
release(farSpeechEchoSrc);
release(micSrc);
release(diffAverager);
release(farEchoAverager);
release(echoCanceller);
release(AECScope2);

回声回波损耗加强比较

步长较大时,因为近端语音引入的错误调整,致使ERLE性能不佳。为了解决此性能难题,声学回声消除器包括一种检测方案,可告知什么时候存在近端语音并在这些时间段内下降步长值。没有这种检测方案,从ERLE图能够看出,具备较大步长的系统的性能不如前者。

使用分区减小延迟

对于长脉冲响应,传统FDAF在数值上比时域自适应滤波更有效,可是因为输入帧大小必须是指定滤波器长度的倍数,所以它具备高延迟。对于许多实际应用程序来讲,这多是不可接受的。经过使用分区的FDAF能够减小延迟,该方法将过滤器脉冲响应分为较短的部分,将FDAF应用于每一个部分,而后合并中间结果。在这种状况下,帧大小必须是分区(块)长度的倍数,从而大大减小了长脉冲响应的等待时间。

% Reduce the frame size from 2048 to 256
frameSize = 256;
nearSpeechSrc.SamplesPerFrame    = frameSize;
farSpeechSrc.SamplesPerFrame     = frameSize;
farSpeechEchoSrc.SamplesPerFrame = frameSize;
micSrc.SamplesPerFrame           = frameSize;
% Switch the echo canceller to Partitioned constrained FDAF
echoCanceller.Method      = 'Partitioned constrained FDAF';
% Set the block length to frameSize
echoCanceller.BlockLength = frameSize;

% Stream processing loop
while(~isDone(nearSpeechSrc))
    nearSpeech = nearSpeechSrc();
    farSpeech = farSpeechSrc();
    farSpeechEcho = farSpeechEchoSrc();
    micSignal = micSrc();
    % Apply FDAF
    [y,e] = echoCanceller(farSpeech, micSignal);
    % Send the speech samples to the output audio device
    player(e);
    % Compute ERLE
    erle = diffAverager((e-nearSpeech).^2)./ farEchoAverager(farSpeechEcho.^2);
    erledB = -10*log10(erle);
    % Plot near-end, far-end, microphone, AEC output and ERLE
    AECScope2(nearSpeech, micSignal, e, erledB);
end

 

 

 

 

开源的音频处理库

Speex:开源语音编解码器

专为语音设计的无专利音频压缩格式。Speex项目旨在经过提供免费替代昂贵的专有语音编解码器的方法来下降语音应用程序的进入门槛。此外,Speex很是适合Internet应用程序,并提供了大多数其余编解码器中没有的有用功能。

Speex基于CELP ,旨在以2到44 kbps的比特率压缩语音Speex的一些功能包括:

  • 同一位流中的窄带(8 kHz),宽带(16 kHz)和超宽带(32 kHz)压缩
  • 强度立体声编码
  • 丢包隐藏
  • 可变比特率操做(VBR)
  • 语音活动检测(VAD)
  • 不连续传输(DTX)
  • 定点端口
  • 回声消除器
  • 噪声抑制

Speex编解码器已被Opus淘汰。它会继续可用,可是因为Opus在各个方面都比Speex更好,所以建议用户切换Opus

Opus互动音频编解码器

Opus是一款彻底开放,免版税,功能普遍的音频编解码器。Opus在互联网上的交互式语音和音乐传输方面无可匹敌,但也适用于存储和流媒体应用程序。

Opus能够处理各类音频应用程序,包括IP语音,视频会议,游戏内聊天,甚至是远程现场音乐表演。它能够从低比特率的窄带语音扩展到高质量的立体声音乐。支持的功能有:

  • 比特率从6 kb / s到510 kb / s
  • 采样率从8 kHz(窄带)到48 kHz(全带)
  • 帧大小从2.5毫秒到60毫秒
  • 支持恒定比特率(CBR)和可变比特率(VBR)
  • 音频带宽从窄带到全带
  • 支持语音和音乐
  • 支持单声道和立体声
  • 最多支持255个通道(多流帧)
  • 动态可调的比特率,音频带宽和帧大小
  • 良好的丢失健壮性和数据包丢失隐藏(PLC)
  • 浮点和定点实现

WebRTC(实时通讯):用户能够经过简单API为浏览器和移动应用程序提供实时通讯(RTC)功能

推荐使用webrtc

 

参考

《基于自适应滤波器的声学回声消除研究——冯江浩》

MATLAB官网audio_Examples_Acoustic Echo Cancellation 

Hand Book of Speech Enhancement and Recognition

语音自适应回声消除算法代码讲解

WebRTC AEC AGC ANC NS示例

相关文章
相关标签/搜索