东方耀AI技术分享
标题:
自适应滤波器之LMS算法实现Demo
[打印本页]
作者:
东方耀
时间:
2021-4-16 09:08
标题:
自适应滤波器之LMS算法实现Demo
自适应滤波器之LMS算法实现Demo
# -*- coding: utf-8 -*-
__author__ = u'东方耀 微信:dfy_88888'
__date__ = '2021/4/15 11:27'
__product__ = 'PyCharm'
__filename__ = '01_自适应LMS滤波算法'
import numpy as np
import matplotlib.pyplot as plt
# 自适应滤波器之LMS算法实现Demo
# 定义向量的内积
# np.convolve()
# np.dot()
# def multiVector(A, B):
# # 两个向量的内积 对应元素相乘后求和 np.dot()
# C = sc.zeros(len(A))
#
# for i in range(len(A)):
# C[i] = A[i] * B[i]
#
# return sum(C)
def inVector(vector, b, a):
'''
从一个长向量vector中按索引截取并返回倒着的序列
:param vector:
:param b: 终点索引
:param a: 起点索引
:return:
'''
sub_vector = np.zeros(shape=(b-a+1, ))
for i in range(b - a + 1):
sub_vector[i] = vector[i + a]
return sub_vector[::-1]
# lMS算法的函数
def LMS(xn, dn, M, learning_rate, itr):
'''
N阶线性系统出发
自适应滤波之LMS算法实现
:param xn: 输入原始信号或序列
:param dn: 期望的
:param M: 滤波器阶数=64
:param learning_rate: 学习率
:param itr: 采样点数
:return:返回的yn与en是 输出和误差
'''
en = np.zeros(shape=(itr, )) # 误差 或 损失 信号
# 空间复杂度有点高 需要优化
W = [[0] * M for i in range(itr)] # 滤波器的参数 初始化 列表长度=采样点数 每个元素有滤波器阶数个值
# print(len(W), len(W[0])) 10000 64
for k in range(itr)[M - 1:]:
# 为什么要从M-1开始切片:63到最后 为根据前面的信号样点作为期望值
# 开始的:k=63 k-M+1=0
x = inVector(xn, k, k - M + 1) # len(x) = 64 滤波器的阶数=滤波器长度 决定了输入信号样点的长度
# 那个LMS函数里的d是滑动平均作为期望 问题:如果噪声均值不为0 效果会差吧?
# 输入原始信号序列还是xn 但是filter是逐步滑动去滤的
d = x.mean()
# y是一次滤波操作的输出: W[k - 1]是上一次的滤波器的参数 x呢?不是xn吗?
# x是前面的 输入样点的 倒序 因为向量点乘要求:长度一致啊
# y = multiVector(W[k - 1], x) 一维滤波
y = np.dot(W[k - 1], x)
# print("第一次应该为0:", y)
# assert 0 == 1, "停"
# 误差信号是从k=63开始的
en[k] = d - y # 误差如果很小了 可以不需要迭代了
# 循环里 每输入一个序列就更新一次滤波器参数 更新频率很高
# 梯度= -2 * learning_rate * en[k] * x
# 标准时域LMS算法的更新公式 最终发现:误差越来越小
W[k] = np.add(W[k - 1], 2 * learning_rate * en[k] * x)
# 求最优时滤波器的输出序列
yn = np.inf * np.ones(len(xn)) # inf 是无穷大的意思
# 先在原始输入序列信号上 不断改进自适应滤波的权重参数
filter_best = W[len(W) - 1]
# 最后根据得到的最优滤波器,计算原始输入信号的输出
for k in range(itr)[M - 1:]:
x = inVector(xn, k, k - M + 1)
# x才是真正的输入信号序列,错了,x是滤波操作的输入
# yn[k] = multiVector(W[len(W) - 1], x)
# 默认:最后的滤波器参数就是最优的
yn[k] = np.dot(filter_best, x)
return (yn, en)
if __name__ == "__main__":
# 参数初始化
itr = 10000 # 采样的点数
# sigma = 0.12
noise_size = itr
X = np.linspace(0, 4 * np.pi, itr, endpoint=True)
Y = np.sin(X)
signal_array = Y # [0.0]*noise_size 真实的信号
noise_array = np.random.normal(0, 0.3, noise_size) # 加上高斯白噪声
# 高斯白噪声是分析信道加性噪声的理想模型,通信中的主要噪声源——热噪声就属于这类噪声
"""noise_array = []
for x in range(itr):
noise_array.append(random.gauss(learning_rate,sigma))"""
signal_noise_array = signal_array + noise_array # 信号+噪声
M = 64 # 滤波器的阶数
learning_rate = 1e-4
xn = signal_noise_array # 原始输入端的信号为被噪声污染的正弦信号
# xn并非输入序列,因为输入序列必须与filter长度一致
dn = signal_array # 对于自适应对消器,用dn作为期望 实际没有用这个
# 调用LMS算法
(yn, en) = LMS(xn, dn, M, learning_rate, itr)
# 画出图形
plt.figure(1)
plt.plot(xn, label="$signal_noise[ DISCUZ_CODE_0 ]quot;)
plt.plot(dn, label="$signal[ DISCUZ_CODE_0 ]quot;)
plt.xlabel("Time(s)")
plt.ylabel("Volt")
plt.title("original signal xn and desired signal dn")
plt.legend()
plt.figure(2)
# plt.plot(xn,label="$xn[ DISCUZ_CODE_0 ]quot;)
# plt.plot(xn,label="$xn[ DISCUZ_CODE_0 ]quot;)
plt.plot(signal_array, label="$signal_array[ DISCUZ_CODE_0 ]quot;)
plt.plot(yn, label="$yn[ DISCUZ_CODE_0 ]quot;)
plt.xlabel("Time(s)")
plt.ylabel("Volt")
plt.title("out signal yn best for filter")
plt.legend()
plt.figure(3)
plt.plot(en, label="$error[ DISCUZ_CODE_0 ]quot;)
plt.xlabel("Time(s)")
plt.ylabel("Volt")
plt.title("error between y and d")
plt.legend()
plt.show()
复制代码
作者:
东方耀
时间:
2021-4-16 09:20
LMS算法步长调整原则:滤波器的收敛速度和稳态误差是一对矛盾。当拥有较大的步长因子会加快滤波器的收敛速度,但同时也会增大稳态失调误差。较小的步长因子会减小滤波器的收敛速度但会拥有较小的稳态误差
作者:
东方耀
时间:
2021-4-16 09:22
东方耀 发表于 2021-4-16 09:20
LMS算法步长调整原则:滤波器的收敛速度和稳态误差是一对矛盾。当拥有较大的步长因子会加快滤波器的收敛速 ...
为了克服这一矛盾,在现有固定步长算法的基础上我们提出了新的算法—变步长自适应算法。其优点是步长值随误差的改变而改变。在误差较大的时候步长因子也大以获得更快的收敛速度;当收敛过程接近稳态,误差小的时候其步长因子也小以获得较小的稳态误差
欢迎光临 东方耀AI技术分享 (http://www.ai111.vip/)
Powered by Discuz! X3.4