The Zambretti Forecaster, an alternative weather forecast

If you want to try a different approach for a weather forecast than my simple weather forecast, based on the barometric pressure history, then you could use the so called Zambretti Forecaster. The Zambretti Forecaster is a weather forecasting tool in the form of a circular slide rule that was introduced by the company Negretti and Zambra in 1920. A more detailed description about the functionality of the Zambretti Forecaster and how to put it into code can be found here.

Below, you can find my Python implementation of the Zambretti Forecaster algorithm. It uses the current barometric pressure, the trend of the barometric pressure (over the last six hours) and the current month of the year as an input. The output of the Zambretti Forecaster is one of 26 different weather conditions. I mapped these weather conditions to a set of four forecast icons (sun, cloud, rain and thunderstorm), to make it more simple. The forecast icon is then shown together with an icon (arrow) that represents the current trend of the barometric pressure. Of course, you could also use more than these four icons, to make the forecast better if you want.

#!/usr/bin/python
 
import os
import shutil
import rrdtool
 
# Filtering the pressure change by using the average from different periods should give better, more stable results
# Read the pressure values for now/t=0, t=-0.5h, t=-1.0h, t=-1.5h, t=-2.0h, t=-2.5h, t=-3.0h, t=-3.5h, t=-4.0h, t=-4.5h, t=-5.0h, t=-5.5h and t=-6.0h
press0 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 600', '-s -600')
press1 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 60', '-s -1800', '-e -1800')
press2 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 60', '-s -3600', '-e -3600')
press3 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 60', '-s -5400', '-e -5400')
press4 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 60', '-s -7200', '-e -7200')
press5 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 60', '-s -9000', '-e -9000')
press6 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 60', '-s -10800', '-e -10800')
press7 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 60', '-s -12600', '-e -12600')
press8 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 60', '-s -14400', '-e -14400')
press9 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 60', '-s -16200', '-e -16200')
press10 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 60', '-s -18000', '-e -18000')
press11 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 60', '-s -19800', '-e -19800')
press12 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 60', '-s -21600', '-e -21600')

# Calculate the single differences and normalize them to a change in pressure over 1h
pressurerdiff1 = (press0[2][0][1] - press1[2][0][1])*2
pressurerdiff2 = (press0[2][0][1] - press2[2][0][1])
pressurerdiff3 = (press0[2][0][1] - press3[2][0][1])/1.5
pressurerdiff4 = (press0[2][0][1] - press4[2][0][1])/2
pressurerdiff5 = (press0[2][0][1] - press5[2][0][1])/2.5
pressurerdiff6 = (press0[2][0][1] - press6[2][0][1])/3
pressurerdiff7 = (press0[2][0][1] - press7[2][0][1])/3.5
pressurerdiff8 = (press0[2][0][1] - press8[2][0][1])/4
pressurerdiff9 = (press0[2][0][1] - press9[2][0][1])/4.5
pressurerdiff10 = (press0[2][0][1] - press10[2][0][1])/5
pressurerdiff11 = (press0[2][0][1] - press11[2][0][1])/5.5
pressurerdiff12 = (press0[2][0][1] - press12[2][0][1])/6

# Calculate the average of the differences
pressurerdiff = (pressurerdiff1 + pressurerdiff2 + pressurerdiff3 + pressurerdiff4 + pressurerdiff5 + pressurerdiff6 + pressurerdiff7 + pressurerdiff8 + pressurerdiff9 + pressurerdiff10 + pressurerdiff11 + pressurerdiff12)/12

# Get the current pressure
currentpress = press0[2][0][1]

# Calculate the trend
if pressurerdiff < -0.25:
    trend = -1
elif pressurerdiff >= -0.25 and pressurerdiff <= 0.25:
    trend = 0
elif pressurerdiff > 0.25:
    trend = 1

# Get the current month
today = datetime.date.today()
date = datetime.datetime.strptime(str(today), "%Y-%m-%d")
month = int(date.month)

