Frage

Ich habe einen Freund, der seinen Master-Abschluss in Luft- und Raumfahrttechnik ist Finishing. Für sein letztes Projekt ist er auf einem kleinen Team die Aufgabe, ein Programm zu schreiben für die Verfolgung von Wetterballons, Raketen und Satelliten. Das Programm empfängt eine Eingabe von einem GPS-Gerät, tut Berechnungen mit den Daten und verwendet die Ergebnisse dieser Berechnungen eine Reihe von Motoren, die eine Richtungskommunikationsantenne entwickelt, um die Steuerung zu orientieren, so dass der Ballon, Rakete oder Satellit bleibt immer im Mittelpunkt steht.

Obwohl ein wenig von einer (ewigen) Anfängern mir, ich mehr Programmiererfahrung habe, als mein Freund. Also, wenn er mich um Rat gefragt, ich überzeugte ihn das Programm in Python zu schreiben, meine Sprache der Wahl.

An diesem Punkt in dem Projekt arbeiten wir an dem Code, der die Eingabe von dem GPS-Gerät analysiert. Hier ist ein Beispiel-Eingang, mit dem Daten, die wir in fett extrahieren müssen:

$ GPRMC, 092204.999, 4250.5589, S, 14718.5084, E , 1,12,24.4, 89,6 , M ,,, 0000 * 1F $ GPRMC, 093345.679, 4234.7899, N, 11344.2567, W , 3,02,24.5, 1.000,23 , M ,,, 0000 * 1F $ GPRMC, 044584.936, 1276.5539, N, 88734.1543, E , 2,04,33.5, 600,323 , M ,,, * 00 $ GPRMC, 199304.973, 3248.7780, N, 11355.7832, W , 1,06,02.2, 25.722,5 , M ,,, * 00 $ GPRMC, 066487.954, 4572.0089, S, 45572.3345, W , 3,09,15.0, 35.000,00 , M ,,, * 1F

Hier sind einige weitere Erläuterung der Daten:

  

"Ich sehe aus wie ich fünf Dinge brauche   aus jeder Zeile. Und beachten   dass eine dieser Gegend kann   leeren. Bedeutung wird es nur zwei sein   Kommas direkt nebeneinander. Eine solche   als ‚,,,‘ Es gibt zwei Felder, die möglicherweise   jederzeit voll sein. Einige von ihnen nur   haben zwei oder drei Optionen, die sie   kann sein, aber ich glaube nicht, dass ich sein   Zählen auf dem. "

Vor zwei Tagen mein Freund konnte das volle Protokoll aus dem GPS-Empfänger erwerben verwendete eine aktuelle Wetterballonstart zu verfolgen. Die Daten sind ziemlich lang, so dass ich sie alle in dieser Pastebin .

Ich bin noch recht neu mit regulären Ausdrücken mich, so dass ich für etwas Unterstützung suchen.

War es hilfreich?

Lösung

Splitting sollte es tun. Hier ist ein guter Weg, um die Daten zu extrahieren, auch:

>>> line = "$GPRMC,199304.973,3248.7780,N,11355.7832,W,1,06,02.2,25722.5,M,,,*00"
>>> line = line.split(",")
>>> neededData = (float(line[2]), line[3], float(line[4]), line[5], float(line[9]))
>>> print neededData
(3248.7779999999998, 'N', 11355.7832, 'W', 25722.5)

Andere Tipps

Es ist einfacher Spaltung als ein Regex zu verwenden.

>>> line="$GPRMC,092204.999,4250.5589,S,14718.5084,E,1,12,24.4,89.6,M,,,0000*1F "
>>> line.split(',')
['$GPRMC', '092204.999', '4250.5589', 'S', '14718.5084', 'E', '1', '12', '24.4', '89.6', 'M', '', '', '0000*1F ']
>>> 

Die getrennten Werte sind Komma, so eine csv-Bibliothek ist die einfachste Lösung.

warf ich, dass die Probendaten, die Sie haben in / var / tmp / sample, dann habe ich diese:

>>> import csv
>>> for line in csv.reader(open('/var/tmp/sampledata')):
...   print line
['$GPRMC', '092204.999', '**4250.5589', 'S', '14718.5084', 'E**', '1', '12', '24.4', '**89.6**', 'M', '', '', '0000\\*1F']
['$GPRMC', '093345.679', '**4234.7899', 'N', '11344.2567', 'W**', '3', '02', '24.5', '**1000.23**', 'M', '', '', '0000\\*1F']
['$GPRMC', '044584.936', '**1276.5539', 'N', '88734.1543', 'E**', '2', '04', '33.5', '**600.323**', 'M', '', '', '\\*00']
['$GPRMC', '199304.973', '**3248.7780', 'N', '11355.7832', 'W**', '1', '06', '02.2', '**25722.5**', 'M', '', '', '\\*00']
['$GPRMC', '066487.954', '**4572.0089', 'S', '45572.3345', 'W**', '3', '09', '15.0', '**35000.00**', 'M', '', '', '\\*1F']

