LMS概述
LMS(Least Mean Square), 由 Widrow 和 Hoff 于1960年提出,也称Δ规则。该算法与感知器网络的学习算法在权值调整上都基于纠错学习规则,但 LMS 更易实现,因此得到广泛应用,成为自适应滤波的标准算法。
LMS滤波器是一类能够“学习”未知传递函数的自适应滤波器。 LMS 滤波器使用一种梯度下降法,其中滤波器系数根据瞬时误差信号更新。自适应滤波器常用于通信系统、均衡器和噪声去除。
LMS过滤器由两个组件组成,如下图所示。第一个组件是一个标准的横向或FIR滤波器。第二部分是系数更新机制。LMS滤波器有两个输入信号。“输入”输入FIR滤波器,而“参考输入”对应于FIR滤波器的期望输出。即更新FIR滤波器系数,使FIR滤波器的输出与参考输入匹配。滤波器系数更新机制是基于FIR滤波器输出与参考输入之间的差值。随着滤波器的适应,这个“错误信号”趋于零。LMS处理函数接受输入和参考输入信号,生成滤波输出和误差信号。
原理解析
函数对数据块进行操作,每次调用函数都会通过过滤器处理blockSize样本。 p S r c pSrc pSrc 指向输入信号, p R e f pRef pRef 指向参考信号, p O u t pOut pOut 指向输出信号, p E r r pErr pErr 指向错误信号。所有数组都包含blockSize值。
这些函数以块为单位进行操作。在内部,过滤器系数 b [ n ] b[n] b[n] 在一个样本一个样本的基础上更新。与归一化 LMS 算法相比, LMS 滤波器的收敛速度较慢。
输出信号 y [ n ] y[n] y[n] 由标准FIR滤波器计算得到
y [ n ] = b [ 0 ] ∗ x [ n ] + b [ 1 ] ∗ x [ n − 1 ] + . . . + b [ n u m T a p s − 1 ] ∗ x [ n − n u m T a p s + 1 ] y[n] = b[0] * x[n] + b[1] * x[n-1] + ... + b[numTaps-1] * x[n-numTaps+1] y[n]=b[0]∗x[n]+b[1]∗x[n−1]+...+b[numTaps−1]∗x[n−numTaps+1]
误差信号为参考信号 d [ n ] d[n] d[n] 与计算结果 y [ n ] y[n] y[n]之间差值
e [ n ] = d [ n ] − y [ n ] e[n] = d[n] - y[n] e[n]=d[n]−y[n]
误差信号被计算出来后,滤波器参数 b [ k ] b[k] b[k] 会被更新
b [ k ] = b [ k ] + e [ n ] ∗ m u ∗ x [ n − k ] , k = 0 , 1 , 2 , . . . , n u m T a p s − 1 b[k] = b[k] + e[n] * mu * x[n-k], k=0,1,2,...,numTaps-1 b[k]=b[k]+e[n]∗mu∗x[n−k],k=0,1,2,...,numTaps−1
式中, m u mu mu 为步长,控制系统收敛速度
在APIs中, p C o e f f s pCoeffs pCoeffs 为一个长度为 n u m T a p s numTaps numTaps 的系数数组,其按时间倒序存储
b [ n u m T a p s − 1 ] , b [ n u m T a p s − 2 ] , . . . , b [ 1 ] , b [ 0 ] ] {b[numTaps-1], b[numTaps-2],..., b[1], b[0]]} b[numTaps−1],b[numTaps−2],...,b[1],b[0]]
** p S t a t e pState pState 为一个长度为 n u m T a p s + b l o c k S i z e − 1 numTaps + blockSize - 1 numTaps+blockSize−1 的状态数组,状态缓冲区的样本按顺序存储**
x [ n − n u m T a p s + 1 ] , x [ n − n u m T a p s ] , x [ n − n u m T a p s − 1 ] , . . . , x [ 0 ] , x [ 1 ] , . . . , x [ b l o c k S i z e − 1 ] {x[n-numTaps+1], x[n-numTaps], x[n-numTaps-1],..., x[0], x[1],..., x[blockSize-1]} x[n−numTaps+1],x[n−numTaps],x[n−numTaps−1],...,x[0],x[1],...,x[blockSize−1]
注意,状态缓冲区的长度超过了样本的系数数组的长度 b l o c k S i z e − 1 blockSize-1 blockSize−1。增加的状态缓冲区长度允许循环寻址,这是传统的FIR滤波器,以避免和产生显著的速度提高。在处理每个数据块之后更新状态变量。
代码
Matlab
clear; close all; clc;
t = 0:199;
xs = 10*cos(0.5*t); %xs为理想的余弦信号
noise = randn(1,length(t)); %噪声信号
xn = xs+noise; %输入信号
dn = xs;
[w,en,yn] = LMS_Simple(xn,dn); %引用LMS算法实现滤波
t_new = 0:length(yn)-1;
figure;
subplot(511); plot(t,xs);
grid;title('理想信号');
subplot(512); plot(noise);
grid;title('随机噪声');
subplot(513); plot(t,xn,'r',t,dn,'blue');
grid;title('输入信号和理想信号的对比');
subplot(514); plot(yn);
grid;title('输出信号');
subplot(515); plot(t,xn,'red',t_new,yn,'blue',t_new,en,'yellow');
grid;title('三种信号的比较');
legend('输入信号','输出信号','误差信号');
%LMS算法
function [w,en,yn] = LMS_Simple(xn,dn) %xn为输入信号(行向量), dn为理想信号(行向量)
M = 30; %滤波器的阶数
zeroize = zeros( (ceil(length(xn)/M) * M) - length(xn) , 1); % 补零
xn = cat(1,xn',zeroize);%行向量转置为列向量,补零
dn = cat(1,dn',zeroize);%行向量转置为列向量,补零
itr = length(xn); % 使得迭代次数为输入信号xn的长度
w = zeros(M,itr); % 滤波器的系数矩阵
en = zeros(itr,1); % 误差信号
yn = zeros(length(xn)); %滤波器的输出信号
lambda = max(eig(xn*xn')); %xn的自相关矩阵的最大特征值
mu = 0.95 * (2/lambda); %求步长,0.95系数可设置,保证小于2/lambda
%迭代更新滤波器的参数
for k = M:itr %要保证输入延时后的信号有效,所以实际的迭代次数只有(itr-M)次,
x = xn(k:-1:k-M+1); %将输入信号延迟,使得滤波器的每个抽头都有输入
y = w(:,k-1)'*x; %计算出滤波器的输出
en(k) = dn(k)-y; %得出误差信号
w(:,k) = w(:,k-1) + mu*en(k)*x;%迭代更新滤波器的系数
yn(k) = w(:,k)'*x; %滤波器的最终输出
end
end
---->>代码来源
Python
# -*- coding: utf-8 -*-
"""
Created on Wed Jun 8 15:38:24 2022
@author: heng.zhang
"""
import numpy as np
import matplotlib.pyplot as plt
import scipy.io as scio
# 信号加噪
def awgn(x, snr):
snr = 10 ** (snr / 10.0)
xpower = np.sum(np.abs(x) ** 2) / len(x)
npower = xpower / snr
if type(x[0]) != np.complex128:
return x + np.random.randn(len(x)) * np.sqrt(npower)
else:
return x + np.random.randn(len(x)) * np.sqrt(npower / 2) + 1j * np.random.randn(len(x)) * np.sqrt(npower / 2)
def lmsFunc(xn, dn, M, mu):
itr = len(xn)
en = np.zeros((itr, 1))
W = np.zeros((M, itr))
for k in range(M, itr):
if k==20:
x = xn[k-1::-1]
else:
x = xn[k-1:k-M-1:-1]
try:
y = np.dot(W[:, k - 2], x)
#print(y)
except:
pass
en[k-1] = dn[k-1] - y
W[:, k-1] = W[:, k - 2] + 2 * mu * en[k-1] * x
yn = np.ones(xn.shape) * np.nan
for k in range(M, len(xn) ):
if k == 20:
x = xn[k - 1::-1]
else:
x = xn[k - 1:k - M - 1:-1]
yn[k] = np.dot(W[:, -2], x)
return yn, W, en
if __name__ == '__main__':
fs = 1 #采样频率
f0 = 0.02 #信号频率
n = 1000
t = np.arange(n)/fs
xs = np.cos(2*np.pi*f0*t)
ws = awgn(xs, 20)
M = 20
xn = ws
dn = xs
mu = 0.001
yn, W, en = lmsFunc(xn, dn, M, mu)
plt.figure()
plt.subplot(211)
plt.plot(t, ws)
plt.subplot(212)
plt.plot(t, yn)
plt.figure()
plt.plot(en)
plt.show()