ГлавнаяАкадемияДатчики и входы: нормализация сигналов → Масштабирование (калибровка): преобразование сырых значений в физические величины

Масштабирование (калибровка): преобразование сырых значений в физические величины

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

Введение: от сырых данных АЦП к физическим величинам

При работе с аналоговыми датчиками инженер сталкивается с фундаментальной задачей: сырые данные, поступающие от аналого-цифрового преобразователя (АЦП), сами по себе неинформативны. Как было рассмотрено в предыдущем уроке (COURSE-04-M04-L02), наш контроллер HI оснащен 12-битным АЦП. Это означает, что любое аналоговое напряжение на его универсальном входе преобразуется в целое число в диапазоне от 0 до 4095.

Что означает для системы значение `2048`? Или `3157`? Без дополнительного контекста — ничего. Это просто абстрактные единицы, отражающие долю от максимального измеряемого напряжения. Чтобы эти цифры обрели физический смысл и могли использоваться в сценариях автоматизации, их необходимо преобразовать в реальные физические величины: градусы Цельсия (°C), проценты относительной влажности (%), килопаскали (кПа) или люксы (лк).

Этот процесс преобразования и является предметом данного урока.

> 💡 Подсказка: В документации и профессиональной среде термины "масштабирование", "калибровка" и "нормализация" часто взаимозаменяемы. Главное — понимать, что это процесс приведения сырых данных к реальным физическим единицам.

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

Цель этого урока — научиться выполнять масштабирование данных с аналоговых входов контроллера HI, используя стандартные инструменты Node-RED. Мы преобразуем абстрактные числа в осмысленные данные, готовые для использования в логике, отображения на панелях управления и отправки в системы верхнего уровня.

---

Математическая основа: линейная функция y = kx + b

В подавляющем большинстве случаев для масштабирования сигналов от промышленных и бытовых датчиков используется линейная функция. Это связано с тем, что производители датчиков с унифицированными выходами (0-10В, 4-20мА) стремятся обеспечить прямо пропорциональную зависимость между измеряемой физической величиной и выходным сигналом.

Математически эта зависимость описывается простым уравнением прямой:

`y = kx + b`

Разберем каждый компонент этой формулы в контексте нашей задачи:

Метод двух точек

Чтобы найти коэффициенты `k` и `b`, нам достаточно знать всего две точки соответствия между сырыми значениями и физическими величинами. Эту информацию мы берем из технического паспорта (datasheet) на датчик.

