ГлавнаяАкадемияДатчики и входы: нормализация сигналов → Проблема 'шума' в аналоговых сигналах

Проблема 'шума' в аналоговых сигналах

Урок 3 · Датчики и входы: нормализация сигналов · 30 мин · theory

Введение в аналоговый шум: природа и источники

В работе с аналоговыми датчиками мы неизбежно сталкиваемся с явлением, известным как аналоговый шум. Это случайные, нежелательные и зачастую высокочастотные колебания в измеряемом сигнале, которые не отражают реальных изменений физической величины. Шум "загрязняет" полезную информацию от датчика, делая ее нестабильной и трудной для интерпретации.

> ⚠️ Внимание: Не путайте шум с флаттерингом. Шум — это постоянные микро-колебания сигнала, а флаттеринг (или "дребезг") — это многократное пересечение одного и того же порогового значения. Для борьбы с флаттерингом мы используем алгоритм гистерезиса, как было подробно рассмотрено в уроке COURSE-04-M05-L02, "Алгоритм гистерезиса: логика 'двойного порога'". Шум является одной из причин флаттеринга, но это разные явления.

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

Последствия 'шумных' данных могут быть весьма серьезными:

  • Ложные срабатывания автоматики: Представьте датчик освещенности, показания которого 'скачут' вокруг порога включения света из-за шума. Это приведет к миганию ламп, что недопустимо.
  • Неточные измерения: Шум делает невозможным получение стабильного значения. Температура на дисплее будет постоянно меняться: 23.1°C, 23.3°C, 23.0°C, хотя в реальности она стабильна. Это создает дискомфорт для пользователя.
  • Повышенная нагрузка на систему: Каждое, даже самое незначительное, изменение сигнала обрабатывается контроллером, записывается в базу данных, отправляется по сети MQTT. Шум генерирует огромный поток бесполезных данных, перегружая CPU контроллера, сеть и систему хранения.
  • Визуально разницу между чистым и зашумленным сигналом легко представить. "Чистый" сигнал от датчика температуры в стабильных условиях — это почти идеально ровная горизонтальная линия на графике. "Зашумленный" сигнал — это та же линия, но испещренная мелкими, хаотичными и быстрыми "зубцами", колеблющимися вверх и вниз от истинного значения. Наша задача — программно "срезать" эти зубцы, оставив только плавную линию, отражающую реальные изменения.

    ---

    Практикум: Визуализация и симуляция шума в Node-RED

    Теория становится понятнее, когда ее можно увидеть и "потрогать". Сейчас мы создадим в Node-RED простой симулятор "шумного" датчика и визуализируем его показания на графике. Для этого нам понадобится пакет `node-red-dashboard`. Если он не установлен, его можно добавить через `Меню -> Manage Palette -> Install`.

    > 💡 Подсказка: Для генерации шума в ноде `Function` можно использовать простой JavaScript-код: `msg.payload = msg.payload + (Math.random() - 0.5) * 2; return msg;`. Эта строка берет входящее значение, добавляет к нему случайное число в диапазоне от -1 до +1 и отправляет дальше. Это отличный способ имитировать показания реального нестабильного датчика.

    Выполним следующие шаги:

  • Создайте новый поток (flow) и разместите на нем три узла: `Inject`, `Function` и `Chart`. Соедините их последовательно: `Inject` -> `Function` -> `Chart`.
  • Настройте узел `Inject`:
  • * Payload: `number`, установите значение `22`. Это будет наше "истинное" значение температуры.

    * Topic: оставьте пустым.

    * Repeat: `interval` с интервалом `1 second`. Это заставит узел отправлять сообщение каждую секунду.

  • Настройте узел `Function`:
  • * Name: "Симулятор шума".

    * Код: скопируйте и вставьте следующий JavaScript-код:

            // Базовое значение, которое мы симулируем

    let baseValue = msg.payload;

    // Амплитуда шума (насколько сильно сигнал будет "дрожать")

    let noiseAmplitude = 1.5;

    // Генерируем случайное отклонение от -0.5 до +0.5,

    // затем умножаем на амплитуду

    let noise = (Math.random() - 0.5) * noiseAmplitude;

    // Добавляем шум к базовому значению

    msg.payload = baseValue + noise;

    // Округляем до 2 знаков после запятой для наглядности

    msg.payload = parseFloat(msg.payload.toFixed(2));

    node.status({fill:"grey", shape:"dot", text:"Value: " + msg.payload});

    return msg;

  • Настройте узел `Chart`:
  • * Group: создайте новую группу на вкладке `Dashboard`.

    * Type: `Line chart`.

    * Label: "Сигнал с 'шумного' датчика".

    * X-axis: установите `last 10 minutes`, чтобы видеть историю.

  • Разверните проект (Deploy) и откройте интерфейс Dashboard. Вы увидите график, на котором значение не стоит на месте (на отметке 22), а постоянно хаотично колеблется вокруг этого значения в пределах примерно от 20.5 до 23.5. Это и есть визуализация нашего аналогового шума. Вы наблюдаете, как из стабильного значения `22` получается "дрожащий", непредсказуемый сигнал, который в реальной системе вызывал бы множество проблем.
  • ---

    Метод простого скользящего среднего (SMA) для фильтрации

    Итак, мы увидели проблему. Как с ней бороться? Один из самых простых и эффективных программных методов фильтрации шума — это Простое Скользящее Среднее (Simple Moving Average, SMA).

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

    Алгоритм SMA выглядит так:

    `SMA = (P1 + P2 + ... + PN) / N`

    Где:

    Выбор размера окна `N` — это всегда компромисс между качеством фильтрации и инерционностью системы.

    | Параметр | Малое окно (N = 3-5) | Большое окно (N = 20-50) |

    | -------------------- | ---------------------------------------------------------- | ------------------------------------------------------------- |

    | Качество фильтрации | Слабое. Хорошо сглаживает мелкий шум, но пропускает крупные выбросы. | Высокое. Эффективно подавляет даже сильный, высокоамплитудный шум. |

    | Инерционность | Низкая. Система быстро реагирует на реальные изменения. | Высокая. Система медленно реагирует на реальные изменения. |

    | Пример использования | Датчики освещенности, датчики движения (для анализа активности). | Датчики температуры в помещении, датчики влажности почвы, датчики CO2. |

    Как выбрать правильный размер окна?

    Это зависит от природы измеряемого процесса:

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

    ---

    Реализация SMA-фильтра с помощью ноды `smooth`

    Вручную реализовывать алгоритм SMA в ноде `Function` (хранить массив последних значений, суммировать, делить) возможно, но нецелесообразно, так как существует готовое и проверенное решение — нода `smooth` из пакета `node-red-contrib-smooth`.

    > 💡 Подсказка: Нода `smooth` хранит последние значения в своем внутреннем буфере (в памяти контроллера). Помните, что при каждом развертывании (Deploy) или перезапуске контроллера этот буфер сбрасывается. Это означает, что первые `N-1` значений на выходе фильтра будут "разогревочными" и не совсем корректными, пока буфер не заполнится полностью. Учитывайте это в логике старта системы.

    Давайте добавим SMA-фильтр в наш предыдущий практикум и посмотрим на результат.

  • Установите пакет, если он отсутствует: `Меню -> Manage Palette -> Install -> node-red-contrib-smooth`.
  • Добавьте ноду `smooth` в наш поток, установив ее между нодой `Function` ("Симулятор шума") и нодой `Chart`.
  • Настройте ноду `smooth`:
  • * Name: "SMA Фильтр (N=10)".

    * Action: `average`.

    * over the last: `10` values. (Это и есть наш размер окна `N`).

    * of property: `msg.payload`.

    * Остальные параметры оставьте по умолчанию.

  • Создайте второй график для сравнения:
  • * Добавьте еще одну ноду `Chart`.

    * Подключите ее до ноды `smooth`, прямо к выходу ноды `Function` ("Симулятор шума").

    * Настройте эту ноду `Chart`, дав ей имя "Сырой сигнал".

    * Существующую ноду `Chart` (которая подключена после `smooth`) переименуйте в "Отфильтрованный сигнал (SMA)".

    Теперь ваш поток выглядит так:

    `Inject -> Function (шум) ->+-> Chart ("Сырой сигнал")`

    ` |`

    ` +-> smooth -> Chart ("Отфильтрованный сигнал (SMA)")`

  • Разверните проект (Deploy) и откройте Dashboard.
  • Теперь вы видите два графика. На верхнем ("Сырой сигнал") — знакомая нам хаотичная "пила". А на нижнем ("Отфильтрованный сигнал") — гораздо более плавная линия, которая все еще колеблется, но уже без резких пиков и провалов. Она плавно следует за "центром" зашумленного сигнала.

    Эксперимент: вернитесь в редактор Node-RED, откройте настройки ноды `smooth` и измените размер окна с `10` на `50`. Разверните проект. Вы увидите, что отфильтрованный график стал еще более гладким, почти превратившись в прямую линию. Но если вы измените базовое значение в ноде `Inject` (например, с 22 на 30), вы заметите, что отфильтрованный график достигнет нового значения с заметной задержкой, демонстрируя инерционность системы.

    ---

    Пример: Комбинация усреднения и гистерезиса

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

    > 🔗 Связанный материал: Подробную реализацию логики гистерезиса на ноде `Function` с использованием контекста потока мы разбирали в уроке COURSE-04-M05-L03. Ключевой принцип — использование двух порогов (включения и выключения) и хранение текущего состояния. В данном потоке нода `smooth` должна быть установлена ПЕРЕД нодой гистерезиса.

    Почему одного метода недостаточно?

    Поэтому правильная последовательность обработки сигнала всегда такова:

    Сигнал с датчика -> [Фильтр усреднения (SMA)] -> [Логика гистерезиса] -> Управление нагрузкой
  • Сначала мы усредняем "сырой", зашумленный сигнал, чтобы получить чистое, плавное, предсказуемое значение.
  • Затем это чистое значение мы подаем на вход логики гистерезиса, которая принимает безошибочное решение о переключении состояния (ВКЛ/ВЫКЛ).
  • Сквозной пример: управление уличным освещением по датчику освещенности. 1. Сигнал с датчика освещенности (например, с аналогового входа 0-10В) поступает в Node-RED.

    2. Он немедленно направляется в ноду `smooth` с окном, скажем, `N=60` (усреднение за последнюю минуту, так как закат — медленный процесс). На выходе мы получаем плавную кривую падения освещенности, очищенную от шума облаков и фар.

    3. Отфильтрованный сигнал поступает в ноду `Function` с логикой гистерезиса. Например:

    * Если свет ВЫКЛ и освещенность < 50 люкс, то ВКЛЮЧИТЬ свет.

    * Если свет ВКЛ и освещенность > 80 люкс, то ВЫКЛЮЧИТЬ свет.

    4. Выход из ноды гистерезиса (`true` или `false`) управляет реле контроллера, которое включает/выключает уличный фонарь.

    В результате мы получаем систему, которая:

    Итоговый поток в Node-RED будет выглядеть как цепочка:

    `Modbus Read (датчик)` -> `smooth` -> `Function (гистерезис)` -> `Relay Control (реле)`

    ---

    Итоги и рекомендации

    В этом уроке мы глубоко погрузились в проблему аналогового шума и освоили мощный инструмент для борьбы с ним — фильтр скользящего среднего.

    Запомнив эти простые правила, вы сможете создавать сценарии автоматизации, которые работают не только в идеальных лабораторных условиях, но и на реальных объектах с их неизбежными помехами и несовершенством сигналов.

    Что дальше

    В следующем уроке мы расширим наши знания о фильтрации, рассмотрев более продвинутые алгоритмы, такие как взвешенное и экспоненциальное скользящее среднее. Мы обсудим, в каких специфических случаях их применение дает преимущества по сравнению с простым скользящим средним и как реализовать их в Node-RED.