kopia lustrzana https://github.com/bristol-seds/pico-tracker
Added python parser for raw pico tracker data.
I haven't rigorously tested it, but the fact that the data starts in Montpelier on the 25th, and it correctly decodes the APRS test longitude of '<*e7' to -72.75 degrees is promising.master
rodzic
eb1ad8d872
commit
249279c56e
|
@ -0,0 +1,140 @@
|
|||
"""
|
||||
This script parses the raw data from the pico tracker.
|
||||
At the very bottom the data is printed. Feel free to change
|
||||
the print statement to suit the data you're interested in.
|
||||
The parsed data is a list of dicts, with keys 'time', 'coords',
|
||||
'battery', 'solar', 'temperature' and 'satellites'.
|
||||
|
||||
Data is expected in the form of a series of lines containing
|
||||
'/A={6 digits} {6 digits}z.{18 chars}{11 chars}\n'. Anything
|
||||
else will be ignored.
|
||||
"""
|
||||
|
||||
import re
|
||||
import sys
|
||||
from datetime import datetime
|
||||
from math import log, exp
|
||||
|
||||
"""
|
||||
Decodes a 'base 91' encoded string
|
||||
"""
|
||||
def base91_decode(enc_str):
|
||||
enc_ints = [ord(x) - 33 for x in enc_str]
|
||||
powers = range(len(enc_ints))[::-1]
|
||||
return sum(x * pow(91, i) for x, i in zip(enc_ints, powers))
|
||||
|
||||
"""
|
||||
Takes a parsed telemetry line and returns a datetime
|
||||
Default year and month are 2015 and July
|
||||
"""
|
||||
def extract_time(line):
|
||||
# Capture a 6 digit string
|
||||
p = re.compile(r'(\d{6})z\S{18}')
|
||||
match = p.match(line)
|
||||
|
||||
if match == None:
|
||||
return None
|
||||
else:
|
||||
date_str = '201507' + match.group(1)
|
||||
|
||||
# Return a datetime object
|
||||
return datetime.strptime(date_str, '%Y%m%d%H%M')
|
||||
|
||||
"""
|
||||
Takes a parsed telemetry line and returns latitude, longitude and
|
||||
altitude. It decodes from base 91 along the way
|
||||
"""
|
||||
def extract_lat_long_alt(line):
|
||||
# Capture a 4 char encoded latitude
|
||||
p = re.compile(r'\d{6}z(\S{4})(\S{4})(\S{2})\S{8}')
|
||||
match = p.match(line)
|
||||
|
||||
if match == None:
|
||||
return None
|
||||
else:
|
||||
enc_lat, enc_long, enc_alt = match.groups()
|
||||
|
||||
# Lat/long in fractional degrees, alt in metres
|
||||
latitude = 90.0 - (base91_decode(enc_lat) / 380926.0)
|
||||
longitude = -180.0 + (base91_decode(enc_long) / 190463.0)
|
||||
altitude = exp(log(1.002) * base91_decode(enc_alt)) / 3.2808
|
||||
|
||||
return (latitude, longitude, altitude)
|
||||
|
||||
"""
|
||||
Takes a parsed telemetry line and returns readings on battery, solar
|
||||
temperature and satellite count. It decodes from base91 along the
|
||||
way
|
||||
"""
|
||||
def extract_telemetry(line):
|
||||
# Capture an 8 char encoded telemetry segment
|
||||
p = re.compile(r'\d{6}z\S{10}(\S{8})')
|
||||
match = p.match(line)
|
||||
|
||||
if match == None:
|
||||
return None
|
||||
else:
|
||||
tel = match.group(1)
|
||||
|
||||
# Split into 2 char chunks
|
||||
parts = [tel[i:i+2] for i in range(0, 8, 2)]
|
||||
batt_enc, sol_enc, temp_enc, sat_enc = tuple(parts)
|
||||
|
||||
# Reverse Richard's conversions
|
||||
battery = base91_decode(batt_enc) / 1000.0
|
||||
solar = base91_decode(sol_enc) / 1000.0
|
||||
temperature = (base91_decode(temp_enc) / 10) - 273.2
|
||||
satellite_count = base91_decode(sat_enc)
|
||||
|
||||
return (battery, solar, temperature, satellite_count)
|
||||
|
||||
"""
|
||||
Exracts the 'raw data' segment from a line of data; this is the 25
|
||||
character section after /A={6 digits}
|
||||
"""
|
||||
def extract_raw_data(line):
|
||||
# Capture the raw data segment
|
||||
p = re.compile(r'/A=\d{6} (\S{25})\|\S{11}$')
|
||||
match = p.search(line)
|
||||
|
||||
if match == None:
|
||||
return None
|
||||
else:
|
||||
return match.group(1)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
if len(sys.argv) != 2:
|
||||
print 'Usage: python raw_parser.py rawdata.txt'
|
||||
sys.exit()
|
||||
|
||||
file_name = sys.argv[1]
|
||||
|
||||
with open(file_name, 'r') as data_file:
|
||||
data = []
|
||||
|
||||
for line in data_file:
|
||||
# Extract raw data string
|
||||
raw = extract_raw_data(line)
|
||||
|
||||
if raw == None:
|
||||
continue
|
||||
else:
|
||||
tele = extract_telemetry(raw)
|
||||
|
||||
data.append({
|
||||
'time': extract_time(raw),
|
||||
'coords': extract_lat_long_alt(raw),
|
||||
'battery': tele[0],
|
||||
'solar': tele[1],
|
||||
'temperature': tele[2],
|
||||
'satellites': tele[3]
|
||||
})
|
||||
|
||||
# Sort data lines by time
|
||||
data = sorted(data, key=lambda x: x['time'])
|
||||
|
||||
# Print data
|
||||
for datum in data:
|
||||
print "%s: %s, %s" % ((str(datum['time']),) + datum['coords'][:2])
|
||||
|
Ładowanie…
Reference in New Issue