Реализация алгоритма Замбретти для предсказания погоды

Нет ответов
PRC
Offline
Зарегистрирован: 03.02.2019

В рускоязычном сегменте почему то очень мало готовых реализаций данного алгоритма предсказания погоды, да и те на не удобоваримых языках вроде 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). В общем алгоритм вполне жизнеспособен и может применяться на практике. Чудес от него ждать конечно не следует, но вполне вменяемые результаты получить можно.