Документация Engee
Notebook

Сглаживание сигнала скользящим окном

Рассмотрим 4 способа сглаживания сигнала скользящим окном, от низкоуровневых до самых высокоуровневых.

Разные способы сглаживания сигнала

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

image.png

Цепочка задержек (явный КИХ)

Во-первых, самый низкоуровневый метод реализации скользящего окна будет состоять в том, чтобы просто запомнить некоторое количество точек сигнала, например 100, по мере их поступления. Результатом будет сумма всех этих "отложенных измерений", деленная на их количество (100).

image.png

Внутри фильтра находится 10 одинаковых блоков, выходы которых суммируются и делятся на 100.

image.png

Внутри каждого такого блока находится по 10 блоков задержки Unit Delay, которые запоминают очередное значение прежде чем передать последующему блоку то значение, которое они получили шагом ранее.

Зачем мы создали такую иерархию блоков? Расположив блоки задержки таким образом мы избежали необходимости создавать линию из 100 блоков задержки.

Этот метод не очень гибок, поскольку нам всё-таки приходится создавать блоки задержки вручную. Будет сложно параметризовать такой фильтр при помощи маски.

Использование готового блока КИХ-фильтра

Гораздо проще расположить на схеме блок Discrete FIR filter

image.png

Укажем блоку одинаковые веса коэффициентов, чтобы каждое измерение имело одинаковый вклад в финальный сигнал.

Сглаживание через CIC фильтр

КИХ-фильтр с одинаковыми весами можно создать при помощи гораздо более простой и изящной конструкции, показанной ниже.

image.png

Здесь при помощи задержки длиной 100 и нескольких простых блоков мы создали каскадный интегрально-гребенчатый фильтр типа БИХ (с бесконечной импульсной характеристикой). Здесь совсем нет операций умножения, поэтому фильтр работает очень быстро.

Блок "Скользящее усреднение"

Еще один блок из стандартной библиотеки, который называется Moving Average, если в его настройках указан метод "скользящего окна", будет реализовывать ту же операцию, что и предыдущие.

Блоку требуется, чтобы ему на вход приходил вектор значений, поэтому мы подаем во входной порт буферизованный сигнал (блок Buffer длиной 100 с перекрытием 99). На выходе он нам вернет одно значение, упакованное в матрицу размером 1х1. Мы переведем его в скаляр при помощи блока Demux.

Запуск модели

Запустим модель на 2500 отсчетов. Входной сигнал порождается следующей подсистемой:

image.png

Это результат суммирования константы 1 с вектором равномерно распределенного шума с амплитудой 0.01. Спустя 500 отсчетов модели к сигналу добавляется ступенька амплитудой 1.

In [ ]:
# Если модель еще не открыта, загрузим из файла
if "moving_average"  getfield.(engee.get_all_models(), :name)
    engee.load( "$(@__DIR__)/moving_average.engee");
end;

data = engee.run( "moving_average" )
Out[0]:
Dict{String, DataFrame} with 5 entries:
  "Сглаженный блоком FIR"    => 2501×2 DataFrame…
  "Исходный"                 => 2501×2 DataFrame…
  "Сглаженный через блок MA" => 2501×2 DataFrame…
  "Сглаженный явным FIR"     => 2501×2 DataFrame…
  "Сглаженный CIC фильтром"  => 2501×2 DataFrame

Сравним результаты между собой. Они должны быть идентичны, но последний метод будет вносить запаздывание на один отсчет из-за того, как реализована буферизация сигнала.

In [ ]:
plot( data["Сглаженный явным FIR"].time, data["Сглаженный явным FIR"].value, label="Сглаженный явным FIR" )
plot!( data["Сглаженный блоком FIR"].time, data["Сглаженный блоком FIR"].value, label="Сглаженный блоком FIR" )
plot!( data["Сглаженный CIC фильтром"].time, data["Сглаженный CIC фильтром"].value, label="Сглаженный CIC фильтром" )
plot!( data["Сглаженный через блок MA"].time, data["Сглаженный через блок MA"].value, label="Сглаженный через блок MA" )
plot!( legend=:bottomright )
Out[0]:

Заключение

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

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

Блоки, использованные в примере