回声消除NLMS算法详解

        在视频或电话会议中,本地用户的声音在被本地麦克风采集后,通过系统传到远端,通过远端的扬声器播放,此时远端麦克风不可避免地会采集到扬声器播放的声音,又通过系统传回本地,并通过本地扬声器播放出来,本地用户就通过本地扬声器听到了自己的声音,这明显降低了会议通信质量。

        为了提高语音的质量,就必须进行回声消除。当参考信号已知时,归一化最小均方(Normalized Least Mean Square,NLMS)算法能很好消除回声,它由最小均方算法扩展而来。

1 NLMS算法原理

        回声消除系统基本结构如图1所示。

                        

                                                 图1  回声消除系统基本结构

        设置自适应滤波器系数w的所有初始值为0,即w(0) = 0,其长度为M。对输入信号进行采样,每次迭代取M个数据进行处理,输入矢量为

                        x(n) = [x1(n) x2(n) … xM(n)]T = [x(n)x(n-1) … x(n-M+1)]T

        加权矢量为

                        w = [w1 w2… w3]

        系统输出y(n)为

                        y(n) = wx(n)

        y(n)相对于期望信号d(n)的误差为

                        e(n) = d(n) – y(n) = d(n) -wx(n)

        运用最小均方误差准则,就是求使得E[|e(n)|^2]最小时的w,因为是通过对其求导并令其等于0求得的,而|e(n)|在最小点不可导,所以使用的是|e(n)|^2。对于LMS算法,其滤波器系数迭代公式为

                        w(n+1) = w(n) + 2µe(n)x(n)

其中µ是步长因子,0 < µ < 1/ xT(n)x(n),在LMS算法中其值是固定的,因而收敛速度较慢。

        在LMS的基础上,用可变的步长因子代替固定的步长因子,就得到了NLMS算法,其迭代方程为

                        w(n+1) = w(n) + µ(n)e(n)x(n)=w(n) +ηe(n)x(n)/(δ+xT(n)x(n))

其中η是修正的步长常量,0 < η < 2,δ为一个较小的整数,一般取0.0001,防止输入数据矢量x(n)的内积过小使得µ(n)过大而引起稳定性能下降。NLMS算法的收敛速度较快,效果较LMS算法好。

2 性能仿真

        用matlab编写程序仿真算法性能,分别对比NLMS算法与LMS算法的性能和不同步长参数η下NLMS算法的性能。代码如下:

       

clear all;
close all;
clc;
snr=20;
order=8;
Hn =[0.8783   -0.5806    0.6537   -0.3223    0.6577   -0.0582   0.2895   -0.2710    0.1278   -0.1508    0.0238   -0.1814   0.2519   -0.0396    0.0423   -0.0152    0.1664   -0.0245   0.1463   -0.0770    0.1304   -0.0148    0.0054   -0.0381    0.0374   -0.0329    0.0313   -0.0253    0.0552  -0.0369   0.0479   -0.0073    0.0305   -0.0138    0.0152   -0.0012  0.0154   -0.0092    0.0177   -0.0161    0.0070   -0.0042  0.0051   -0.0131    0.0059   -0.0041    0.0077   -0.0034   0.0074   -0.0014    0.0025   -0.0056    0.0028   -0.0005   0.0033   -0.0000    0.0022   -0.0032    0.0012   -0.0020   0.0017   -0.0022    0.0004   -0.0011      0          0   ];
          Hn=Hn(1:order);
          N=1000;
          EE=zeros(N,1);   Loop=150;  mu=0.5;
          EE1=zeros(N,1);EE2=zeros(N,1);EE3=zeros(N,1);
   for   nn=1:Loop
          r=sign(rand(N,1)-0.5);
          output=conv(r,Hn); 
          output=awgn(output,snr,'measured');
          win=zeros(1,order); 
          win1=zeros(1,order); 
          win2=zeros(1,order); 
          win3=zeros(1,order); 
          error=zeros(1,N)';
          error1=zeros(1,N)';
          error2=zeros(1,N)';
          error3=zeros(1,N)';
          
          for i=order:N
              input=r(i:-1:i-order+1);
              y(i)=win*input;
              e=output(i)-win*input;
              e1=output(i)-win1*input;
              e2=output(i)-win2*input;
              e3=output(i)-win3*input;
              fai=0.0001; 
              if i<200
                  mu=0.32;
              else
                  mu=0.15;
              end
              win=win+0.3*e*input'/(fai+input'*input);     % 不同步长的NLMS
              win1=win1+0.8*e1*input'/(fai+input'*input);
              win2=win2+1.3*e2*input'/(fai+input'*input);
              win3=win3+1.8*e3*input'/(fai+input'*input);
              error(i)=error(i)+e^2;
              error1(i)=error1(i)+e1^2;
              error2(i)=error2(i)+e2^2;
              error3(i)=error3(i)+e3^2;
