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
归一化最小均方算法用于数字滤波,它基本上试图模仿 "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