I have a friend who is finishing up his masters degree in aerospace engineering. For his final project, he is on a small team tasked with writing a program for tracking weat
If you need to do some more extensive analysis of your GPS data streams, here is a pyparsing solution that breaks up your data into named data fields. I extracted your pastebin'ned data to a file gpsstream.txt, and parsed it with the following:
"""
Parse NMEA 0183 codes for GPS data
http://en.wikipedia.org/wiki/NMEA_0183
(data formats from http://www.gpsinformation.org/dale/nmea.htm)
"""
from pyparsing import *
lead = "$"
code = Word(alphas.upper(),exact=5)
end = "*"
COMMA = Suppress(',')
cksum = Word(hexnums,exact=2).setParseAction(lambda t:int(t[0],16))
# define basic data value forms, and attach conversion actions
word = Word(alphanums)
N,S,E,W = map(Keyword,"NSEW")
integer = Regex(r"-?\d+").setParseAction(lambda t:int(t[0]))
real = Regex(r"-?\d+\.\d*").setParseAction(lambda t:float(t[0]))
timestamp = Regex(r"\d{2}\d{2}\d{2}\.\d+")
timestamp.setParseAction(lambda t: t[0][:2]+':'+t[0][2:4]+':'+t[0][4:])
def lonlatConversion(t):
t["deg"] = int(t.deg)
t["min"] = float(t.min)
t["value"] = ((t.deg + t.min/60.0)
* {'N':1,'S':-1,'':1}[t.ns]
* {'E':1,'W':-1,'':1}[t.ew])
lat = Regex(r"(?P\d{2})(?P\d{2}\.\d+),(?P[NS])").setParseAction(lonlatConversion)
lon = Regex(r"(?P\d{3})(?P\d{2}\.\d+),(?P[EW])").setParseAction(lonlatConversion)
# define expression for a complete data record
value = timestamp | Group(lon) | Group(lat) | real | integer | N | S | E | W | word
item = lead + code("code") + COMMA + delimitedList(Optional(value,None))("datafields") + end + cksum("cksum")
def parseGGA(tokens):
keys = "time lat lon qual numsats horiz_dilut alt _ geoid_ht _ last_update_secs stnid".split()
for k,v in zip(keys, tokens.datafields):
if k != '_':
tokens[k] = v
#~ print tokens.dump()
def parseGSA(tokens):
keys = "auto_manual _3dfix prn prn prn prn prn prn prn prn prn prn prn prn pdop hdop vdop".split()
tokens["prn"] = []
for k,v in zip(keys, tokens.datafields):
if k != 'prn':
tokens[k] = v
else:
if v is not None:
tokens[k].append(v)
#~ print tokens.dump()
def parseRMC(tokens):
keys = "time active_void lat lon speed track_angle date mag_var _ signal_integrity".split()
for k,v in zip(keys, tokens.datafields):
if k != '_':
if k == 'date' and v is not None:
v = "%06d" % v
tokens[k] = '20%s/%s/%s' % (v[4:],v[2:4],v[:2])
else:
tokens[k] = v
#~ print tokens.dump()
# process sample data
data = open("gpsstream.txt").read().expandtabs()
count = 0
for i,s,e in item.scanString(data):
# use checksum to validate input
linebody = data[s+1:e-3]
checksum = reduce(lambda a,b:a^b, map(ord, linebody))
if i.cksum != checksum:
continue
count += 1
# parse out specific data fields, depending on code field
fn = {'GPGGA' : parseGGA,
'GPGSA' : parseGSA,
'GPRMC' : parseRMC,}[i.code]
fn(i)
# print out time/position/speed values
if i.code == 'GPRMC':
print "%s %8.3f %8.3f %4d" % (i.time, i.lat.value, i.lon.value, i.speed or 0)
print count
The $GPRMC records in your pastebin don't seem to quite match with the ones you included in your post, but you should be able to adjust this example as necessary.