Меню

Усреднение показаний датчика ардуино

Библиотека фильтров данных для Arduino

ОБНОВЛЕНИЯ

  • v1.6 от 12.11.2019
  • v1.7: исправлен GLinear
  • v1.8: небольшие улучшения
  • v2.0:
    • Улучшен и исправлен median и median3
    • Улучшен linear
    • Смотрите примеры! Использование этих фильтров чуть изменилось
  • v2.1: Исправлен расчёт дельты в линейном фильтре
  • v2.2: Исправлена ошибка компиляции
  • v3.0: Добавлен FastFilter и RingAverage

ТЕОРИЯ

Несколько фильтров подробно разобраны в этом уроке

БИБЛИОТЕКА

GyverTM1637 v1.0

GyverFilters – библиотека с некоторыми удобными фильтрами для Arduino

  • GFilterRA – компактная альтернатива фильтра экспоненциальное бегущее среднее (Running Average)
  • GMedian3 – быстрый медианный фильтр 3-го порядка (отсекает выбросы)
  • GMedian – медианный фильтр N-го порядка. Порядок настраивается в GyverFilters.h – MEDIAN_FILTER_SIZE
  • GABfilter – альфа-бета фильтр (разновидность Калмана для одномерного случая)
  • GKalman – упрощённый Калман для одномерного случая (на мой взгляд лучший из фильтров)
  • GLinear – линейная аппроксимация методом наименьших квадратов для двух массивов
  • FastFilter – быстрый целочисленный экспоненциальный фильтр
  • RingAverage – бегущее среднее с кольцевым буфером

Поддерживаемые платформы: все Arduino

Источник

Полезные алгоритмы Arduino. Обновляемая статья!

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

НЕСКОЛЬКО ТРЮКОВ

  • Автоформатирование – Arduino IDE умеет автоматически приводить ваш код в порядок (имеются в виду отступы, переносы строк и пробелы). Для автоматического форматирования используйте комбинацию CTRL+T на клавиатуре, либо Инструменты/АвтоФорматирование в окне IDE. Используйте чаще, чтобы сделать код красивым (каноничным, классическим) и более читаемым для других!
  • Скрытие частей кода – сворачивайте длинные функции и прочие куски кода для экономии места и времени на скроллинг. Включается здесь: Файл/Настройки/Включить сворачивание кода

Не используйте мышку! Чем выше становится ваш навык в программировании, тем меньше вы будете использовать мышку (да-да, как в фильмах про хакеров). Используйте обе руки для написания кода и перемещения по нему, вот вам несколько полезных комбинаций и хаков, которыми я пользуюсь ПОСТОЯННО:

  • Ctrl+← , Ctrl+→ – переместить курсор влево/вправо НА ОДНО СЛОВО
  • Home , End – переместить курсор в начало/конец строки
  • Shift+← , Shift+→ – выделить символ слева/справа от курсора
  • Shift+Ctrl+← , Shift+Ctrl+→ – выделить слово слева/справа от курсора
  • Shift+Home , Shift+End – выделить все символы от текущего положения курсора до начала/конца строки
  • Ctrl+Z – отменить последнее действие
  • Ctrl+Y – повторить отменённое действие
  • Ctrl+C – копировать выделенный текст
  • Ctrl+X – вырезать выделенный текст
  • Ctrl+V – вставить текст из буфера обмена
  • Ctrl+U – загрузить прошивку в Arduino
  • Ctrl+R – скомпилировать (проверить)
  • Ctrl+Shift+M – открыть монитор порта

Также для отодвигания комментариев в правую часть кода используйте TAB, а не ПРОБЕЛ. Нажатие TAB перемещает курсор по некоторой таблице, из-за чего ваши комментарии будут установлены красиво на одном расстоянии за вдвое меньшее количество нажатий!

Питание от пинов – во время разработки прототипов без брэдборда всегда не хватает пинов для питания датчиков и модулей. Так вот, слабые (с потреблением тока менее 40 мА) 5 Вольтовые датчики можно питать от любых пинов! Достаточно сформировать пин как выход, и подать на него нужный сигнал (HIGH – 5 Вольт, LOW – GND).

Пример: подключаем трёхпиновый датчик звука, не используя пины 5V и GND

Питание от штекера для программатора. Вы наверняка задавались вопросом, а зачем на Arduino NANO на краю платы расположены 6 пинов? Это порт для подключения ISP программатора. Что он делает в списке лайфхаков? Вот вам фото распиновки, используйте!

  • Использовать библиотеку энергосбережения GyverPower, есть подробный урок
  • В паре с библиотекой сделать несколько модификаций: отключить светодиод питания и отрезать левую ногу регулятора напряжения. ВНИМАНИЕ! Резать ногу регулятору можно только в том случае, если плата питается от источника 3-5 Вольт в пины 5V и GND.

