越有魅力的事物,往往存在一种“反差”,即其存在两个相互关联的特性,但是各自表现得十分不同
————小白
一阶滞后滤波又称作RC低通滤波、一阶滤波、一阶惯性滤波、一阶低通滤波等,下文统一称为一阶滞后滤波。
01 - 一阶滞后滤波算法简介
嵌入式中的ADC数字滤波算法有很多,搜索一下会有常用的10种算法,一阶滞后滤波是其中一种,也是大名鼎鼎的一种,在这10种算法中,虽然一直有人评论其各有优缺点,各有使用场合,但是如果在条件十分受限的实际嵌入式项目中让我选择一种,即使知道或不知道数据源的特性,我都会毫不犹豫地选择一阶滞后滤波算法,数学算法公式为:
Y
n
=
α
X
n
+
(
1
−
α
)
Y
n
−
1
(1)
Y_{n} = α X_{n} + (1 - α) Y_{n-1} \tag{1}
Yn=αXn+(1−α)Yn−1(1)
式中:
Y
n
Y_{n}
Yn是本次滤波输出值,
α
α
α是滤波系数,
X
n
X_{n}
Xn是本次采样,
Y
n
−
1
Y_{n-1}
Yn−1是上一次滤波输出。
公式十分简单,只有乘、加的操作并且只有一条计算公式,没有额外的数据计算。
02 - 硬件低通滤波器
下图为一阶滞后滤波所对应的硬件低通滤波器等效电路,其中:
Input
相当于于 X n X_{n} Xn:作为信号源的输入Output
相当于 Y n Y_{n} Yn:作为目标信号的输出电阻
相当于 α α α:作为滤波系统,设计实验测试阶段可调电容
相当于 Y n − 1 Y_{n-1} Yn−1:用于储存上一次的输出值
如果在原理图中看到类似的结构,可以认为添加了硬件低通滤波器,此等效电路算是比较简单的一种,还有比较复杂的需要有三极管等电子元件。
03 - 稳定滤波的原理
滤波的目标是过滤掉数据的各种干扰,得到期望的稳定值,使得系统收敛。下面用坐标轴对公式作一个解释,
x
x
x轴作为时间Time,
y
y
y轴作为AD值Value,AD采集过程中我们能够得到一段采集的数据输入输出记录:
就
x
x
x轴某一个时刻
T
T
T而言,我们只能得到当前时刻
T
T
T的输入值Input
和前面时刻的
(
T
−
1
,
T
−
2
,
…
…
1
)
(T-1,T-2,……1)
(T−1,T−2,……1)输出值Output
,我们把当前时刻得到的输入值记为
X
n
X_{n}
Xn,紧挨着的上一个时刻的输出值记为
Y
n
−
1
Y_{n-1}
Yn−1。滤波的目标是得到一个稳定值,何为稳定?什么样的值是稳定的?在不同时刻是否不同?根据一阶滞后滤波算法,如果要回答这些问题,无论如何我们只能假设在上一个时刻的输出值
Y
n
−
1
Y_{n-1}
Yn−1是稳定值。
因为除开第一个数据,所有数据都有前驱,当前值的滤波与前驱有关,那么随着时间的推移,所有的数据历史会形成一个链条,相邻的项是有联系的,因此只要某个时刻的值发生了变化,那么后面的值都会随之变化,如果我们限定了这些变化的敏感度(与α有关),比如降低敏感度,那么在一个有限的波形内由于变化不敏感,就会过滤掉波动的数据,得到一个认为是收敛的值
根据假设,因为
Y
n
−
1
Y_{n-1}
Yn−1是稳定值,所以
X
n
X_{n}
Xn与它存在一个误差
e
e
e,也就是:
X
n
=
Y
n
−
1
+
e
(2)
X_{n} = Y_{n-1} + e \tag{2}
Xn=Yn−1+e(2)
其中
e
e
e可正可负,我们代入公式(1)得到:
Y
n
=
α
X
n
+
(
1
−
α
)
Y
n
−
1
=
α
(
Y
n
−
1
+
e
)
+
(
1
−
α
)
Y
n
−
1
=
α
Y
n
−
1
+
α
e
+
Y
n
−
1
−
α
Y
n
−
1
=
α
e
+
Y
n
−
1
(3)
\begin{aligned} Y_{n} =& α X_{n} + (1 - α) Y_{n-1} \tag{3} \\ =& α(Y_{n-1} + e) + (1 - α) Y_{n-1}\\ =& αY_{n-1} + αe + Y_{n-1} - α Y_{n-1}\\ =& αe + Y_{n-1} \end{aligned}
Yn====αXn+(1−α)Yn−1α(Yn−1+e)+(1−α)Yn−1αYn−1+αe+Yn−1−αYn−1αe+Yn−1(3)
原理就在这个公式里面,因为我们假设
Y
n
−
1
Y_{n-1}
Yn−1是稳定值,因此当前时刻
T
T
T的输出
Y
n
Y_{n}
Yn就取决于滤波系数
α
α
α和误差
e
e
e,而滤波系数
α
α
α一般为固定值:
当趋向于0,
α
→
0
α\rightarrow 0
α→0,
Y
n
=
e
⋅
O
(
0
)
+
Y
n
−
1
Y_{n} =e\cdot O(0) + Y_{n-1}
Yn=e⋅O(0)+Yn−1 ,多数情况下
α
⋅
∣
e
∣
≤
0.5
α\cdot|e| \leq 0.5
α⋅∣e∣≤0.5,根据C语言的四舍五入,这个误差会被忽略,这就是降低敏感度,稳定数据,系统收敛性明显,但是数据的变化会滞后,因为需要一个较大的误差才能让
Y
n
Y_{n}
Yn发生变化。
当趋向于1,
α
→
1
α\rightarrow 1
α→1,
Y
n
=
e
⋅
O
(
1
)
+
Y
n
−
1
Y_{n} =e\cdot O(1) + Y_{n-1}
Yn=e⋅O(1)+Yn−1,多数情况下
α
⋅
∣
e
∣
≥
0.5
α\cdot|e| \geq 0.5
α⋅∣e∣≥0.5,根据C语言的四舍五入,这个误差会被记录并且马上反应,这就是升高敏感度,实时反映数据波动,系统收敛性不明显,数据并不稳定。
由C语言中四舍五入可知,需要
α
⋅
∣
e
∣
≥
1
2
α\cdot|e| \geq \frac{1}{2}
α⋅∣e∣≥21的时候,
Y
n
Y_{n}
Yn才会变化,也就是当
α
⋅
∣
e
∣
<
0.5
α\cdot|e| < 0.5
α⋅∣e∣<0.5的时候不变化,解不等式得到
e
∈
(
−
1
2
a
,
1
2
a
)
e \in (-\frac{1}{2a},\frac{1}{2a})
e∈(−2a1,2a1),代入(2)式,得到AD值的稳定和变化范围:
Y
n
=
{
Y
n
−
1
:
(
Y
n
−
1
−
1
2
a
)
<
X
n
<
(
Y
n
−
1
+
1
2
a
)
X
n
+
[
α
⋅
e
]
:
X
n
∈
Others
,
[
x
]
代
表
对
x
四
舍
五
入
(4)
Y_{n} = \left\{ \begin{array}{lr} Y_{n-1} &: & (Y_{n-1} - \frac{1}{2a}) < X_{n} < (Y_{n-1} + \frac{1}{2a})& \tag{4}\\ X_{n}+[α\cdot e] &:& X_{n} \in \text{Others} ,[x]代表对x四舍五入& \end{array} \right.
Yn={Yn−1Xn+[α⋅e]::(Yn−1−2a1)<Xn<(Yn−1+2a1)Xn∈Others,[x]代表对x四舍五入(4)
对于一个上一次的输出值
Y
n
−
1
Y_{n-1}
Yn−1,如果当前时刻的输入值
X
n
∈
(
Y
n
−
1
−
1
2
a
,
Y
n
−
1
+
1
2
a
)
X_{n} \in(Y_{n-1} - \frac{1}{2a},Y_{n-1} + \frac{1}{2a})
Xn∈(Yn−1−2a1,Yn−1+2a1),都将都被认为是
Y
n
−
1
Y_{n-1}
Yn−1,必须有一个较大的误差
e
e
e才能让
Y
n
Y_{n}
Yn发生变化,这就是滞后的意思。
04 - 实际应用与变形
嵌入式的实际应用会根据实际情况作相应的变形和改变,以下只举一个例子,体验一阶滞后滤波的实际应用。
场景:一个电控盆栽,有ARM逻辑主板+8051辅助板,8051系列的单片机作为盆栽的辅助板,需要采集温度传感器的AD值,反馈给主板作处理。
分析:盆栽一般放置在家庭中,环境温度在一大段时间内一般都是稳定的(比如上午、下午、晚上),而且温度是线性变换的,不会出现突变的情况,因此系统需要的是一个稳定的AD值,不允许环境温度没有有效变化的时候AD值却在波动,因此降低滤波系数
α
α
α,降低敏感度,使得系统收敛,稳定数据。
问题:8051系统的芯片处理浮点数非常吃力,不能让系统浪费在这些时间上。
解决:不作浮点数处理,把滤波系数
α
α
α平移到整数范围内,也就是扩大
K
K
K倍,整个公式变形为:
原来
:
Y
n
=
α
X
n
+
(
1
−
α
)
Y
n
−
1
变形
:
Y
n
=
α
X
n
+
(
K
−
α
)
Y
n
−
1
K
(6)
\begin{aligned} \text{原来}: Y_{n} =& α X_{n} + (1 - α) Y_{n-1}\\ \text{变形}: Y_{n} =& \frac{α X_{n} + (K - α) Y_{n-1} }{K}\tag{6} \end{aligned}
原来:Yn=变形:Yn=αXn+(1−α)Yn−1KαXn+(K−α)Yn−1(6)
除法也是会占用很多CPU资源,不过我们可以把
K
K
K定为2的幂次方,除法就可以轻松转成位移运算:
Y
(
n
)
=
(
α
X
n
+
(
K
−
α
)
Y
n
−
1
)
>
>
l
o
g
2
K
(7)
Y(n) = (α X_{n} + (K - α) Y_{n-1})>> log_2{K}\tag{7}
Y(n)=(αXn+(K−α)Yn−1)>>log2K(7)
(7)式就是最终公式,定好
K
K
K和
α
α
α后,就可以编程实现了,比如
K
=
128
,
α
=
8
K=128,α = 8
K=128,α=8,那么:
Y
n
=
(
8
⋅
X
n
+
120
⋅
Y
n
−
1
)
>
>
7
Y_{n}= (8 \cdot X_{n} + 120 \cdot Y_{n-1} )>> 7
Yn=(8⋅Xn+120⋅Yn−1)>>7
对应的编程代码:
extern uint32_t LastValue;
uint32_t ADC_filter(uint32_t CurrValue)
{
uint32_t tmp = (8 * CurrValue + 120 * LastValue) >> 7;
LastValue = tmp;
return LastValue;
}
公式只有整数的乘法、加法和位移运算,这些运算在8051单片机系列中的消耗是可以接受的(不到万不得已,不会用浮点数和除法运算)。
05 - 滤波效果展示
选取上述公式,并代入随机值,这些随机值都认为是各种干扰因素造成的波动,也就是实际的ADC数据理应不变:
Y
n
=
(
8
⋅
X
n
+
120
⋅
Y
n
−
1
)
>
>
7
Y_{n}= (8 \cdot X_{n} + 120 \cdot Y_{n-1} )>> 7
Yn=(8⋅Xn+120⋅Yn−1)>>7
系列1蓝色线为随机值,模拟干扰因素的波动,系列2红色线为滤波后的数据,能够观察到,因为我们定的滤波系数
α
α
α较小,因此会降低敏感度,在源数据从64突然跳变到70的时候,滤波得到的值也是不变的,可以稍微提高滤波系数,比如
α
=
32
α = 32
α=32,再看一下滤波效果:
在这个实验中,充分能够看到一阶滞后滤波中滞后的过程,在源数据蓝色线波动后,滤波结果红色线并不是马上跟随波动,而是滞后一段时间,需要源数据和上一次的滤波输出值有较大差别的时候才进行变化。
06 - 高性能的表现
一阶滞后滤波的高性能表现在:
- 易于实现:2-3句代码就能实现。
- 适应性强:公式变形简单,可应用在很多场合内。
- 运算简单:一条公式,几个基本运算符,计算速度也快。
- 可调属性:能够轻易调整收敛速度和敏感性,而且调节的范围参考。
以上4点可以作为和其它滤波算法作比较的点,对比的实验会在另一篇博客中,期待下一篇。
07 - 总结
- 一阶滞后滤波公式: Y n = α X n + ( 1 − α ) Y n − 1 Y_{n} = α X_{n} + (1 - α) Y_{n-1} Yn=αXn+(1−α)Yn−1,可适当变形
- AD值的稳定和变化范围:
Y n = { Y n − 1 : ( Y n − 1 − 1 2 a ) < X n < ( Y n − 1 + 1 2 a ) X n + [ α ⋅ e ] : X n ∈ Others , [ x ] 代 表 对 x 四 舍 五 入 Y_{n} = \left\{ \begin{array}{lr} Y_{n-1} &: & (Y_{n-1} - \frac{1}{2a}) < X_{n} < (Y_{n-1} + \frac{1}{2a})& \\ X_{n}+[α\cdot e] &:& X_{n} \in \text{Others} ,[x]代表对x四舍五入& \end{array} \right. Yn={Yn−1Xn+[α⋅e]::(Yn−1−2a1)<Xn<(Yn−1+2a1)Xn∈Others,[x]代表对x四舍五入 - 高性能的表现在:易于实现、适应性强、运算简单、可调属性