I am really enjoying having this weather station. I say weather station, but it is just a raspberry pi with a pressure and temperature sensor attached to it. Computers are versatile, you can run any software on them, so they can do a lot of different things.

But the pi takes this to a whole different level. They are $40 or so, depending on taxes and stuff. Now you need a whole bunch of other stuff: leads, keyboards, sensors, cameras, touch screens and lots more.

I have been using Adafruit. They have been very helpful with orders.

I found browsing for parts and finding what I needed to get started with the weather stuff a bit confusing for a while.

I had other stuff to do anyway, I needed to get used to just installing software on them and setting up environments where I can figure out how things are working.

I found a great posting about building a weather station, with enough detail I thought I would be able to work through it.

I order a cheap humidity sensor ($5) that also should do temperature. I haven't got it working yet, not sure if it is hardware or software. Meanwhile, I now have a better sensor. The humidity here is often outside the range the cheaper sensor is supposed to work.

The good thing is that I should be able to find a use for it at some point.

I also have a camera for this thing and a touchscreen. I am thinking of trying to combine them to make a camera.

The one on my phone can do some neat stuff, but the interface keeps changing and not in ways that are making things easier.

The night skies have been spectacular of late, with Venus and Jupiter close together in the early evening sky to the west. If you see two bright stars after sunset, that is probably them.

Then the moon is just past full. Here in Bermuda there is often cloud, not heavy, but patchy clouds. The humidity is often very high, so the atmosphere is interesting.

The best sunsets usually have some clouds for the setting sun to reflect off. The same with sunrises.

And the full moon too. Tonight it rose behind cloud. Last night it was clearer and it rose orange/red.

Back to weather

Since I got this thing working it has been hot and settled weather. There is a strong Bermuda high in place. Someone described it to me as like a pit-bull, once it gets hold it does not let go. So, we may be in for a long hot spell.

With the pressure changing quite smoothly, the plots I created still showed quite an interesting pattern.

Skip the next bit, or go back to the earlier post, it is just setting things up to do some plotting.


In [82]:
# Tell matplotlib to plot in line
%matplotlib inline

# import pandas
import pandas

# seaborn magically adds a layer of goodness on top of Matplotlib
# mostly this is just changing matplotlib defaults, but it does also
# provide some higher level plotting methods.
import seaborn

# Tell seaborn to set things up
seaborn.set()



def smooth(data, thresh=None):
    
    means = data.mean()

    if thresh is None:
        sds = data.std()
    else:
        sds = thresh
    
    delta = data - data.shift()
    
    good = delta[abs(delta) < sds]

    print(good.describe())
    
    return delta.where(good, 0.0)

In [83]:
# set the path to the file we are going to analyse
infile = "../files/light.csv"

!scp 192.168.0.127:Adafruit_Python_BMP/light.csv ../files


light.csv                                     100% 2025KB   2.0MB/s   00:01    

In [84]:
""" assume it is csv and let pandas do magic

  index_col tells it to use the 'date' column in the data
  as the row index, plotting picks up on this and uses the
  date on the x-axis

  The *parse_dates* bit just tells it to try and figure out
  the date/time in the columne labeled 'date'.
"""
data = pandas.read_csv(infile, index_col='date', parse_dates=['date'])

In [85]:
# incantation to extract the first record in the data
start = data[['temp', 'altitude']].irow(0)

# smooth the data to filter out bad temps and pressures
sdata = (smooth(data, 5.0).cumsum() + start)

# now use smooth to throw away dodgy data, and plot the temp and altitude fieldsa
sdata[['temp', 'altitude']].plot(subplots=True)


               temp      pressure      altitude  sealevel_pressure
count  30304.000000  16155.000000  30077.000000       16182.000000
mean       0.000043      0.017580      0.000820          -0.000309
std        0.034749      2.460094      0.516706           2.460453
min       -0.400000     -4.000000     -2.330888          -4.000000
25%        0.000000     -2.000000     -0.331984          -2.000000
50%        0.000000      0.000000      0.000000           0.000000
75%        0.000000      2.000000      0.332114           2.000000
max        1.300000      4.000000      2.748358           4.000000
Out[85]:
array([<matplotlib.axes._subplots.AxesSubplot object at 0x7fed54cfdfd0>,
       <matplotlib.axes._subplots.AxesSubplot object at 0x7fed54a521d0>], dtype=object)

Temperature

The temperature plot shows a steady up and down, warming during the days, cooling a little, but only 2C at night.

There is one day, where I think we had some thunder storms where it dropped during the day.

The last week or so the temperature has been steadily climbing.

Pressure

The Pressure also shows slow drifting up and down. But there is this other strange ripple up and down.

I mentioned this to a meteorologist and immediately got the reply that it was because the atmosphere is tidal.

So the pattern we see in the pressure should be driven largely by the moon.


In [86]:
import astropy

In [87]:
from astropy import units
from astropy import find_api_page

In [88]:
# find_api_page is handy, even opens a browser windo.

#find_api_page(units)

In [89]:
# astropy is cool, but I need data for the moon.  Let's try pyephem

# uncommented the line below and run this cell if you need to install using
# pip.  This will install into the environment that is being used to run your
# ipython notebook server.

#!pip install pyephem

In [90]:
import ephem

In [91]:
# Create a Moon

moon = ephem.Moon()

In [92]:
# Tell it to figure out where it is
moon.compute()

# pring out the phase
moon.phase


Out[92]:
12.865459442138672

