我有一个简单的电路设置,可以通过LDR将光水平读取到Arduino中。我正在尝试为读取的数据实现一个简单的低通滤波器。鉴于analogRead()返回一个无符号整数,如何最好地解决这个问题。
我试图实现一个简单的定点表示,但是不确定这是否正确。
这是一个代码片段:
#define WLPF 0.1
#define FIXED_SHIFT 4
ldr_val = ((int)analogRead(A0)) << FIXED_SHIFT;
while (true) {
int newval = (int)analogRead(A0) << FIXED_SHIFT;
ldr_val += WLPF*(newval - ldr_val);
Serial.println(ldr_val >> FIXED_SHIFT, DEC);
}
请注意,ADC的分辨率为10位,而我正在使用8位Arduino Micro。
在没有FPU的设备上,然后乘以0.1(无论如何使它成为浮点而不是固定点的实现),您应该除以10:
#define WLPF_DIV 10
...
ldr_val += (newval - ldr_val) / WLPF_DIV;
但是,在8位处理器上进行除法通常很昂贵(尽管可能与Serial.println()
循环中的执行时间相形见--但这是一个不同的问题)。取而代之的是,选择2的幂可以更有效地进行除法运算。
#define WLPF_SHIFT 3 // divide by 8
...
ldr_val += (newval - ldr_val) >> WLPF_SHIFT ;
int
由于带符号类型的右移是未定义的行为,因此使用带符号是有问题的。在这种情况下,可以通过将代码更改为:
#define WLPF_DIV 8
...
ldr_val += (newval - ldr_val) / WLPF_DIV ;
无论如何,编译器很可能会发现2的幂,并使用算术右移来生成代码。但是,您可能最好重新考虑数据类型。
您仍然可以在Serial.println()
通话中右移,但也可以用16分频代替:
#define WLPF_DIV 8
#define FIXED_MUL 16
ldr_val = (int)analogRead(A0) * FIXED_MUL ;
for(;;)
{
int newval = (int)analogRead(A0) * FIXED_MUL ;
ldr_val += (newval - ldr_val) / WLPF_DIV
Serial.println(ldr_val / FIXED_MUL, DEC);
}
在每个样本的基础上,不确定的数据输出并不能构成一个非常精确的滤波器,在任何情况下,它都将主导时序,因此您几乎无法控制频率响应,并且它将不稳定。这也使先前的性能优化变得毫无意义。您可能想考虑一下它是否对您的应用程序很重要-但这是一个不同的问题。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句