指数移动平均线的“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
总是不同于 epsilon
和 input
,所以我无法检查 input == z
它总是错误的。 Here's 一个例子,无限循环。
z
和 input
之间的 epsilon 是多少?所以如果它在那个范围内,我可以检查并避免进一步的操作。
您可以检查 z
的新值与前一个值之间的值,而不是检查 z
和 input
之间的 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.
这些限制明显大于大多数其他应用程序的要求。
我在我的音频应用程序中应用 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
总是不同于 epsilon
和 input
,所以我无法检查 input == z
它总是错误的。 Here's 一个例子,无限循环。
z
和 input
之间的 epsilon 是多少?所以如果它在那个范围内,我可以检查并避免进一步的操作。
您可以检查 z
的新值与前一个值之间的值,而不是检查 z
和 input
之间的 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.
这些限制明显大于大多数其他应用程序的要求。