How GPS Actually Works

A working understanding of satellite navigation, built from nothing. Every idea here arrives with something you can drag, scrub or break: a live constellation propagating real orbital mechanics, a fix you assemble one satellite at a time, a genuine C/A code correlator pulling a satellite out of noise three times louder than it is.

TypeScript Orbital Mechanics Least Squares Signal Processing three.js

1 · It is a stopwatch problem

Strip away the acronyms and GPS is one idea repeated four times. A satellite broadcasts, in effect, a single sentence: the time is now T, and here is where I am. Your receiver hears it, notes the time of arrival, and subtracts. The difference is how long the message spent in flight, and since radio travels at the speed of light, that duration is a distance.

ρ  =  c(treceivedtsent)\rho \;=\; c \,\bigl(t_{\text{received}} - t_{\text{sent}}\bigr)

Knowing a distance to a known point puts you on a sphere. Repeat with a second satellite and you are on the circle where two spheres meet; a third narrows it to two points, one of which is absurd. That is the entire geometric content of the system, and it would be a solved problem in an afternoon were it not for the factor of c.

Because c is enormous, timing errors are punished brutally. Light crosses 29.98 cm in a nanosecond. A microsecond — a rounding error for most software — is three hundred metres. Drag the slider and watch an interval you would never think about become a distance you certainly would.

1.00 ns of timing error
30.0 cm of position error
1 ps1 ns1 µs1 ms

≈ one nanosecond of light

What a free-running clock would cost you

If the receiver had to keep time by itself, its drift would become range error at the speed of light. After one hour untethered:

quartz wristwatch drifts a second a fortnight 1.08e+3 km
oven-controlled quartz a good receiver reference 108 m
rubidium (GPS block IIF) flying today 10.8 cm
caesium (GPS block II) the classic choice 1.08 cm

Even the best of these would need help. The receiver's escape is that it never tries: it treats its own clock offset as a fourth unknown and solves for it, which is why a $2 quartz oscillator in a phone can produce nanosecond-grade timing it has no business producing.

This is the single most useful intuition to carry through the rest of the page: GPS is a clock problem wearing a geometry problem's clothes. Atomic standards in orbit, relativistic corrections, a fourth satellite you would not otherwise need — all of it exists to control a term that gets multiplied by 300 million.

2 · Where the satellites are

The receiver's half of the sentence — here is where I am — is only useful if the satellite's position is genuinely knowable in advance. It is, because orbits are among the most predictable things in engineering. A satellite in vacuum follows Kepler's laws, and its period depends on one number:

T  =  2πa3μ,μ=GMT \;=\; 2\pi\sqrt{\dfrac{a^{3}}{\mu}}, \qquad \mu = GM_{\oplus}

GPS runs that backwards. The designers wanted a period of half a sidereal day — 11 hours 58 minutes, not 12, because the relevant day is the Earth's rotation against the stars, not against the Sun. Two orbits per rotation means each satellite retraces the same ground track every day, which makes coverage predictable and station-keeping cheap. Solving for the semi-major axis gives 26,560 km, an altitude of about 20,180 km.

That altitude is a deliberate compromise. Lower orbits sweep small footprints and need hundreds of satellites; geostationary orbit is too far north-south blind to serve the poles and gives dreadful vertical geometry. At 20,180 km a single satellite is above the horizon for roughly 38% of the Earth's surface at once:

ψ  =  arccos ⁣(Rrcosε)ε  =  76.1 at ε=0\psi \;=\; \arccos\!\left(\frac{R_{\oplus}}{r}\cos\varepsilon\right) - \varepsilon \;=\; 76.1^{\circ} \ \text{at}\ \varepsilon = 0

Twenty-four of those, spread over six orbital planes inclined 55° and spaced 60° apart in longitude, is the baseline constellation. The phasing within each plane is famously uneven — the published slot table is a list of awkward numbers like 268.126° and 11.676° — because even spacing optimises a single plane in isolation while GPS was optimised for the worst geometry anywhere on Earth. Those awkward numbers are the fingerprint of a global optimisation, and they are the ones propagating below.

