在密闭空间里与外界通信时,来自于对方的信号称之为远端信号,自己向对方表达的信号称之为近端信号。远端信号通过喇叭转变成声音信号,在密闭空间里多次反射后,会被麦克接收,与近端信号叠加在一起,传向对方。对方在听到近端信号的语音之外,也能听到自己的声音,即回声。
声学回声是指扬声器播出的声音在接受者听到的同时,也通过多种路径被麦克风拾取到。多路径反射的结果产生了不同延时的回声,包括直接回声和间接回声:
(1)直接回声:是指由扬声器播出的声音未经任何反射直接进入麦克风。这种回声的延时最短,它同远端说话者的语音能量,扬声器与麦克风之间的距离、角度 ,扬声器的播放音量,麦克风的拾取灵敏度等因素直接相关;
(2)间接回声:是指由扬声器播出的声音经过不同的路径(如房屋或房屋内的任何物体)的一次或多次反射后进入麦克风所产生的回声的集合。房屋内的任何物体的任何变动都会改变回声的通道。因此,这种回声的特点是多路径的、时变的。
自适应回声抵消(AEC,Adaptive Echo Cancellation) 的基本思想是估计回声路径的特征参数,产生一个模拟的回声路径,得出模拟回声信号,从接收信号中减去该信号,实现回声抵消。其关键就是得到回声路径的冲击响应h(n),由于回声路径通常是未知的和时变的,所以一般采用自适应滤波器来模拟回声路径。自适应回声抵消的显著特点是实时跟踪,实时性强。
变量 | 计算 | 定义 |
---|---|---|
x ( n ) x(n) x(n) | 远端信号 | |
s ( n ) s(n) s(n) | 近端信号 | |
y ( n ) y(n) y(n) | y ( n ) = x ( n ) ∗ h ( n ) y(n)=x(n)*h(n) y(n)=x(n)∗h(n) | 回声信号 |
y ^ ( n ) \hat y(n) y^(n) | y ^ ( n ) = x ( n ) ∗ h ^ ( n ) \hat y(n)=x(n)*\hat h(n) y^(n)=x(n)∗h^(n) | 模拟回声信号 |
d ( n ) d(n) d(n) | d ( n ) = s ( n ) + y ( n ) d(n)=s(n)+y(n) d(n)=s(n)+y(n) | 参考信号 |
e ( n ) e(n) e(n) | e ( n ) = d ( n ) − y ^ ( n ) e(n)=d(n)-\hat y(n) e(n)=d(n)−y^(n) | 误差信号 |
H ( z ) \mathbf H(z) H(z) | 回声路径 | |
H ^ ( z ) \mathbf {\hat H}(z) H^(z) | 模拟回声路径 |
自适应回声抵消就是通过自适应算法估计回声路径 H ( z ) \mathbf H(z) H(z)的特征参数,产生一个模拟的回声路径 H ^ ( z ) \mathbf {\hat H}(z) H^(z),得出模拟回声信号 y ^ ( n ) \hat y(n) y^(n),从参考信号 d ( n ) d(n) d(n)中减去该信号,实现回声抵消。
在自适应过程中,自适应算法根据误差信号 e ( n ) e(n) e(n),利用某种最优准则不断地调整滤波器抽头系数 h ^ \mathbf {\hat h} h^,最终使得滤波器的输出信号 y ^ ( n ) \hat y(n) y^(n)无限接近 y ( n ) y(n) y(n),抽头系数 h ^ \mathbf {\hat h} h^收敛于 h \mathbf h h。
最有代表性的自适应算法有最小均方(LMS,Least Mean Square)算法、递归最小二乘(Recursive Least Square)算法。LMS算法因其结构简单、计算复杂度低和在平稳信号中具有良好的收敛性,成为应用最广泛的自适应算法。
根据最小均方误差准则,该准则要求滤波器输出与期望信号之差的均方值最小,将目标函数(性能函数)定义为:
ε ( n ) = E [ ∣ e ( n ) ∣ 2 ] = E [ ∣ d ( n ) − h ^ T ( n ) x ( n ) ∣ 2 ] = E [ d 2 ( n ) ] − 2 R d x T h ^ ( n ) + h ^ T ( n ) R x h ^ ( n ) \begin{align} \varepsilon(n) & = E[|e(n)|^2]\\ & = E[|d(n)-\hat h^T(n)x(n)|^2]\\ & =E[d^2(n)]-2R_{dx}^T\hat h(n)+\hat h^T(n)R_x\hat h(n)\\ \end{align} ε(n)=E[∣e(n)∣2]=E[∣d(n)−h^T(n)x(n)∣2]=E[d2(n)]−2RdxTh^(n)+h^T(n)Rxh^(n)其中, R x = E [ x ( n ) x T ( n ) ] R_x=E[x(n)x^T(n)] Rx=E[x(n)xT(n)]为输入信号的自相关函数, R d x = E [ d ( n ) x T ( n ) ] R_{dx}=E[d(n)x^T(n)] Rdx=E[d(n)xT(n)]为输入信号和参考信号的互相关函数。
为了选择最优权系数 h ^ \hat h h^,使性能函数 ε ( n ) \varepsilon(n) ε(n)最小,一些常用的自适应算法都是基于梯度法的,用 ∇ \nabla ∇表示性能函数的梯度向量,式 ( 3 ) (3) (3)对 h ^ \hat h h^求导得:
∇ = ∂ ε ( n ) ∂ h ^ = 2 R x h ^ − 2 R d x (4) \nabla=\frac{\partial\varepsilon(n)}{\partial\hat h}=2R_x\hat h-2R_{dx}\tag4 ∇=∂h^∂ε(n)=2Rxh^−2Rdx(4)令上式等于0,得到最优权矢量:
h ^ 0 = R x − 1 R d x (5) \hat h^0=R_x^{-1}R_{dx}\tag5 h^0=Rx−1Rdx(5)所得到的滤波器最优权矢量也即为维纳最优解,当自适应滤波器的权系数满足上式时,均方误差达到最小值。
要求得维纳最优解,需要求相关矩阵并计算相关矩阵的逆,这在实际应用中限制较多。最陡梯度下降法由于不需要对相关矩阵求逆,收敛速度较快,被广泛应用到实际工程当中。其算法可以表示为:
h ^ ( n + 1 ) = h ^ ( n ) + 1 2 μ ( − ∇ ) (6) \hat h(n+1)=\hat h(n)+\frac{1}{2}\mu(-\nabla)\tag6 h^(n+1)=h^(n)+21μ(−∇)(6)其中 μ \mu μ是调整步长的参数,它控制着系统的稳定性和算法的收敛速度,把式 ( 4 ) (4) (4)代入 ( 6 ) (6) (6)式,得到最陡梯度下降法的递推公式:
h ^ ( n + 1 ) = h ^ ( n ) + μ ( R d x − R x h ^ ) (7) \hat h(n+1)=\hat h(n)+\mu(R_{dx}-R_x\hat h)\tag7 h^(n+1)=h^(n)+μ(Rdx−Rxh^)(7)用上面的递推公式能够让滤波器的权系数收敛到它的最佳状态,即维纳最优解。但是,每次迭代都需要求出其梯度矢量的准确值,要求输入信号和期望信号是随机平稳过程,这给具体实现带来了很大的困难。
LMS算法采用一种用梯度的估计值代替梯度的精确值的方法,具体实现是采用瞬时误差的平方来代替均方误差,则式 ( 4 ) (4) (4)的梯度估计值表达式为:
∇ ^ = ∂ [ e 2 ( n ) ] ∂ h ^ = − 2 e ( n ) x ( n ) (8) \hat\nabla=\frac{\partial[e^2(n)]}{\partial\hat h}=-2e(n)x(n)\tag8 ∇^=∂h^∂[e2(n)]=−2e(n)x(n)(8)由式 ( 6 ) (6) (6)和式 ( 8 ) (8) (8)可以得到LMS算法的递推公式:
h ^ ( n + 1 ) = h ^ ( n ) + μ e ( n ) x ( n ) (9) \hat h(n+1)=\hat h(n)+\mu e(n)x(n)\tag9 h^(n+1)=h^(n)+μe(n)x(n)(9)式中, μ \mu μ为固定步长因子, μ \mu μ的大小很大程度上决定了算法的收敛与稳态性能。 μ \mu μ越大,算法收敛越快,但稳态误差也越大; μ \mu μ越小,算法收敛越慢,但稳态误差也越小。为保证算法稳态收敛,应使 μ \mu μ在以下范围取值:
0 < μ < 2 x T ( n ) x ( n ) (10) 0<\mu<\frac{2}{x^T(n)x(n)}\tag{10} 0<μ<xT(n)x(n)2(10)LMS算法的具体实现步骤如下:
1 ) 1) 1) 假设起始时刻 n = 0 n=0 n=0,自适应滤波器权矢量的初始值 h ^ ( 0 ) \hat h(0) h^(0)为任意值(一般设置为 0 0 0);
2 ) 2) 2) 计算误差信号 e ( n ) e(n) e(n);
3 ) 3) 3) 利用权矢量递推公式 h ^ ( n + 1 ) = h ^ ( n ) + μ e ( n ) x ( n ) \hat h(n+1)=\hat h(n)+\mu e(n)x(n) h^(n+1)=h^(n)+μe(n)x(n),更新权矢量;
4 ) 4) 4) 重复步骤 2 ) 2) 2)和 3 ) 3) 3),直至达到平稳状态。
LMS算法在自适应滤波中流行的主要原因是其计算简单,比其他常用的自适应算法更易于实现。但是总体而言,LMS算法复杂度低,它的收敛速度还是慢。而且是固定步长,这就需要在开始自适应滤波操作之前了解输入信号的统计信息。实际上,这是很难实现的。即使我们假设自适应回声抵消系统的唯一输入信号是语音,但仍有许多因素如信号输入功率和振幅会影响其性能,为改善LMS这个不足之处,科研人员提出一系列改进算法,NLMS算法就是其中一种。
NLMS算法是LMS算法的一个扩展,利用可变的步长因子代替固定的步长因子,就得到了NLMS算法,它通过计算最大步长值绕过了LMS固定步长的问题。
μ ( n ) = α x T ( n ) x ( n ) (11) \mu(n)=\frac{\alpha}{x^T(n)x(n)}\tag{11} μ(n)=xT(n)x(n)α(11)为了使算法收敛 α \alpha α应该满足:
0 < α < 2 (12) 0<\alpha<2\tag{12} 0<α<2(12)实际中,为了避免输入信号 x ( n ) x(n) x(n)的内积过小而使步长过大,进一步修改式 ( 12 ) (12) (12)为:
μ ( n ) = α c + x T ( n ) x ( n ) (13) \mu(n)=\frac{\alpha}{c+x^T(n)x(n)}\tag{13} μ(n)=c+xT(n)x(n)α(13)其中 c c c为一个很小的正常数。
NLMS算法的递推公式为:
h ^ ( n + 1 ) = h ^ ( n ) + α c + x T ( n ) x ( n ) e ( n ) x ( n ) (14) \hat h(n+1)=\hat h(n)+\frac{\alpha}{c+x^T(n)x(n)}e(n)x(n)\tag{14} h^(n+1)=h^(n)+c+xT(n)x(n)αe(n)x(n)(14)
修改自: https://github.com/kamejosh/Acoustic-Echo-Canceller/blob/master/nlms_finished.m.
clc;
clear all;
close all;
%% 回声路径
% 频率
fs=8000;
M=fs/2 + 1;
% 产生冲激响应
[B,A]=cheby2(4,20,[0.1 0.7]);
impulseResponseGenerator=dsp.IIRFilter('Numerator',[zeros(1,6) B],'Denominator',A);
% 产生房间的冲激响应,即回声路径h(n)
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');
%% 近端语音信号
% 读入近端语音信号s(n)
[v,Fs1]=audioread('D:\audio\nearspeech.wav');
near=v';
%% 远端语音信号
% 读入远端语音信号x(n)
[x,Fs2]=audioread('D:\audio\farspeech.wav');
far=x';
%% 回声信号
farEcho=room(far); % 间接回声x(n)*h(n)
farEcho=farEcho*0.2+far; % 回声信号=直接回声+间接回声
% y(n)=x(n)+x(n)*h(n)
%% 参考信号
micSignal=farEcho+near; % d(n)=y(n)+s(n)
N=length(micSignal);
%% LMS
% 初始化
ANNCx1=zeros(1,N); % 自适应滤波器的状态
ANNCw1=zeros(1,M); % 自适应滤波器的权系数
e_cont1=zeros(1,N); % 误差信号
mu1=0.05; % 固定步长
% 开始迭代
for epoch=1:N
ANNCx1=[far(epoch) ANNCx1(1:(M-1))]; % 更新滤波器输入
ANNCy1=sum(ANNCx1.*ANNCw1); % 滤波器输出
e_cont1(epoch)=micSignal(epoch)-ANNCy1; % 计算误差信号
ANNCw1=ANNCw1+mu1*e_cont1(epoch)*ANNCx1; % 权系数递推公式
end
%% NLMS
% 初始化
alfa=0.004; % 避免步长过大
c=0.04; % 避免输入信号内积过小
ANNCx2=zeros(1,N);
ANNCw2=zeros(1,M);
e_cont2=zeros(1,N);
% 开始迭代
for epoch=1:N
mu2=alfa/(c+(far(epoch)'*far(epoch))); % 变步长
ANNCx2=[far(epoch) ANNCx2(1:(M-1))];
ANNCy2=sum(ANNCx2.*ANNCw2);
e_cont2(epoch)=micSignal(epoch)-ANNCy2;
ANNCw2=ANNCw2+mu2*e_cont2(epoch)*ANNCx2;
end
%% 画图
figure(1);
subplot(2,1,1);
plot(near);
xlabel('采样点');
ylabel('幅度');
xlim([1 N]);
ylim([-1 1]);
title('近端信号');
subplot(2,1,2);
plot(far);
xlabel('采样点');
ylabel('幅度');
xlim([1 N]);
ylim([-1 1]);
title('远端信号');
figure(2);
subplot(2,1,1);
plot(farEcho);
xlabel('采样点');
ylabel('幅度');
xlim([1 N]);
ylim([-1 1]);
title('回声信号');
subplot(2,1,2);
plot(micSignal);
xlabel('采样点');
ylabel('幅度');
xlim([1 N]);
ylim([-1 1]);
title('参考信号');
figure(3);
subplot(2,1,1);
plot(e_cont1);
xlabel('采样点');
ylabel('幅度');
xlim([1 N]);
ylim([-1 1]);
title('LMS误差信号');
subplot(2,1,2);
plot(e_cont2);
xlabel('采样点');
ylabel('幅度');
xlim([1 N]);
ylim([-1 1]);
title('NLMS误差信号');
近端语音信号和远端语音信号时域波形图。
回声信号和参考信号时域波形图。
LMS和NLMS算法输出的误差信号时域波形图。
https://www.cnblogs.com/LXP-Never/p/11703440.html.
如有问题,恳请指正。