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

Hen*_*oke 46 theory algorithm moving-average

我正在编写一些东西,我随着时间的推移从硬件指南针中获取了一堆值.这个指南针非常准确并且经常更新,结果是如果它略微摇晃,我最终会得到与其邻居非常不一致的奇数值.我想要平滑这些价值观.

做了一些阅读后,看起来我想要的是高通滤波器,低通滤波器或移动平均器.我可以得到移动平均线,只保留最后5个值或其他值的历史记录,并使用我的代码中下游的那些值的平均值,我曾经只使用最近的值.

我认为这应该可以很好地消除那些摇摆不定的情况,但是我觉得它可能非常低效,这可能是正确的程序员已知问题之一,有一个非常巧妙的Clever Math解决方案.

然而,我是那些可怕的自学成才的程序员之一,在与CompSci或Math几乎模糊不清的任何事情上都没有一丝正规教育.稍微阅读一下就表明这可能是一个高通或低通滤波器,但是我找不到任何可以理解为像我这样的黑客可以理解这些算法对一组数值的影响的术语,更不用说如何数学运作.例如,这里给出的答案技术上确实回答了我的问题,但只有那些可能已经知道如何解决问题的人才能理解.

确实是一个非常可爱和聪明的人可以用艺术毕业生可以理解的方式来解释这个问题以及解决方案的工作原理.

e.J*_*mes 58

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

移动平均线可能不够,因为数据中单个"blip"的影响将影响几个后续值,具体取决于移动平均窗口的大小.

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

if (abs(thisValue - averageOfLast10Values) > someThreshold)
{
    thisValue = averageOfLast10Values;
}
Run Code Online (Sandbox Code Playgroud)

这是一个guick图来说明:

图比较

第一个图是输入信号,带有一个令人不快的故障.第二张图显示了10个样本移动平均线的影响.最终图表是10样本平均值和上面显示的简单毛刺检测算法的组合.检测到毛刺时,使用10个样本平均值而不是实际值.

  • 移动平均值*是低通滤波器. (3认同)

Rex*_*err 38

如果你的移动平均线必须很长,以达到所需的平滑,并且你真的不需要任何特定形状的内核,那么如果你使用指数衰减的移动平均线,你会更好:

a(i+1) = tiny*data(i+1) + (1.0-tiny)*a(i)
Run Code Online (Sandbox Code Playgroud)

你选择tiny适当的常数(例如,如果你选择微小的= 1/1/N,它将具有与大小为N的窗口相同的平均量,但在旧点上的分布不同).

无论如何,由于移动平均线的下一个值仅取决于前一个值和您的数据,因此您不必保留队列或其他任何内容.而且你可以把它想象成"嗯,我有一个新的观点,但我真的不相信它,所以我将保留80%的旧测量估计值,并且仅相信这个新数据点20%".这几乎与说"嗯,我只相信这个新点20%,我将使用其他4个我信任相同数量的点",除了不是明确地采取其他4个点,你是假设你上次做的平均值是明智的,所以你可以使用你以前的工作.

  • 很好的解释,谢谢雷克斯.我是否正确地认为表达相同事物的另一种方式是:workingAverage =(newValue*smoothingFactor)+(workingAverage*(1.0 - smoothingFactor))? (6认同)
  • @Henry - 对,这是在不使用任何额外存储的情况下完成它的方法. (4认同)
  • 嘿,我知道这已经晚了5年,但感谢你们的回答.我正在研究一种声音根据你的速度而变化的游戏,但是由于在慢速计算机上运行游戏,速度会剧烈波动,这对于转向很好,但在声音方面却非常烦人.这是一个非常简单和廉价的解决方案,我认为这将是一个非常复杂的问题. (2认同)

Dan*_*Tao 6

移动平均线我可以下降...但它让我觉得它可能效率很低.

移动平均线真的没有理由效率低下.您将所需的数据点数保留在某个缓冲区中(如循环队列).在每个新数据点上,弹出最旧的值并从总和中减去它,然后按最新值并将其添加到总和中.因此,每个新数据点实际上只需要弹出/推送,加法和减法.您的移动平均值始终是此移位总和除以缓冲区中的值的数量.

如果你从多个线程同时接收数据,它会变得有点棘手,但是因为你的数据来自一个对我来说非常值得怀疑的硬件设备.

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