Envirophat - visualizing motion data


#1

I’m trying to think of the best way to visualize motion data from Envirophat. The application is to measure movement from local HGV traffic. I have it logging to a remote MySQL host where I can use PHP etc which I am more comfortable with than Python.

Question is how can I graph the X Y Z values into something more meaningful like Magnitude for example? So two questions really,:

  1. Convert X Y Z into magnitude values
  2. Graph magnitude (probably easy as it’ll be one figure over time, a line graph with an x and y axis)

#2

I would be surprised if the motion sensor is accurate enough to pick HGV traffic out of background noise- I would probably start by normalising all of the data into a single channel, something like:

level = ( (Z- Gravity) + abs(Y) + abs(Z) ) / 3

And then running it for a bit and seeing if I can pick anything out of the datastream.

It’s been a long time since I’ve done any meaningful web front-end stuff, but I’d probably use a javascript graphing library to spit out the data in realtime until I found a satisfactory formula for picking signal from noise. @sandyjmacdonald has done something like this for Enviro pHAT.


#3

Thank you for that. I managed to get it calculating a ‘figure’ - what that figure was I dont know, my brother suggested I try the below

    magnitude = math.pow(axisx, 2) + math.pow(axisy, 2) + math.pow(axisz, 2)
    magnitude = math.sqrt(magnitude)
    magnitude = magnitude - gravity

It does actually render over a 12 hour period a graph where you can noticeably see an increase in movements. But drilling down to find out spikes is as you say quite tricky. Its graphing using d3js

I shall have a go with your formula as well! Thank you

EDIT: For the purposes of subtracting gravity, is it 9.8 or 1 I need to subtract? The sensor uses g’s as it’s unit - http://www.st.com/content/ccc/resource/technical/document/datasheet/1c/9e/71/05/4e/b7/4d/d1/DM00057547.pdf/files/DM00057547.pdf/jcr:content/translations/en.DM00057547.pdf

EDIT 2: This is using your formula with gravity as 1 - http://oliver-partridge-fltc.temp-dns.com/


#4

The formula your brother suggested is calculating the total magnitude of the acceleration vector, this might be what you’d use in combination with calculating the angle of the vector to determine the speed/direction of movement. I’m not sure how useful this- or indeed my own crude formula- is to measuring vibrations from passing trucks, since they will usually be noisy and unpredictable.

What you might find, if you were to plot X, Y and Z individually, is some (to possibly misuse a phrase) correlated noise between them. That is to say that if a passing truck causes a vibration on X, it’s possible that it produces an event of a similar magnitude and time on Y and Z.

Now a vibration is, in all but the most extreme of cases, generally also an audible sound and there are ways to process audible sound (and any other signals involving magnitude measurements over time) in order to filter unwanted components and pay particular attention to frequencies of interest- these are a Low-pass Filter, and a Fast-Fourier Transform respectively.

Low Pass

Low Pass is, as its name might allude, a filter that allows low frequencies to pass through, while blocking high ones. In your case you would be interested in the mid frequencies that suggest truck vibrations but not the low frequencies or high frequency noise.

A crude implementation of a Low Pass filter is a moving average- this involves a sliding window of samples over time, and produces an average of those samples. This causes high-frequency noise to cancel itself out, while the lower frequency component is still visible.

IE: say we have the signals: 6 -1 1 -1 1 -1 1 and 6 0 0 0 0 0 0, these are all 7 samples long and when you take the average of them, they both give a single sample of 0.428

FFT

This is somewhat more complicated, and you should google for ways to apply this in Python because it’ll make this thread ten pages long if I try to approach it.

In brief, for signals like this FFT will transform a set of samples over a period of time into a collection of magnitudes for each frequency.

Careful application of FFT should allow you to measure the magnitude of the frequency group that corresponds to “trucks passing” at any given time.

Back on track…

You should probably start by applying a low pass filter - or moving average - across your data to attempt to cancel out some of the noise.

Since your logged signal is actually pretty low frequency anyway - it looks like once every 3-4sec - you should probably sample the accelerometer at a higher frequency and log the moving average value at a fixed rate- IE: once a second.

Try logging the X/Y/Z individually, plotting them, and looking for correlations. It might also help to either grab a timer and manually log every time a truck passes, or set up a microphone so you can correlate points of interest in your data with actual events and see if things line up.

If you go the microphone route (audacity recording from a laptop mic might even do) give the desk a couple of slaps to generate a spike that both the accelerometer and microphone will log for syncing up.


#5

Thank you for that. I do have an earlier experiment where I did graph x, y, z separately.

I did try a previous experiment a couple of years ago with a crude slinky Geophone which was incredibly sensitive even picking up the wife on the phone!

You are entirely correct in that it is difficult to correlate movement from the sensor to an actual vehicle and I did consider a microphone, or even better some video device (law permitting)

import time
import math
import pymysql.cursors
import datetime
from envirophat import motion

timestamp = datetime.datetime.now().isoformat()

conn = pymysql.connect(user="my_uname",passwd="my_pass",host="local",database="envirophat")
cursor = conn.cursor()

try:
    while True:

        acc = str(motion.accelerometer())[1:-1]
        axisx, axisy, axisz = acc.split(", ")
        axisx = float(axisx)
        axisy = float(axisy)
        axisz = float(axisz)
        
        magnitude = ( (axisz - 1) + abs(axisy) + abs(axisx) ) / 3
        
        # magnitude = math.pow(axisx, 2) + math.pow(axisy, 2) + math.pow(axisz, 2)
        # magnitude = math.sqrt(magnitude)
        # magnitude = magnitude - gravity

        sql = "INSERT INTO `sensor` (`axisx`, `axisy`, `axisz`, `magnitude`) VALUES (%s, %s, %s, %s)"
        cursor.execute(sql, (axisx, axisy, axisz, magnitude))

        conn.commit()

        time.sleep(1)

except KeyboardInterrupt:
    conn.close()