Build a GPS-Disciplined Oscillator (GPSDO) for Precision Timing and Frequency Reference
- u-blox NEO-M8N or NEO-7M GPS module with PPS output
- GPS active antenna with SMA connector
- 10MHz OCXO module, voltage-controlled (VCOCXO), 3.3V or 5V
- ESP32 or Raspberry Pi Pico development board
- MCP4725 or similar 12-bit I2C DAC module
- 0.96 inch I2C OLED display module
- Precision voltage reference IC, e.g. LM4040 or REF5040
- Low-noise linear voltage regulator module (LDO), 5V and 3.3V rails
- SMA female bulkhead connector for the 10MHz output
- Small aluminum diecast enclosure
- 50-ohm coaxial jumper cables, SMA to SMA
- Perfboard or protoboard for point-to-point wiring
A GPS-disciplined oscillator, or GPSDO, uses the extremely stable timing signal broadcast by GPS satellites to continuously correct a local crystal or oven-controlled crystal oscillator (OCXO), producing a frequency reference accurate to a few parts in 10^11 — orders of magnitude better than a free-running crystal, and traceable to the atomic clocks onboard the GPS constellation itself. This project builds a standalone GPSDO with a 10MHz reference output, useful for calibrating test equipment, disciplining a ham radio transceiver's internal reference, feeding a frequency counter, or just satisfying the itch to build something genuinely precise. It pairs well with the site's Build a Stratum 1 NTP Time Server project if you want both frequency and time-of-day references from the same GPS antenna feed.
How It Works
A cheap GPS module outputs a Pulse-Per-Second (PPS) signal that is extremely accurate on average but jittery pulse-to-pulse. A GPSDO does not use PPS to directly generate the output frequency; instead, a microcontroller compares the local oscillator's frequency against the PPS reference over a sliding window (typically tens of seconds to a few minutes), calculates the accumulated drift, and feeds a slow correction back into the oscillator — either as an analog tuning voltage (for a voltage-controlled OCXO) or as a digital control word (for a DAC-controlled design). Averaging over a long window is what turns the noisy single-pulse PPS signal into a smooth, highly stable long-term frequency standard.
Difficulty and Time
This is an intermediate build: no exotic RF design skills are required, but you will be working with a PID-style control loop in firmware and need a way to verify the result (a frequency counter or a second reference to compare against). Budget a full weekend: one session for wiring and enclosure work, a second for firmware tuning and initial lock, and then several days of the unit running in the background while you check long-term stability.
Parts List
- - [u-blox NEO-M8N or NEO-7M GPS module with PPS output](https://www.amazon.com/s?k=u-blox+NEO-M8N+GPS+module+PPS&tag=42308b-20)
- - [GPS active antenna with SMA connector](https://www.amazon.com/s?k=GPS+active+antenna+SMA&tag=42308b-20)
- - [10MHz OCXO module, voltage-controlled (VCOCXO), 3.3V or 5V](https://www.amazon.com/s?k=10MHz+OCXO+voltage+controlled+oscillator+module&tag=42308b-20)
- - [ESP32 or Raspberry Pi Pico development board](https://www.amazon.com/s?k=ESP32+development+board&tag=42308b-20)
- - [MCP4725 or similar 12-bit I2C DAC module](https://www.amazon.com/s?k=MCP4725+I2C+DAC+module&tag=42308b-20)
- - [0.96 inch I2C OLED display module](https://www.amazon.com/s?k=0.96+inch+I2C+OLED+display+module&tag=42308b-20)
- - [Precision voltage reference IC, e.g. LM4040 or REF5040](https://www.amazon.com/s?k=precision+voltage+reference+LM4040&tag=42308b-20)
- - [Low-noise linear voltage regulator module (LDO), 5V and 3.3V rails](https://www.amazon.com/s?k=low+noise+LDO+voltage+regulator+module&tag=42308b-20)
- - [SMA female bulkhead connector for the 10MHz output](https://www.amazon.com/s?k=SMA+female+bulkhead+connector&tag=42308b-20)
- - [Small aluminum diecast enclosure](https://www.amazon.com/s?k=aluminum+diecast+enclosure+project+box&tag=42308b-20)
- - [50-ohm coaxial jumper cables, SMA to SMA](https://www.amazon.com/s?k=SMA+to+SMA+coaxial+jumper+cable&tag=42308b-20)
- - [Perfboard or protoboard for point-to-point wiring](https://www.amazon.com/s?k=perfboard+protoboard+prototype+circuit+board&tag=42308b-20)
Build Steps
1. Wire the GPS Module and Verify PPS Lock
Connect the GPS module's UART TX/RX to your microcontroller and power it from a clean 3.3V rail. Route the module's PPS output to a GPIO pin configured for interrupt-on-rising-edge. Before wiring anything else, confirm the module achieves a 3D fix outdoors or near a window with sky visibility, and that your firmware correctly counts PPS interrupts (you should see exactly one interrupt per second, with the GPS module's NMEA output confirming satellite count and fix quality).
2. Wire the OCXO and DAC
Most low-cost VCOCXOs accept a 0-5V (or 0-3.3V) tuning voltage on an EFC (Electronic Frequency Control) pin, with the tuning range typically specified in parts-per-million across that voltage range. Wire the DAC's output through a simple RC low-pass filter (a few kΩ and a few hundred nF is enough) into the EFC pin — this filtering matters, because DAC quantization steps translate directly into frequency jitter if the correction voltage is not smoothed. Power the OCXO from a clean, well-regulated rail; oven-controlled oscillators draw meaningfully more current during warm-up (often 500mA-1A for the first few minutes) than at steady state, so size your supply accordingly.
3. Implement the Discipline Loop
The firmware loop is conceptually simple but the tuning constants matter: count a windowed number of the OCXO's output cycles (you'll need to either divide the 10MHz output down to something your microcontroller can count directly, or use a dedicated counter/timer peripheral) gated by the PPS pulse, compare against the expected count, and adjust the DAC output by a small, slowly-changing correction. Use a long integration time (60-100 seconds) once initial lock is achieved; the entire point of averaging over a long window is trading response speed for stability, which is exactly what you want from a reference clock as opposed to a fast control loop like a 3D printer's PID-tuned hotend.
4. Add Status Display and Output Buffering
Drive the OLED with GPS fix status, satellite count, current DAC correction value, and a rough estimate of parts-per-billion error so you can watch the loop converge in real time. Buffer the OCXO's sine or square wave output through a simple transistor or logic buffer stage before the SMA output connector so that whatever you connect the reference to cannot load down or detune the oscillator itself.
5. Verify Long-Term Stability
Let the unit run for at least 24 hours after achieving GPS lock before trusting the output. Compare it against a known-good reference if you have access to one (a frequency counter with a rubidium or GPSDO reference of its own, or simply zero-beating it against WWV/WWVH on 10MHz using a shortwave receiver like the ATS Mini V4, which is a genuinely useful low-cost sanity check for a homebrew 10MHz reference).
Safety Notes
This build runs at low voltage (typically 5V/3.3V logic and DC power) with no significant electrical hazard, but OCXO modules run warm continuously by design — mount them with some airflow clearance inside the enclosure rather than pressed against a wall, and avoid enclosing the unit in anything sealed and non-vented if you live somewhere with high ambient temperatures. As with any GPS antenna installation, keep the coax run reasonably short or use an inline amplifier if running more than a few meters of cable to an outdoor antenna.
Once running and disciplined, this reference is genuinely useful well beyond a novelty: it turns a basic frequency counter into a calibration-lab-grade instrument, lets you verify the actual output frequency of any oscillator-based project on the bench (including checking whether that "10MHz" crystal in a junk-bin module is actually anywhere close), and gives licensed ham operators a legitimately traceable reference for calibrating rig frequency displays without sending anything off to a cal lab.