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

Алгоритм гистерезиса: логика 'двойного порога'

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

Введение в гистерезис: защита от 'дребезга' состояний

При работе с аналоговыми датчиками мы неизбежно сталкиваемся с естественным "шумом" сигнала. Как мы уже обсуждали в уроке, посвященном флаттерингу (COURSE-04-M05-L01), даже незначительные колебания значения вокруг одного порогового значения могут вызывать многократные, ложные переключения исполнительного механизма. Этот эффект, известный как "дребезг" или флаттеринг (flapping), приводит к нестабильной работе системы, повышенному износу оборудования (особенно реле и контакторов) и, в конечном итоге, к недоверию пользователя к системе автоматизации.

Представим систему управления отоплением, настроенную на включение при температуре ниже 22°C. Если показания датчика колеблются между `21.99°C` и `22.01°C` из-за погрешности измерения или легкого сквозняка, система будет непрерывно включать и выключать котел. Это является классическим примером проблемы, которую решает гистерезис.

> 📋 Ключевые понятия:

> * Гистерезис (в контексте автоматизации) — это свойство системы, при котором її реакция на входной сигнал зависит не только от текущего значения сигнала, но и от ее предыдущего состояния. Проще говоря, это введение "памяти" в логику переключения.

> * Зона нечувствительности (Deadband) — это диапазон значений входного сигнала, внутри которого система не меняет своего текущего состояния. Это ключевой механизм, который создает гистерезис.

Для наглядности представим бытовой комнатный термостат. Вы устанавливаете желаемую температуру 22°C. Замечали ли вы, что обогреватель не включается в тот же миг, как температура опускается до 21.9°C, и не выключается, как только она достигает 22.1°C? Вместо этого он включается, например, при 21.5°C и выключается при 22.5°C. Этот диапазон в 1°C и есть зона нечувствительности. Система намеренно "игнорирует" мелкие колебания температуры внутри этой зоны, что обеспечивает стабильную работу и предотвращает частые старты и остановки отопительного прибора.

Именно этот принцип "двойного порога" мы научимся реализовывать программно на нашем контроллере с помощью Node-RED для создания надежных и предсказуемых систем автоматизации.

---

Алгоритм двойного порога: логика High и Low