Arduino Pro Mini бывает двух типов: с кварцем на 16 МГц и 8 МГц. Китайцы обычно не подписывают плату, и есть риск перепутать разные платы, если у вас есть и те и те. На средних по цене Pro Mini стоит качественный полноразмерный кварц в овальном металлическом корпусе, на нём крупно написана цифра, обозначающая частоту в Мгц:

На недорогих платах стоит крошечный дешёвый кварц в SMD корпусе, вот он:

Берём лупу и смотрим: 16 МГц кварц маркируется примерно как “A1” or “A’N”, 8 МГц кварц маркируется “80’0” или что-то в этом стиле. Ну вот, теперь вы не перепутаете свои Pro Mini!

РАБОТА С ПЕРИФЕРИЕЙ (ДЛЯ ATMEGA328)

Или облегчённые и ускоренные куски ядра Arduino и не только

Источник

Фильтрация сигналов

Шум при измерениях

Шум можно условно разделить на два типа: постоянный шум датчика с одинаковым отклонением (скриншот 1), и случайный шум, который возникает при различных случайных (чаще всего внешних) обстоятельствах (скриншот 2). Небольшой шум наблюдается у любого аналогового датчика, который опрашивается средствами АЦП Ардуино. Причем сам АЦП практически не шумит, если обеспечить качественное питание платы и отсутствие электромагнитных наводок – сигнал с того же потенциометра будет идеально ровный. Но как только питание становится некачественным, например от дешёвого блока питания, картина меняется. Или, например, без нагрузки блок питания даёт хорошее питание и шума нет, но как только появляется нагрузка – вылезают шумы, связанные с устройством блока питания и отсутствием нормальных выходных фильтров. Или другой вариант – где то рядом с проводом к аналоговому датчику появляется мощный источник электромагнитного излучения (провод с большим переменным током), который наводит в проводах дополнительную ЭДС и мы опять же видим шум. Да, от этих причин можно избавиться аппаратно, добавив фильтры по питанию и экранировав все аналоговые провода, но это не всегда получается и поэтому в этом уроке мы поговорим о программной фильтрации значений.

Измерение значений

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

Фильтры

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

Среднее арифметическое

Однократная выборка

Среднее арифметическое вычисляется как сумма значений, делённая на их количество. Первый алгоритм именно так и работает: в цикле суммируем всё в какую-нибудь переменную, потом делим на количество измерений. Вуаля!

Особенности использования

  • Отлично усредняет шум любого характера и величины
  • Для целочисленных значений количество измерений есть смысл брать из степеней двойки (2, 4, 8, 16, 32…) тогда компилятор оптимизирует деление в сдвиг, который выполняется в сотню раз быстрее. Это если вы совсем гонитесь за оптимизацией выполнения кода
  • “Сила” фильтра настраивается размером выборки (NUM_READS)
  • Делает несколько измерений за один раз, что может приводить к большим затратам времени!
  • Рекомендуется использовать там, где время одного измерения ничтожно мало, или измерения в принципе делаются редко

Растянутая выборка

Отличается от предыдущего тем, что суммирует несколько измерений, и только после этого выдаёт результат. Между расчётами выдаёт предыдущий результат:

Особенности использования

  • Отлично усредняет шум любого характера и величины
  • “Сила” фильтра настраивается размером выборки (NUM_READS)
  • Для целочисленных значений количество измерений есть смысл брать из степеней двойки (2, 4, 8, 16, 32…) тогда компилятор оптимизирует деление в сдвиг, который выполняется в сотню раз быстрее. Это если вы совсем гонитесь за оптимизацией выполнения кода
  • Делает только одно измерение за раз, не блокирует код на длительный период
  • Рекомендуется использовать там, где сам сигнал изменяется медленно, потому что за счёт растянутой по времени выборки сигнал может успеть измениться

Бегущее среднее арифметическое

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

Особенности использования

  • Усредняет последние N измерений, за счёт чего значение запаздывает. Нуждается в тонкой настройке частоты опроса и размера выборки
  • Для целочисленных значений количество измерений есть смысл брать из степеней двойки (2, 4, 8, 16, 32…) тогда компилятор оптимизирует деление в сдвиг, который выполняется в сотню раз быстрее. Это если вы совсем гонитесь за оптимизацией выполнения кода
  • “Сила” фильтра настраивается размером выборки (NUM_READS)
  • Делает только одно измерение за раз, не блокирует код на длительный период
  • Данный фильтр показываю чисто для ознакомления, в реальных проектах лучше использовать бегущее среднее. О нём ниже

