原理
自适应滤波是近年以来发展起来的一种最佳滤波方法。它是在维纳滤波,Kalman滤波等线性滤波基础上发展起来的一种最佳滤波方法。由于它具有更强的适应性和更优的滤波性能。从而在工程实际中,尤其在信息处理技术中得到了广泛的应用。自适应滤波存在于信号处理、控制、图像处理等许多不同领域,它是一种智能更有针对性的滤波方法,通常用于去噪。
变量值和自适应滤波滤波器系数W(n)进行矩阵相乘得到系统输出的Y(j),Y(j)和期望信号D(n)相减得到差值E(n).通过不断的迭代得到合适的滤波器系数W(N+1)。
代码
参考:https://blog.youkuaiyun.com/xdzhujy/article/details/105638797?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522161543561316780255269410%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=161543561316780255269410&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allbaidu_landing_v2~default-6-105638797.pc_search_result_cache&utm_term=%E8%87%AA%E9%80%82%E5%BA%94%E7%AE%97%E6%B3%95
上诉博主理论和MATLAB代码说得很详细,在他MATLAB代码的基础,理解了一下,写出C语言代码,运行环境Microsft Visual Studio.
下面展示一些 内联代码片
。
#include<stdio.h>
#define F_COUNT 1024
#define M 15
/* xn--------输入的信号序列(列向量)
* itr-------迭代次数,标量,默认为xn的长度,M<itr<sizeof(xn)
* en--------误差序列(itr*1)列向量
* dn--------所期望的响应序列(列向量)
* M---------滤波器的阶数(标量)
* mu--------收敛因子(步长)标量
* W---------滤波器权值矩阵,大小为M*itr
* yn--------实际输出序列(列向量)*/
float xn[250] = { 10,10.2,9.8,10,10.1,9.9,10.1,10.2,9.78,9.9,10, 10,10.1,9.8,10,10.1,9.9,10.1,10.2,9.78,9.9,10, 10,9.8,9.8,10,10.1,9.9,10.1,10.2,9.78,9.9,10, 10,10.2,9.8,10,10.1,9.9,10.1,10.2,9.78,9.9,10, 10,10,9.8,10,10.1,9.9,10.10,10.2,9.78,9.9,10, 10,9,9.8,10,10.1,9.9,10.1,10.2,9.78,9.9,10, 10,9,9.8,10,10.1,9.9,10.1,10.2,9.78,9.9,10, 10,9.8,9.8,10,10.1,9.9,10.1,10.2,9.78,9.9,10, 10,9.8,9.8,10,10.1,9.9,10.1,10.2,9.78,9.9,10,10,9.8,9.8,10,10.1,9.9,10.1,10.2,9.78,9.9,10, 10,9.8,9.8,10,10.1,9.9,10.1,10.2,9.78,9.9,10, 10,9.8,9.8,10,10.1,9.9,10.1,10.2,9.78,9.9,10, 10,9.8,9.8,10,10.1,9.9,10.1,10.2,9.78,9.9,10, 10,9.8,9.8,10,10.1,9.9,10.1,10.2,9.78,9.9,10, 10,9.8,9.8,10,10.1,9.9,10.1,10.2,9.78,9.9,10, 10,9.8,9.8,10,10.1,9.9,10.1,10.2,9.78,9.9,10, 10,9.8,9.8,10,10.1,9.9,10.1,10.2,9.78,9.9,10, 10,9.8,9.8,10,10.1,9.9,10.1,10.2,9.78,9.9,10,20.0,20.1,20.2,20.3,20.4,20.5,20.6,20.7,20.8,20.9,21,21.1,21.2,21.3,21.4,21.5,21.6,21.7,21.8,21.9,22,22.1,22.2,22.3,22.4,22.51,22.62,22.72,22.78,22.89,23.02,23.12,23.18,23.31,23.42,23.53,23.62,23.67,23.78,23.89,24.02,24.08,24.18,24.32,24.38,24.52,24.61,24.74,24.81,24.92,25,25.1 };
float dn[251] = {10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10 ,10,10,10,10,10,10,10,10,10,10 ,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10 ,10,10,10,10,10,10,10,10,10,10 ,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10 ,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10 ,10,10,10,10,10,10,10,10,10,10 ,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10 ,10,10,10,10,10,10,10,10,10,10 ,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10 ,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,20.0,20.1,20.2,20.3,20.4,20.5,20.6,20.7,20.8,20.9,21,21.1,21.2,21.3,21.4,21.5,21.6,21.7,21.8,21.9,22,22.1,22.2,22.3,22.4,22.5,22.6,22.7,22.8,22.9,23.0,23.1,23.2,23.3,23.4,23.5,23.6,23.7,23.8,23.9,24.0,24.1,24.2,24.3,24.4,24.5,24.6,24.7,24.8,24.9,25 };
float* LMS_Filter(int itr, const float* xn, const float* dn, double mu, int length)
{
static int i = 0;
static int k = 0;
static float y = 0.0;
static float en[F_COUNT];
static float W[M];//static float W[M][F_COUNT];
static float x[M];
static float yn[F_COUNT];
//下面两行代码打印出xn原始数据,需要可以取消注释
//for (i = 0; i < 250; i++)
// printf("y=%f k=%d\n", xn[i], i);
for(i=0;i<M;i++)
printf("y=%f k=%d\n", xn[i], i);
/*创建一个en全零矩阵,en(k)表示第k次迭代时预期输出与实际输入的误差*/
for (i = 0; i < itr; i++)
{
en[i] = 0;
}
/*创建一个W全零矩阵,每一行代表一个加权参量,每一列代表一次迭代*/
for (i = 0; i < M; i++)
W[i] = 0;
/*创建一个x全零矩阵*/
for (i = 0; i < M; i++)
x[i] = 0;
/*迭代计算*/
for (k = M; k <= itr; k++)
{
/* 滤波器M个抽头的输入:从xn第k-1个值倒序取出M个样点的值放入x
* y为滤波器输出:W的第K-2列与x的积的和*/
for (i = 0; i < M; i++)
{
x[i] = xn[k-i-1];
}
for (i = 0; i < M; i++)
y += W[i] * x[i]; //卷积乘法
en[k] = dn[k] - y; //第k次迭代的误差
/*滤波器权值计算的迭代式*/
for (i = 0; i < M; i++)
{
W[i] = W[i]+ mu * en[k] * x[i];
}
printf("y=%f k=%d\n", y,k);
y = 0.0;
}
return yn;
}
int main()
{
LMS_Filter(250, xn, dn, 0.0008, 250);
printf("hellow");
}
结果
经过自适应滤波后,确实起到滤波效果,而且在前后段数据波动较大时,系统也可以很快的拟合数据。效果比固定拟合系数的卡尔曼滤波好。代码中xn是原始数据,DN是期望数据,代码中可以更改步长,和滤波器阶数。有啥问题评论区留言,一起探讨,博主也是半懂不懂。