В основе гистерезиса лежит простой, но чрезвычайно эффективный алгоритм двойного порога. Вместо одного порогового значения, которое служит точкой переключения, мы вводим два:

  • Верхний порог (Threshold ON / High): Порог, при пересечении которого снизу вверх система переходит в состояние "Включено" (ON).
  • Нижний порог (Threshold OFF / Low): Порог, при пересечении которого сверху вниз система переходит в состояние "Выключено" (OFF).
  • Разница между верхним и нижним порогами и образует ту самую зону нечувствительности (deadband).

    Принцип работы алгоритма

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

    Рассмотрим логику переходов:

    1. Переход из состояния OFF в ON

    2. Переход из состояния ON в OFF

    3. Нахождение в зоне нечувствительности

    Это поведение устраняет "дребезг". Колебания сигнала внутри зоны нечувствительности полностью игнорируются, обеспечивая стабильное состояние на выходе.

    > 💡 Подсказка: Ключевое правило: Порог включения (Threshold ON) всегда должен быть численно больше, чем порог выключения (Threshold OFF). Инвертирование этих значений (`ON < OFF`) или их равенство (`ON = OFF`) нарушает саму логику алгоритма. В первом случае система "залипнет" в одном из состояний, во втором — мы вернемся к исходной проблеме с одним порогом и флаттерингом.

    | Состояние системы (в памяти) | Значение сигнала | Решение | Новое состояние |

    | :--------------------------- | :--------------- | :------------------ | :-------------- |

    | OFF | > Threshold ON | Включить | ON |

    | OFF | < Threshold ON | Ничего не делать | OFF |

    | ON | < Threshold OFF | Выключить | OFF |

    | ON | > Threshold OFF | Ничего не делать | ON |

    ---

    Практическая реализация в Node-RED: узел Function

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

  • Выполнить кастомную логику сравнения.
  • Хранить "память" о текущем состоянии между отдельными сообщениями (`msg`).
  • Идеальным инструментом для этой задачи в Node-RED является узел `Function`. Он позволяет писать произвольный код на JavaScript и, что крайне важно, имеет доступ к переменным контекста.

    > 📋 Ключевые понятия:

    > * Контекст (context) в Node-RED — это специальное хранилище, позволяющее узлам сохранять и извлекать данные между выполнениями. Существует три уровня контекста: `node` (локальный для узла), `flow` (общий для всех узлов на одной вкладке) и `global` (общий для всего проекта Node-RED). Для нашей задачи мы будем использовать контекст потока (`flow context`) или контекст узла (`node context`).

    Создание узла гистерезиса

  • Добавьте узел `Function` в ваш поток.
  • Настройте вход и выход. Узел будет иметь один вход (для приема аналогового значения) и один выход (для отправки команды `true`/`false` на реле).
  • Напишите код. Скопируйте следующий код в редактор узла `Function`.
  • // --- НАСТРОЙКИ АЛГОРИТМА ---
    

    // Определяем верхний и нижний пороги.

    // В реальном проекте их можно вынести в переменные потока или глобальные переменные.

    const THRESHOLD_ON = 22.5; // Порог включения (например, температура, при которой включаем котел)

    const THRESHOLD_OFF = 21.5; // Порог выключения (температура, при которой выключаем котел)

    // --- ЛОГИКА ГИСТЕРЕЗИСА ---

    // 1. Получаем текущее значение из входящего сообщения.

    // Ожидается, что msg.payload содержит числовое значение, например, температуру.

    // Применяем parseFloat для надежности.

    let currentValue = parseFloat(msg.payload);

    // Проверка на корректность входных данных

    if (isNaN(currentValue)) {

    node.status({ fill: "red", shape: "ring", text: "Ошибка: некорректный payload" });

    node.error("Входной msg.payload не является числом!", msg);

    return null; // Останавливаем поток, если данные невалидны

    }

    // 2. Получаем текущее состояние из контекста узла.

    // 'hysteresis_state' - имя нашей переменной в памяти.

    // Если переменная не существует (первый запуск), присваиваем ей начальное состояние 'false' (выключено).

    let currentState = context.get('hysteresis_state') || false;

    // 3. Основной алгоритм двойного порога.

    if (currentState === false && currentValue > THRESHOLD_ON) {

    // Условие: система ВЫКЛЮЧЕНА и значение ПРЕВЫСИЛО верхний порог

    // Действие: переключиться в состояние ON

    currentState = true;

    } else if (currentState === true && currentValue < THRESHOLD_OFF) {

    // Условие: система ВКЛЮЧЕНА и значение УПАЛО НИЖЕ нижнего порога

    // Действие: переключиться в состояние OFF

    currentState = false;

    }

    // Если ни одно из условий не выполнено, currentState остается без изменений.

    // 4. Сохраняем новое (или старое) состояние обратно в контекст.

    // Это обеспечивает "память" для следующего сообщения.

    context.set('hysteresis_state', currentState);

    // 5. Формируем выходное сообщение и визуальный статус для отладки.

    // В msg.payload отправляем чистое булево значение, понятное для узлов управления реле.

    msg.payload = currentState;

    // Обновляем статус узла для наглядной диагностики в редакторе Node-RED

    let statusText = "Вход: " + currentValue + "°C | Состояние: " + (currentState ? "ON" : "OFF");

    let statusColor = currentState ? "green" : "grey";

    node.status({ fill: statusColor, shape: "dot", text: statusText });

    // 6. Возвращаем измененное сообщение для дальнейшей обработки.

    return msg;

    > ℹ️ Информация: Использование `context.get()` и `context.set()` является краеугольным камнем этого паттерна. Каждое новое сообщение `msg` заново запускает код в узле `Function`, но благодаря контексту мы всегда "помним", в каком состоянии система находилась на предыдущем шаге. При перезагрузке контроллера данный контекст будет сброшен, если не настроено персистентное хранилище (в `settings.js`), что является темой продвинутого курса.

    ---

    Пример: управление отоплением по датчику температуры

    Рассмотрим наш код в действии на реальном сценарии.

    * `THRESHOLD_ON`: `22.5` °C

    * `THRESHOLD_OFF`: `21.5` °C

    * Ширина зоны нечувствительности: `1.0` °C

    Пошаговый разбор потока сообщений

    Проследим за поведением системы при изменении температуры.

    | Шаг | Вход (`msg.payload`) | Состояние в `context` (до) | Логика в узле `Function` | Состояние в `context` (после) | Выход (`msg.payload`) | Статус узла |

    |:---:|:---------------------|:-----------------------------|:---------------------------------------------------------------------------------------------|:--------------------------------|:-----------------------|:---------------------------------|

    | 1 | `21.0` | `false` | `21.0 < 22.5`. Условие включения не выполнено. | `false` | `false` | `Вход: 21.0°C \| Состояние: OFF` |

    | 2 | `21.8` | `false` | `21.8 < 22.5`. Находимся в зоне нечувствительности. Состояние не меняется. | `false` | `false` | `Вход: 21.8°C \| Состояние: OFF` |

    | 3 | `22.6` | `false` | `22.6 > 22.5`. Система была `false`. Условие включения выполнено! | `true` | `true` | `Вход: 22.6°C \| Состояние: ON` |

    | 4 | `22.8` | `true` | `22.8 > 21.5`. Условие выключения не выполнено. | `true` | `true` | `Вход: 22.8°C \| Состояние: ON` |

    | 5 | `22.0` | `true` | `22.0 > 21.5`. Находимся в зоне нечувствительности. Состояние не меняется. | `true` | `true` | `Вход: 22.0°C \| Состояние: ON` |

    | 6 | `21.4` | `true` | `21.4 < 21.5`. Система была `true`. Условие выключения выполнено! | `false` | `false` | `Вход: 21.4°C \| Состояние: OFF` |

    | 7 | `21.0` | `false` | `21.0 < 22.5`. Условие включения не выполнено. | `false` | `false` | `Вход: 21.0°C \| Состояние: OFF` |

    Как видно из таблицы, котел включается только один раз (шаг 3) и выключается только один раз (шаг 6), несмотря на плавное изменение температуры и прохождение через множество промежуточных значений. Колебания температуры внутри диапазона от 21.5°C до 22.5°C полностью игнорируются, что обеспечивает стабильную работу отопительной системы.

    ---

    Тонкая настройка и выбор ширины гистерезиса

    Реализация алгоритма — это только половина дела. Критически важным этапом является правильный подбор ширины зоны нечувствительности (разницы между `THRESHOLD_ON` и `THRESHOLD_OFF`), так как она напрямую влияет на поведение системы, комфорт пользователей и долговечность оборудования.

    > ⚠️ Внимание: Неправильно подобранная ширина гистерезиса может не только снизить комфорт, но и привести к преждевременному износу исполнительных механизмов из-за частых переключений. Всегда тестируйте алгоритм на реальном объекте и собирайте обратную связь.

    Слишком узкий гистерезис

    Если зона нечувствительности слишком мала (например, 0.1°C для системы отопления), то даже незначительный "шум" сигнала, который не удалось полностью отфильтровать на предыдущих этапах, может пересечь оба порога и снова вызвать флаттеринг. Хоть и в меньшей степени, чем при одном пороге, но проблема останется. Это приведет к частым, но коротким циклам работы оборудования, что является одним из худших режимов эксплуатации для компрессоров, насосов и контакторов.

    Слишком широкий гистерезис

    С другой стороны, если зона нечувствительности чрезмерно велика (например, 5°C для отопления), система станет очень инертной и некомфортной для пользователя. Представьте: котел включится при 19°C и будет работать, пока температура не достигнет 24°C. Такие колебания температуры будут очень заметны и вызовут дискомфорт. Для систем управления освещением по датчику освещенности это будет означать, что свет включится при почти полной темноте, а выключится только когда станет очень светло, игнорируя промежуточные сумеречные состояния.

    Рекомендации по выбору

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

    * Отопление/кондиционирование: `0.5°C` - `2.0°C`.

    * Теплые полы: `1.0°C` - `3.0°C`.

    * Контроль влажности: `5%` - `10% RH`.

    * Управление освещением по датчику освещенности: `10%` - `20%` от диапазона `THRESHOLD_ON`. Например, вкл. при `100 люкс`, выкл. при `120 люкс`.

    * Контроль уровня в баке/давлении в системе: `5%` - `10%` от целевого значения.

    🔗 Связанный материал: Помните, что гистерезис — это один из нескольких методов нормализации сигнала. Он отлично работает в паре с алгоритмами усреднения (например, скользящее среднее), которые сглаживают исходный сигнал еще до того, как он попадет в узел гистерезиса. Такая комбинация позволяет использовать более узкую зону нечувствительности без риска флаттеринга.

    ---

    Итоги и ключевые тезисы

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

    Давайте закрепим основные положения:

    Что дальше?

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