# Use the Zambretti-algorithm to finally make the forecast
# --------------------------------------------------------
# Falling Conditions
# ------------------
if trend == -1:
    shutil.copyfile('/home/pi/pressure_info/DownRight.png', '/var/www/html/Arrow.png')
    zambretti = 0.0009746*currentpress*currentpress-2.1068*currentpress+1138.7019
    if month < 4 | month > 9:
        zambretti = zambretti + 1
    zambretti = int(round(zambretti))
    if zambretti == 1:
        forecast = 'Settled Fine'
        shutil.copyfile('/home/pi/pressure_info/Sun.png', '/var/www/html/Forecast.png')
    elif zambretti == 2:
        forecast = 'Fine Weather'
        shutil.copyfile('/home/pi/pressure_info/Sun.png', '/var/www/html/Forecast.png')
    elif zambretti == 3:
        forecast = 'Fine Becoming Less Settled'
        shutil.copyfile('/home/pi/pressure_info/SunCloud.png', '/var/www/html/Forecast.png')
    elif zambretti == 4:
        forecast = 'Fairly Fine Showers Later'
        shutil.copyfile('/home/pi/pressure_info/SunCloud.png', '/var/www/html/Forecast.png')
    elif zambretti == 5:
        forecast = 'Showery Becoming unsettled'
        shutil.copyfile('/home/pi/pressure_info/SunCloud.png', '/var/www/html/Forecast.png')
    elif zambretti == 6:
        forecast = 'Unsettled, Rain later'
        shutil.copyfile('/home/pi/pressure_info/Rain.png', '/var/www/html/Forecast.png')
    elif zambretti == 7:
        forecast = 'Rain at times, worse later'
        shutil.copyfile('/home/pi/pressure_info/Rain.png', '/var/www/html/Forecast.png')
    elif zambretti == 8:
        forecast = 'Rain at times, becoming very unsettled'
        shutil.copyfile('/home/pi/pressure_info/Rain.png', '/var/www/html/Forecast.png')
    elif zambretti == 9:
        forecast = 'Very Unsettled, Rain'
        shutil.copyfile('/home/pi/pressure_info/Rain.png', '/var/www/html/Forecast.png')
# Steady Conditions
# -----------------
elif trend == 0:
    shutil.copyfile('/home/pi/pressure_info/Right.png', '/var/www/html/Arrow.png')
    zambretti = 138.24-0.133*currentpress
    zambretti = int(round(zambretti))
    if zambretti == 1:
        forecast = 'Settled Fine'
        shutil.copyfile('/home/pi/pressure_info/Sun.png', '/var/www/html/Forecast.png')
    elif zambretti == 2:
        forecast = 'Fine Weather'
        shutil.copyfile('/home/pi/pressure_info/Sun.png', '/var/www/html/Forecast.png')
    elif zambretti == 3:
        forecast = 'Fine, Possibly showers'
        shutil.copyfile('/home/pi/pressure_info/SunCloud.png', '/var/www/html/Forecast.png')
    elif zambretti == 4:
        forecast = 'Fairly Fine, Showers likely'
        shutil.copyfile('/home/pi/pressure_info/SunCloud.png', '/var/www/html/Forecast.png')
    elif zambretti == 5:
        forecast = 'Showery Bright Intervals'
        shutil.copyfile('/home/pi/pressure_info/SunCloud.png', '/var/www/html/Forecast.png')
    elif zambretti == 6:
        forecast = 'Changeable some rain'
        shutil.copyfile('/home/pi/pressure_info/SunCloud.png', '/var/www/html/Forecast.png')
    elif zambretti == 7:
        forecast = 'Unsettled, rain at times'
        shutil.copyfile('/home/pi/pressure_info/Rain.png', '/var/www/html/Forecast.png')
    elif zambretti == 8:
        forecast = 'Rain at Frequent Intervals'
        shutil.copyfile('/home/pi/pressure_info/Rain.png', '/var/www/html/Forecast.png')
    elif zambretti == 9:
        forecast = 'Very Unsettled, Rain'
        shutil.copyfile('/home/pi/pressure_info/Rain.png', '/var/www/html/Forecast.png')
    elif zambretti == 10:
        forecast = 'Stormy, much rain'
        shutil.copyfile('/home/pi/pressure_info/Storm.png', '/var/www/html/Forecast.png')
