Parsing GPS receiver output via regex in Python

后端 未结 7 1316
没有蜡笔的小新
没有蜡笔的小新 2020-12-14 11:01

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

7条回答
  •  无人及你
    2020-12-14 11:31

    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.

提交回复
热议问题