如果我想计算 400 个数据点的平均值(来自加速度计传感器的噪声值),我可以使用像这样的低通函数来实现这一目的吗?
private float lowPass(float alpha, float input, float previousOutput) {
return alpha * previousOutput + (1 - alpha) * input;
}
我将此与简单地将 400 个数据点存储在 List<float>
中进行比较,将它们相加并除以 400。
即使 alpha
的值很高,我也会得到截然不同的结果。难道我做错了什么?我可以使用低通滤波器来计算平均值,还是简单地计算“真实”平均值通常更好?
编辑
我的低通函数最初采用 float[]
作为输入和输出,因为我的数据来自 3 轴加速度计。我将其更改为 float
并删除了内部 for
循环以避免混淆。这也意味着输入/输出现在作为原始值传递,因此该方法返回 float
而不是直接对输出数组进行操作。
最佳答案
如果您有能力计算算术平均值(如果您保留运行总和,甚至不需要额外的存储空间),那么在大多数情况下,出于下面所述的原因,这可能是更好的选择。
警告:数学领先
为了将算术平均值与您正在使用的一阶递归低通滤波器进行比较,让我们从信号 N
开始样本,其中每个样本的值等于 m
加上一些方差高斯噪声 v
。我们进一步假设噪声与样本无关。
计算该信号的算术平均值将为您提供平均值为 m
的随机结果。和方差v/N
.
假设第一个previousOutput
初始化为零,导出低通滤波器最后一个输出 ( output[N-1]
) 的均值和方差,我们将得到均值 m * (1 - alpha^N)
和方差v * (1-alpha)^2 * (1-alpha^(2*N)) / (1 - alpha^2)
。
可以看到的一个直接问题是对于大 m
,估计平均值m * (1 - alpha^N)
与真实值可能相差很远 m
。不幸的是,这个问题变得更糟,如 alpha
接近 1。出现这种情况是因为滤波器没有时间上升到其稳态值。
为了避免此问题,可以考虑初始化第一个 previousOutput
使用第一个输入样本。
在这种情况下,最后输出的均值和方差将为 m
和v * ((1-alpha)^2*(1-alpha^(2*N-2))/(1-alpha^2) + alpha^(2*N-2))
分别。这次的问题是,对于更大的alpha
输出方差很大程度上取决于用于初始化的第一个样本的方差。这在下面的输出方差比较图中尤其明显(由输入方差归一化):
因此,要么在初始化 previousOutput
时估计平均值出现偏差为零,或者在使用第一个样本初始化时会得到很大的残差方差(比算术平均值计算要大得多)。
最后请注意,实际性能可能会因您的特定数据而异,具体取决于观察到的变化的性质。
关于java - 使用低通滤波器来计算平均值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43411539/