我正在应用一个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
总是会epsilon
与input
不同,所以我无法检查它input == z
总是假的。下面是一个具有无限循环的示例。
z
和input
之间的ε是什么?因此,如果它在该范围内,我可以检查并避免进一步的操作。
对于音频应用,您需要考虑采样位数,以了解何时听不清结果。每个位代表 2 的幂。例如,16 位将是 216 或 65536,因此适当的 epsilon 将是样本比例除以 65536。对于 20 位,它是 220 或 1048576。
这些限制明显大于大多数其他应用程序所需的限制。
考虑"新 z"与"旧 z"的比率,减去 1:
(z + a(i - z)) / z - 1
(这显然简化为ia / z - a
)。如果此大小小于,例如1e-6
,则接受为已完成。如果z
为零,则始终继续。将此乘法容差调整为适合您的要求。
(从科学上讲,公差将与数据流的标准偏差相关 - 我敢建议甚至成正比,但是如果不研究实际数据,我就无法提供更多提示。
而不是检查 z
和 input
之间的 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;
}