Экспоненциальное бегущее среднее

Бегущее среднее (Running Average) – самый простой и эффективный фильтр значений, по эффекту аналогичен предыдущему, но гораздо оптимальнее в плане реализации:

Особенности использования

  • Самый лёгкий, быстрый и простой для вычисления алгоритм! В то же время очень эффективный
  • “Сила” фильтра настраивается коэффициентом (0.0 – 1.0). Чем он меньше, тем плавнее фильтр
  • Делает только одно измерение за раз, не блокирует код на длительный период
  • Чем чаще измерения, тем лучше работает
  • При маленьких значениях коэффициента работает очень плавно, что также можно использовать в своих целях

Вот так бегущее среднее справляется с равномерно растущим сигналом + случайные выбросы. Синий график – реальное значение, красный – фильтрованное с коэффициентом 0.1, зелёное – коэффициент 0.5.
Пример с шумящим синусом

Пример с шумным квадратным сигналом, на котором видно запаздывание фильтра:

Адаптивный коэффициент

Чтобы бегущее среднее корректно работало с резко изменяющимися сигналами, коэффициент можно сделать адаптивным, чтобы он подстраивался под резкие изменения значения, например так: если фильтрованное значение “далеко” от реального – коэффициент резко увеличивается, позволяя быстро сократить “разрыв” между величинами. Если значение “близко” – коэффициент ставится маленьким, чтобы хорошо фильтровать шум:

Таким образом даже простейший фильтр можно “программировать” и делать более умным. В этом и заключается прелесть программирования!

Простой пример

Покажу отдельный простой пример реальной работы фильтра бегущее среднее, как самого часто используемого. Остальные фильтры – по аналогии. Фильтровать будем сигнал с аналогового пина А0:

Код выводит в порт реальное и фильтрованное значение. Можно подключить к А0 потенциометр и покрутить его, наблюдая за графиком.

Медианный фильтр

Медианный фильтр тоже находит среднее значение, но не усредняя, а выбирая его из представленных. Алгоритм для медианы 3-го порядка (выбор из трёх значений) выглядит так:

Мой постоянный читатель Андрей Степанов предложил сокращённую версию этого алгоритма, которая занимает одну строку кода и выполняется чуть быстрее за счёт меньшего количества сравнений:

Можно ещё визуально сократить за счёт использования функций min() и max() :

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

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

Медиана для большего окна значений описывается весьма внушительным алгоритмом, но я предлагаю пару более оптимальных вариантов:

  • Медиана отлично фильтрует резкие изменения значения
  • Делает только одно измерение за раз, не блокирует код на длительный период
  • Алгоритм “больше трёх” весьма громоздкий
  • Запаздывает на половину размерности фильтра

Простой “Калман”

Данный алгоритм я нашёл на просторах Интернета, источник потерял. В фильтре настраивается разброс измерения (ожидаемый шум измерения), разброс оценки (подстраивается сам в процессе работы фильтра, можно поставить таким же как разброс измерения), скорость изменения значений (0.001-1, варьировать самому).

Особенности использования

  • Хорошо фильтрует и постоянный шум, и резкие выбросы
  • Делает только одно измерение за раз, не блокирует код на длительный период
  • Слегка запаздывает, как бегущее среднее
  • Подстраивается в процессе работы
  • Чем чаще измерения, тем лучше работает
  • Алгоритм весьма тяжёлый, вычисление длится

90 мкс при системной частоте 16 МГц

Альфа-Бета фильтр

AB фильтр тоже является одним из видов фильтра Калмана, подробнее можно почитать можно на Википедии.

Особенности использования

  • Хороший фильтр, если правильно настроить
  • Но очень тяжёлый!

Метод наименьших квадратов

Следующий фильтр позволяет наблюдать за шумным процессом и предсказывать его поведение, называется он метод наименьших квадратов, теорию читаем тут. Чисто графическое объяснение здесь такое: у нас есть набор данных в виде несколько точек. Мы видим, что общее направление идёт на увеличение, но шум не позволяет сделать точный вывод или прогноз. Предположим, что существует линия, сумма квадратов расстояний от каждой точки до которой – минимальна. Такая линия наиболее точно будет показывать реальное изменение среди шумного значения. В какой то статье я нашел алгоритм, который позволяет найти параметры этой линии, опять же портировал на с++ и готов вам показать. Этот алгоритм выдает параметры прямой линии, которая равноудалена от всех точек.

