Sensors

GNSS — satellite positioning, timestamps, and NMEA

A GNSS receiver never talks back to a satellite — it's purely a listener. Everything it computes, including position and an extremely precise timestamp, comes from timing exactly how long one-way radio signals took to arrive from satellites whose orbits are known to within centimeters.

Quick reference
What it is
A receive-only radio system that computes position and time by measuring how long signals took to arrive from multiple satellites.
Mental model
Distance-from-known-points math (trilateration) — each satellite tells you "I'm exactly here, and this is when I sent this," and your position falls out of the timing.
Key numbers
Minimum 4 satellites for a 3D fix, NMEA output typically at 9600 baud over UART, position accuracy commonly 2–5 m unaided.
Reach for it when
You need absolute position or a precise, drift-free time reference and have a clear-ish sky view.

Constellations, briefly

"GPS" is technically just the United States' system; "GNSS" (Global Navigation Satellite System) is the umbrella term covering all of them — GPS, Russia's GLONASS, the EU's Galileo, and China's BeiDou. A modern receiver typically tracks satellites from several constellations simultaneously (visible in NMEA output as talker IDs like GP for GPS-only sentences or GN for a combined multi-constellation fix), simply because more visible satellites means a faster, more accurate fix.

Pseudorange: turning a timestamp into a distance

Every satellite carries an atomic clock and continuously broadcasts two things: its own precise orbital position at that moment (ephemeris data) and the exact time it sent the signal. Radio waves travel at a known, constant speed (the speed of light), so:

distance to satellite ≈ speed of light × (receive time − transmit time)

That's called a pseudorange rather than a true range because the receiver's own clock is a cheap quartz oscillator, not an atomic clock — it's off by some unknown amount, so every one of these computed "distances" is off by the same unknown timing error. That error turns out to be solvable rather than a fatal flaw — see why four satellites below.

Trilateration: turning distances into a position

Knowing your distance from one satellite puts you somewhere on a sphere centered on that satellite. Knowing your distance from a second satellite narrows that down to a circle (where two spheres intersect). A third narrows it to (at most) two points — and usually one of those two is obviously wrong (e.g. it's out in space), leaving a single position.

Three satellite range circles intersecting at the receiver's position Sat A Sat B Sat C receiver position
Each circle is "all points this far from that satellite." With clean measurements, three circles meet at one point — the receiver's location.

In reality this happens in three dimensions with spheres, not circles, and the receiver solves it numerically (least-squares, typically) — the picture above is the 2D intuition for what's fundamentally the same idea.

Why (at least) four satellites

A 3D position has three unknowns: x, y, z. That alone would suggest three satellites are enough. But because the receiver's clock error is also unknown and affects every single pseudorange equally, it becomes a fourth unknown — so the receiver needs a fourth independent equation (a fourth satellite) to solve for all four unknowns simultaneously: position and clock bias. This is also, incidentally, how the receiver ends up with an accurate clock of its own — solving for that bias is a byproduct of solving for position at all.

What I learned

With only three satellites and a known, fixed altitude (e.g. sea level), a receiver can still produce a 2D fix by using altitude as the missing constraint instead of a fourth satellite — this is why some receivers report a valid-looking fix with only three satellites tracked, but it's leaning on an assumption rather than solving the problem outright.

GPS time, UTC, and why GNSS makes a great clock

GPS time is a continuous count of seconds since January 6, 1980, with no leap seconds — unlike UTC, which periodically inserts them to stay aligned with Earth's slightly irregular rotation. The navigation message broadcasts the current accumulated offset between GPS time and UTC (currently on the order of eighteen seconds), which is how a receiver converts the raw satellite time it solves for into the UTC timestamp it actually reports.

Because that timestamp is derived from atomic clocks in orbit and corrected as part of the same position solve, it's accurate to tens of nanoseconds — dramatically better than almost any other cheap embedded time source. This is exactly why GNSS receivers are commonly used purely as precision clocks (GNSS-disciplined oscillators), completely independent of anyone actually caring where the receiver physically is.

NMEA 0183: how the position actually reaches you

Most GNSS modules hand off fixes to a microcontroller as plain ASCII text sentences over UART (commonly starting at 9600 baud), following the NMEA 0183 standard. Each sentence starts with $, a two-letter talker ID (GP, GN, ...) plus a three-letter sentence type, comma-separated fields, and ends with * followed by a two-hex-digit checksum.

Layout of a GGA sentence's comma-separated fields $GPGGA UTC time Lat, N/S Lon, E/W Fixquality Satsused HDOP Altitude+ checksum
A trimmed view of $GPGGA — real sentences also carry geoid separation and DGPS fields between altitude and the checksum.
SentenceCarries
GGAFix data: time, latitude/longitude, fix quality, satellite count, HDOP, altitude.
RMC"Recommended minimum": time, date, latitude/longitude, ground speed, course, validity flag — the single most common sentence for "give me a fix."
GSAWhich satellites are being used in the current solution, plus DOP values (position/horizontal/vertical).
GSVSatellites in view and their signal strength — useful for diagnosing a weak-signal environment, not for the fix itself.

See examples for actually parsing one of these out.

Decoding latitude and longitude

NMEA encodes coordinates as DDMM.MMMM — degrees, then minutes with a decimal fraction — not plain decimal degrees, which is the most common gotcha when writing a parser for the first time:

decimal_degrees = degrees + (minutes / 60)
// then negate if the hemisphere field is 'S' or 'W'

For example 4807.038,N is 48 degrees, 07.038 minutes — 48 + 07.038/60 = 48.1173° north.

Fix quality and HDOP

FieldMeaning
Fix quality 0No fix — the rest of the sentence's fields are meaningless.
Fix quality 1Standard GPS fix.
Fix quality 2DGPS-corrected fix — better accuracy via a correction service.
HDOPHorizontal Dilution of Precision — a unitless number describing how much the current satellite geometry amplifies measurement error. Lower is better; satellites clustered close together in the sky (poor geometry) produce a high HDOP even with otherwise clean signals.

Time to first fix

How long a receiver takes to produce its first fix depends heavily on what it already knows:

Hot start
Recent ephemeris, almanac, position, and time are all still valid (e.g. power-cycled seconds ago) — a fix in a few seconds.
Warm start
Approximate position/time and almanac are known, but ephemeris (which expires in a few hours) needs re-downloading — tens of seconds.
Cold start
Nothing usable is stored (first power-up, or moved a long distance while off) — the receiver has to download a fresh almanac from scratch, which can take a few minutes.

Sources of error

Real-world applications

Gotchas

Field notes

→ Code examples for GNSS