Июльский вечер я запомнил по телевизионному синоптику: ясно, без осадков. Барометр на подоконнике к тому моменту четыре часа полз вниз — с 1011 на 1006 гектопаскалей — и за ночь добавил ещё четыре. К шести утра град положил малину и половину теплицы. Синоптик смотрел на карту фронта, мой барометр — на собственное давление, и барометр, как ни странно, оказался откровеннее.
С тех пор моё правило прогноза звучит так: важна не величина давления, а её скорость. 1005 гектопаскалей могут стоять три дня без капли, если циклон встал стеной, а могут сорваться ливнем за час, если столько же улетело за последние два часа. Один замер — фотография; прогноз живёт в разнице: упало три-четыре миллиметра за три часа — фронт уже на подходе. Именно поэтому метеостанции, которым вы верите, смотрят не на цифру, а на её ход за последние часы.
В этом уроке соберём прибор, который сам держит историю: замер раз в пятнадцать минут, кольцевой буфер на шесть часов наблюдений, дельта за три часа, сглаживание средним по трём и пороги — ясно, переменки, осадки. Схема прежняя: BMP280 на A4/A5, адрес 0x76 из первого урока, всё остальное — арифметика и дисциплина.
Ритм замеров и кольцевой буфер
Частота опроса для прогноза контринтуитивна: нужна не максимальная, а редкая. Давление между фронтами меняется на десятые доли гектопаскаля в час, и опрос раз в десять-пятнадцать минут ловит всё, что нужно для тренда, не заполняя память шумом. Кристалл при таком ритме не разогревается, а история занимает мало места: двадцать четыре ячейки по пятнадцать минут — это шесть часов непрерывных наблюдений.
Задержки в цикле тут не годятся: delay(900000) заморозит всё остальное, что живёт на плате, от кнопок до дисплея. Таймер на millis() — тот самый приём из урока про millis() вместо delay(): каждые девятьсот тысяч миллисекунд делаем замер, а между ними плата свободна для любой другой работы.
Кольцевой буфер — массив с указателем головы, который по кругу перезаписывает самое старое значение. Для шести часов истории хватает массива из двадцати четырёх float и одного целочисленного индекса: меньше сотни байт памяти, по силам даже Uno без расширений. Захотите вести историю за сутки — увеличьте буфер до девяноста шести ячеек, логика не изменится ни на строчку. Никаких библиотек, никакой SD-карты на этом этапе — буфер живёт в оперативке и переживает только сброс питания, чего для прогноза достаточно.
| Дельта за 3 часа | Что происходит | Вердикт на экране |
|---|---|---|
| +1 мм и больше | рост давления, приходит антициклон | ЯСНО |
| от −1 до +1 мм | штиль или медленный сдвиг | СТАБИЛЬНО |
| от −1 до −3 мм | циклон приближается | ПЕРЕМЕНКИ |
| −3 мм и ниже | фронт близко, осадки вероятны | ОСАДКИ |
// Тренд давления: буфер 24 замера по 15 минут, дельта за 3 часа #include <Wire.h>#include <Adafruit_BMP280.h> Adafruit_BMP280 bmp; float buf[24]; // кольцевой буфер, мм рт. ст.int head = 0; // куда пишем следующий замерint count = 0; // сколько замеров набраноunsigned long last = 0;const unsigned long interval = 900000UL; // 15 минут void setup() { Serial.begin(9600); if (bmp.begin(0x76) == 0) { Serial.println("BMP280 ne nayden"); while (1) delay(1000); }} void loop() { if (millis() - last >= interval) { last += interval; buf[head] = bmp.readPressure() / 133.322; // паскали -> мм рт. ст. head = (head + 1) % 24; if (count < 24) count++; if (count == 24) forecast(); // вердикт только на полном буфере }} void forecast() { // свежее среднее: три последних замера float fresh = (buf[(head + 23) % 24] + buf[(head + 22) % 24] + buf[(head + 21) % 24]) / 3.0; // старое среднее: замеры 12-14 назад, то есть три часа float old = (buf[head % 24] + buf[(head + 1) % 24] + buf[(head + 2) % 24]) / 3.0; float delta = fresh - old; Serial.print("mm="); Serial.print(fresh, 2); Serial.print(" delta="); Serial.println(delta, 2); if (delta <= -3.0) { Serial.println("FRONT: osadki veroyatny"); } else { if (delta <= -1.0) { Serial.println("CIKLON: peremenki"); } else { if (delta >= 1.0) { Serial.println("ANTICIKLON: yasno"); } else { Serial.println("STABILNO"); } } }}Сначала про шум. Шум одиночного замера у BMP280 — сотые доли гектопаскаля, но вместе с наводками и сквозняками отдельные кадры дрожат на две-три сотых миллиметра. Дельта за три часа — разность двух средних, и брать её из сырых значений нельзя: шум сложится в обеих точках сравнения. Среднее по трём последним замерам гасит дрожь без всякой магии фильтров, а применять его стоит к обеим точкам: и к свежей тройке, и к тройке из начала трёхчасового окна. Тогда ложных тревог не будет — чтобы сдвинуть вердикт, реальное давление должно уйти, а не один кадр дрогнуть.
Теперь механика буфера. Каждые пятнадцать минут новое значение давления в миллиметрах записывается в ячейку head, указатель сдвигается по модулю 24 — и самое старое значение перезаписывается само собой, без сдвигов массива. Вердикт печатается только при полном буфере: счётчик count добирается до двадцати четырёх за шесть часов, и до этого честно показывать нечего. Деление на 133,322 превращает паскали сразу в миллиметры — это те же гектопаскали, умноженные на 0,750062, только в одно действие.
Отдельно про единицы: в буфере лежат миллиметры, а не гектопаскали — так пороги читаются с экрана без пересчёта, и дельта сразу говорит на языке настенного барометра. Кто-то хранит паскали и умножает только при выводе — разницы по сути нет, важно лишь не смешивать ступени в одном кадре. Сдвиги массива не нужны: кольцо перезаписывает старое само — в этом весь секрет сотни байт памяти.
Дельта — свежее среднее по трём последним замерам против старого среднего по трём замерам начала трёхчасового окна. Такой двойной зумир стоит в кадре метеостанции DHT22 и BMP280 рядом с температурой и влажностью: пороговые значения из вводного урока про барометр дают грубый компас, тренд — прогноз. Печать парой mm= и delta= позволяет строить оба ряда на графике Serial Plotter без пересечений.
Физика тренда: почему падение обещает осадки
Атмосферное давление — вес столба воздуха над головой. Циклон несёт менее плотный воздух, антициклон — плотный и сухой; приход фронта виден заранее именно как устойчивое падение. Три-четыре миллиметра за три часа — скорость сильного фронта; один миллиметр за сутки — обычное дыхание атмосферы, на него вердикт менять нельзя.
Пороги у меня подобраны практикой, а не из учебника: минус один миллиметр за три часа — переменки, минус три — почти наверняка осадки, плюс один и выше — прояснение. Между ними — стабильно, и честнее показать это слово, чем изображать уверенность. После месяца наблюдений пороги подстроятся под местный климат: у побережья амплитуда больше, в континентальной глуши — меньше. Запишите свои пороги в шапку скетча — через сезон они станут вашей личной таблицей погоды. Проверить их можно на прошлогодних сводках своего города: три дня с ливнями и три ясных, посчитайте ход давления — будущие пороги почти совпадут.
Абсолютное давление остаётся полезным фоном: пороги ниже 1005 и выше 1020 гектопаскалей из вводного урока про барометр — грубый компас погоды. Но работают они в паре с трендом: 1004 и падает — совсем не то, что 1004 и стоит. Обе величины на одном экране — уже метеостанция, а не датчик.
Что дальше с этим прибором. Первое — экран: вердикт из пары слов отлично живёт на индикаторе, и после урока про TM1637 четыре цифры давления с мигающим двоеточием собираются за вечер. Второе — журнал: давление с метками времени за неделю стоит дороже любого порога, добавьте SD-модуль и пишите кадры по расписанию. Кадр из пяти чисел весит десятки байт — за сезон наберётся пара мегабайт, и никакого облака не нужно.
И третье — связка с климатом: когда тренд скажет про похолодание, климат-контроль комнаты из финала раздела подхватит управление обогревателем. Прогноз погоды и климат комнаты — разные задачи, но на одной плате они уживаются без конфликтов: у барометра свой адрес на шине, у DHT22 — свой пин; распиновка с номиналами подтяжки — на лендинге про подключение DHT22. Барометр в этой связке — старший товарищ: его тренд меняется медленнее комнатной температуры, и пороги обогревателя можно привязать к погоде за окном.
- 1. С каким интервалом разумно мерить давление для прогноза?
- 2. Сколько замеров хранит буфер из урока и какой это период истории при шаге 15 минут?
- 3. Давление упало с 1010 на 1006 гПа за три часа. Сколько это в мм рт. ст.?
- 4. Что напечатает прибор при дельте −3,5 мм за три часа?
- 5. Почему в первый час после включения прибор не выдаёт прогноз?
- Опрос раз в 10-15 минут по таймеру millis(): чаще — только шум и лишний нагрев кристалла.
- Кольцевой буфер на 24 ячейки — шесть часов истории; дельта считается между средними по трём замерам с шагом в три часа.
- Упало 3-4 мм рт. ст. за три часа — фронт; меньше миллиметра — штиль, вердикт не менять.
- Первые три часа после включения тренда нет: буфер должен наполниться, счётчик count честнее фиктивной дельты.
- Пороги подстраиваются под местный климат после месяца наблюдений; абсолют — компас, тренд — прогноз.
Частые вопросы по теме урока
- С каким интервалом разумно мерить давление для прогноза?
- Давление меняется медленно: интервал в 10-15 минут ловит тренд без шума и не греет кристалл. Секундные опросы нужны высотомерам, а не прогнозу. раз в 10-15 минут
- Сколько замеров хранит буфер из урока и какой это период истории при шаге 15 минут?
- Двадцать четыре ячейки по пятнадцать минут — шесть часов истории. Трёхчасовое окно для дельты занимает в нём ровно половину. 24 замера — 6 часов
- Давление упало с 1010 на 1006 гПа за три часа. Сколько это в мм рт. ст.?
- Четыре гектопаскаля умножить на 0,750062 — три миллиметра. Это порог фронтового падения, при котором скетч печатает предупреждение. на 3
- Что напечатает прибор при дельте −3,5 мм за три часа?
- Падение глубже трёх миллиметров за три часа — скорость сильного фронта. Между −1 и −3 прибор честно говорит про переменки. фронт близко, вероятны осадки
- Почему в первый час после включения прибор не выдаёт прогноз?
- Дельте нужны две точки: свежая тройка и тройка трёхчасовой давности. Пока их нет, счётчик count держит вердикт и печатает nabrano= буфер ещё не набран — дельте не из чего считаться