Sie können dann die Daten verarbeiten, wie Sie wollen. Es sieht ein wenig seltsam mit dem ‚**‘ am Anfang und Ende von einigen der Werte, möchten Sie vielleicht das Zeug abzustreifen, können Sie tun:

>> eastwest = 'E**'
>> eastwest = eastwest.strip('*')
>> print eastwest
E

Sie müssen einige Werte als Schwimmer werfen. So zum Beispiel der dritte Wert in der ersten Zeile von Beispieldaten ist:

>> data = '**4250.5589'
>> print float(data.strip('*'))
4250.5589

Sie sollten auch zuerst die Prüfsumme der Daten überprüfen. Es wird berechnet, indem XOR-Verknüpfung der Zeichen zwischen $ und * (ohne sie) und auf den Hex-Wert am Ende verglichen wird.

Ihre Pastebin sieht aus wie es einige korrupte Linien in ihm hat. Hier ist eine einfache Prüfung, es wird davon ausgegangen, dass die Linie mit $ beginnt und hat keine CR / LF am Ende. Zum Aufbau eines robusteren Parser Sie für die ‚$‘ suchen müssen und die Arbeit durch den Strang bis Schlagen der ‚*‘.

def check_nmea0183(s):
    """
    Check a string to see if it is a valid NMEA 0183 sentence
    """
    if s[0] != '$':
        return False
    if s[-3] != '*':
        return False

    checksum = 0
    for c in s[1:-3]:
        checksum ^= ord(c)

    if int(s[-2:],16) != checksum:
        return False

    return True

Sie können eine Bibliothek verwenden, wie pynmea2 für das NMEA Protokoll Parsen.

>>> import pynmea2
>>> msg = pynmea2.parse('$GPGGA,142927.829,2831.4705,N,08041.0067,W,1,07,1.0,7.9,M,-31.2,M,0.0,0000*4F')
>>> msg.timestamp, msg.latitude, msg.longitude, msg.altitude
(datetime.time(14, 29, 27), 28.524508333333333, -80.683445, 7.9)

Disclaimer: Ich bin der Autor des pynmea2

Wenn Sie etwas umfangreichere Analyse der GPS-Datenströme tun müssen, ist hier eine pyparsing Lösung, die Ihre Daten in benannte Datenfelder aufbricht. Ich extrahiert Ihre pastebin'ned Daten in eine Datei gpsstream.txt und analysiert sie mit folgendem:

"""
 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<deg>\d{2})(?P<min>\d{2}\.\d+),(?P<ns>[NS])").setParseAction(lonlatConversion)
lon = Regex(r"(?P<deg>\d{3})(?P<min>\d{2}\.\d+),(?P<ew>[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

Die $ GPRMC Datensätze in Ihrer Pastebin scheinen nicht ganz mit denen übereinstimmen Sie in Ihrem Beitrag enthalten, aber Sie sollten dieses Beispiel nach Bedarf anzupassen können.

Ich schlage vor, eine kleine Korrektur in Ihrem Code, weil, wenn verwendet, um Daten aus dem vorigen Jahrhundert zu analysieren das Datum wie irgendwann in der Zukunft sieht (zB 2094 statt 1994)

Meine Lösung ist nicht ganz genau, aber ich nehme den Stand, der keine GPS-Daten bestanden zu den 70er Jahren vor.

In der def Parse-Funktion für RMC Sätze ersetzen Sie einfach das Format Zeile:

p = int(v[4:])
print "p = ", p
if p > 70:
    tokens[k] = '19%s/%s/%s' % (v[4:],v[2:4],v[:2])
else:
    tokens[k] = '20%s/%s/%s' % (v[4:],v[2:4],v[:2])

Dies wird an den beiden yy Ziffern des Jahres schauen und geht davon aus, dass vergangenes Jahr 70 wir mit Sätzen aus dem vorigen Jahrhundert handeln. Es könnte besser durch Vergleich mit dem heutigen Datum erfolgen und unter der Annahme, dass jedes Mal, wenn Sie mit einigen Daten in der Zukunft beschäftigen, sind sie in der Tat aus dem vergangenen Jahrhundert

Vielen Dank für alle Teile des Codes Ihrer oben zur Verfügung gestellt ... Ich hatte etwas Spaß mit diesem.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top