NLMS 算法不收敛,多个实现结果相同

NLMS Algorithm is not converging, multiple implementation resulting equally

归一化最小均方算法用于数字滤波,它基本上试图模仿 "unknown" 滤波器,因此它们的差异(被认为是误差)趋于零。收敛的"factor"是开始时误差会很高,随着算法的连续运行误差会变小。

NLMS和LMS(它的继任者)之间的唯一区别是NLMS对滤波器的入口进行了归一化处理,因此对于高输入功率来说并不容易。

维基页面中有两种算法的方程式:https://en.wikipedia.org/wiki/Least_mean_squares_filter 与我的实现类似。

我目前正在使用自适应植物,因此我可以将白噪声输入过滤到低通滤波器中,并尝试调整我的算法系数以模仿低通,它是在 matlab 中实现的:

clear all;close all;clc;

fid = fopen('ruidoBranco.pcm', 'rb');
s = fread(fid, 'int16');
fclose(fid);

itera = length(s);
L = 50;
passo = 0.00000000001;
H = passaBaixa(L,1000,2);
W = zeros(L,1);
y = zeros(itera,1);
sav_erro = zeros(itera,1);

for i=(L+1):itera,
    D=0;
    Y=0;
    for j=1:(L),
        Y = Y + W(j,1)*s(i-j,1);
        D = D + H(j,1)*s(i-j,1);
    end
    erro = D-Y;
    k=passo*erro;
    for j=1:(L),
        W(j,1) = W(j,1)+(k*s(i-j,1)/(s(i-j,1)^2+0.000001));
    end
    sav_erro(i,1) = (erro);
end
subplot(2,1,1);
plot(sav_erro);
subplot(2,1,2);
plot(W);
hold on;
plot(H,'r');

fid = fopen('saidaFIR.pcm', 'wb');
fwrite(fid,sav_erro,'int16');
fclose(fid);

"passaBaixa"函数就是之前说的低通滤波器:

function H = passaBaixa(M,FC,op)
    iteracoes = M;
    FS=8000;
    FC=FC/FS;
    M=iteracoes;
    H = zeros(iteracoes,1);
    for i=1:iteracoes,                                          
        if(i-M/2==0)
           H(i,1)=2*pi*FC;
        else
            H(i,1)=sin(2*pi*FC*(i-M/2))/(i-M/2);
        end
        if(op==1)
            H(i,1)=H(i,1);
        else if (op==2)
                 H(i,1) = H(i,1)*(0.42-0.5*cos(2*pi*i/M)+0.08*cos(4*pi*i/M));
            else
                 H(i,1)=H(i,1)*(0.54-0.46*cos(2*pi*i/M));
            end
        end
    end
    soma = sum(H);
    for i=1:iteracoes,
        H(i,1)=H(i,1)/soma;
    end
end

文件 ruidoBranco.pcm 只是一个由 80.000 个样本生成的白噪声。

得到的结果如下:

其中上图是误差,下图是低通滤波器(红色)和 "adapted" 算法滤波器(蓝色)的脉冲响应。

它没有收敛,应该看起来像这样:

如您所见,上图收敛到几乎为 0 的错误,下图不再有蓝色,因为它在红色后面(因为它几乎完美地调整了过滤器的系数)

我想知道我的实现是否有任何明显的错误,也许这可能是以后有类似错误的人的参考。

解决方法是我没有为算法使用正确的乘法,它需要是点积而不是简单的 2 的幂

因此修复在 for 循环中:

dotprod = dot(s(i-j,1),s(i-j,1));    
for j=1:(L),
    W(j,1) = W(j,1)+(k*s(i-j,1)/dotprod);
end