Предположим, у нас есть две пары известных значений:

  • Точка 1: сырому значению `x1` соответствует физическая величина `y1`.
  • Точка 2: сырому значению `x2` соответствует физическая величина `y2`.
  • Зная это, мы можем составить систему из двух уравнений и легко найти `k` и `b`:

  • Находим коэффициент наклона `k`:
  • `k = (y2 - y1) / (x2 - x1)`

    Формула интуитивно понятна: мы делим "прирост" физической величины на "прирост" сырого значения, получая таким образом "цену" одной единицы АЦП.

  • Находим смещение `b`:
  • `b = y1 - k * x1`

    (или `b = y2 - k * x2`, результат будет тем же)

    Пример:

    Датчик давления имеет выходной сигнал 0-10В, что соответствует диапазону давления 0-1000 кПа. Наш контроллер HI измеряет напряжение 0-10В как сырое значение АЦП 0-4095.

    Наши две калибровочные точки:

    Рассчитаем коэффициенты:

    `b = 0 - k 0 = 0`

    Итоговая формула для этого датчика: `Давление (кПа) = 0.2442 * (Значение АЦП) + 0`.

    Теперь, если АЦП вернет нам значение `2048`, мы можем легко рассчитать реальное давление:

    `y = 0.2442 * 2048 ≈ 500.1` кПа.

    Результат логичен: половина шкалы АЦП соответствует половине измеряемого диапазона.

    ---

    Практика: калибровка датчика температуры 0-10В в Node-RED

    Рассмотрим реальный сценарий. У нас есть канальный датчик температуры для системы вентиляции с диапазоном измерения от -20°C до +80°C. Его выходной сигнал — линейный, 0-10В. Датчик подключен к универсальному входу контроллера HI.

    > ⚠️ Внимание: Линейное масштабирование предполагает, что зависимость между сигналом и физической величиной строго линейна. Если датчик имеет нелинейную характеристику (например, большинство NTC-термисторов), этот метод даст погрешность. Продвинутые методы для нелинейных датчиков рассматриваются в курсе по продвинутой работе с датчиками (COURSE-04-M05).

    Наша задача — создать поток в Node-RED, который будет принимать сырое значение с АЦП и преобразовывать его в градусы Цельсия.

    Шаг 1: Определение калибровочных точек

    Из технического описания датчика и знания характеристик нашего контроллера мы получаем две точки:

    Шаг 2: Расчет коэффициентов 'k' и 'b'

    Используем формулы из предыдущего раздела:

    `b = y1 - k x1 = -20 - k * 0 = -20`

    Шаг 3: Составление итоговой формулы

    Наша формула для преобразования:

    `Температура (°C) = 0.02442 * (Значение АЦП) - 20`

    Шаг 4: Реализация в Node-RED

    Для реализации этой формулы идеально подходит узел `Function`. Мы создадим поток, где узел, читающий данные с АЦП (в нашем примере мы его симулируем узлом `Inject`), передает сырое значение в узел `Function`, который выполняет расчет и формирует структурированное сообщение.

    Схема потока (Flow):
    // AI_RAW_VALUE — сырое значение с аналогового входа (0-4095)
    

    // В реальной системе здесь будет узел, читающий GPIO или получающий данные по MQTT

    [Inject: AI_RAW_VALUE] --> [Function: Scale Temp] --> [Debug: Scaled Value]

    Пример входящего сообщения `msg` в узел `Function`:

    Предположим, с АЦП пришло значение `1680`.

    {
    

    "payload": 1680,

    "topic": "hi/inputs/universal/ui-05/raw"

    }

    Код для узла `Function: Scale Temp`:
    // Получаем сырое значение от АЦП
    

    const rawValue = msg.payload;

    // Коэффициенты, рассчитанные ранее

    const k = 100 / 4095; // 0.02442...

    const b = -20;

    // Проверка, что на входе число. Это базовая валидация.

    if (typeof rawValue !== 'number') {

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

    node.status({fill:"red", shape:"dot", text:"Invalid input"});

    return null; // Останавливаем поток для этого сообщения

    }

    // Применяем формулу масштабирования y = kx + b

    let temperature = k * rawValue + b;

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

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

    // Формируем новое сообщение в соответствии с "Контрактом сообщений"

    // Это хороший тон — передавать дальше не просто число, а структурированный объект

    msg.payload = {

    "value": temperature,

    "unit": "°C",

    "source": "vent-temp-sensor-supply",

    "ts": Date.now()

    };

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

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

    return msg;

    Результат на выходе узла `Function` (показан в узле `Debug`):

    При `rawValue = 1680`, температура будет `(100 / 4095) * 1680 - 20 ≈ 21.0` °C.

    {
    

    "value": 21.0,

    "unit": "°C",

    "source": "vent-temp-sensor-supply",

    "ts": 1678886400000

    }

    Мы успешно преобразовали абстрактное число `1680` в понятное значение `21.0 °C`.

    ---

    Инструменты Node-RED: узел Range для быстрой настройки

    Хотя узел `Function` является универсальным и мощным инструментом, для стандартных задач линейного масштабирования в Node-RED существует более простой и наглядный узел — `Range`.

    Этот узел выполняет ту же самую математическую операцию `y = kx + b`, но скрывает от пользователя расчет коэффициентов. Вместо этого он предлагает простой графический интерфейс, где нужно указать всего две вещи:

  • Входной диапазон (Input range): Минимальное и максимальное сырое значение (наши `x1` и `x2`).
  • Выходной диапазон (Target range): Соответствующие им минимальное и максимальное физическое значение (наши `y1` и `y2`).
  • Давайте решим ту же задачу с датчиком температуры (-20...+80 °C, 0-4095) с помощью узла `Range`.

    Настройка узла `Range`: Схема потока:
    [Inject: 1680] --> [Range: Scale -20..80] --> [Debug: Scaled Value]
    

    Когда сообщение с `msg.payload = 1680` пройдет через этот узел, на выходе мы получим `msg.payload`, равный `21.001221...`. Результат идентичен расчету в узле `Function`.

    Сравнение узлов `Range` и `Function`

    | Критерий | Узел `Range` | Узел `Function` |

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

    | Простота | ✅ Очень просто. Настройка занимает несколько секунд. | ❌ Сложнее. Требует знания базового JavaScript и ручного расчета. |

    | Наглядность | ✅ Высокая. Диапазоны видны прямо в интерфейсе узла. | ❌ Низкая. Логика скрыта внутри кода. |

    | Гибкость | ❌ Низкая. Только линейное масштабирование. | ✅ Максимальная. Можно реализовать любую логику (нелинейную, с условиями). |

    | Формат вывода | ❌ Ограниченный. По умолчанию изменяет только `msg.payload`. | ✅ Полный контроль. Можно сформировать любой объект `msg` (с `unit`, `ts` и т.д.). |

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

    В большинстве простых сценариев на объектах автоматизации узел `Range` является предпочтительным выбором для масштабирования благодаря своей простоте и скорости настройки.

    ---

    Частный случай: масштабирование инвертированных сигналов

    Некоторые датчики имеют инвертированную (обратную) характеристику. Это означает, что с ростом измеряемой физической величины их выходной сигнал (и, соответственно, сырое значение АЦП) уменьшается. Классический пример — NTC-термистор, чье сопротивление падает с ростом температуры.

    > 🔗 Связанный материал: Для высокоточных измерений с помощью нелинейных NTC-термисторов рекомендуется использовать таблицы пересчета (Lookup Table) или формулу Стейнхарта-Харта. Это подробно рассматривается в уроке по работе с нелинейными датчиками (COURSE-04-M05-L02).

    С точки зрения математики, инвертированная характеристика означает, что коэффициент наклона `k` будет отрицательным.

    Пример:

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

    Рассчитаем коэффициенты `k` и `b` для этого случая:

    `b = y1 - k x1 = 50 - (-0.38) * 3500 = 50 + 1330 = 1380`

    Итоговая формула: `Освещенность (лк) = -0.38 * (Значение АЦП) + 1380`.

    Отрицательный `k` — верный признак инвертированной зависимости.

    Обработка в Node-RED

    Хорошая новость заключается в том, что узел `Range` прекрасно справляется с такими ситуациями без каких-либо дополнительных настроек. Ему неважно, в каком порядке вы указываете диапазоны.

    Для нашего примера с датчиком освещенности настройка узла `Range` будет выглядеть так:

    Узел автоматически рассчитает отрицательный коэффициент наклона и корректно преобразует значения. Если на вход придет `msg.payload = 2250` (середина входного диапазона), на выходе мы получим `msg.payload = 525` (середина выходного диапазона), что полностью соответствует линейной зависимости.

    ---

    Итоги и лучшие практики

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

    Чтобы выполнять калибровку профессионально и избегать ошибок на объектах, следуйте этим простым правилам:

  • Всегда изучайте Datasheet. Технический паспорт датчика — это ваш главный источник информации о диапазоне измерения, типе выходного сигнала (линейный/нелинейный) и полярности. Не начинайте работу без него.
  • Используйте осмысленные имена. Чтобы избежать путаницы, разделяйте сырые и обработанные данные. Например, используйте топики MQTT `.../raw` для сырых значений и `.../value` или просто `.../temperature` для физических величин. Это упростит отладку и интеграцию.
  • Документируйте вашу работу. Прямо в Node-RED, используя узел `Comment`, запишите, откуда взят датчик, его диапазон и формулу, которую вы использовали для калибровки. Через год вы скажете себе спасибо. Пример комментария:
  •     // Масштабирование датчика температуры в приточной установке

    // Модель: T-Sensor-Duct-01, -20..+80C -> 0..10V

    // Вход: UI-05 (АЦП 0-4095)

    // Формула: T = (100/4095) * raw_val - 20

    Что дальше

    В следующем уроке мы рассмотрим более сложные сценарии, включая работу с нелинейными датчиками (термисторами) и применение таблиц пересчета (Lookup Tables) для достижения максимальной точности измерений.