macOS · Leo Bodnar LBE-1421

MacGPSDO

Configure and watch a GPS-disciplined clock, natively.

MacGPSDO edits the clock's settings and shows what it is doing. Output frequencies, 1PPS, PLL or FLL, lock state. It also decodes the u-blox receiver inside the box, so you get satellite positions, Allan deviation, the 1PPS quantisation error and front-end health. Every second goes to a local database you can scroll back through.

Download MacGPSDO

macOS 15, Apple silicon. Signed and notarised. No driver needed.

MacGPSDO sky view: satellites from GPS, Galileo and GLONASS on a polar plot with predicted passes
Measured satellite positions, with predicted passes drawn underneath.
0.2°prediction vs. receiver, GPS, Galileo and GLONASS
1 Hzlogged to SQLite on whole seconds, ~8 MB/day
4overlapping estimators: ADEV, MDEV, HDEV, TDEV
5grid formats: Maidenhead-10, H3, Plus Code, Geohash, MGRS
The Movement tab: a skeletonised watch movement whose gears are driven by receiver data
Movement

The instrument as a calibre

Every moving part is driven by something the receiver reports. The escape wheel steps on the 1PPS edge. The balance swings once a second with its amplitude set by the sawtooth. Barrel winding shows satellites in the fix, and the σy hand reads the current stability decade.

The chapter ring around it is the last 24 hours: signal strength on the inner band, discipline on the outer, midnight at the top. Numbers sit outside the dial, where numbers belong.

Stability tab: Allan deviation plotted against averaging time on log-log axes
Stability

Allan deviation

Four estimators run over the logged phase series: ADEV, MDEV, HDEV, TDEV. Slope guides at τ⁻¹ and τ⁻½ sit behind the curves, dot size follows sample count, and the cursor snaps to a computed τ.

A difference counts only when its own timestamps are spaced correctly, so a dropout removes just the differences crossing it. HDEV cancels linear frequency drift, which ADEV reads as noise.

The series is the receiver's clock against GNSS time. Short τ measures receiver noise. Disciplining shows past about 100 s. σy(1 s) here reads 1.0e-8, σy(100 s) 5.0e-10.

Sawtooth tab: the quantisation error of each 1PPS edge over the last half hour
Sawtooth

1PPS quantisation error

Pulses fire on an internal clock edge, landing a few nanoseconds from the intended time. The receiver reports that offset per pulse. Applying it takes a ±20 ns edge down to sub-nanosecond.

Logged alongside everything else, so it also reads as a trace over days.

History tab: several logged quantities over time with a cursor readout
History

Scroll back through the log

Drag pans, scroll zooms about the pointer, double-click returns to live. Nine quantities are selectable: clock bias and drift, sawtooth, time accuracy, signal, satellites, geometry, front-end gain, interference. Each keeps its own vertical scale.

SQL decimation returns roughly one point per pixel column, so a thirty-day window costs what five minutes does. Bucket contents are averaged. Sawtooth carries min and max. Lock states take the worst value in the bucket, so a one-second dropout inside a five-minute bucket still appears.

Passes tab: a translucent sky dome with satellite tracks over a compass ring
Passes

Where the satellites will be

Orbits come from the navigation message the receiver forwards. GPS and Galileo broadcast Keplerian elements. GLONASS broadcasts state vectors, integrated here with fourth-order Runge-Kutta. The GPS almanac covers satellites this antenna has never tracked.

Agreement with the receiver's own orbit model runs at 0.2°, its reporting resolution. Four hours of each pass draws under the measured trails. A satellite predicted above 12° with nothing received gets a ring.

Dome tab: obstruction map drawn as pegs on a hemisphere
Obstructions

What the antenna cannot see

Signal strength accumulates in 5°×5° cells. After a few hours the antenna pattern emerges, each cell compared against the median of its elevation ring so low-angle roll-off stays out of the result.

Blocked sky yields no samples, which looks the same as sky nothing has crossed. Prediction resolves it. Cells expected at least three times with nothing received are marked blocked.