%               y1(i)=win1*input;
%               e1=output(i)-win1*input;
%               win1=win1+0.2*e1*input';                   % LMS
%               error1(i)=error1(i)+e1^2;
          end
          EE=EE+error;
          EE1=EE1+error1;
          EE2=EE2+error2;
          EE3=EE3+error3;
   end
   error=EE/Loop;
   error1=EE1/Loop;
   error2=EE2/Loop;
   error3=EE3/Loop;
   
%    figure;
%    error=10*log10(error(order:N));
%    error1=10*log10(error1(order:N));
%    plot(error,'r');
%    hold on;
%    plot(error1,'b.');
%    axis tight;
%    legend('NLMS算法','LMS算法');
%    title('NLMS算法和LMS算法误差曲线');
%    xlabel('样本');
%    ylabel('误差/dB');
%    grid on;
%    
%    figure;
%    plot(win,'r');
%    hold on;
%    plot(Hn,'b');
%    grid on;
%    axis tight;
% figure;
% subplot(2,1,1);
% plot(y,'r');
% subplot(2,1,2);
% plot(y1,'b');
    figure;
   error=10*log10(error(order:N));
   error1=10*log10(error1(order:N));
   error2=10*log10(error2(order:N));
   error3=10*log10(error3(order:N));
   hold on;
   plot(error,'r');
   hold on;
   plot(error1,'b');
  hold on;
   plot(error2,'y');
   hold on;
   plot(error3,'g');
   axis tight;
   legend('η = 0.3','η = 0.8','η = 1.3','η = 1.8');
   title('不同步长对NLMS算法的影响');
   xlabel('样本');
   ylabel('误差/dB');
   grid on;

        输入信号为加了高斯噪声后的随机信号,首先我们对比一下NLMS算法和LMS算法的性能差异,取η = 1,δ = 0.001,µ = 0.2,得到两种算法的误差曲线如图2所示

                        

                                                    图2  NLMS算法和LMS算法误差曲线

        图2中下降曲线的斜率反映了算法的收敛速度,稳定后的误差反映了算法的精度。由图可知,NLMS算法的收敛速度快于LMS算法,且NLMS算法精度也大于LMS算法。

        然后分析步长大小对算法性能的影响。以NLMS算法为基础,分别分析当η= 0.3,η = 0.9,η = 1.3,η = 1.8(0< η < 2)时算法的收敛特性,得到误差曲线如图3所示。

                          

                                                    图3 不同步长对NLMS算法的影响
        由图3可看出,随着步长的增大,算法收敛速度先有所提高,之后又下降,而算法精度却逐渐减小。

        由以上两组仿真实验可以看出,算法自适应收敛时收敛速度和精度是一对矛盾,步长大,即收敛系数大,收敛速度可能有所改善,但精度却变差,反之亦然。

        由于LMS算法中步长是不变的,所以很难找到一个适当的步长来解决这一矛盾;而NLMS算法则采用变步长的方式在保证精度的情况下缩短自适应收敛过程。实际应用中要不断调整步长,以得到算法的最优性能。

3 算法效果

        分别采用NLMS算法和LMS算法来处理混响语音信号。此时输入信号是一段混响9秒的语音信号,参考信号是无混响的语音信号。为了有较快的收敛速度和精度,在NLMS迭代开始时设置步长η为0.32使算法较快收敛,之后设置步长η为0.15以得到较高精度。在LMS迭代中设置步长µ=0.1。代码如下:

       

clear all
close all
clc

hold off    
sysorder=50; %抽头数
[inp,sr]=mp3read('T60=9.0.mp3');       %输入
inp=inp(:);

[d,sr] = mp3read('T60=0.mp3');
d=d(:);
totallength=size(d,1);                 %步长
N=length(inp);
%k=0:1382493;
k=0:691246;

%算法开始
w=zeros(sysorder,1);                   %初始化
w1=zeros(sysorder,1);                  %初始化
error=zeros(N,1);                  %初始化
EE=zeros(N,1);
Loop=15000;
   
for n=sysorder:N
    u=inp(n:-1:n-sysorder+1);          %u的矩阵
    %u=inp(n-sysorder+1:n); 
    %NLMS算法
    y(n)=w'*u;                         %系统输出
    r(n)=u'*u;                         %自相关矩阵
    e(n)=d(n)-y(n);                    %误差
    srr(n)=10*log10(d(n)/(inp(n)-d(n)));
    srr1(n)=10*log10(d(n)/(y(n)-d(n)));
    %e(n)=inp(n)-y(n);                 %误差        
    fai=1e-10;                         %修正参数,防止r(n)过小导致步长值太大
    if n<2000
        mu=0.32;
    else
        mu=0.15;
    end
    w=0.8*w+mu*u*e(n)/(r(n)+fai);      %NLMS迭代方程
    error(n)=error(n)+e(n)^2;
   
    %LMS算法
    y1(n)=w1'*u;
    e1(n)=d(n)-y1(n);
    w1=0.8*w1+0.1*u*e1(n);               %LMS迭代方程
