消除传感器测量中的峰值

Eliminating spikes in sensor measurements

我正在测量 pwm 信号。有两种状态。测量要么非常接近 1000,要么非常接近 2000; 我不想对这些值进行平均以消除测量噪声。我只是为了摆脱一两个非常不精确的值。

举个例子,这是预期的(准确的)数据图:

这是实测数据图:

我想消除由 3 或 4 次测量引起的中间尖峰。我想忽略那些测量值。

我实际上认为我会创建一个包含 10 个元素的队列并将测量结果推送到其中。如果新测量值比队列中的平均值少或多 500,则它不会添加到实际数据数组中。每当队列的平均值与新测量值之间的差异小于 500,即 10 元素队列中的 5 个测量值时,我将开始添加到实际数据数组并重置队列。

但这似乎不是一种有效的方法。我还是个数学菜鸟。所以我不知道如何更有效地编写它,我需要效率,因为代码将在 Arduino 上运行。

谢谢

编辑:

我尝试按照建议使用中值过滤

这是我的实际测量图:

这是中值滤波器应用图:

如您所见,它运行良好。但是,我不得不使用长度为 20 的过滤器。那是要缓存并推送到队列的大量数据。特别是在 Ardunio,c++ 中,它只有 16 兆赫的处理能力。我的情况有更有效的方法吗?

我假设现在的问题是如何加速 Arduino 的中值滤波器。我对 Arduino 的体验仅限于抱怨它产生的数据没有定期采样。显然,当他们转向 Raspberry Pi 时,这种情况就消失了,因为 Raspberry Pi 更强大,所以这可能是一个选择。

我不知道你是如何计算中值滤波器的,但网络搜索表明有一些实现可供你尝试。如果从 C++ STL 开始,您可以使用允许您插入、删除和查找最大或最小项目的数据结构来计算 运行 中位数。将一组 N/2 个项目保持在中位数以上,将一组 N/2 个项目保持在中位数以下。当您获得新数据点时,删除最旧的值并将新值与中值进行比较,并将其放入指向的任何池中。现在你可能在一侧有 N/2+1 项,在另一侧有 N/2-1 项。如果是这样,那么,例如,从顶部池中移除最小的项目并将其插入底部池中。将中值重新计算为现在位于顶部的最小项目和现在位于底部的最大项目的平均值(如果 N 为奇数,则您在池外有一个中值项目,而 book-keeping 稍微复杂一点)。接受新数据点的成本现在是 O(log N) 而不是 O(N) 或更糟,所以这可能会有所帮助。

(FWIW 我认识的最令人印象深刻的程序员也是专家数学家,所以我会继续数学)。

想想看,如果每个值真的是 1000 或 2000,那么您就不需要花哨的数据结构:您所需要的只是一个循环缓冲区和一个 运行 值的计数 > = 缓冲区内的 2000,您可以在删除最旧的值并添加最新的值时对其进行更新。这将花费您 20 个整数,但如果您的值确实是 1000 或 2000,则每个值都可以由一个位表示,因此您可以将整个队列保存在一个 32 位字中,并计算设置位的数量POPCNT,如果 arduino C/C++ 提供它

正如@mcdowella 所建议的那样。我将所有输入都转换为 1 和 0。

我没有使用中值滤波器,因为我将实时使用消除。

我只取我的伺服器生成的最后 10 个值的平均值并将其四舍五入以收集我的最终值。所以当 0 在最后 10 个值中占主导地位时,我使用 0.

这种方法有延迟的缺点。当我的传感器开始测量 0 值时,我的算法会在 5 个测量周期后检测到它。每个 25 毫秒。有 250 毫秒的延迟。

我知道这是一个懒惰的解决方案,但它似乎对我有用。不过,@mcdowella 的回答非常有用。希望以后的读者能比我受益更多