Waterfall tab: per-satellite carrier-to-noise history as a colour waterfall
Signal

Carrier-to-noise

Live bars per satellite, a 5°×5° sky map of mean C/N₀, and a per-satellite waterfall. The colour scale auto-ranges over visible data, putting the top of the ramp at your strongest satellite. A checkbox fixes it at 12…48 dB-Hz for comparison between sessions.

RF health tab: jamming indicator, AGC and broadband noise plotted over the last hour
RF health

Interference and antenna faults

Front-end gain, broadband noise, jamming state, antenna line. A rising interference indicator with falling C/N₀ points at interference. An AGC jump with a dead antenna line points at the cable or the bias-T. Satellite count alone separates neither.

MacGPSDO enables the receiver's interference monitor (CFG-ITFM) at connect, which is what gives its jamming state meaning. Left disabled, the raw indicator free-runs.

Locks tab: GPS, PLL, antenna and fix state over time with an alarm log
Discipline

Lock history

GPS lock, PLL lock, antenna and 3D fix show as bands over time, with dropouts listed below. Alarms hold down before firing: a few seconds to raise, fifteen to clear. Lock bits flicker, and an alert per flicker gets ignored.

Every transition is written to the database, so "the antenna was open for six minutes at 04:12" outlives the notification.

Clock tab: large UTC display with GPS week, leap seconds, sun and moon
Clock

Time, sun and moon

UTC in large type, with local time, the receiver's own UTC, and the offset of the Mac's clock beneath it. GPS week, 10-bit week, rollover count, time of week, leap seconds with any announced change counted down, MJD, day of year, sidereal time.

Sun position matches pyephem to 0.01°. Moon matches to 0.3°, once topocentric parallax is applied.

World tab: day and night across a world map with real time zone boundaries
World

Daylight and time zones

Day and night come from the solar position, with the subsolar point and your station marked. Zone boundaries ship as data from timezone-boundary-builder, tinted by UTC offset. China's single zone spanning five nominal ones appears at its real extent.

Twelve cities run local time alongside, each matching its dot on the map.

Signal map tab: mean carrier-to-noise per sky cell drawn as annular sectors
Position

Grid references

Maidenhead to ten characters, H3 cell, Plus Code, Geohash, MGRS. Click any row to copy it. Every encoder is checked against its reference implementation: H3 against Uber's library across resolutions 0-15, MGRS against pyproj, Plus Codes against the OLC test vectors.

A running survey averages the fix and reports scatter, which measures multipath better than the receiver's own accuracy figure.

Hardware

What it talks to

LBE-1421developed and tested on this unit
LBE-1420, LBE-1423same settings protocol, untested
mini GPS Reference Clockunsupported, different protocol

Settings ride on the device's USB HID interface. Satellite data comes from the u-blox M8 inside it, over a stream worked out by listening. Leo Bodnar Electronics publishes an official macOS app on the App Store. This is a separate project with no affiliation or endorsement.

Also

Beyond the panels

  • Telemetry server: JSON at 1 Hz over TCP, or one object over HTTP, so another machine can record whether the reference was disciplined
  • CSV export: the full log, for other tools
  • Log replay: open an archived database from another run or machine
  • Alarms: holdover, antenna fault, interference, with an event log that survives restarts
  • Command-line probe: GPSDOProbe covers settings, message survey, ephemeris check and the encoders
  • Light and dark: the whole instrument face, either way
Download

Current build

MacGPSDO.dmg

macOS 15, Apple silicon. Signed and notarised. The clock presents as a vendor HID interface plus a serial port, so nothing has to be installed alongside it.

Credits

Built on

  • H3: Uber's hexagonal index, vendored under Apache-2.0
  • OpenStreetMap: map tiles, © OpenStreetMap contributors (ODbL)
  • timezone-boundary-builder: zone boundaries derived from OSM data (ODbL), simplified for drawing
  • bvernoux/lbe-142x and hamarituc/lbgpsdo: documented the HID settings protocol; reimplemented here in Swift