end
EE=EE+error;
error=EE/Loop;
error=error.^2;
error(n)=error'*error;

% for i=sysorder:N1
%     u1=inp2(i:-1:i-sysorder+1);
%     y_out(i)=w'*u1;
% end
%srr=10*log10(d/(inp-d));
%srr1=10*log10(d/(y-d));

y=y(:);
y1=y1(:);
e=e(:);
e1=e1(:);
srr=srr(:);
srr1=srr1(:);
%y_out=y_out(:);

inp1=reshape(inp,691247,2);
%inp3=reshape(inp2,342191,2);
d1=reshape(d,691247,2);
y_nlms=2*reshape(y,691247,2);
y_lms=2*reshape(y1,691247,2);
%y_out1=20*reshape(y_out,342191,2);
error=10*log10(error);
e_nlms=reshape(e,691247,2);
e_lms=reshape(e1,691247,2);
error_nlms=reshape(error,691247,2);
srr2=reshape(srr,691247,2);
srr3=reshape(srr1,691247,2);

figure(1);
subplot(3,1,1);
plot(k,inp1);
title('系统输出波形对比');
xlabel('样本n');
ylabel('混响9秒信号波形');
subplot(3,1,2);
plot(k,y_nlms,'r');
xlabel('样本n');
ylabel('NLMS输出信号波形');
subplot(3,1,3);
plot(k,y_lms,'g');
axis([0 691246 -1 1]);
xlabel('样本n');
ylabel('LMS输出信号波形');
 
sound(d1,sr);
sound(inp1,sr);
sound(y_nlms,sr);
mp3write(y_nlms,sr,'nlms.mp3');
 sound(y_lms,sr);
mp3write(y_lms,sr,'lms.mp3');

        其处理后波形图如图4所示。

                        

                                                      图4 NLMS算法和LMS算法去混响

        由图4可看出,NLMS算法和LMS算法均成功的去掉了混响,实际听音表明NLMS算法得到的语音很清晰,LMS算法得到语音则有些失真。



  • 16
    点赞
  • 93
    收藏
    觉得还不错? 一键收藏
  • 20
    评论
NLMS算法是一种自适应滤波算法,可以用于回声消除。具体步骤如下: 1. 初始化自适应滤波器的系数向量w和步长μ,其中w的长度为自适应滤波器的阶数加1,步长μ的大小需要根据实际情况进行调整。 2. 读入含有回声的信号x(n)和参考信号d(n),其中x(n)为麦克风采集到的信号,d(n)为扬声器播放的信号。 3. 利用自适应滤波器的系数向量w对x(n)进行滤波,得到滤波后的信号y(n)。 4. 计算误差信号e(n)=d(n)-y(n)。 5. 根据NLMS算法的更新公式更新自适应滤波器的系数向量w,即w(n+1)=w(n)+μe(n)x(n)/(x(n)·x(n)+δ),其中δ为一个小正数,用于避免分母为0的情况。 6. 重复步骤3-5,直到误差信号e(n)足够小或者达到预设的迭代次数。 以下是一个使用NLMS算法消除回声的Python代码示例: ```python import numpy as np # NLMS算法 def nlms(x, d, M, mu, eps): N = len(x) w = np.zeros(M+1) # 初始化自适应滤波器的系数向量w y = np.zeros(N) # 初始化滤波后的信号y e = np.zeros(N) # 初始化误差信号e for n in range(M, N): x_n = x[n:n-M-1:-1] # 取得当前时刻的输入信号向量 y[n] = np.dot(w, x_n) # 计算滤波后的信号y e[n] = d[n] - y[n] # 计算误差信号e w = w + mu * e[n] * x_n / (np.dot(x_n, x_n) + eps) # 更新自适应滤波器的系数向量w return y, e # 生成含有回声的信号 N = 1000 x = np.random.randn(N) d = np.zeros(N) d[100:300] = x[0:200] + 0.5 * x[100:300] # 回声信号 # 使用NLMS算法消除回声 M = 100 # 自适应滤波器的阶数 mu = 0.01 # 步长 eps = 1e-8 # 避免分母为0 y, e = nlms(x, d, M, mu, eps) # 输出结果 import matplotlib.pyplot as plt plt.figure() plt.plot(d, label='Original signal') plt.plot(y, label='Filtered signal') plt.plot(e, label='Error signal') plt.legend() plt.show() ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值