Главная → Академия → Датчики и входы: нормализация сигналов → Физический сигнал, логическое событие, состояние системы: фундаментальные различия

Физический сигнал, логическое событие, состояние системы: фундаментальные различия

Введение: от физики к логике

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

> ℹ️ Информация: В рамках этого курса мы будем использовать термины «сигнал», «событие» и «состояние» в строго определенном контексте, который является стандартом для инженеров сертификационной академии. Четкое разделение этих понятий — залог успешного проектирования и безошибочной диагностики.

Представьте себе простую аналогию:

  • Физический сигнал — это как прикосновение к горячему предмету. Нервные окончания на вашей коже (датчики) регистрируют изменение температуры. Это сырая, необработанная информация.
  • Логическое событие — это нервный импульс, который доходит до мозга и интерпретируется как «Опасно! Горячо!». Мозг отфильтровал незначительные колебания температуры и сгенерировал осмысленное предупреждение.
  • Состояние системы — это ваше знание: «Плита сейчас горячая». Вы можете не прикасаться к ней постоянно, но ваша внутренняя «память» хранит эту информацию. Если кто-то спросит вас, можно ли трогать плиту, вы ответите, исходя из сохраненного состояния, а не будете ждать нового «события» от прикосновения.
  • В экосистеме контроллера HI этот поток данных выглядит следующим образом:

    • Физический сигнал: Изменение напряжения или сопротивления на универсальном входе (UI) контроллера от подключенного датчика.
    • Логическое событие: Программный код в Node-RED анализирует этот сигнал, приводит его к человекочитаемому виду (например, в градусы Цельсия) и формирует стандартизированное сообщение `msg`.
    • Состояние системы: Это сообщение обновляет переменную в памяти контроллера (контексте Node-RED), которая хранит актуальное значение, например, `office_temperature = 23.5`.

    Понимание этой триады позволяет инженеру-инсталлятору корректно настраивать обработку данных от любого, даже самого сложного датчика, и создавать автоматизацию, которая работает не только «здесь и сейчас», но и будет стабильной, масштабируемой и простой в обслуживании в будущем.

    ---

    Физический сигнал: язык датчиков

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

    | Характеристика | Аналоговый сигнал | Дискретный сигнал |

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

    | Природа | Непрерывно изменяющаяся величина в определенном диапазоне. | Имеет только два или несколько фиксированных состояний. |

    | Примеры на объекте | Датчик температуры (NTC/PT1000), датчик освещенности (0-10В), датчик давления (4-20мА). | Кнопка, геркон на двери, датчик протечки, выход "сухой контакт" другого устройства. |

    | Физическое проявление | Изменение напряжения (e.g., 0-3.3В), изменение сопротивления. | Замкнутая или разомкнутая цепь (сопротивление близко к 0 или бесконечности). |

    | Роль контроллера HI | АЦП (Аналого-цифровой преобразователь) измеряет напряжение и преобразует его в число. | Универсальный вход в режиме DI (Digital Input) определяет, замкнута цепь или нет. |

    | "Сырые" данные | Число, пропорциональное напряжению. Например, `1532` (из диапазона 0-4095 для 12-битного АЦП). | `0` (разомкнуто) или `1` (замкнуто). |

    Аналоговый сигнал на примере датчика температуры NTC

    Датчик температуры NTC (Negative Temperature Coefficient) — это, по сути, резистор, сопротивление которого уменьшается при увеличении температуры. Контроллер HI подает на него опорное напряжение через делитель и измеряет результирующее напряжение на входе. Это напряжение напрямую зависит от сопротивления NTC-датчика, а значит, и от температуры.

    АЦП контроллера замеряет это напряжение и выдает "сырое" (raw) цифровое значение. Например, для 12-битного АЦП, работающего с напряжением от 0 до 3.3В, мы получим:

    • 0В → число `0`
    • 1.65В → число `2048`
    • 3.3В → число `4095`

    В Node-RED, из специализированного узла для чтения аналоговых входов (например, гипотетического `HI-AI`), придет сообщение `msg` с `payload`, содержащим это сырое число: `1532`. Это и есть физический сигнал в его цифровом представлении. Он еще не несет для нас никакого смысла, кроме как "напряжение на входе составляет примерно `1532/4095 * 3.3В`".

    Дискретный сигнал на примере геркона

    Геркон (герметизированный контакт) на окне — это классический пример источника дискретного сигнала. Когда окно закрыто, магнит рядом с герконом замыкает его контакты. Когда окно открывается, магнит удаляется, и контакты под действием упругости размыкаются.

    Универсальный вход контроллера HI, настроенный как дискретный, постоянно проверяет состояние этой цепи.

    • Цепь замкнута → Вход "видит" логический `1` (или `true`).
    • Цепь разомкнута → Вход "видит" логический `0` (или `false`).

    В Node-RED от узла `HI-DI` придет сообщение с `msg.payload`, равным `0` или `1`. Это тоже "сырой" физический сигнал. Он говорит нам о состоянии электрической цепи, но еще не говорит о состоянии окна в понятных для автоматизации терминах.

    > 💡 Подсказка: Для стабильного чтения дискретных сигналов всегда используйте внешнюю или внутреннюю "подтяжку" (pull-up/pull-down резисторы), чтобы избежать "плавающего" состояния входа, когда он не подключен ни к `GND`, ни к питанию. Подробнее об этом было рассмотрено в уроке 🔗 COURSE-03-M02-L01.

    ---

    Логическое событие: рождение смысла

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

    Этот процесс происходит внутри Node-RED, как правило, в узле `function`.

    Техники нормализации и фильтрации

  • Приведение аналогового сигнала к физическим величинам. Сырое значение от АЦП (например, `1532`) бесполезно для логики. Его нужно преобразовать в градусы Цельсия, проценты влажности или паскали давления. Для этого используется формула или таблица преобразования из документации на датчик. Это и есть нормализация.
  • Фильтрация "дребезга контактов" (debounce). При замыкании механических контактов (кнопка, реле, геркон) возникает серия очень быстрых, хаотичных замыканий-размыканий, прежде чем контакт станет стабильным. Это называется "дребезг". Если не фильтровать его, одно нажатие кнопки может сгенерировать десятки сигналов `0` и `1`, что приведет к непредсказуемой работе логики. Для борьбы с этим используются специальные узлы (например, `delay` в режиме "rate limit" или `trigger`) или программные таймеры.
  • Использование пороговых значений (thresholds). Аналоговый сигнал может генерировать события. Например, мы можем решить, что событие `TEMPERATURE_HIGH` происходит, когда значение температуры превышает 25°C, а событие `TEMPERATURE_NORMAL` — когда опускается ниже 24.5°C (гистерезис для предотвращения частых переключений).
  • Формирование канонического `msg` объекта

    После нормализации и фильтрации результат должен быть упакован в стандартный, предсказуемый формат. Как мы знаем из паттернов Node-RED, это "контракт сообщения".

    • `msg.topic` используется для семантической идентификации источника. Он должен отвечать на вопросы "что это?" и "откуда?". Например, `telemetry/living_room/temperature` или `events/front_door/status`.
    • `msg.payload` должен содержать структурированные данные в формате JSON.

    Давайте посмотрим на примере преобразования сигнала с NTC-датчика в логическое событие.

    /*
    

    Узел Function: "Нормализация температуры в гостиной"

    Вход: msg.payload = 1532 (сырое значение от АЦП узла HI-AI)

    Выход: структурированное сообщение с температурой в °C

    */

    // --- 1. Нормализация ---

    // Предположим, мы экспериментально или по документации выяснили,

    // что для нашего датчика и делителя формула такова:

    // Temp_C = (3800 - raw_value) / 30.5

    let rawValue = msg.payload;

    let temperature = (3800 - rawValue) / 30.5;

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

    temperature = Math.round(temperature * 10) / 10;

    // --- 2. Валидация ---

    // Отсекаем нереалистичные значения, которые могут возникнуть при обрыве или КЗ датчика.

    if (temperature < -40 || temperature > 100) {

    // Если значение некорректно, логируем ошибку и останавливаем поток.

    // Узел Catch поймает эту ошибку.

    node.error(`Некорректное значение температуры после нормализации: ${temperature}°C, raw: ${rawValue}`, msg);

    return null; // Остановить обработку этого сообщения

    }

    // --- 3. Формирование каноничного сообщения (События) ---

    // Заполняем topic для маршрутизации

    msg.topic = "telemetry/living_room/temperature";

    // Заполняем payload согласно контракту

    msg.payload = {

    "value": temperature,

    "unit": "°C",

    "source": "ui-05-ntc-livingroom", // Уникальный ID источника

    "ts": Date.now(), // Временная метка события

    "raw": rawValue // Опционально сохраняем сырое значение для отладки

    };

    node.status({fill:"green", shape:"dot", text:`${temperature} °C`});

    return msg;

    Теперь на выходе узла мы имеем не просто число, а полноценное, понятное системе логическое событие, которое можно отправлять в MQTT, сохранять в базу данных или использовать в сценариях автоматизации.

    ---

    Состояние системы: цифровая память объекта

    Если событие — это сообщение о том, что что-то изменилось, то состояние — это информация о том, как обстоят дела прямо сейчас. Состояние системы — это "снимок" всех её важных параметров в определенный момент времени, хранящийся в памяти контроллера.

    События порождают изменения состояния. Например, событие «Дверь открылась» изменяет состояние `system.doors.front_door` с `'closed'` на `'open'`.

    В Node-RED для хранения состояний используется механизм контекста. Контекст — это, по сути, область памяти, где можно хранить переменные. Существует три уровня контекста:

    • Node Context: Переменная видна только тому узлу, который ее создал. Используется редко, для очень специфичных задач.
    • Flow Context: Переменные видны всем узлам на одной вкладке (flow). Это основной инструмент для хранения локальных состояний. Например, состояние света в одной комнате.
    • Global Context: Переменные видны абсолютно всем узлам на всех вкладках. Используется для хранения глобальных состояний, к которым нужен доступ из разных подсистем (например, режим «Я ушел из дома», статус охранной системы).

    > ⚠️ Внимание: Избегайте хранения слишком больших или сложных объектов в контексте. Это увеличивает использование оперативной памяти (ОЗУ) контроллера и может замедлить время развертывания потоков (deploy). Храните только необходимую информацию: `{'state': 'ON', 'brightness': 80}`, а не весь объект `msg`.

    Преимущества работы с состояниями

    Представьте, что вам нужно включить кондиционер, только если все окна в доме закрыты.

    • Подход без состояний: Вам пришлось бы подписаться на события от каждого геркона на каждом окне и в сложной логике отслеживать их.
    • Подход с состояниями: Каждый геркон при изменении своего статуса (событие `WINDOW_OPENED`/`WINDOW_CLOSED`) обновляет свою переменную в глобальном контексте. Например, `global.set('windows.living_room.state', 'closed')`. Сценарий управления кондиционером перед включением просто проверяет значения всех этих переменных: `global.get('windows.living_room.state')`, `global.get('windows.bedroom.state')` и т.д.

    Этот подход делает систему декомпозированной и масштабируемой. Логика управления кондиционером ничего не знает о герконах — она работает с абстрактными состояниями окон. А логика обработки герконов ничего не знает о кондиционере. Систему становится легко отлаживать и расширять.

    Пример чтения состояния из контекста в `function` узле:

    // Получаем текущий статус входной двери из глобального контекста
    

    const frontDoorStatus = global.get('security.doors.front_door');

    // frontDoorStatus может выглядеть так:

    // { "status": "closed", "last_change": 1678886400000 }

    if (frontDoorStatus && frontDoorStatus.status === 'open') {

    // Логика, если дверь открыта

    }

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

    ---

    Сквозной пример: от кнопки до управления светом

    Давайте объединим все три концепции на простом, но очень показательном примере: управление светом в комнате с помощью одной кнопки без фиксации. Каждое нажатие должно инвертировать состояние света (был включен — выключится, был выключен — включится).

    Наша задача:
  • Прочитать физический сигнал от кнопки, подключенной к универсальному входу HI-контроллера.
  • Отфильтровать дребезг и преобразовать сигнал в однократное логическое событие "Кнопка нажата".
  • На основе этого события изменить состояние света (`'ON'` или `'OFF'`), которое хранится в памяти.
  • Отправить команду на реле, управляющее светильником.
  • Схема потока в Node-RED:
               [HI-DI In]        [rbe]           [function]          [HI-Relay Out]
    

    (сигнал) -- (Кнопка) --.-- (Фильтр) -- (Событие) -- (Логика) -- (Изменение состояния) -- (Команда) --> (Реле света)

    | | | |

    0/1 1 "PRESSED" msg.payload: true/false

    Шаг 1: Чтение физического сигнала

    Используем узел `HI-DI In` (или его аналог для дискретных входов), настроенный на пин, к которому подключена кнопка. На выходе этого узла мы будем получать `msg.payload` со значением `1` при нажатии и `0` при отпускании.

    Шаг 2: Создание события "Кнопка нажата"

    Нам важно отреагировать только на факт нажатия, а не на дребезг или отпускание.

  • Подключаем выход узла `HI-DI In` к стандартному узлу `rbe` (report by exception). Этот узел будет пропускать сообщение дальше, только если его `payload` изменился. Он является простейшим фильтром.
  • После `rbe` ставим узел `switch`, который будет пропускать сообщение дальше, только если `msg.payload == 1`. Таким образом, мы отсекаем событие отпускания кнопки (`0`) и получаем только однократное событие "нажатие".
  • Теперь на выходе узла `switch` мы имеем чистое логическое событие, которое можно обрабатывать.

    Шаг 3: Обработка события и управление состоянием

    Это сердце нашей логики. Мы используем узел `function` для инвертирования состояния.

    /*
    

    Узел Function: "Логика переключения света"

    Вход: любое сообщение (событие нажатия кнопки)

    Выход: msg.payload = true (включить) или false (выключить)

    */

    // --- 1. Чтение текущего состояния ---

    // Сначала получаем текущее состояние света из контекста потока.

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

    let currentState = flow.get('light_state') || false;

    // --- 2. Инвертирование состояния ---

    // Меняем состояние на противоположное.

    let newState = !currentState;

    // --- 3. Сохранение нового состояния ---

    // Записываем новое состояние обратно в контекст потока для следующего нажатия.

    flow.set('light_state', newState);

    // --- 4. Формирование команды для реле ---

    // Помещаем новое состояние в msg.payload. Узел HI-Relay Out

    // ожидает `true` для включения или `false` для выключения.

    msg.payload = newState;

    // Обновляем визуальный статус узла для удобства отладки

    if (newState) {

    node.status({fill:"yellow", shape:"dot", text:"State: ON"});

    } else {

    node.status({fill:"grey", shape:"dot", text:"State: OFF"});

    }

    return msg;

    Шаг 4: Исполнение команды

    На выходе узла `function` мы имеем `msg.payload`, равный `true` или `false`. Это сообщение мы отправляем напрямую в узел `HI-Relay Out`, который настроен на управление нужным реле. Узел получит `true` и замкнет реле, или `false` и разомкнет его.

    Таким образом, мы прошли весь путь: от нестабильного сигнала `0/1/0/1/1...` на входе до чистого события "нажатие", которое изменило внутреннее состояние системы и привело к физическому действию.

    ---

    Резюме: Сигнал → Событие → Состояние

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

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

    • Сигнал — это "сырая", необработанная физическая величина на входе контроллера (напряжение, сопротивление, замыкание цепи). Это язык оборудования. В Node-RED это, как правило, простое число или `true`/`false` в `msg.payload`.
    • Событие — это результат обработки и нормализации сигнала. Это осмысленное, структурированное сообщение о том, что в реальном мире произошло нечто важное (температура превысила порог, дверь открылась, кнопка нажата). Это язык логики. В Node-RED это `msg` с осмысленным `topic` и структурированным `payload`.
    • Состояние — это актуальная информация об объекте или системе, хранящаяся в "памяти" контроллера (контексте) и изменяемая событиями. Это цифровая модель реального мира. Она позволяет разным частям системы принимать решения, не дожидаясь новых событий.

    Освоив эту модель, вы перестаете мыслить в терминах "замкнуть реле, когда на входе X появится напряжение Y". Вместо этого вы начинаете проектировать на более высоком уровне абстракции: "Изменить состояние `climate.mode` на `heating`, когда произойдет событие `TEMPERATURE_TOO_LOW`". Это и есть профессиональный подход к автоматизации на платформе HI.

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

    >

    > - Физический сигнал (аналоговый/дискретный): Необработанная информация от датчика.

    > - Логическое событие: Осмысленное сообщение об изменении в системе.

    > - Состояние системы: Актуальный "снимок" параметров системы, хранящийся в памяти.

    > - Контекст Node-RED (global/flow): Механизм для хранения состояний.

    > - Нормализация сигнала: Преобразование сырых данных в реальные физические величины.

    > - Фильтрация дребезга (Debounce): Устранение ложных сигналов от механических контактов.

    > - АЦП (ADC): Аналого-цифровой преобразователь.

    > - Дискретный вход (DI): Вход для определения двух состояний (замкнуто/разомкнуто).

    Что дальше?

    В следующем уроке мы углубимся в практические аспекты работы с аналоговыми сигналами. Мы рассмотрим различные типы датчиков (NTC, Pt1000, 0-10В, 4-20мА), изучим типовые схемы их подключения к универсальным входам контроллера HI и разберем более сложные примеры нормализации и калибровки в Node-RED.