Особенности использования

  • В моей реализации принимает два массива и рассчитывает параметры линии, равноудалённой от всех точек

Быстрые целочисленные фильтры

Все рассмотренные выше фильтры не могут похвастаться высокой скоростью выполнения вычислений: куча сложений, деление, работа с float и всё такое. Иногда бывает нужно максимально быстро отфильтровать например целочисленный сигнал с АЦП, и тут на помощь приходят шустрые целочисленные фильтры. Основную информацию по точной и осмысленной настройке фильтров можно почитать на easyelectronics, а мы с вами разберём три простых алгоритма, которые являются быстрыми аналогами бегущего среднего. За счёт целочисленных вычислений фильтры имеют небольшое отклонение от реального сигнала (см. графики ниже).

Первый

Фильтр не имеет настроек, состоит из сложения и двух сдвигов, выполняется моментально. Но и фильтрует совсем чуть-чуть:

Второй

Коэффициенты у этого фильтра выбираются следующим образом:

  • k = 1, 2, 3…
  • A + B = 2^k
  • Чем больше А, тем плавнее фильтр (отношение A/B)
  • Чем больше k, тем более плавным можно сделать фильтр. Но больше 5 уже нет смысла, т.к. A=31, B=1 уже очень плавно, а при увеличении может переполниться int.
  • Результат умножения не должен выходить за int, иначе придётся преобразовывать к long
  • Более подробно о выборе коэффициентов читайте в статье, ссылка выше
  • Особенность: если “ошибка” сигнала (signal – filter) меньше 2^k – фильтрованное значение меняться не будет. Для повышения “разрешения” фильтра можно домножить (или сдвинуть) переменную фильтра, то есть фильтровать в бОльших величинах

Например k = 4, значит A+B = 16. Хотим плавный фильтр, принимаем A=14, B=16: filt = (14 * filt + 2 * signal) >> 4;

Третий

Третий алгоритм вытекает из второго: коэффициент B принимаем равным 1 и экономим одно умножение: filt = (A * filt + signal) >> k;

Тогда коэффициенты выбираются так:

  • k = 1, 2, 3…
  • A = (2^k) – 1
    • k=2 A=3, k=3 A=7, k=4 A=15, k=5 A=31…
  • Чем больше k, тем плавнее фильтр

Какой фильтр выбрать?

Выбор фильтра зависит от типа сигнала и ограничений по времени фильтрации. Среднее арифметическое – хорошо подходит, если фильтрации производятся редко и время одного измерения значения мало. Для большинства ситуаций подходит бегущее среднее, он довольно быстрый и даёт хороший результат на правильной настройке. Медианный фильтр 3-го порядка тоже очень быстрый, но он может только отсеить выбросы, сам сигнал он не сгладит. Медиана большего порядка является довольно более громоздким и долгим алгоритмом, но работает уже лучше. Очень хорошо работает медиана 3 порядка + бегущее среднее, получается сглаженный сигнал с отфильтрованными выбросами (сначала фильтровать медианой, потом бегущим). AB фильтр и фильтр Калмана – отличные фильтры, справляются с шумным сигналом не хуже связки медиана + бегущее среднее, но нуждаются в тонкой настройке, также они довольно громоздкие с точки зрения кода. Линейная аппроксимация – инструмент специального назначения, позволяющий буквально предсказывать поведение значения за период – ведь мы получаем уравнение прямой. Если нужно максимальное быстродействие – работаем только с целыми числами и используем целочисленные фильтры.

Библиотека GyverFilters

Библиотека содержит все описанные выше фильтры в виде удобного инструмента для Arduino. Документацию и примеры к библиотеке можно посмотреть здесь.

  • GFilterRA – компактная альтернатива фильтра экспоненциальное бегущее среднее (Running Average)
  • GMedian3 – быстрый медианный фильтр 3-го порядка (отсекает выбросы)
  • GMedian – медианный фильтр N-го порядка. Порядок настраивается в GyverFilters.h – MEDIAN_FILTER_SIZE
  • GABfilter – альфа-бета фильтр (разновидность Калмана для одномерного случая)
  • GKalman – упрощённый Калман для одномерного случая (на мой взгляд лучший из фильтров)
  • GLinear – линейная аппроксимация методом наименьших квадратов для двух массивов

Видео

Источник

Читайте также:  Классификация для датчика давления
Adblock
detector