building the constellation…
drag to orbit · click the globe to move the observer · click a satellite
00:00:00
observer 41.88°, -87.63°
in view 0 / 24
HDOP
VDOP
footprint 71.2° · 34%

Each faint disc is one satellite's footprint — where it brightens, more satellites overlap. Click a satellite to isolate its own.

Drag to orbit. Each faint disc is one satellite's footprint; where discs overlap the surface brightens, so the glow is literally a map of how many satellites reach each place. Click the globe to move the observer, click a satellite to isolate it. The two dashed parallels at ±55° are the highest latitudes any GPS satellite ever passes directly over — which is why polar users see plenty of satellites but never one at the zenith.

The design target was four satellites visible anywhere, always. Propagating this constellation over a full sidereal day and sampling every two minutes, the realised numbers are more generous: never fewer than six in view at Chicago, Quito, Reykjavík, Sydney or the pole, typically eight to nine, and horizontal geometry never worse than 1.9 on the scale introduced in section 6. The margin is deliberate — satellites fail, and the constellation is supposed to survive it.

3 · One satellite at a time

Now put the two halves together and watch a position appear. The demo below drops a dimension — it works in the plane rather than in space — because every counting argument survives the simplification and the pictures become drawable. Two dimensions means two unknowns of position, so each conclusion here maps onto the real thing with one added to every number.

Start in perfect clock mode with one station and step upward. One range leaves you on a circle. Two leave two candidate points. Three pick one. Drag the stations around and the conclusion holds regardless of where they sit, which is the point: trilateration is not fragile, it is just underdetermined until it isn't.

stations

One range: you are somewhere on this circle.

The green dot is where the receiver truly is; drag it, or drag the numbered stations. In three dimensions the same argument needs three satellites, because two spheres meet in a circle and three meet at two points — one of which is out in space and can be discarded on sight.

4 · The clock you do not have

Everything so far assumed the receiver knows what time it is. It does not, and it cannot. The satellites carry caesium and rubidium standards worth more than the car you would put a receiver in; your phone has a quartz crystal that is off by microseconds within seconds of being disciplined — which, from section 1, is kilometres.

So the measurement is not a range. It is a range plus an unknown common offset, which is why it has its own name — the pseudorange:

ρi  =  xxitrue range  +  cδtclock offset\rho_i \;=\; \underbrace{\lVert \mathbf{x} - \mathbf{x}_i \rVert}_{\text{true range}} \;+\; \underbrace{c\,\delta t}_{\text{clock offset}}

The saving grace is in that word common. A clock error does not corrupt each measurement independently; it adds the identical bias to every one. So it is not really noise, it is a fifth quantity to be determined — and a quantity you can solve for is a quantity you do not need hardware for.

Switch the demo to unknown clock. Now two stations no longer leave two candidate points; they leave an entire curve. Sweep the assumed-offset slider and watch the intersection slide along it. That curve is a hyperbola, and its appearance is not a coincidence: subtract two pseudoranges and the clock term cancels exactly, leaving a constant range difference — the defining property of a hyperbola with the two stations as foci.

ρiρj  =  xxixxj\rho_i - \rho_j \;=\; \lVert \mathbf{x} - \mathbf{x}_i \rVert - \lVert \mathbf{x} - \mathbf{x}_j \rVert

This is the operating principle of every hyperbolic navigation system built since the 1940s, LORAN included. Add the third station and the curves intersect: position and time, together, from measurements that individually knew neither. The residual plot under the slider is the same fact drawn differently — it shows how badly the circles fail to concur at each assumed offset, and it has exactly one minimum.

Restore the third dimension and the count goes up by one. Three unknowns of position, one of time, four equations needed. That is the whole reason GPS asks for four satellites rather than three: the fourth is not buying you position, it is buying you a clock.

5 · Actually solving it

