Algorithm 简单移动平均总和/抵销问题
我写了一个简单的移动平均值,其中温度的移动窗口读数为0到10V之间的电压 该算法似乎工作正常,但是,它存在一个问题,即根据窗口中首先填充的温度,移动平均值将有一个不接近该值的任何值的偏移。例如,使用temp运行此程序。插入室温的传感器产生4.4伏或21.3摄氏度,但如果我拔下温度。传感器电压降至1.4V,但移动平均值保持在1.6V。当我增加窗口的大小时,该偏移会变小。如何消除这种偏移,即使是小窗户尺寸,如20Algorithm 简单移动平均总和/抵销问题,algorithm,basic,moving-average,embedded-control,Algorithm,Basic,Moving Average,Embedded Control,我写了一个简单的移动平均值,其中温度的移动窗口读数为0到10V之间的电压 该算法似乎工作正常,但是,它存在一个问题,即根据窗口中首先填充的温度,移动平均值将有一个不接近该值的任何值的偏移。例如,使用temp运行此程序。插入室温的传感器产生4.4伏或21.3摄氏度,但如果我拔下温度。传感器电压降至1.4V,但移动平均值保持在1.6V。当我增加窗口的大小时,该偏移会变小。如何消除这种偏移,即使是小窗户尺寸,如20 REM SMA Num Must be greater than 1 #DEFINE
REM SMA Num Must be greater than 1
#DEFINE SMANUM 20
PROGRAM
'Program 3 - Simple Moving Average Test
CLEAR
DIM SA(1)
DIM SA0(SMANUM) : REM Moving Average Window as Array
DIM LV1
DIM SV2
LV0 = 0 : REM Counter
SV0 = 0 : REM Average
SV1 = 0 : REM Sum
WHILE(1)
SA0(LV0 MOD SMANUM) = PLPROBETEMP : REM add Temperature to head of window
SV1 = SV1 + SA0(LV0 MOD SMANUM) : REM add new value to sum
IF(LV0 >= (SMANUM)) : REM check if we have min num of values
SV1 = SV1 - SA0((LV0+1) MOD SMANUM) : REM remove oldest value from sum
SV0 = SV1 / SMANUM : REM calc moving average
PRINT "Avg: " ; SV0 , " Converted: " ; SV0 * 21.875 - 75
ENDIF
LV0 = LV0 + 1 : REM increment counter
WEND
ENDP
(请注意,这是Parker用ACROBASIC为ACR9000编写的)
输出-温度传感器已连接
Raw: 4.43115 Avg: 4.41926 Converted: 21.6713125
Raw: 4.43115 Avg: 4.41938 Converted: 21.6739375
Raw: 4.43359 Avg: 4.41963 Converted: 21.67940625
Raw: 4.43359 Avg: 4.41987 Converted: 21.68465625
Raw: 4.43359 Avg: 4.42012 Converted: 21.690125
Raw: 4.43359 Avg: 4.42036 Converted: 21.695375
Raw: 4.43359 Avg: 4.42061 Converted: 21.70084375
…在程序运行时卸下温度传感器
Raw: 1.40625 Avg: 1.55712 Converted: -40.938
Raw: 1.40381 Avg: 1.55700 Converted: -40.940625
Raw: 1.40625 Avg: 1.55699 Converted: -40.94084375
Raw: 1.40625 Avg: 1.55699 Converted: -40.94084375
Raw: 1.40381 Avg: 1.55686 Converted: -40.9436875
Raw: 1.40381 Avg: 1.55674 Converted: -40.9463125
Raw: 1.40625 Avg: 1.55661 Converted: -40.94915625
Raw: 4.43848 Avg: 4.28554 Converted: 18.7461875
Raw: 4.43848 Avg: 4.28554 Converted: 18.7461875
Raw: 4.43848 Avg: 4.28554 Converted: 18.7461875
Raw: 4.43848 Avg: 4.28554 Converted: 18.7461875
Raw: 4.43848 Avg: 4.28554 Converted: 18.7461875
Raw: 4.43359 Avg: 4.28530 Converted: 18.7409375
移除传感器后,原始平均值和移动平均值之间出现明显偏移
偏移也按相反的顺序发生:
输出-开始程序,温度传感器已拆除
Raw: 1.40381 Avg: 1.40550 Converted: -44.2546875
Raw: 1.40625 Avg: 1.40550 Converted: -44.2546875
Raw: 1.40625 Avg: 1.40549 Converted: -44.25490625
Raw: 1.40625 Avg: 1.40549 Converted: -44.25490625
Raw: 1.40625 Avg: 1.40548 Converted: -44.255125
Raw: 1.40625 Avg: 1.40548 Converted: -44.255125
。。。程序运行时连接温度传感器
Raw: 1.40625 Avg: 1.55712 Converted: -40.938
Raw: 1.40381 Avg: 1.55700 Converted: -40.940625
Raw: 1.40625 Avg: 1.55699 Converted: -40.94084375
Raw: 1.40625 Avg: 1.55699 Converted: -40.94084375
Raw: 1.40381 Avg: 1.55686 Converted: -40.9436875
Raw: 1.40381 Avg: 1.55674 Converted: -40.9463125
Raw: 1.40625 Avg: 1.55661 Converted: -40.94915625
Raw: 4.43848 Avg: 4.28554 Converted: 18.7461875
Raw: 4.43848 Avg: 4.28554 Converted: 18.7461875
Raw: 4.43848 Avg: 4.28554 Converted: 18.7461875
Raw: 4.43848 Avg: 4.28554 Converted: 18.7461875
Raw: 4.43848 Avg: 4.28554 Converted: 18.7461875
Raw: 4.43359 Avg: 4.28530 Converted: 18.7409375
附加传感器后,原始平均值和移动平均值之间再次出现明显偏移。问题似乎在于,从总和中减去的值实际上不是数组中最早的值——最早的值实际上被
循环中第一行的新值覆盖。这是从总和中减去的第二个最古老的值
根据OP的建议,编辑将平均值和总和变量更改为64位浮点,以解决随时间推移的精度损失问题
确保先减去最早的值(一旦数组已满),即可得到预期的答案:
PROGRAM
'Program 3 - Simple Moving Average Test
CLEAR
DIM SA(1)
DIM SA0(SMANUM) : REM Moving Average Window as Array
DIM LV1
DIM DV2
LV0 = 0 : REM Counter
DV0 = 0 : REM Average
DV1 = 0 : REM Sum
WHILE(1)
IF(LV0 >= (SMANUM)) : REM check if we have min num of values
DV1 = DV1 - SA0(LV0 MOD SMANUM) : REM remove oldest value from sum
ENDIF
SA0(LV0 MOD SMANUM) = PLPROBETEMP : REM add Temperature to head of window
DV1 = DV1 + SA0(LV0 MOD SMANUM) : REM add new value to sum
IF(LV0 >= (SMANUM)) : REM check if we have min num of values
DV0 = DV1 / SMANUM : REM calc moving average
PRINT "Avg: " ; DV0 , " Converted: " ; DV0 * 21.875 - 75
ENDIF
LV0 = LV0 + 1 : REM increment counter
WEND
我没有一个运行的基本环境,但我在Python中测试了它,得到了与您的版本相同的错误代码输出,以及与我上面插入的版本相同的预期代码输出 这与VBA有什么关系?错误标记。谢谢,我已经更新了。非常感谢,这是解决方案。您是对的,当我获得新温度时,我正在覆盖最旧的值。这件事我已经忙了好一阵子了,再次谢谢你。看来我可能是逃之夭夭了。我仍然注意到原始平均线和移动平均线之间有一个小的偏移。例如:Raw:4.55322平均值:4.42033
,约为2.9C
关闭。明天我将做一些进一步的调查,并在这里用我的发现进行评论。你可以像我一样尝试测试代码,将一系列电压放入一个数组(比如,V
),然后从V(LV0)
读取每个电压。这样,我可以使V
的前半部分的值等于(比如说)1
,使V
的后半部分的值等于(比如说)5
,并观察基于输入值的一致阶梯序列输出的移动平均值。另一种方法是每次计算数组SA0
中的值之和,并将其与SV1
进行比较。这对于生产使用来说可能不够快,但可能有助于发现任何剩余的bug。感谢Simon,我用C#重写了算法,并确认您的答案中的窗口索引是正确的。我让基本版本在控制器上运行了一夜,并注意到偏移量随着时间的推移而增加。我怀疑sum变量SV1的精度有所下降,它随时间增加偏移量。由于这些是32位浮点数,您认为移动到64位浮点数会解决这个问题吗?这可能是一个精度损失问题,因为在温度转换中减去75
会损失32位中的略多于8位。因此,将总和保持在摄氏度而不是原始单位可能会大大减少精度损失。或者,我希望移动到64位浮点将解决这个问题。或者,您可以每隔几百个周期从数组中定期重新计算SV0
,这将重置逐渐丢失的精度。