Найти тему
SamON

Цифровой фильтр: SMA, EMA

Оглавление

Всем привет! Сегодня поговорим о цифровой фильтрации сигнала.

И начать этот разговор я хочу с простых фильтров. Если тема покажется полезной, то я расскажу и о других вариантах фильтрации сигнала.

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

Simple moving average (SMA)

На самом деле, это просто нахождение среднего арифметического значения. Формула его известна еще со школы. Как показало наблюдение, это один из самых часто используемых фильтров.

-2

Тут все просто. Накапливаем значения, например 10 измерений, складываем их и делим на 10.

Можно немного оптимизировать этот алгоритм следующим образом.

Накопить первые 10 измерений в буфер, посчитать SMA, а потом вычитать самое старое значение и добавлять самое новое.

-3

Работает уже лучше, работа фильтра идет быстрее, но можно оптимизировать еще лучше!

Exponentially moving average (EMA)

Тут уже интереснее. Фильтрация не требует буфера, а сам фильтр представляет собой одну строку кода. Но давайте по порядку.

В общем виде, формула фильтра выглядит так

-4

a - сглаживающая константа (от 0 до 1) , p_t - новое значение измерения, EMA_t - новое фильтрованное значение, EMA_t-1 - предыдущее фильтрованное значение.

Если раскрыть скобки относительно альфа, то формула примет вид

EMA_t += (p_t - EMA_t) * a;

Именно так и будет выглядеть формула на сях, которая пойдет в прошивку MCU.

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

Код для теста фильтра выглядит так.

каракули в функции sprintf нужны для формирования массива данных что бы плоттер мог эти данных визуализировать. К фильтру это не имеет отношения.
каракули в функции sprintf нужны для формирования массива данных что бы плоттер мог эти данных визуализировать. К фильтру это не имеет отношения.
Пара слов о стенде. Основа - Nucleo board на STM32L476, ардуиновский шилд с дисплеем и кнопками. Кнопки включены так, что при нажатии шунтируют резисторы делителя напряжения. В итоге, по выходному напряжению делителя можно судить о том, какая кнопка нажата.
Используемое ПО: генератор кода CubeMX, плоттер Serial Port Plotter.

Выглядит это вот так

-6

Проверяем отклик фильтра при нажатии на кнопку.

Красный луч - значение, которое измерил АЦП (тупо читаем регистр, без перевода в напряжение), желтый луч - выход фильтра. Период опроса 10 мс. альфа = 0,5
Красный луч - значение, которое измерил АЦП (тупо читаем регистр, без перевода в напряжение), желтый луч - выход фильтра. Период опроса 10 мс. альфа = 0,5

Красный луч - значение, которое измерил АЦП (тупо читаем регистр, без перевода в напряжение), желтый луч - выход фильтра. Период опроса 10 мс. альфа = 0,05
Красный луч - значение, которое измерил АЦП (тупо читаем регистр, без перевода в напряжение), желтый луч - выход фильтра. Период опроса 10 мс. альфа = 0,05

К сожалению, под рукой нет ни одного датчика. Потому я просто снял ардуиновский шилд, тем самым АЦП вход у меня повис в воздухе. К нем я периодически подносил руку, что усиливало помехи. Ниже, в карусели, можно сравнить работу фильтра на тех же настройках при подавлении помехи. Сначала альфа 0,5, затем 0,05.

Недостатком является то, что при резком изменении входного сигнала, выходной сигнал будет запаздывать и время запаздывания зависит от альфы. К слову, мы имеем БИХ фильтр со всеми вытекающими. Чем меньше, тем больше запаздывает. Вот, для имитации быстро меняющейся величины, я несколько раз нажал на кнопку. альфа 0,05

-10

Стоит отметить, что при сильно маленьком коэф. альфа выходное значение не достигнет уровня входного сигнала. Пример при альфа 0,01

-11

По этому, выбор коэф. альфа должен осуществляться индивидуально, под каждую задачу. Нет единого алгоритма выбора коэф. Хотя, его можно выразить через формулу a = 2/(n+1), где n - окно усреднения.