Масштабирование (калибровка): преобразование сырых значений в физические величины
Введение: от сырых данных АЦП к физическим величинам
При работе с аналоговыми датчиками инженер сталкивается с фундаментальной задачей: сырые данные, поступающие от аналого-цифрового преобразователя (АЦП), сами по себе неинформативны. Как было рассмотрено в предыдущем уроке (COURSE-04-M04-L02), наш контроллер HI оснащен 12-битным АЦП. Это означает, что любое аналоговое напряжение на его универсальном входе преобразуется в целое число в диапазоне от 0 до 4095.
Что означает для системы значение `2048`? Или `3157`? Без дополнительного контекста — ничего. Это просто абстрактные единицы, отражающие долю от максимального измеряемого напряжения. Чтобы эти цифры обрели физический смысл и могли использоваться в сценариях автоматизации, их необходимо преобразовать в реальные физические величины: градусы Цельсия (°C), проценты относительной влажности (%), килопаскали (кПа) или люксы (лк).
Этот процесс преобразования и является предметом данного урока.
> 💡 Подсказка: В документации и профессиональной среде термины "масштабирование", "калибровка" и "нормализация" часто взаимозаменяемы. Главное — понимать, что это процесс приведения сырых данных к реальным физическим единицам.
📋 Ключевые понятия:
- Сырое значение (Raw Value): Дискретное числовое значение, полученное напрямую от АЦП (например, 0-4095 для 12-битного АЦП).
- Физическая величина: Реальное, измеряемое свойство окружающего мира (температура, давление, влажность и т.д.) в общепринятых единицах измерения.
- Масштабирование (Scaling): Процесс применения математической функции для преобразования одного диапазона значений (сырых) в другой (физических величин).
- Калибровка (Calibration): Процесс настройки или проверки точности измерительного прибора (в нашем случае, связки "датчик-контроллер") путем сравнения его показаний с эталонными значениями. Масштабирование является неотъемлемой частью калибровки.
Цель этого урока — научиться выполнять масштабирование данных с аналоговых входов контроллера HI, используя стандартные инструменты Node-RED. Мы преобразуем абстрактные числа в осмысленные данные, готовые для использования в логике, отображения на панелях управления и отправки в системы верхнего уровня.
---
Математическая основа: линейная функция y = kx + b
В подавляющем большинстве случаев для масштабирования сигналов от промышленных и бытовых датчиков используется линейная функция. Это связано с тем, что производители датчиков с унифицированными выходами (0-10В, 4-20мА) стремятся обеспечить прямо пропорциональную зависимость между измеряемой физической величиной и выходным сигналом.
Математически эта зависимость описывается простым уравнением прямой:
`y = kx + b`
Разберем каждый компонент этой формулы в контексте нашей задачи:
- `y` (игрек) — это искомая нами физическая величина. Например, температура в °C.
- `x` (икс) — это сырое значение, которое мы получаем от АЦП нашего контроллера. Для платформы HI это число в диапазоне от 0 до 4095.
- `k` (ка) — это коэффициент наклона (или масштаб, gain, slope). Он определяет, насколько сильно изменится `y` при изменении `x` на одну единицу. Это самый важный коэффициент, отвечающий за масштабирование.
- `b` (бэ) — это смещение (или оффсет, offset). Оно определяет значение `y`, когда `x` равен нулю. Этот коэффициент позволяет "сдвигать" всю калибровочную кривую вверх или вниз по оси Y.
Метод двух точек
Чтобы найти коэффициенты `k` и `b`, нам достаточно знать всего две точки соответствия между сырыми значениями и физическими величинами. Эту информацию мы берем из технического паспорта (datasheet) на датчик.
Предположим, у нас есть две пары известных значений:
Зная это, мы можем составить систему из двух уравнений и легко найти `k` и `b`:
`k = (y2 - y1) / (x2 - x1)`
Формула интуитивно понятна: мы делим "прирост" физической величины на "прирост" сырого значения, получая таким образом "цену" одной единицы АЦП.
`b = y1 - k * x1`
(или `b = y2 - k * x2`, результат будет тем же)
Пример:Датчик давления имеет выходной сигнал 0-10В, что соответствует диапазону давления 0-1000 кПа. Наш контроллер HI измеряет напряжение 0-10В как сырое значение АЦП 0-4095.
Наши две калибровочные точки:
- Точка 1: Напряжение 0В (сырое значение `x1 = 0`) соответствует давлению `y1 = 0` кПа.
- Точка 2: Напряжение 10В (сырое значение `x2 = 4095`) соответствует давлению `y2 = 1000` кПа.
Рассчитаем коэффициенты:
- `k = (1000 - 0) / (4095 - 0) = 1000 / 4095 ≈ 0.244200`
Итоговая формула для этого датчика: `Давление (кПа) = 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: Определение калибровочных точек
Из технического описания датчика и знания характеристик нашего контроллера мы получаем две точки:
- Точка 1: Напряжение 0В (`x1 = 0` единиц АЦП) соответствует температуре `y1 = -20` °C.
- Точка 2: Напряжение 10В (`x2 = 4095` единиц АЦП) соответствует температуре `y2 = +80` °C.
Шаг 2: Расчет коэффициентов 'k' и 'b'
Используем формулы из предыдущего раздела:
- `k = (y2 - y1) / (x2 - x1) = (80 - (-20)) / (4095 - 0) = 100 / 4095 ≈ 0.0244200244`
Шаг 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`, но скрывает от пользователя расчет коэффициентов. Вместо этого он предлагает простой графический интерфейс, где нужно указать всего две вещи:
Давайте решим ту же задачу с датчиком температуры (-20...+80 °C, 0-4095) с помощью узла `Range`.
Настройка узла `Range`:- Action: `Scale` (Масштабировать)
- Input range: `0` to `4095`
- Target range: `-20` to `80`
- Опцию "Round result to nearest integer" (Округлить результат) оставляем выключенной, чтобы получить дробное значение.
[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` будет отрицательным.
Пример:Предположим, мы работаем с самодельным датчиком уровня освещенности на фоторезисторе, подключенным так, что:
- Точка 1: При 50 люксах (`y1`) АЦП показывает 3500 (`x1`).
- Точка 2: При 1000 люксах (`y2`) АЦП показывает 1000 (`x2`).
Рассчитаем коэффициенты `k` и `b` для этого случая:
- `k = (y2 - y1) / (x2 - x1) = (1000 - 50) / (1000 - 3500) = 950 / -2500 = -0.38`
Итоговая формула: `Освещенность (лк) = -0.38 * (Значение АЦП) + 1380`.
Отрицательный `k` — верный признак инвертированной зависимости.
Обработка в Node-RED
Хорошая новость заключается в том, что узел `Range` прекрасно справляется с такими ситуациями без каких-либо дополнительных настроек. Ему неважно, в каком порядке вы указываете диапазоны.
Для нашего примера с датчиком освещенности настройка узла `Range` будет выглядеть так:
- Action: `Scale`
- Input range: `3500` to `1000` (обратите внимание на порядок!)
- Target range: `50` to `1000`
Узел автоматически рассчитает отрицательный коэффициент наклона и корректно преобразует значения. Если на вход придет `msg.payload = 2250` (середина входного диапазона), на выходе мы получим `msg.payload = 525` (середина выходного диапазона), что полностью соответствует линейной зависимости.
---
Итоги и лучшие практики
Масштабирование — это не опциональный, а обязательный шаг в обработке данных с любых аналоговых датчиков. Он превращает бессмысленные единицы АЦП в ценную информацию для системы автоматизации.
- Основным инструментом для масштабирования в 90% случаев выступает линейная функция `y = kx + b`.
- В Node-RED для этой цели служат два узла: `Range` (простой и быстрый) и `Function` (гибкий и мощный).
- Для инвертированных сигналов математика остается той же, просто коэффициент наклона `k` становится отрицательным. Узел `Range` обрабатывает это автоматически.
Чтобы выполнять калибровку профессионально и избегать ошибок на объектах, следуйте этим простым правилам:
// Масштабирование датчика температуры в приточной установке
// Модель: T-Sensor-Duct-01, -20..+80C -> 0..10V
// Вход: UI-05 (АЦП 0-4095)
// Формула: T = (100/4095) * raw_val - 20
Что дальше
В следующем уроке мы рассмотрим более сложные сценарии, включая работу с нелинейными датчиками (термисторами) и применение таблиц пересчета (Lookup Tables) для достижения максимальной точности измерений.