指数移动平均线的“epsilon”是什么?

What's the “epsilon” of an Exponential Moving Average?

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

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

Here's 代码和前 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;
}

我需要检查上一个平滑值是否与当前值相同,这意味着过滤器有 "finished" 平滑过程,并且值将始终相同。

但是 z 总是不同于 epsiloninput,所以我无法检查 input == z 它总是错误的。 Here's 一个例子,无限循环。

zinput 之间的 epsilon 是多少?所以如果它在那个范围内,我可以检查并避免进一步的操作。

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

在 C++ 中有

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

其中 returns 机器 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;
}

考虑比率 "new z" 与 "old z",减去 1:

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

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

(从科学上讲,公差将与您的数据流的标准偏差有关 - 我什至敢建议 成比例 ,但如果不研究实际数据。)

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

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