Реализация алгоритма Замбретти для предсказания погоды
- Войдите на сайт для отправки комментариев
В рускоязычном сегменте почему то очень мало готовых реализаций данного алгоритма предсказания погоды, да и те на не удобоваримых языках вроде php)) В результате предлагаю версию, сделанную на основе https://github.com/fandonov/weatherstation.
Основной код:
#include "math.h"
#define SEALEVELPRESSURE_HPA (1013.25) // Аналог давления 760 мм.рт.ст.
int pressureArray[10]={0};
unsigned char counter=0;
int altitude=170;
unsigned char delta_time=0;
#define WeatherClear 1
#define WeatherCloud 2
#define WeatherRain 3
#define WeatherClearCloud 4
#define WeatherWorsening 5
//***************************************************
int calc_zambretti(int curr_pressure, int prev_pressure, int mon){
if (curr_pressure<prev_pressure){
//FALLING
if (mon>=4 && mon<=9)
//summer
{
if (curr_pressure>=1030)
return 2;
else if(curr_pressure>=1020 && curr_pressure<1030)
return 8;
else if(curr_pressure>=1010 && curr_pressure<1020)
return 18;
else if(curr_pressure>=1000 && curr_pressure<1010)
return 21;
else if(curr_pressure>=990 && curr_pressure<1000)
return 24;
else if(curr_pressure>=980 && curr_pressure<990)
return 24;
else if(curr_pressure>=970 && curr_pressure<980)
return 26;
else if(curr_pressure<970)
return 26;
}
else{
//winter
if (curr_pressure>=1030)
return 2;
else if(curr_pressure>=1020 && curr_pressure<1030)
return 8;
else if(curr_pressure>=1010 && curr_pressure<1020)
return 15;
else if(curr_pressure>=1000 && curr_pressure<1010)
return 21;
else if(curr_pressure>=990 && curr_pressure<1000)
return 22;
else if(curr_pressure>=980 && curr_pressure<990)
return 24;
else if(curr_pressure>=970 && curr_pressure<980)
return 26;
else if(curr_pressure<970)
return 26;
}
}
else if (curr_pressure>prev_pressure){
//RAISING
if (mon>=4 && mon<=9){
//summer
if (curr_pressure>=1030)
return 1;
else if(curr_pressure>=1020 && curr_pressure<1030)
return 2;
else if(curr_pressure>=1010 && curr_pressure<1020)
return 3;
else if(curr_pressure>=1000 && curr_pressure<1010)
return 7;
else if(curr_pressure>=990 && curr_pressure<1000)
return 9;
else if(curr_pressure>=980 && curr_pressure<990)
return 12;
else if(curr_pressure>=970 && curr_pressure<980)
return 17;
else if(curr_pressure<970)
return 17;
}
else
//winter
{
if (curr_pressure>=1030)
return 1;
else if(curr_pressure>=1020 && curr_pressure<1030)
return 2;
else if(curr_pressure>=1010 && curr_pressure<1020)
return 6;
else if(curr_pressure>=1000 && curr_pressure<1010)
return 7;
else if(curr_pressure>=990 && curr_pressure<1000)
return 10;
else if(curr_pressure>=980 && curr_pressure<990)
return 13;
else if(curr_pressure>=970 && curr_pressure<980)
return 17;
else if(curr_pressure<970)
return 17;
}
}
else
{
if (curr_pressure>=1030)
return 1;
else if(curr_pressure>=1020 && curr_pressure<1030)
return 2;
else if(curr_pressure>=1010 && curr_pressure<1020)
return 11;
else if(curr_pressure>=1000 && curr_pressure<1010)
return 14;
else if(curr_pressure>=990 && curr_pressure<1000)
return 19;
else if(curr_pressure>=980 && curr_pressure<990)
return 23;
else if(curr_pressure>=970 && curr_pressure<980)
return 24;
else if(curr_pressure<970)
return 26;
}
return 0;
}
//***************************************************
int station2sealevel(int p, int height, int t){
return (int) ((double) p*pow(1-0.0065*(double)height/(t+0.0065*(double)height+273.15),-5.275));
}
//***************************************************
// Вызывать раз в минуту
int Weather_Calc(int pressure,int temperature, unsigned char month)
{
int Z=0;
int seapressure = station2sealevel(pressure,altitude,temperature);
delta_time++;
if (delta_time>10)
{
delta_time=0;
if (counter==10)
{
for (int i=0; i<9;i++) pressureArray[i]=pressureArray[i+1];
pressureArray[counter-1]=seapressure;
}
else
{
pressureArray[counter]=seapressure;
counter++;
}
}
Z=calc_zambretti((pressureArray[9]+pressureArray[8]+pressureArray[7])/3,(pressureArray[0]+pressureArray[1]+pressureArray[2])/3, month);
//
if (pressureArray[9]>0 && pressureArray[0]>0)
{
if (pressureArray[9]+pressureArray[8]+pressureArray[7]-pressureArray[0]-pressureArray[1]-pressureArray[2]>=3)
{
//RAISING
if (Z<3) return WeatherClear;
else if (Z>=3 && Z<=9) return WeatherClearCloud;
else if (Z>9 && Z<=17) return WeatherCloud;
else if (Z>17) return WeatherRain;
}
else if (pressureArray[0]+pressureArray[1]+pressureArray[2]-pressureArray[9]-pressureArray[8]-pressureArray[7]>=3)
{
//FALLING
if (Z<4) return WeatherClear;
else if (Z>=4 && Z<14) return WeatherClearCloud;
else if (Z>=14 && Z<19) return WeatherWorsening;
else if (Z>=19 && Z<21) return WeatherCloud;
else if (Z>=21) return WeatherRain;
}
else
{
//STEADY
if (Z<5) return WeatherClear;
else if (Z>=5 && Z<=11) return WeatherClearCloud;
else if (Z>11 && Z<14) return WeatherCloud;
else if (Z>=14 && Z<19) return WeatherWorsening;
else if (Z>19) return WeatherRain;
}
}
else
{
if (seapressure<1005) return WeatherRain;
else if (seapressure>=1005 && seapressure<=1015) return WeatherCloud;
else if (seapressure>1015 && seapressure<1025) return WeatherClearCloud;
else return WeatherRain;
}
return WeatherWorsening;
}
Основная вызываемая функция - Weather_Calc(int pressure,int temperature, unsigned char month) с параметрами pressure - давление в hPa, temperature - температура в цельсиях, целое значение, month - текущий месяц. Вызывать данную функцию нужно раз в минуту. Так же надо указать высоту над уровнем моря в altitude.
Обрабатывать полученное значение можно так:
if(weather==WeatherClear)
{
if(night) // Вывод луны
else // Вывод солнца
}
if(weather==WeatherCloud) // Вывод только облака
if(weather==WeatherRain)
{
if(temp<2) // Вывод снег
else // Вывод дождь
}
if(weather==WeatherClearCloud)
{
if(night) // Вывод месяц и облака
else // Вывод солнце и облака
}
if(weather==WeatherWorsening)
{
if(night)
{
if(temp<2) // Вывод луна,облака, снег
else // Вывод луна, облака, дождь
}
else
{
if(temp<2) // Вывод солнце,облака, снег
else // Вывод солнце, облака, дождь
}
}
Где "night==1" признак, что сейчас ночь и "temp==температура на улице". Я temp использую от 0 до значения датчика. По результатам сравнения с прогнозом от станции vitek результаты как правило одинаковые, разница в скорости реакции на изменения и разнице в измерении давлений (у витька давление всегда ниже, чем у bme280). В общем алгоритм вполне жизнеспособен и может применяться на практике. Чудес от него ждать конечно не следует, но вполне вменяемые результаты получить можно.
А еще есть библиотека Forecaster от Алекса Гайвера (https://github.com/GyverLibs/Forecaster), она как раз реализует алгоритм Замбретти.
день добрый!
а подскажите, на какой период сгенерится прогноз (т.е. через сколько времени должно произойти то, о чем говорит предсказатель?
если опрос давления идет 1 раз в минуту, для усреднения берется 10 опросов - значит, период = 10 минутам?
или это не так работает?
спасибо!