In [93]:
def moon_orbitals(index):
    """ Given an index of times create a DataFrame of moon orbitals
    
    For now, just Phase, geocentric latitude and geocentric longitude
    """
    
    # Create dataframe with index as the index
    df = pandas.DataFrame(index=index)
    
    # Add three series
    df['phase'] = pandas.Series()
    df['glat'] = pandas.Series()
    df['glon'] = pandas.Series()
    
    # Now generate the data
    # NB this is slow, solpy might work out faster
    moon = ephem.Moon()
    for ix, timestamp in enumerate(index):
        
        # Compute the moon posigion
        moon.compute(timestamp.strftime("%Y/%m/%d %H:%M:%S"))
        
        df.phase[ix] = moon.phase
        df.glat[ix] = moon.hlat
        df.glon[ix] = moon.hlon
        
    return df

In [94]:
# See what we got

moon = moon_orbitals(data.index)
moon.describe()


Out[94]:
phase glat glon
count 30397.000000 30397.000000 30397.000000
mean 58.143320 0.009210 3.272469
std 36.001448 0.063526 1.943755
min 0.172035 -0.087831 0.000126
25% 22.124449 -0.062341 1.274654
50% 69.537071 0.026644 3.743553
75% 91.296631 0.070193 4.961365
max 99.811104 0.087505 6.283139

In [95]:
moon.plot(subplots=True)


Out[95]:
array([<matplotlib.axes._subplots.AxesSubplot object at 0x7fed54facdd8>,
       <matplotlib.axes._subplots.AxesSubplot object at 0x7fed547378d0>,
       <matplotlib.axes._subplots.AxesSubplot object at 0x7fed547ad630>], dtype=object)

In [96]:
# Try feeding in a longer time series
days = pandas.date_range('7/7/2015', periods=560, freq='D')

In [97]:
moon_orbitals(days).plot(subplots=True)


Out[97]:
array([<matplotlib.axes._subplots.AxesSubplot object at 0x7fed544abd30>,
       <matplotlib.axes._subplots.AxesSubplot object at 0x7fed5451c2b0>,
       <matplotlib.axes._subplots.AxesSubplot object at 0x7fed54841b70>], dtype=object)

In [98]:
sdata['moon_phase'] = moon.phase
sdata['moon_glat'] = moon.glat
sdata['moon_glon'] = moon.glon

# FIXME -- must be a pandas one liner eg data += moon ?

In [99]:
sdata[['temp', 'altitude', 'moon_phase', 'moon_glon', 'moon_glat']].plot(subplots=True)


Out[99]:
array([<matplotlib.axes._subplots.AxesSubplot object at 0x7fed54641978>,
       <matplotlib.axes._subplots.AxesSubplot object at 0x7fed545cb470>,
       <matplotlib.axes._subplots.AxesSubplot object at 0x7fed54596518>,
       <matplotlib.axes._subplots.AxesSubplot object at 0x7fed54550550>,
       <matplotlib.axes._subplots.AxesSubplot object at 0x7fed544d6d30>], dtype=object)

The latitude is almost in phase with the phase of the moon, at least at the moment.

Next job is to add these series to our data frame and then take a look at scikit-learn


In [100]:
print(sdata.index[0])
sdata.index[0].hour + (sdata.index[0].minute / 60.)


2015-06-25 15:07:37.174400
Out[100]:
15.116666666666667

In [101]:
sdata.describe()


Out[101]:
altitude pressure sealevel_pressure temp moon_phase moon_glat moon_glon
count 30397.000000 0 0 30397.000000 30397.000000 30397.000000 30397.000000
mean -31.879161 NaN NaN 29.392555 58.143320 0.009210 3.272469
std 20.589351 NaN NaN 0.894486 36.001448 0.063526 1.943755
min -69.792586 NaN NaN 27.200000 0.172035 -0.087831 0.000126
25% -50.325302 NaN NaN 28.700000 22.124449 -0.062341 1.274654
50% -34.975717 NaN NaN 29.400000 69.537071 0.026644 3.743553
75% -10.941520 NaN NaN 30.000000 91.296631 0.070193 4.961365
max 8.379000 NaN NaN 31.500000 99.811104 0.087505 6.283139

In [102]:
def tide_proxy(df):
    # Create dataframe with index as the index
    series = pandas.Series(index=df.index)
    
    for ix, timestamp in enumerate(df.index):
        hour_min = timestamp.hour + (timestamp.minute / 60.)
	
        hour_min += df.moon_glat[ix]

        series[ix] = hour_min
        
    return series

In [103]:
xx = tide_proxy(sdata)

xx.plot()

xx.describe()


Out[103]:
count    30397.000000
mean        12.141895
std          6.996605
min         -0.087386
25%          5.998249
50%         12.296909
75%         18.230285
max         24.070675
dtype: float64

In [104]:
# See what we got
moon = moon_orbitals(data.index)
moon.describe()


Out[104]:
phase glat glon
count 30397.000000 30397.000000 30397.000000
mean 58.143320 0.009210 3.272469
std 36.001448 0.063526 1.943755
min 0.172035 -0.087831 0.000126
25% 22.124449 -0.062341 1.274654
50% 69.537071 0.026644 3.743553
75% 91.296631 0.070193 4.961365
max 99.811104 0.087505 6.283139

In [105]:
sdata['tide'] = tide_proxy(sdata)

In [106]:
fields = ['altitude', 'temp', 'tide']

sdata[fields].plot()


Out[106]:
<matplotlib.axes._subplots.AxesSubplot at 0x7fed54167be0>

In [107]:
sdata.temp.plot()


Out[107]:
<matplotlib.axes._subplots.AxesSubplot at 0x7fed5425d550>

In [108]:
with open("../files/moon_weather.csv", 'w') as outfile:
     sdata.to_csv(outfile)