# Rising Conditions
# -----------------
elif trend == 1:
    shutil.copyfile('/home/pi/pressure_info/UpRight.png', '/var/www/html/Arrow.png')
    zambretti = 142.57-0.1376*currentpress
    if month < 4 | month > 9:
        zambretti = zambretti + 1
    zambretti = int(round(zambretti))
    if zambretti == 1:
        forecast = 'Settled Fine'
        shutil.copyfile('/home/pi/pressure_info/Sun.png', '/var/www/html/Forecast.png')
    elif zambretti == 2:
        forecast = 'Fine Weather'
        shutil.copyfile('/home/pi/pressure_info/Sun.png', '/var/www/html/Forecast.png')
    elif zambretti == 3:
        forecast = 'Becoming Fine'
        shutil.copyfile('/home/pi/pressure_info/Sun.png', '/var/www/html/Forecast.png')
    elif zambretti == 4:
        forecast = 'Fairly Fine, Improving'
        shutil.copyfile('/home/pi/pressure_info/Sun.png', '/var/www/html/Forecast.png')
    elif zambretti == 5:
        forecast = 'Fairly Fine, Possibly showers, early'
        shutil.copyfile('/home/pi/pressure_info/SunCloud.png', '/var/www/html/Forecast.png')
    elif zambretti == 6:
        forecast = 'Showery Early, Improving'
        shutil.copyfile('/home/pi/pressure_info/SunCloud.png', '/var/www/html/Forecast.png')
    elif zambretti == 7:
        forecast = 'Changeable, Improving'
        shutil.copyfile('/home/pi/pressure_info/SunCloud.png', '/var/www/html/Forecast.png')
    elif zambretti == 8:
        forecast = 'Rather Unsettled Clearing Later'
        shutil.copyfile('/home/pi/pressure_info/SunCloud.png', '/var/www/html/Forecast.png')
    elif zambretti == 9:
        forecast = 'Unsettled, Probably Improving'
        shutil.copyfile('/home/pi/pressure_info/SunCloud.png', '/var/www/html/Forecast.png')
    elif zambretti == 10:
        forecast = 'Unsettled, short fine Intervals'
        shutil.copyfile('/home/pi/pressure_info/SunCloud.png', '/var/www/html/Forecast.png')
    elif zambretti == 11:
        forecast = 'Very Unsettled, Finer at times'
        shutil.copyfile('/home/pi/pressure_info/SunCloud.png', '/var/www/html/Forecast.png')
    elif zambretti == 12:
        forecast = 'Stormy, possibly improving'
        shutil.copyfile('/home/pi/pressure_info/Storm.png', '/var/www/html/Forecast.png')
    elif zambretti == 13:
        shutil.copyfile('/home/pi/pressure_info/Storm.png', '/var/www/html/Forecast.png')
        forecast = 'Stormy, much rain'

 

Overview of my weather station website

The website of my weather station includes contents from most of the articles here in the blog, so I finally want to give you an overview, of how the website that I mentioned several times before looks like.

Because I included all the information on one single page, I put a navigation bar at the top of the page. If you click on one of the links, the page scrolls automatically to the correspondent area. By clicking on one of the graphs, you will get back to the top of the page, so that there is actually no excessively scrolling necessary, despite the fact that the page is actually rather long. If you stay on the website for a longer period of time, it will automatically reload itself after five minutes, so that it always shows you the latest values.

website

A simple weather forecast, based on the barometric pressure history

Everybody knows the little weather stations that uses different symbols to show you a rough weather forecast, based on the change in the barometric pressure during the last hours.

Since I am also measuring the barometric pressure and having all the values from the past already in a database, I thought it would be nice to also make a small and independent forecast that is just based on the barometric pressure history.

There are not so much information available that shows you the details of that kind of algorithm. Only thing to find are general statements like rising pressure means good/better weather and falling weather means bad/worse weather. So, I ended up to implement my own little algorithm that should give similar, or even better results than a small weather station will give you.

Most of the small weather stations are using three basic symbols, rain, sun/cloud and sun and also an arrow up and an arrow down for the tendency. In case of a quickly falling pressure, the arrow down will blink as a storm warning. Since I don’t want to have something blinking on the website of my weather station, I introduced two more symbols, one for quickly falling pressure, and also one for quickly raising pressure. Additionally, I introduced three more arrows, to make the tendency a bit more detailed. The following table shows you the possible combination of the symbols and the meaning of it.

Unstable Up Quickly rising, very unstable weather condition

Sun UpRight Slowly rising, good weather condition, tendency rising

Sun Right Good weather condition, tendency stable

SunCloud UpRight Condition change is possible, tendency rising

SunCloud Right Condition change is possible, tendency steady/unclear

SunCloud DownRight Condition change is possible, tendency falling

Rain Right Rainy weather condition, tendency stable

Rain DownRight Slowly falling, rainy weather condition, tendency falling

Storm Down Quickly falling, thunderstorm is highly possible

For making the forecast, I consider the change of the barometric pressure during the last six hours. To get better, more stable results, I implemented a filter by calculating the average of different periods.

This is what the weather forecast looks like in the status bar of the website of my weather station, together with the air quality, the current season, sunset and sunrise times and the current moon phase.

Benningen

The Python script for the weather forecast is shown below. The pressure values from the past are read from the RRDtool database and afterwards are used to calculate the value for the average pressure change during the last six hours. Afterwards a decision regarding the forecast is made and the two icons (or just one, in case of stable conditions) are copied to the directory of the web server. I was playing around a bit with the rates for falling and rising and settled with absolute values of 0.25, 0.42 and 0.75. These values are giving me good results here in Germany. If you live in another part in the world, you may increase or decrease the values to get satisfying results.

#!/usr/bin/python
 
import os
import shutil
import rrdtool
 
