TestBench.tools
GitHub

NMEA 0183 Decoder

Parse NMEA 0183 sentences into labeled fields with checksum check.

GP · GGAchecksum VALID (0x47)
#FieldValue
1UTC time123519
2Latitude4807.038
3N/SN
4Longitude01131.000
5E/WE
6Fix quality (0=invalid, 1=GPS, 2=DGPS)1
7Satellites in use08
8HDOP0.9
9Altitude545.4
10Altitude unitM
11Geoid separation46.9
12Separation unitM
13DGPS age
14DGPS station id

This tool decodes an NMEA 0183 sentence into a labeled field table: talker and type up top, checksum verdict, then every field with its meaning for the common types (GGA, RMC, GLL, VTG, GSA) or numbered fields for anything else. Paste a line straight from your serial capture and see what the receiver is actually saying.

How it works

NMEA 0183 sentences are printable ASCII: $TTSSS,field1,field2,…*HH, where TT is the talker (GP = GPS, GN = multi-constellation), SSS the sentence type, and HH an XOR checksum over everything between $ and *. Field positions are fixed per sentence type, so decoding is a split on commas plus a lookup table of meanings — which is exactly what this tool applies, after verifying the checksum so you know the line survived the serial link intact.

Worked example

$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47
→ GP / GGA · checksum VALID (0x47)
→ UTC 12:35:19 · lat 48°07.038′N · lon 011°31.000′E
→ fix quality 1 (GPS) · 8 satellites · HDOP 0.9 · alt 545.4 M

Writing a parser that survives real receivers

The format is simple; the failure modes are all in the assumptions. Four rules cover most of what breaks hand-written NMEA parsers.

Match the type, not the talker. The first two letters of the address are the constellation — GP for GPS, GL for GLONASS, GA for Galileo, GN for a combined fix. A parser that hard-matches $GPGGA stops working the day a multi-constellation module starts emitting $GNGGA, which is the default on modern receivers. Match the last three letters and keep the talker as data.

Empty fields are normal, not errors. Before a fix, a receiver sends the sentence anyway with the position fields blank: $GPGGA,,,,,,0,00,,,M,,M,,*66 is a valid sentence that means "no fix yet". Code that doesparseFloat on every field without checking for empty strings turns start-up into NaN.

The coordinate field is not a decimal number.ddmm.mmmm has to be split at the minutes boundary — degrees are the digits before the last two integer digits, the rest is minutes to divide by 60. Reading 3733.9900 as 37.339900° puts the fix in the wrong place by about 25 km, and nothing warns you.

Field counts vary by revision. Later NMEA revisions appended fields — RMC grew a mode indicator, then a navigation status. Parse positionally from the front and tolerate extra fields at the end rather than requiring an exact count.

Feeding NMEA into LabVIEW or a PLC

NMEA is plain ASCII on a serial port, so any environment that can read lines can consume it — the work is always the same three steps: frame on $…CR/LF, verify the checksum, split on commas. In LabVIEW that is a serial read wired to a string subset/scan pattern; on a PLC it is a string instruction block. The two places implementations go wrong are the coordinate conversion above and dropped partial lines at start-up — always resynchronise on the next $ rather than assuming the buffer starts at a sentence boundary.

To test a consumer without a live receiver, the companion generator on this site builds valid sentences — including the no-fix and southern-hemisphere cases a bench receiver rarely produces on demand.

Parameters

ParameterValueNotes
Structure$address,fields*HHASCII, CR LF terminated
TalkerGP · GN · GL · P (proprietary)…
Labeled typesGGA · RMC · GLL · VTG · GSA
ChecksumXOR between $ and *
Coordinatesddmm.mmmm + hemispheredegrees·minutes packed

Python implementation

Python
# Minimal NMEA field split with checksum verification
def parse_nmea(line: str):
    body, _, cs = line.strip().lstrip("$").rpartition("*")
    computed = 0
    for ch in body:
        computed ^= ord(ch)
    fields = body.split(",")
    return fields[0], fields[1:], computed == int(cs, 16)

addr, fields, ok = parse_nmea(
    "$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47")
assert addr == "GPGGA" and ok and fields[0] == "123519"

FAQ

Which sentence types get labeled fields?

GGA (fix data), RMC (recommended minimum), GLL (position), VTG (course/speed) and GSA (DOP and satellites) — the types that carry most of the information engineers actually read. Anything else, including proprietary $P… sentences, decodes generically with numbered fields.

How do I read the latitude field 4807.038?

NMEA packs degrees and minutes together: ddmm.mmmm. 4807.038 means 48° 07.038′ — to get decimal degrees, 48 + 7.038/60 = 48.1173°. The hemisphere letter in the following field (N/S) sets the sign.

What does fix quality 0/1/2 mean in a GGA sentence?

0 = no valid fix, 1 = standard GNSS fix, 2 = differential (DGPS) fix. Higher values exist for RTK modes on capable receivers. Combined with the satellites-in-use and HDOP fields, this is the quick health check of a receiver.

Why are some fields empty?

NMEA leaves a field's position in place but empty when the receiver has no value — two adjacent commas. Empty DGPS age or altitude fields are normal on receivers without those features; the decoder shows them as dashes.

Is my data uploaded?

No. Decoding runs locally in your browser.

Related tools