平滑价值随着时间的推移:移动平均或更好的东西?

我正在编写一些东西,我正在从一个硬件指南针随着时间的推移一堆价值。 这个指南针是非常准确的,经常更新,结果是,如果它轻微抖动,我会得到与其邻居大不相同的奇数值。 我想要平滑这些价值观。

经过一些阅读,看来我想要的是高通滤波器,低通滤波器或移动平均。 移动平均数我可以记住,只是保留最后5个值的历史logging,或者在我刚刚使用最近值的代码中使用这些值的平均值。

我认为,这应该很好地消除这些抖动,但是这让我觉得这可能是效率很低的,这可能是适合程序员的已知问题之一,其中有一个巧妙的math解决scheme。

然而,我是那些可怕的自学成才的程序员之一,没有任何与CompSci或Math相关的正规教育。 仔细阅读,可以看出这可能是高通滤波器或低通滤波器,但是我找不到任何可以用像我这样的黑客理解的东西来解释这些algorithm对一系列值的影响,更不用说如何math作品。 例如, 在这里给出的答案在技术上确实回答了我的问题,但仅仅是对那些可能已经知道如何解决问题的人来说是可理解的。

这真是一个非常可爱,聪明的人,他可以用这个问题来解释这个问题,以及这个解决scheme是如何工作的。

如果你的移动平均线需要很长才能达到所需的平滑,而你并不需要任何特定形状的内核,那么如果你使用指数衰减的移动平均线,那么你最好:

a(i+1) = tiny*data(i+1) + (1.0-tiny)*a(i) 

你selecttiny的是一个适当的常量(例如,如果你select微小= 1/1,它将有一个大小为N的窗口的平均数量,但分布在旧的点不同)。

无论如何,由于移动平均值的下一个值仅取决于前一个值和您的数据,因此您不必保留队列或任何东西。 你可以把这个想法看做是这样的:“我有一个新的观点,但是我不太相信它,所以我会保留我以前的测量结果的80%相信这个新的数据点20%“。 这就好像说:“呃,我只相信这个新点数20%,而且我会用另外4个我相信相同数量的点”,除了不是明确地采取其他4个点,而是假设你上次做的平均值是明智的,所以你可以使用你以前的工作。

如果您尝试去除偶然的奇数值,则低通滤波器是您已识别的三个选项中最好的。 例如,低通滤波器允许手动旋转罗盘引起的低速变化,同时拒绝诸如道路颠簸引起的高速变化。

移动平均线可能还不够,因为根据移动平均窗口的大小,数据中单个“blip”的效果会影响多个后续值。

如果奇数值很容易被检测到,那么使用完全忽略它们的毛刺去除algorithm可能会更好:

 if (abs(thisValue - averageOfLast10Values) > someThreshold) { thisValue = averageOfLast10Values; } 

这里是一个guick图来说明:

图表比较

第一个图是input信号,有一个不愉快的毛刺。 第二个图表显示了10样本移动平均线的效果。 最终graphics是上述10个样本平均值和简单毛刺检测algorithm的组合。 当检测到毛刺时,使用10个样本的平均值代替实际值。

移动平均值我可以放下…但是这让我觉得这可能是相当低效的。

移动平均数实际上没有理由是低效率的。 你保留在一些缓冲区中的数据点的数量(如循环队列)。 在每个新数据点上,popup最旧的值并从总和中减去它,然后推入最新的值并将其添加到总和中。 所以每个新的数据点只需要一个popup/推送,一个加法和一个减法。 你的移动平均值总是这个移动总和除以缓冲区中的数值。

如果你从多个线程同时接收数据,它会变得有点麻烦,但是因为你的数据来自一个硬件设备,这对我来说似乎是非常可疑的。

哦,还有:可怕的自学成才的程序员团结起来! ;)

如果使用适当的值,指数衰减的移动平均值可以只用趋势“手动”计算。 见http://www.fourmilab.ch/hackdiet/e4/了解如何使用纸笔快速做到这一点,如果你正在寻找“平滑10%的指数平滑移动平均”。 但是既然你有一台电脑,你可能想做二进制移位而不是十进制移位;)

这样,所有你需要的是一个variables为您的当前值和一个平均值。 下一个平均值可以从中计算出来。

有一种称为距离门(range gate)的技术可以很好地适用于低出错的假样本。 假设使用上面提到的滤波器技术之一(移动平均,指数),一旦你有足够的历史(一个时间常数),你可以testing新的,传入的数据样本的合理性, 然后它被添加到计算。

需要了解信号的最大合理变化率。 将原始样本与最近的平滑值进行比较,如果该差值的绝对值大于允许的范围,则将该样本丢弃(或者用一些启发式代替,例如,基于斜率的预测;差分或来自双指数平滑的“趋势”预测值)