Этим топиком начинаю небольшую серию статей о цифровой фильтрации в FLProg.
Я долго думал с чего начать и что вообще рассказывать по данной теме. О фильтрации и фильтрах есть огромное количество статей в Интернете. Все вроде расписано, разобрано по косточкам, но вопросов меньше не становится, особенно в среде пользователей FLProg. Поэтому начну с основной, грубой, фатальной, но тем не менее очень часто встречающейся ошибки.
Основная ошибка фильтрации.
На форуме, да и в чатах довольно много Пользовательских Блоков различных цифровых фильтров. Одни из них имеют вход EN для тактирования, другие настройки таймингов в параметрах пользователя, третьи вообще ничего такого не предлагают. Не скажу что всегда, но очень часто, вижу вот такую картину.
.
.
Ну и потом тирада. Типа не работает этот фильтр. Фильтрует очень плохо. И т.д.
Конечно же не совсем корректно называть вход тактирования обозначением En.
Естественно первое что приходит в голову неискушенному пользователю это то, что если на входе true - фильтр фильтрует, если же false - не фильтрует. Значит надо тупо инвертировать вход и всё.
И что же получается в итоге.
Каждый раз, когда очередь в цикле доходит до алгоритма блока, этот алгоритм исполняется. И это происходит в каждом цикле.
А что же делает алгоритм.
В каждом цикле он берет очередную переменную со входа, складывает ее в буфер и в купе с переменными взятыми со входа ранее высчитывает какое то среднее или медианное значение.
Вроде бы все норм, с первого взгляда. НО! Время меду циклами составляет микросекунды (иногда миллисекунды). А сигнал какого нибудь датчика изменяется к примеру 1 раз в секунду. Нам надо сравнивать и обрабатывать эти разные значения, а вместо этого, мы тысячу раз (каждый цикл) загоняем в буфер алгоритма одно и то же значение. В результате на выходе имеем почти то же самое что и на входе. Но процессор наш потрудился, мы с успехом заняли его процессорное время, тем самым еще и усугубив быстродействие и так не особо мощного контроллера.
Рассмотрим процесс на примере медианного фильтра из 3х.
У такого фильтра буфер на три значения. И очень часто слышу - "Три значения для фильтрации очень мало". Это далеко не так.
Для наглядности я нарисовал условную диаграмму сигнала с помехой, которую требуется отфильтровать.
.
.
Алгоритм медианы из 3х такой.
Берем со входа три последовательных значения складываем их в буфер, находим медиану и выдаем на выход. При получении следующей переменной, выкидываем из буфера самую старую переменную и заменяем ее новой, после чего повторяем нахождение медианы.
Если мы делаем это каждый цикл, то медиана будет очень близка к исходному значению и на выходе сигнал почти не изменится.
Для того, чтобы отфильтровать помеху, частота выборки (период дискретизации) должен быть как минимум больше чем время действия этой помехи.
Для достижения хорошего результата, необходимо знать или хотя бы представлять тайминги фильтруемых помех. Можно взять с небольшим запасом время тактирования. Но слишком большой таймаут выборки будет фильтровать лишнее и создавать задержку выходного сигнала относительно входного. Особенно это будет заметно на алгоритмах с большим буфером.
Как же регулировать дискретизацию выборки.
Все очень просто. Тактирование можно реализовать обычным генератором. Обязательным моментом в этом случае будет R-триггер. Он не позволит делать выборки на всем протяжении высокого уровня в сигнале генератора.
.
.
Так же можно тактировать плату на которой находится фильтр. Вот в этом случае вход En можно и инвертировать (подать true).
Тактирование платы может оказаться полезным если используется цепочка разных фильтров и их время тактирования совпадает.
.