回声就是声音信号经过一系列反射之后,又听到了自己讲话的声音,这就是回声。一些回声是必要的,比如剧院里的音乐回声以及延迟时间较短的房间回声;而大多数回声会造成负面影响,比如在有线或者无线通信时重复听到自己讲话的声音(回想那些年我们开黑打游戏时,如果其中有个人开了外放,他的声音就会回荡来回荡去)。因此消除回声的负面影响对通信系统是十分必要的。
针对回声消除(Acoustic Echo Cancellation,AEC )问题,现如今最流行的算法就是基于自适应滤波的回声消除算法。本文从回声信号的两种分类以及 AEC 的基本原理出发,介绍几种经典的 AEC 算法并对其性能进行阐释。
本文是奔着边学便抄的态度,摘录自声学回声消除(Acoustic Echo Cancellation)原理与实现,原文写的很好,相关博客也很精彩。
在通信系统中,回声主要分为两类:电路回声和声学回声
电路回声通常产生于有线通话中,为了降低电话中心局与电话用户之间电话线的价格,用户间线的连接采用两线制;而电话中心局之间连接采用四线制(上面两条线路用于发送给用户端信号,下面两条线路用于接收用户端信号)。问题就出来了,造成电路回声的根本原因是转换混合器的二线-四线阻抗不能完全匹配(使用的不同型号的电线或者负载线圈没有被使用的原因),导致混合器 接收线路 上的语音信号流失到了 发送线路 ,产生了回声信号,使得另一端的用户在接收信号的同时听到了自己的声音。电路回声产生原理如下图:
在现如今的数字通信网络中,转换混合器与数模转换器融为一体,但无论是模拟电子线路还是数字电子线路,二-四线的转换都会造成阻抗不匹配问题,从而导致其产生电路回声,影响现代通信质量。由于电路回声的线性以及稳定性,用一个简单的线性叠加器就可以实现电路回声消除。首先将产生的回声信号在数值上取反,线性地叠加在回声信号上,将产生的回声信号抵消,实现电路回声的初步消除。然而由于技术缺陷,线性叠加器不能完整地将回声信号抹去,因此需要添加一个非线性处理器,其实质是一个阻挡信号的开关,将残余的回声信号经过非线性处理之后,就可以实现电路回声的消除,或者得到噪声很小的静音信号。由于电路回声信号是线性且稳定的,所以比较容易将其消除,而本文主要研究的是如何消除非线性的声学回声。
在麦克风与扬声器互相作用影响的双工通信系统中极易产生声学回声。如下图所示
远端讲话者A–>麦克风A–>电话A–>电话B---->扬声器B—>麦克风B–>电话B–>电话A–>扬声器A—>麦克风A—>…就这样无限循环。
详细讲解:远端讲话者A的话语被麦克风采集并传入至通信设备,经过无线或有线传输之后达到近端的通信设备,并通过近端 B 的扬声器播放,这个声音又会被近端 B 的麦克风拾取至其通信设备形成声学回声,经传输又返回了远端 A 的通信设备,并通过远端 A 的扬声器播放出来,从而远端讲话者就听到了自己的回声。
近端语音信号:说话人说话 被近端麦克风采集的信号。
远端语音信号:远端的语音信号通过近端扬声器播放,与房间的回声路径卷积后 被近端麦克风采集到的语音信号。
声学回声信号根据传输途径的差别可以分别直接回声信号和间接回声信号。
直接回声:近端扬声器B将语音信号播放出来后,近端麦克风B直接将其采集后得到的回声。直接回声不受环境的印象,与扬声器到麦克风的距离及位置有很大的关系,因此直接回声是一种线性信号。
间接回声:近端扬声器B将语音信号播放出来后,语音信号经过复杂多变的墙面反射后由近端麦克风B将其拾取。间接回声的大小与房间环境、物品摆放以及墙面吸引系数等等因素有关,因此间接回声是一种非线性信号。
回声消除技术主要用于在免提电话、电话会议系统等情形中。
如今解决 AEC 问题最常用的方法,就是:
使用不同的自适应滤波算法调整滤波器的权值向量,估计一个近似的回声路径来逼近真实回声路径,从而得到估计的回声信号,并在纯净语音和回声的混合信号中除去此信号来实现回声的消除。
AEC的基本原理如下图:
x ( n ) x(n) x(n) 为远端输入信号,经过未知的回声路径 w ( n ) w(n) w(n)得到 y ( n ) = x ( n ) ∗ w ( n ) y(n)=x(n)∗w(n) y(n)=x(n)∗w(n),再加上观测噪声 v ( n ) v(n) v(n),得到期望信号 d ( n ) = y ( n ) + v ( n ) d(n)=y(n)+v(n) d(n)=y(n)+v(n)。 x ( n ) x(n) x(n)通过自适应滤波器 w ^ ( n ) \hat{w}(n) w^(n)得到估计的回声信号,并与期望信号 d ( n ) d(n) d(n)相减得到误差信号 e ( n ) e(n) e(n),即 e ( n ) = d ( n ) − w ^ T ( n ) x ( n ) e(n)=d(n)−\hat{w}^T(n)x(n) e(n)=d(n)−w^T(n)x(n),误差信号的值越小说明自适应滤波算法所估计的回声路径就越接近实际的回声路径。
滤波器采用特定的自适应算法不停地调整权值向量,使估计的回声路径 w ^ ( n ) \hat{w}(n) w^(n)逐渐趋近于真实回声路径 w ( n ) w(n) w(n)。显然,在AEC问题中,自适应滤波器的选择对回声消除的性能好坏起着十分关键的作用。
自适应滤波器是一个对输入信号进行处理并不停学习,直到其达到期望值的器件。自适应滤波器在输入信号非平稳条件下,也可以根据环境不断调节滤波器权值向量,使算法达到特定的收敛条件,从而实现自适应滤波过程。
自适应滤波器按输入信号类型可分为模拟滤波器和离散滤波器,本文中使用的是离散滤波器中的数字滤波器(数字滤波器按结构可划分为输入不仅与过去和当前的输入有关、还与过去的输出有关的无限冲激响应滤波器(IIR),以及输出与有限个过去和当前的输入有关的有限冲激响应滤波器(FIR))为了使得自适应滤波器具有更强的稳定性,并且具有足够的滤波器系数可以用来调整以达到特定的收敛准则,一般选取横向的 FIR 滤波器进行来进行回声的消除。(解释:无限冲激响应类型的优势在于零极点都包含于传递函数中,所以 IIR 能够实现较低的阶数构造较为理想化的尖锐带通特性的传递函数,而劣势也很明显,即极点会造成量化误差大,使系统鲁棒性下降,并且对相位特性的控制变得困难;FIR(有限冲击响应滤波器)的传递函数都是零点,所以鲁棒性很稳定,相对而言更能实现线性特性)
x ( n ) x(n) x(n)是远端输入信号, w ^ i ( n ) \hat{w}_i(n) w^i(n)是滤波器系数,其中 i = 0 , 1 , . . . , L − 1 i=0,1,...,L−1 i=0,1,...,L−1, L L L为滤波器的长度, n n n为采样点数, w ^ ( n ) \hat{w}(n) w^(n)为滤波器的权值向量且 w ^ ( n ) = [ w ^ 0 ( n ) , w ^ 1 ( n ) , . . . w ^ L − 1 ( n ) ] T \hat{w}(n)=[\hat{w}_0(n),\hat{w}_1(n),...\hat{w}_{L-1}(n)]^T w^(n)=[w^0(n),w^1(n),...w^L−1(n)]T ,根据误差信号 e ( n ) = d ( n ) − w ^ T ( n ) x ( n ) e(n)=d(n)−\hat{w}^T(n)x(n) e(n)=d(n)−w^T(n)x(n)的值以及不同算法的收敛准则调整滤波器的权值向量。
然而自适应滤波算法的选择从根本上决定了回声消除的效果是否良好,接下来将介绍几种解决 AEC 问题的经典自适应滤波算法。
通过上面AEC的基本原理我们知道了误差信号 e ( n ) e(n) e(n)等于期望信号减去滤波器输出信号:
e ( n ) = d ( n ) − w ^ T ( n ) x ( n ) e(n)=d(n)−\hat{w}^T(n)x(n) e(n)=d(n)−w^T(n)x(n)
运用最小均方误差准则,通过对其求导并令其等于0,求到使得误差 ∣ e ( n ) ∣ 2 |e(n)|^2 ∣e(n)∣2最小时的 w w w—— ∣ e ( n ) ∣ |e(n)| ∣e(n)∣在最小点不可导,所以使用的是 ∣ e ( n ) ∣ 2 |e(n)|^2 ∣e(n)∣2,对于LMS算法,其滤波器系数迭代公式为
w ( n + 1 ) = w ( n ) + μ ∂ e ( n ) 2 ∂ w = w ( n ) + 2 μ e ( n ) ∂ ( d ( n ) − w ∗ x ( n ) ) ∂ w = w ( n ) + 2 μ e ( n ) x ( n ) w(n+1)=w(n)+μ\frac{∂e(n)^2}{∂w}=w(n)+2μe(n)\frac{∂(d(n)−w∗x(n))}{∂w}=w(n)+2μe(n)x(n) w(n+1)=w(n)+μ∂w∂e(n)2=w(n)+2μe(n)∂w∂(d(n)−w∗x(n))=w(n)+2μe(n)x(n)
式中, μ μ μ为固定步长因子, μ μ μ的大小很大程度上决定了算法的收敛与稳态性能。 μ μ μ越大,算法收敛越快,但稳态误差也越大; μ μ μ越小,算法收敛越慢,但稳态误差也越小。为保证算法稳态收敛,应使 μ μ μ在以下范围取值:
0 < μ < 2 ∑ i = 1 N x ( i ) 2 0<μ<\frac{2}{\sum_{i=1}^Nx(i)^2} 0<μ<∑i=1Nx(i)22
LMS算法的每次迭代都需要三个不同的步骤,顺序如下
我们将算法用到音频效果中,音频获取地址,代码如下
clear;clc;
snr=20; % 信噪比
order=8; % 自适应滤波器的阶数为8
[d, fs_orl] = audioread('./audio/handel.wav'); % 期望输出(73113,1)
[x, fs_echo] = audioread('./audio/handel_echo.wav'); % 回声输入
mu=0.02; % mu表示步长 0.02,
N=length(x);
Loop=10; % 150次循环
EE_LMS = zeros(N,1);
y_LMS = zeros(N,1);
for nn=1:Loop % epoch=150
win_LMS = zeros(order,1); % 自适应滤波器权重初始化w
y = zeros(N,1); % 输出
error_LMS=zeros(N,1); % 误差初始化
for i=order:N % i=8:73113
input=x(i:-1:i-order+1); % 每次迭代取8个数据进行处理,(8,1)->(9,2)
y(i)=win_LMS'*input; % (8,1)'*(8*1)=1
error_LMS(i) = d(i)-y(i); % (8,1)'*(8,1)=1
win_LMS = win_LMS+2*mu*error_LMS(i)*input;
error_LMS(i)=error_LMS(i)^2; % 记录每个采样点的误差
end
% 把总误差相加
EE_LMS = EE_LMS+error_LMS;
y_LMS=y_LMS+y;
end
error_LMS = EE_LMS/Loop; % 对总误差求平均值
y_LMS=y_LMS/Loop; % 对输出求平均
audiowrite("audio/done.wav", y_LMS, fs_orl);
sound(y_LMS) % 听一听回声消除后的音效
figure;
error1_LMS=10*log10(error_LMS(order:N));
plot(error1_LMS,'b.'); % 蓝色
axis tight; % 使用紧凑的坐标轴
legend('LMS算法'); % 图例
title('LMS算法误差曲线'); % 图标题
xlabel('样本'); % x轴标签
ylabel('误差/dB'); % y轴标签
grid on; % 网格线
LMS算法在自适应滤波中流行的主要原因是其计算简单,比其他常用的自适应算法更易于实现。对于每次迭代,LMS算法需要 2 N 2N 2N加法和 2 N + 1 2N+1 2N+1乘法。但是总体而言,LMS 算法复杂性低,它的收敛速度还是慢。而且是固定步长,这就需要在开始自适应滤波操作之前了解输入信号的统计信息。实际上,这是很难实现的。即使我们假设自适应回声抵消系统的唯一输入信号是语音,但仍有许多因素如信号输入功率和振幅会影响其性能,为改善 LMS 这个不足之处,科研人员提出一系列改进算法,NLMS 算法就是其中一种。
归一化最小均方(NLMS)算法是LMS算法的一个扩展,利用可变的步长因子代替固定的步长因子,就得到了NLMS算法,它通过计算最大步长值绕过了这个问题。
步 长 = 1 x T ( n ) x ( n ) 步长=\frac{1}{x^T(n)x(n)} 步长=xT(n)x(n)1
这个步长与输入向量 x ( n ) x(n) x(n)的系数的瞬时值的总期望能量的倒数成正比。输入样本的期望能量之和也等于输入向量与自身的点积。
NLMS算法迭代方程为
w ( n + 1 ) = w ( n ) + μ ( n ) e ( n ) x ( n ) = w ( n ) + 1 x T ( n ) x ( n ) e ( n ) x ( n ) w(n+1)=w(n)+μ(n)e(n)x(n)=w(n)+\frac{1}{x^T(n)x(n)}e(n)x(n) w(n+1)=w(n)+μ(n)e(n)x(n)=w(n)+xT(n)x(n)1e(n)x(n)
由于步长参数是根据当前的输入值来选择的,因此NLMS算法在未知信号下具有更大的稳定性。该算法具有良好的收敛速度和相对简单的计算能力,是实时自适应回波抵消系统的理想算法。
NLMS算法的每次迭代都需要按照以下顺序执行这些步骤。
我们将算法用到音频效果中,音频获取地址,代码如下:
clear;clc;
snr=20; % 信噪比
order=8; % 自适应滤波器的阶数为8
[d, fs_orl] = audioread('./audio/handel.wav'); % 期望输出(73113,1)
[x, echo] = audioread('./audio/handel_echo.wav'); % 回声输入
fai=0.0001;
mu=0.02; % mu表示步长
N=length(x);
Loop=10; % 150次循环
EE_NLMS = zeros(N,1); % 初始化总损失
y_NLMS = zeros(N,1); % 初始化AEC音频输出
for nn=1:Loop % epoch=150
win_NLMS = zeros(order,1); % 权重初始化w
y = zeros(N,1); % 输出
error_NLMS=zeros(N,1); % 初始化误差
for i=order:N % i=8:73113
input=x(i:-1:i-order+1); % 每次迭代取8个数据进行处理,(8,1)->(9,2)
y(i)=win_NLMS'*input; % (8,1)'*(8*1)=1
error_NLMS(i) = d(i)-y(i); % (8,1)'*(8,1)=1
k = mu/(fai + input'*input);
win_NLMS = win_NLMS+2*k*error_NLMS(i)*input;
error_NLMS(i)=error_NLMS(i)^2; % 记录每个采样点的误差
end
% 把总误差相加
EE_NLMS = EE_NLMS+error_NLMS;
y_NLMS=y_NLMS+y;
end
error_NLMS = EE_NLMS/Loop; % 对总误差求平均值
y_NLMS=y_NLMS/Loop; % 对输出求平均
audiowrite("audio/done.wav", y_NLMS, fs_orl);
sound(y_NLMS) % 听一听回声消除后的音效
figure;
error1_NLMS=10*log10(error_NLMS(order:N));
plot(error1_NLMS,'b.'); % 蓝色
axis tight; % 使用紧凑的坐标轴
legend('NLMS算法'); % 图例
title('NLMS算法误差曲线'); % 图标题
xlabel('样本'); % x轴标签
ylabel('误差/dB'); % y轴标签
grid on; % 网格线
NLMS算法的每次迭代需要 3 N + 1 3N+1 3N+1个乘法,仅比标准LMS算法多 N N N个。考虑到所获得的稳定性和回波衰减增益,这是一个可接受的增加。有的时候会对NLMS进行改进,设 μ ( n ) = η δ + x T ( n ) x ( n ) μ(n)=\frac{η}{δ+x^T(n)x(n)} μ(n)=δ+xT(n)x(n)η, 0 < η < 2 0<η<2 0<η<2, δ δ δ为一个较小的整数,防止输入数据矢量 x ( n ) x(n) x(n)的内积过小使得μ(n)过大而引起稳定性能下降,一般取0.0001。
当需要同时进行语音通信(或全双工传输)时,回声消除对于音频电话会议非常重要。在回声消除中,测得的麦克风信号 d ( n ) d(n) 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使用快速卷积技术来计算输出信号和过滤器更新。该计算可在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),这是对回声衰减量的平滑度量(以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的一些功能包括:
Speex编解码器已被Opus淘汰。它会继续可用,但是由于Opus在各个方面都比Speex更好,因此建议用户切换Opus。
Opus是一款完全开放,免版税,功能广泛的音频编解码器。Opus在互联网上的交互式语音和音乐传输方面无可匹敌,但也适用于存储和流媒体应用程序。
Opus可以处理各种音频应用程序,包括IP语音,视频会议,游戏内聊天,甚至是远程现场音乐表演。它可以从低比特率的窄带语音扩展到高质量的立体声音乐。支持的功能有:
谷歌公司在 2010 年收购了 Global IP Solutions 后逐步开源的音视频解决方案 WebRTC。该方案中的 AEC 模块是实现自适应滤波算法的优秀平台,它集成了声学回声消除所需要的所有结构。用户可以通过简单API为浏览器和移动应用程序提供实时通信(RTC)功能
回声消除需要时候的技术:双讲检测技术(语音活动检测,区分希腊佛中是否存在双端讲话)、自适应滤波技术(主要性能指标:跟踪性能、抗冲激性、鲁棒性和计算复杂性)、后处理(消除自适应滤波器的输出误差)
《基于自适应滤波器的声学回声消除研究——冯江浩》
MATLAB官网audio_Examples_Acoustic Echo Cancellation
Hand Book of Speech Enhancement and Recognition
语音自适应回声消除算法代码讲解
WebRTC AEC AGC ANC NS示例
Markdown数学公式语法
Markdown数学符号&公式