Датчик температуры и усреднение показаний

Реальные датчики врут: их показания дрожат от помех. Хороший код не верит одному замеру, а усредняет несколько.

Один замер температуры — это мнение. Среднее из десяти замеров — это уже факт. Усреднение превращает шумные данные в надёжные.

Вспомни, как ты меряешь температуру градусником: первые секунды цифры скачут, и только подождав, ты доверяешь результату. С электронными датчиками то же самое, только дрожь не от тебя, а от помех — рядом включился мотор, по проводу пробежала наводка, чуть просел блок питания. В итоге датчик, лежащий в комнате с ровной температурой 21.5°C, может выдать подряд 21.4, 21.6, потом внезапно 35.0, а затем снова 21.5. Если программа поверит каждому числу буквально, она будет дёргаться от каждого случайного скачка.

Популярный датчик температуры и влажности — DHT22, а для точной температуры — DS18B20, который работает по протоколу 1-Wire. Но какой бы датчик ни был, у всех общая проблема: показания «шумят», скачут на доли градуса от помех. Поэтому грамотный код относится к датчику как к слегка ненадёжному свидетелю: выслушивает несколько раз и делает выводы из совокупности, а не из одной фразы.

Как работает под капотом

   DS18B20 датчик
   +---------+
   | VDD     |---- 3.3V
   | DATA    |---- GPIO4  --[резистор 4.7к]-- 3.3V
   | GND     |---- GND
   +---------+
        |
   1-Wire протокол -> цифровое значение температуры

Откуда вообще берётся шум? Сигнал от датчика идёт по проводу, а провод — это маленькая антенна: он ловит наводки от всего, что рядом излучает (зарядки, моторы, Wi-Fi). К тому же сам датчик измеряет с конечной точностью и иногда «округляет» в разные стороны. Резистор 4.7к на схеме выше (его называют подтягивающим) как раз помогает линии DATA держаться в чётком состоянии, но полностью убрать дрожь он не может — поэтому финальную чистку делает уже код.

   Сырой поток:   21.4  21.6  35.0  21.5  21.3
                          ^
                       выброс (наводка)

   Фильтр выбросов  ->  усреднение  ->  21.5 ровно

Чтение настоящего датчика зависит от железа и библиотек, поэтому это пример для Pi:

# на Pi: датчик DS18B20 виден как файл в /sys/bus/w1/...
from w1thermsensor import W1ThermSensor

sensor = W1ThermSensor()
print(sensor.get_temperature())

А вот сглаживание показаний — чистая логика, которую отладим в браузере. Соберём несколько замеров и посчитаем среднее, заодно отбросив явные выбросы. Попробуй сам ▶

# Усреднение шумных показаний температуры
raw = [21.4, 21.6, 35.0, 21.5, 21.3, 21.7, 21.5]  # 35.0 - выброс

# 1) отбрасываем выбросы, далёкие от среднего
avg_all = sum(raw) / len(raw)
clean = [t for t in raw if abs(t - avg_all) < 5]

# 2) усредняем оставшиеся
smooth = sum(clean) / len(clean)

print("Сырые замеры:", raw)
print("После фильтра:", [round(t, 1) for t in clean])
print(f"Сглаженная температура: {smooth:.2f}°C")

Сначала мы выкинули явно ошибочный замер 35.0, потом усреднили остальное. Так одна помеха не испортит результат.

Есть приём ещё надёжнее простого среднего — скользящее среднее. Вместо того чтобы копить замеры вечно, мы держим «окно» из последних N значений: пришёл новый замер — выкинули самый старый. Так температура реагирует на реальные изменения (например, ты открыл окно), но всё ещё сглаживает мгновенную дрожь. Отрепетируем эту идею на чистом Python. Попробуй сам ▶

# Скользящее среднее по окну из последних 3 замеров
stream = [21.5, 21.6, 35.0, 21.4, 21.5, 21.7]
window = []
N = 3

for value in stream:
    window.append(value)
    if len(window) > N:
        window.pop(0)              # держим только последние N
    avg = sum(window) / len(window)
    print(f"замер {value:5.1f} -> окно {window} -> среднее {avg:.2f}")

Частые ошибки

  • Верят одному замеру. Из-за шума одно значение может сильно отличаться — усредняй.
  • Не отбрасывают выбросы. Один аномальный замер может перекосить среднее.
  • Опрашивают слишком часто. DHT22, например, нельзя читать чаще раза в 2 секунды.
  • Берут слишком большое окно. Если усреднять сотню замеров, датчик станет «тормозным» и не заметит реальное похолодание.
  • Молча глотают ошибку чтения. Иногда датчик возвращает None или мусор — такой замер надо пропустить, а не подмешивать в среднее.

Best practices

  • Собирай окно из нескольких замеров и усредняй (скользящее среднее).
  • Отбрасывай явные выбросы перед усреднением.
  • Соблюдай минимальный интервал опроса для своего датчика.
  • Подбирай размер окна под задачу: маленькое — быстрая реакция, большое — гладкость.
  • Проверяй замер на адекватность диапазона (например, −40…+80°C) и отбрасывай явный мусор.

Эта идея — не верить одному измерению, а смотреть на серию — выходит далеко за рамки термометра. Точно так же сглаживают сигнал GPS в навигаторе, шаги в фитнес-браслете и пульс в умных часах. Научившись усреднять температуру, ты освоил приём, которым пользуются почти все устройства, имеющие дело с «живыми», шумными данными из реального мира.

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

Проверьте себя
1. Почему не стоит доверять одному замеру температуры с датчика?
AДатчики всегда сломаны
BПоказания шумят из-за помех, поэтому одно значение может сильно отличаться от реального
CОдин замер слишком медленный
DPython не умеет читать датчики
2. Что полезно сделать перед усреднением показаний?
AУмножить на 2
BОтбросить явные выбросы — аномальные значения, далёкие от остальных
CПерезагрузить Pi
DНичего