前言
使用电机速度做闭环控制时,发现传感器的数据受到了高频噪声的影响,于是想先对其进行滤波处理。
原理
滑动平均滤波器本质是一个低通滤波器,可以看成FIR滤波器的一个特例。其时域表达为
y
(
k
)
=
1
N
∑
i
=
0
N
−
1
x
(
k
+
i
)
y(k)=\frac{1}{N} \sum_{i=0}^{N-1} x(k+i)
y(k)=N1i=0∑N−1x(k+i)
,其中N为滤波器长度。
代码
代码比较简单,我就没有注释。大概思想就是设置一个滤波器长度的数组,然后不断更新数组内容,再求平均就可以了。写的时候发现其实用队列写应该会更快,但是我懒了一把,因为单片机性能够用所以就算了,如果有写出来的,欢迎一起讨论哈。
/*滑动平均滤波器长度*/
#define MVF_LENGTH 8
float moving_average_filtre(float xn)
{
static int index = -1;
static float buffer[MVF_LENGTH];
static float sum = 0;
float yn = 0;
int i = 0;
if(index == -1)
{
//初始化
for(i = 0; i <MVF_LENGTH; i++)
{
buffer[i] = xn;
}
sum = xn*MVF_LENGTH;
index = 0;
}
else
{
sum -= buffer[index];
buffer[index] = xn;
sum += xn;
index++;
if(index >= MVF_LENGTH)
{
index = 0;
}
}
yn = sum/MVF_LENGTH;
return yn;
}
讨论
滑动平均滤波器的长度选择也是个值得讨论的问题。太短的话消除了不了高频噪声,太长的话延迟比较严重。
参考文章里给出了滤波器长度与系统截止频率的经验公式:
N
=
0.443
∗
f
s
/
f
c
o
\mathrm{N}=0.443* \mathrm{f}_{\mathrm{s}} / \mathrm{fco}
N=0.443∗fs/fco
其中,fs为采样频率,fco为截至频率。推导的过程简单讲就是假设输入信号为正弦信号,且将离散信号变为连续信号之后,对输出信号进行傅里叶变换,进而得到他们的关系。
滑动平均滤波器频率响应
图片来源:https://www.cnblogs.com/pingwen/p/6670675.html
改进
最近又看到一个改进的计算公式,可以节省计算时间,原理很简单,学而不思则罔啊。
改进后的公式为:
y ( k ) = y ( k − 1 ) + 1 N ( x ( k ) − x ( k − N ) ) y(k)=y(k-1)+\frac{1}{N} (x(k)-x(k-N)) y(k)=y(k−1)+N1(x(k)−x(k−N))