指数移动平均线的"ε"是多少?



我正在应用一个Exponential Moving Average作为音频应用程序中平滑参数的过滤器:

a0 = 0.01
z += a0 * (input - z);

以下是代码和前 50 个步骤:

#include <iostream>
int main ()
{
    double a0 = 0.1;
    double input = 0.8;
    double z = 0.0;
    std::cout << "init z: " << z << std::endl << std::endl;
    for(int i=0; i < 50; i++) {
        z += a0 * (input - z);
        std::cout << z << std::endl;
    }
    std::cout << std::endl << "final z: " << z << std::endl;
}

我需要检查 prev 平滑值是否与当前值相同,这意味着过滤器已"完成"其烟熏过程,并且值将始终相同。

但是z总是会epsiloninput不同,所以我无法检查它input == z总是假的。下面是一个具有无限循环的示例。

zinput之间的ε是什么?因此,如果它在该范围内,我可以检查并避免进一步的操作。

对于音频应用,您需要考虑采样位数,以了解何时听不清结果。每个位代表 2 的幂。例如,16 位将是 216 或 65536,因此适当的 epsilon 将是样本比例除以 65536。对于 20 位,它是 220 或 1048576。

这些限制明显大于大多数其他应用程序所需的限制。

考虑"新 z"与"旧 z"的比率,减去 1:

(z + a(i - z)) / z - 1

(这显然简化为ia / z - a)。如果此大小小于,例如1e-6,则接受为已完成。如果z为零,则始终继续。将此乘法容差调整为适合您的要求。

(从科学上讲,公差将与数据流的标准偏差相关 - 我敢建议甚至成正比,但是如果不研究实际数据,我就无法提供更多提示。

而不是检查 zinput 之间的 epsilon,您可以在新值 z 和前一个值之间检查它。

在C++中有

std::numeric_limits<double>::epsilon()

它返回机器 epsilon,即 1.0 与浮点类型 T 表示的下一个值之间的差值。

这里是修改后的代码:

#include <iostream>
int main()
{
    int counter = 0;
    double a0 = 0.1;
    double input = 0.8;
    double z = 0.0;
    std::cout << "init z: " << z << std::endl << std::endl;
    while (true) {
        z += a0 * (input - z);
        std::cout << counter++ << " | process: " << z << std::endl;
        double eps = std::numeric_limits<double>::epsilon();
        double diff = abs(z - input);
        if (diff <= 2 * eps) {
            break;
        }
    }
    std::cout << std::endl << "final z: " << z << std::endl;
}