Что такое «эпсилон» экспоненциальной скользящей средней?

Я применяю 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;
}

Мне нужно проверить, совпадает ли предыдущее сглаженное значение с текущим, что означает, что фильтр «завершил» процесс удаления, и значение всегда будет таким же.

Но z всегда будет отличаться epsilon от inputпоэтому я не могу проверить input == z это всегда будет ложью. Вот пример с бесконечным циклом.

Каким будет эпсилон между z а также input? Так что, если это в этом диапазоне, я могу проверить и избежать дальнейших операций.

-1

Решение

Вместо этого проверяя эпсилон между z а также inputВы можете проверить это между новым значением z и предыдущий.

1

Другие решения

Для аудиоприложения вам необходимо учитывать количество бит выборки, чтобы знать, когда результат будет не слышен. Каждый бит представляет степень 2. Например, 16 бит будут 216 или 65536, так что подходящим эпсилоном будет ваша выборочная шкала, деленная на 65536. Для 20 бит это 220 или 1048576.

Эти пределы значительно больше, чем требуется большинству других приложений.

2

Рассмотрим соотношение «новый z» к «старому z», меньше 1:

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

(Что, очевидно, упрощает ia / z - a). Если величина этого меньше, чем, скажем, 1e-6, а затем принять как закончено. Если z ноль, то всегда продолжайте. Отрегулируйте эту мультипликативную толерантность в соответствии с вашими требованиями.

(С научной точки зрения толерантность будет связана — смею даже предложить пропорциональный — к стандартному отклонению вашего потока данных, но я не могу предложить больше подсказок без изучения фактических данных.)

2

В С ++ есть

std::numeric_limits<double>::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;
}
-4
По вопросам рекламы [email protected]