# Filtering the pressure change by using the average from different periods should give better, more stable results
# Read the pressure values for now/t=0, t=-0.5h, t=-1.0h, t=-1.5h, t=-2.0h, t=-2.5h, t=-3.0h, t=-3.5h, t=-4.0h, t=-4.5h, t=-5.0h, t=-5.5h and t=-6.0h
press0 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 600', '-s -600')
press1 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 60', '-s -1800', '-e -1800')
press2 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 60', '-s -3600', '-e -3600')
press3 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 60', '-s -5400', '-e -5400')
press4 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 60', '-s -7200', '-e -7200')
press5 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 60', '-s -9000', '-e -9000')
press6 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 60', '-s -10800', '-e -10800')
press7 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 60', '-s -12600', '-e -12600')
press8 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 60', '-s -14400', '-e -14400')
press9 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 60', '-s -16200', '-e -16200')
press10 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 60', '-s -18000', '-e -18000')
press11 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 60', '-s -19800', '-e -19800')
press12 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 60', '-s -21600', '-e -21600')
 
# Calculate the single differences and normalize them to a change in pressure over 1h
pressurerdiff1 = (press0[2][0][1] - press1[2][0][1])*2
pressurerdiff2 = (press0[2][0][1] - press2[2][0][1])
pressurerdiff3 = (press0[2][0][1] - press3[2][0][1])/1.5
pressurerdiff4 = (press0[2][0][1] - press4[2][0][1])/2
pressurerdiff5 = (press0[2][0][1] - press5[2][0][1])/2.5
pressurerdiff6 = (press0[2][0][1] - press6[2][0][1])/3
pressurerdiff7 = (press0[2][0][1] - press7[2][0][1])/3.5
pressurerdiff8 = (press0[2][0][1] - press8[2][0][1])/4
pressurerdiff9 = (press0[2][0][1] - press9[2][0][1])/4.5
pressurerdiff10 = (press0[2][0][1] - press10[2][0][1])/5
pressurerdiff11 = (press0[2][0][1] - press11[2][0][1])/5.5
pressurerdiff12 = (press0[2][0][1] - press12[2][0][1])/6
 
# Calculate the average of the differences
pressurerdiff = (pressurerdiff1 + pressurerdiff2 + pressurerdiff3 + pressurerdiff4 + pressurerdiff5 + pressurerdiff6 + pressurerdiff7 + pressurerdiff8 + pressurerdiff9 + pressurerdiff10 + pressurerdiff11 + pressurerdiff12)/12
 
# Get the current pressure
currentpress = press0[2][0][1]
 
# Use the calculated pressure difference to finally make the forecast
# -------------------------------------------------------------------
# Rising Conditions
# -----------------
# Quickly rising, very unstable weather condition
if pressurerdiff > 0.75:
    shutil.copyfile('/home/pi/pressure_info/Unstable.png', '/var/www/html/Forecast.png')
    shutil.copyfile('/home/pi/pressure_info/Up.png', '/var/www/html/Arrow.png')
# Slowly rising, good weather condition, tendency rising
elif pressurerdiff > 0.42:
    shutil.copyfile('/home/pi/pressure_info/Sun.png', '/var/www/html/Forecast.png')
    shutil.copyfile('/home/pi/pressure_info/UpRight.png', '/var/www/html/Arrow.png')
# Change in weather condition is possible, tendency rising
elif pressurerdiff > 0.25:
    shutil.copyfile('/home/pi/pressure_info/UpRight.png', '/var/www/html/Arrow.png')
    if (currentpress >= 1006 and currentpress <= 1020) or currentpress < 1006:
        shutil.copyfile('/home/pi/pressure_info/SunCloud.png', '/var/www/html/Forecast.png')
# Falling Conditions
# ------------------
# Quickly falling, thunderstorm is highly possible
elif pressurerdiff < -0.75:
    shutil.copyfile('/home/pi/pressure_info/Storm.png', '/var/www/html/Forecast.png')
    shutil.copyfile('/home/pi/pressure_info/Down.png', '/var/www/html/Arrow.png')
# Slowly falling, rainy weather condition, tendency falling
elif pressurerdiff < -0.42:
    shutil.copyfile('/home/pi/pressure_info/Rain.png', '/var/www/html/Forecast.png')
    shutil.copyfile('/home/pi/pressure_info/DownRight.png', '/var/www/html/Arrow.png')
# Condition change is possible, tendency falling
elif pressurerdiff < -0.25:
    shutil.copyfile(’/home/pi/pressure _info/DownRight.png’, ’/var/www/html/Arrow.png’)
    if (currentpress >= 1006 and currentpress <= 1020) or currentpress > 1020:
        shutil.copyfile(’/home/pi/pressure _info/SunCloud.png’, ’/var/www/html/Forecast.png’)
# Steady Conditions
# -----------------
# Condition is stable, don't change the weather symbol (sun, rain or sun/cloud), just change the arrow
elif pressurerdiff <= 0.25 and pressurerdiff >= -0.25:
    shutil.copyfile('/home/pi/pressure_info/Right.png', '/var/www/html/Arrow.png')