Вадим, фильтры с накоплением не годятся на все случаи жизни.
Один из примеров - в радиационно стойких видео камерах используют ламповые трубки (видиконы). Из-за того что фоточувствительный слой трубки инерционный при быстрых поворотах камеры за яркими объектами тянутся хвосты. В условиях радиации изображение подобных камер тем светлее чем выше уровень радиации вплоть до полного насыщения (белый цвет). Связано это с тем что при соударении гамма частиц с люминофором трубки выделяется энергия которая интегрируется инерционным люминофором.
Изображение CMOS камеры в тех же самых условиях выглядит зашумлённым случайно разбросанными сменяющимися от кадра к кадру насыщенными пикселями. Я предложил простейший алгоритм фильтрации при котором при заполнении нового кадра в видео буфере на месте насыщенных пикселей остаются данные с прошлого кадра. Работал подобный фильтр довольно не плохо, жаль что тогда я скептически относился к медианным фильтрам. Применив в дополнение медианный фильтр эффективность фильтрации можно было бы значительно увеличить. Это пример успешного применения нелинейной фильтрации, в то время как линейная описаная выше (инертность люминофора) ни к чему хорошему не привела.
Так вот медианный фильтр как раз таки не плохо справляется с импульсными помехами. Для примера вот реальный шум АЦП stm32f205 (чёрным цветом) и результат фильтрации медианным фильтром с окном в три точки (красным цветом):
Фазовый сдвиг на выходе фильтра не зависит от частоты и составляет всего один сэмпл!
На пред идущей странице были ссылки, одна из них вообще не имеет отношения к программированию - почитайте там всё на пальцах изложено.
Нашёл ошибки в функции фильтра, вот исправленный вариант. Отличие от оригинала в том что количество сравнений 1..4 против 2..3.
Код:
void Filter(void)
{
static unsigned char stmp[2][3], idx[2];
if (idx[input] > 2) idx[input] = 0;
stmp[input][idx[input]++]=adc[input];
// find the middle value between three samples
if (stmp[input][0]<=stmp[input][1] && stmp[input][1]<=stmp[input][2]) mdl = stmp[input][1];
else if(stmp[input][0]>=stmp[input][1] && stmp[input][1]>=stmp[input][2]) mdl = stmp[input][1];
else if(stmp[input][1]<=stmp[input][0] && stmp[input][0]<=stmp[input][2]) mdl = stmp[input][0];
else if(stmp[input][1]>=stmp[input][0] && stmp[input][0]>=stmp[input][2]) mdl = stmp[input][0];
else mdl = stmp[input][2];
}
Вот результат работы Медианного и цифрового эквивалента RC цепочки. Первая колонка входные данные, вторая результат фильтра выше, третья оригинальная версия медианного фильтра, четвёртая IIR с альфа равной 0.5:
Код:
****************************************
*** One Sample Noise (Unipolar)
****************************************
In=0, MEDOut=0, MEDOutOri=0, IIROut=0
In=100, MEDOut=0, MEDOutOri=0, IIROut=50
In=100, MEDOut=100, MEDOutOri=100, IIROut=75
In=100, MEDOut=100, MEDOutOri=100, IIROut=87
In=100, MEDOut=100, MEDOutOri=100, IIROut=94
In=100, MEDOut=100, MEDOutOri=100, IIROut=97
In=100, MEDOut=100, MEDOutOri=100, IIROut=98
In=100, MEDOut=100, MEDOutOri=100, IIROut=99
In=100, MEDOut=100, MEDOutOri=100, IIROut=100
In=100, MEDOut=100, MEDOutOri=100, IIROut=100
In=90, MEDOut=100, MEDOutOri=100, IIROut=95
In=100, MEDOut=100, MEDOutOri=100, IIROut=97
In=100, MEDOut=100, MEDOutOri=100, IIROut=99
In=100, MEDOut=100, MEDOutOri=100, IIROut=99
In=100, MEDOut=100, MEDOutOri=100, IIROut=100
In=100, MEDOut=100, MEDOutOri=100, IIROut=100
In=100, MEDOut=100, MEDOutOri=100, IIROut=100
In=100, MEDOut=100, MEDOutOri=100, IIROut=100
In=100, MEDOut=100, MEDOutOri=100, IIROut=100
In=100, MEDOut=100, MEDOutOri=100, IIROut=100
In=110, MEDOut=100, MEDOutOri=100, IIROut=105
In=100, MEDOut=100, MEDOutOri=100, IIROut=102
In=100, MEDOut=100, MEDOutOri=100, IIROut=101
In=100, MEDOut=100, MEDOutOri=100, IIROut=101
In=100, MEDOut=100, MEDOutOri=100, IIROut=100
In=100, MEDOut=100, MEDOutOri=100, IIROut=100
In=100, MEDOut=100, MEDOutOri=100, IIROut=100
In=100, MEDOut=100, MEDOutOri=100, IIROut=100
In=100, MEDOut=100, MEDOutOri=100, IIROut=100
In=100, MEDOut=100, MEDOutOri=100, IIROut=100
In=0, MEDOut=100, MEDOutOri=100, IIROut=50
In=100, MEDOut=100, MEDOutOri=100, IIROut=75
In=100, MEDOut=100, MEDOutOri=100, IIROut=88
In=100, MEDOut=100, MEDOutOri=100, IIROut=94
In=100, MEDOut=100, MEDOutOri=100, IIROut=97
In=100, MEDOut=100, MEDOutOri=100, IIROut=98
In=100, MEDOut=100, MEDOutOri=100, IIROut=99
In=100, MEDOut=100, MEDOutOri=100, IIROut=100
In=100, MEDOut=100, MEDOutOri=100, IIROut=100
In=100, MEDOut=100, MEDOutOri=100, IIROut=100
In=255, MEDOut=100, MEDOutOri=100, IIROut=177
In=100, MEDOut=100, MEDOutOri=100, IIROut=139
In=100, MEDOut=100, MEDOutOri=100, IIROut=119
In=100, MEDOut=100, MEDOutOri=100, IIROut=110
In=100, MEDOut=100, MEDOutOri=100, IIROut=105
In=100, MEDOut=100, MEDOutOri=100, IIROut=102
In=100, MEDOut=100, MEDOutOri=100, IIROut=101
In=100, MEDOut=100, MEDOutOri=100, IIROut=101
In=100, MEDOut=100, MEDOutOri=100, IIROut=100
In=100, MEDOut=100, MEDOutOri=100, IIROut=100