Four equations, four unknowns — but the equations are nonlinear, because a distance is a square root. There is a closed-form solution (Bancroft's, which is elegant and worth looking up), but essentially every receiver in the world does something simpler: guess, linearise, correct, repeat.

Linearising is a matter of asking how each pseudorange responds to a small nudge in the estimate. Nudging the receiver along the line of sight to a satellite changes that range one-for-one; nudging it perpendicular barely changes it at all. So the derivative is just the unit vector pointing at the satellite, and the clock enters every row identically:

G  =  [u^1T1u^2T1u^nT1],Δx  =  (GTG)1GTΔρ\mathbf{G} \;=\; \begin{bmatrix} -\hat{\mathbf{u}}_1^{\mathsf T} & 1 \\ -\hat{\mathbf{u}}_2^{\mathsf T} & 1 \\ \vdots & \vdots \\ -\hat{\mathbf{u}}_n^{\mathsf T} & 1 \end{bmatrix}, \qquad \Delta\mathbf{x} \;=\; \bigl(\mathbf{G}^{\mathsf T}\mathbf{G}\bigr)^{-1}\mathbf{G}^{\mathsf T}\,\Delta\boldsymbol{\rho}

With more than four satellites the system is overdetermined and the same expression becomes a least-squares fit, which is strictly better — extra satellites average down noise rather than going to waste. Weighting the rows by measurement quality (low satellites get trusted less) turns it into weighted least squares, which is what a good receiver actually runs.

The remarkable part is how forgiving it is. Seeding the solver in this project at the centre of the Earth — about as wrong as an initial guess can be — the correction steps shrink like this:

7,400 km1,000 km20 km8.5 m1.6 µm

Five iterations from a hopeless start to sub-micrometre agreement, recovering the clock offset exactly along the way. Roughly quadratic convergence, because the problem is only mildly nonlinear over the distances involved: from 20,000 km away, the curvature of a sphere across the width of your uncertainty is almost nothing. In practice a receiver seeds from its last known position and converges in one or two.

Press solve in the demo above to watch the same thing happen in the plane — the green track is the sequence of estimates, walking in from the centroid of the stations.

Do it a few times with three stations and eventually the solver will announce that it landed somewhere other than where you are, with residuals of zero. That is not a bug and not a numerical accident: the minimum number of measurements generally admits two solutions, both fitting the data exactly. It is the same algebra that gives the four-satellite problem in three dimensions a pair of roots. Real receivers resolve it by inspection, because one root lands near the Earth's surface and the other is thousands of kilometres out in space — but the ambiguity is genuinely there, and a fifth satellite is the principled way to kill it rather than the eyeball.

6 · Geometry is a multiplier

Two receivers with identical hardware, identical atmospheres and identical measurement noise can produce wildly different accuracy, because accuracy depends on where the satellites are. Four satellites clustered in one patch of sky triangulate about as well as four surveyors standing on the same hilltop.

That effect has a name and a number. Take the geometry matrix from the previous section, form the covariance factor, and read off its diagonal:

Q  =  (GTG)1,HDOP=Qee+Qnn,VDOP=Quu\mathbf{Q} \;=\; \bigl(\mathbf{G}^{\mathsf T}\mathbf{G}\bigr)^{-1}, \qquad \text{HDOP} = \sqrt{Q_{ee} + Q_{nn}}, \quad \text{VDOP} = \sqrt{Q_{uu}}

Note what is absent: no measured values appear anywhere. DOP is a pure function of satellite directions, which is why a receiver can report expected accuracy before it has finished computing a position, and why mission planners can predict a survey's quality days ahead. The final error is then a single multiplication — range error times geometry.

5 satellites
GDOP
2.65
PDOP
2.33
HDOP
1.42
VDOP
1.85
TDOP
1.26
horizontal geometry: excellent

7.1 m horizontal, 1σ — that is HDOP × σ, the whole error budget in one multiplication.

Drag satellites around the skyplot. Try the clustered and street canyon presets and watch the error ellipse turn into a blade — the long axis always points the way the satellites failed to cover.

Two things fall out of playing with it. First, VDOP is always worse than HDOP for a ground receiver, without exception, and the reason is structural rather than accidental: horizontal accuracy benefits from satellites on opposite sides of you, but nothing ever transmits from beneath your feet. Every satellite is in the upper hemisphere, so the vertical direction is always sampled one-sidedly. This is why your phone's altitude is so much worse than its street position, and why aviation needed an entire augmentation system before GPS could be trusted for approaches.

Second, adding satellites helps quickly and then stops. Going from four to five is a large improvement; going from ten to eleven is nearly nothing. Geometry saturates once the sky is reasonably covered — which is the real argument for multi-constellation receivers, and it is not the one people usually give. Thirty visible satellites are not thirty times better than four. They are worth having because in a city you will only actually see six of them.

7 · Finding a signal under the noise

A detail quietly skipped so far: how does the receiver know when the signal was sent, and how does it hear anything at all? By the time a 27-watt transmission has crossed 20,000 km, it arrives roughly 20 dB below the thermal noise floor — a hundred times weaker than the static it is buried in. A spectrum analyser pointed at the GPS band sees noise.

The trick is that the signal is not weak so much as spread. Each satellite multiplies its data by a unique 1023-chip pseudorandom sequence — a Gold code — transmitted at 1.023 million chips per second, repeating every millisecond. The receiver generates the same sequence locally and slides it against the incoming samples, and at the right alignment 1023 chips add coherently while the noise, being noise, does not.

The codes are built from two ten-stage shift registers, tapped differently per satellite, and their defining property is that any two are almost orthogonal. For the 1023-chip family the off-peak correlations take exactly three values — −65, −1 and +63, over 1023 — while the correct alignment gives 1. A factor of sixteen separates signal from everything else, by construction.

The correlator below is the real thing: genuine Gold codes generated from the IS-GPS-200 polynomials, verified against the specification's published code table for all 32 satellites. Turn the noise up to 3× and look at the top trace, which is what the antenna sees. Then look at the peak.

Locked. Peak at lag 311 — exactly the true delay, standing 3.6× above the next-highest sidelobe.
one chip293.1 m
code repeats every1 ms = 300 km
peak height0.932
worst sidelobe0.259

Two experiments worth running. Add interfering satellites and watch the peak refuse to move — that is code-division multiple access, and it is why every GPS satellite can share one frequency. Then set the receiver to look for a different PRN than the one transmitting, and watch the peak disappear entirely.

Finding the peak to the nearest chip locates the signal to 293 metres, which would be a disappointing GPS. Receivers do far better by tracking the correlation peak's shape — comparing correlators placed slightly early and late and steering to balance them — routinely resolving to about 1% of a chip, or a few metres. Carrier phase does better still, and that is section 10.

Two consequences worth noting. The code repeats every millisecond, so on its own it is ambiguous every 300 km; the resolution comes from the navigation message modulated on top at a leisurely 50 bits per second, which carries the time-of-week, the satellite's own clock corrections, and the orbital elements the receiver needs to compute where the transmitter was. That 50 bps is why a cold receiver takes 30 seconds or more to produce a first fix — it is not computing, it is waiting for the paperwork, and it is exactly what assisted GPS eliminates by delivering the ephemeris over the network instead.

8 · Everything that goes wrong

A perfect measurement of an imperfectly known quantity is still wrong. Between the satellite's clock and the receiver's correlator, the range picks up errors from half a dozen sources, and the standard bookkeeping is to treat each as an independent contribution to one satellite's pseudorange, combine them in quadrature into the User Equivalent Range Error, and multiply by the geometry factor from section 6.

σUERE=kσk2,σhorizontal=HDOP×σUERE\sigma_{\text{UERE}} = \sqrt{\textstyle\sum_k \sigma_k^2}, \qquad \sigma_{\text{horizontal}} = \text{HDOP} \times \sigma_{\text{UERE}}

Quadrature has a blunt practical consequence: the largest term dominates and the small ones are nearly free. With a five-metre ionospheric error present, driving receiver noise from half a metre to zero improves the total by under a centimetre. Chase the big term or do not bother.

Range error budget, 1σ

5.00 m 72%

Free electrons slow the code and advance the carrier. The delay scales as 1/f^2, so two frequencies measure it directly and cancel it — the single largest reason L5 exists. Mitigation: dual-frequency.

0.50 m 1%

Neutral air, so no frequency dependence and no dual-frequency escape. A dry component that models beautifully from surface pressure, and a wet one that does not — water vapour is why the last centimetres are hard. Mitigation: model + estimate.

2.00 m 12%

The broadcast ephemeris is a curve fit valid for a couple of hours. Post-processed IGS orbits are two orders of magnitude better, which is what makes centimetre-level PPP possible. Mitigation: precise orbits.

2.00 m 12%

Even a caesium standard drifts. The navigation message carries polynomial corrections; the residual after applying them is what is left here. Mitigation: precise clocks.

1.00 m 3%

Reflections arrive late and bias the correlation peak. The one error source that is local, unmodellable, and immune to differential correction — see the Urban Canyon project. Mitigation: choke ring / good siting.

0.50 m 1%

Thermal noise in the correlator. Small, and the only term that improves simply by averaging longer. Mitigation: narrow correlator.

UERE 5.87 m
horizontal error, 1σ 7.05 m
95% of the time, within 17.3 m

The 95% figure uses the 2-D Rayleigh factor of 2.45, not 1.96 — a horizontal error has two components, and the radius containing 95% of a circular bivariate normal is wider than the one-dimensional interval people usually reach for.

Toggle mitigations and watch the total. Removing the ionosphere alone does more than perfecting everything else combined.

The ionosphere is the big one, and it is also the most elegantly defeated. Free electrons delay the code by an amount that depends on frequency:

Δiono  =  40.3TECf2\Delta_{\text{iono}} \;=\; \frac{40.3\,\text{TEC}}{f^{2}}

Because that 1/f² is exact rather than empirical, a receiver listening on two frequencies gets two equations in two unknowns and can eliminate the ionosphere outright instead of modelling it. This is the entire reason GPS broadcasts on L1, L2 and L5, and the reason a dual-frequency receiver is categorically — not incrementally — better. It is not free: the ionosphere-free combination weights the two measurements by about +2.55 and −1.55, so uncorrelated noise comes out three times larger. Trading a five-metre bias for a one-and-a-half-metre noise increase is an easy trade, and everyone makes it.

The troposphere offers no such escape. Neutral air is non-dispersive, so both frequencies are delayed identically and differencing gains nothing. The dry component is about 2.3 m at the zenith and models beautifully from surface pressure; the wet component is small but stubborn, because water vapour is patchy and unpredictable. Everything hard about the last centimetre of GNSS is, ultimately, weather.

Multipath is the awkward one: signals arriving via reflection are late, biasing the correlation peak, and being purely local they cannot be differenced away by any reference station. It is the error that survives every mitigation on this list — and the subject of a companion project that ray-traces it through real Manhattan geometry, linked at the end.

9 · Relativity, unavoidably

GPS is the standard example of relativity mattering in ordinary engineering, and unusually for a standard example, it is true. Two effects act on an orbiting clock in opposite directions.

Special relativity: the satellite is moving at 3,874 m/s, so its clock runs slow by v²/2c² — about 7.2 microseconds a day. General relativity: it also sits higher in the Earth's gravitational well, where time passes faster, gaining about 45.7 microseconds a day. They do not cancel. Gravity wins by roughly six to one:

Δff  =  v22c27.2 μs/day  +  μc2 ⁣(1R1r)+45.7 μs/day  =  +38.4 μs/day\frac{\Delta f}{f} \;=\; \underbrace{-\frac{v^{2}}{2c^{2}}}_{-7.2\ \mu\text{s/day}} \;+\; \underbrace{\frac{\mu}{c^{2}}\!\left(\frac{1}{R_{\oplus}} - \frac{1}{r}\right)}_{+45.7\ \mu\text{s/day}} \;=\; +38.4\ \mu\text{s/day}

Thirty-eight microseconds a day sounds negligible until it meets the speed of light: it is 11.5 kilometres of range error per day. GPS would be useless within two hours and comically wrong by the weekend.

The fix is disarmingly simple. Because the shift is a known constant for a known orbit, the clocks are detuned before launch: rather than 10.23 MHz they are set to 10.22999999545 MHz, so that once in orbit, viewed from the ground, they tick at exactly the right rate. The correction is built into the hardware and needs no ongoing intervention. (A small residual remains for orbital eccentricity, since a slightly elliptical orbit varies in both speed and altitude; receivers apply that one in software, and it is worth up to about 45 nanoseconds.)

Both effects depend only on orbital radius, which means there is an altitude where they cancel exactly. Setting v²/2c² equal to the potential term and using v² = μ/r for a circular orbit collapses to r = 1.5 R — about 3,190 km up. Below it, clocks lose time; above it, they gain. The ISS is below and runs slow; GPS is far above.

special relativity — motion slows the clock general relativity — altitude speeds it up net
altitude 20182 km
special relativity -7.21 µs/day
general relativity +45.65 µs/day
net +38.44 µs/day
range error if ignored 11.5 km/day

Hover to read any altitude. At GPS altitude the net is +38.4 µs/day, which is 11.5 km/day of range error — so the caesium and rubidium standards are set to 10.23000000 MHz before launch instead of a round 10.23, and arrive in orbit ticking correctly as seen from the ground.

Hover anywhere to read the two effects and their sum at that altitude. The crossover is a genuine null, not an artefact of the plot.

10 · From metres to millimetres

Everything above describes the standard service: a few metres, from code measurements, alone. Getting to centimetres means exploiting two further ideas.

The first is that most errors are shared. Two receivers a few kilometres apart see the same satellites through nearly the same atmosphere with the same orbit and clock errors. Differencing their measurements cancels almost everything correlated, leaving only the genuinely local terms. That is differential GPS, and with a reference station at a surveyed point it takes metres to decimetres.

The second is the carrier phase. The receiver has been tracking a 1.023 MHz code whose chips are 293 m long; underneath it is a 1575.42 MHz carrier whose wavelength is 19 centimetres. Tracking that to a hundredth of a cycle means measuring range to about two millimetres — four orders of magnitude better than the code.

The catch is that a phase measurement only tells you the fractional part of the cycle. How many whole 19 cm wavelengths lie between you and the satellite is unknown, and it is an integer. Resolving those integers — the ambiguity resolution problem, solved by methods like LAMBDA — is what real-time kinematic positioning does, and once the integers are fixed the phase measurements become ranges good to millimetres. RTK is why a surveyor's pole and a farm tractor can both hold a line to a couple of centimetres.

Precise point positioning takes a different route to the same place: instead of a nearby reference station, it uses precisely computed satellite orbits and clocks published after the fact, reaching centimetres anywhere on Earth without local infrastructure, at the cost of a convergence period. Wide-area augmentation systems like WAAS and EGNOS split the difference, broadcasting corrections from geostationary satellites — enough to make GPS safe for aircraft approaches, which is exactly the vertical-accuracy problem section 6 predicted.

And GPS is now one system among several. Galileo, GLONASS and BeiDou broadcast comparable signals, and a modern receiver tracking all four sees thirty or more satellites at once. As section 6 argued, that is not thirty times the accuracy — geometry saturates. It matters because in a street canyon, under trees, or beside a building, you will only see a handful of them, and which handful is no longer a matter of luck.

Where to go next

The one error source that resists every technique above is multipath: purely local, uncorrelated between receivers, invisible to differential correction. If you want to see what it actually does to a fix, GPS Urban Canyon ray-traces satellite visibility and facade reflections through 2,000 real Manhattan building footprints, using real IGS precise orbits, and computes the position error that results — the concrete version of the abstraction this page ends on.

Everything on this page computes in your browser from first principles. The constellation is the published 24-slot baseline propagated with Keplerian motion plus J2 nodal regression (−0.039°/day); the C/A codes are generated from the IS-GPS-200 shift-register polynomials and match the specification's published code table for all 32 satellites; the solver is Gauss-Newton least squares with the same geometry matrix a receiver builds. It is idealised in one deliberate respect — the orbits are the design constellation rather than today's live broadcast ephemeris — because the goal here is to show the geometry the system was designed to produce, not to navigate you home.