|
自适应滤波器之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()
复制代码
|
-
01.png
(134.31 KB, 下载次数: 132)
-
02.png
(261.14 KB, 下载次数: 132)
-
03.png
(130.38 KB, 下载次数: 134)
-
04.png
(129.59 KB, 下载次数: 137)
-
05.png
(176.75 KB, 下载次数: 133)
-
06.png
(125.8 KB, 下载次数: 137)
-
07.png
(79.28 KB, 下载次数: 137)
-
08.png
(116.76 KB, 下载次数: 132)
-
lr1.png
(15.09 KB, 下载次数: 136)
-
lr2.png
(21.67 KB, 下载次数: 134)
-
lr3.png
(24.72 KB, 下载次数: 133)
-
lr4.png
(21.9 KB, 下载次数: 133)
-
lr5.png
(22.3 KB, 下载次数: 135)
-
lr6.png
(31.03 KB, 下载次数: 136)
|