NTP with GPS and PPS working without network clock

Is it possible to have a PPS disciplined NTP server without a network reference clock or network connection?

While doing some camera synchronisation and timestamp testing, I setup a Raspberry Pi NTP server with PPS using an Adafruit GPS hat so that I could sync my cameras’ time to NTP, trigger them using the PPS signal, generate UTC timestamps and check the timestamps against the expected UTC second boundaries.

As part of this the question once again arose – Can I configure an NTP server with GPS time and PPS without having to configure a network reference clock along with the GPS and PPS sources?  This was important as my test setup didn’t have access to an external network, and yet I wanted typical NTP offsets of < 100us.

Well with quite a bit of messing I finally got it working, at this stage there are lots of pages that detail how to setup a Pi as an NTP server with PPS, some mention that you must have a network reference and some mention that you don’t – I had to do a lot of digging and a lot of messing to get to the bottom of things.

Amusingly, NTP configuration is something that ChatGPT is simply terrible at – don’t use it for this, it will just waste your time!

I had lots of problems, but the 2 most persistent was:

  1. The PPS source being marked as a false ticker (with an x to its left in the ntpq -p output)
  2. The PPS source not being referenced at all, “when” would remain at “-“

For ages, I lurched between problems 1 and 2…

Eventually I got it working for my setup.  The trick to get it working for me is that:

  • I needed 3 reference clocks in my setup for the PPS source to be used: PPS time, GPS time and a 3rd reference, normally this is a network NTP server but I found that configuring the local clock ( worked instead.
  • I needed to be careful with my stratum settings, what worked for me was to put the local clock at stratum 15, GPS at stratum 10 and PPS at stratum 0.
  • Marked the PPS source as prefer (and not the GPS source as is often recommended?)

My working configuration:

tos mindist 0.500
# Local Clock
fudge stratum 15
# GPS/NMEA Source from Hat
server minpoll 4 maxpoll 4 prefer iburst
fudge time1 0.000 refid GPS stratum 10
# PPS Source, stratum 0 and prefer
server minpoll 4 maxpoll 4
fudge refid PPS stratum 0 flag3 1 flag4 1 prefer

I deliberately left the time offset for the GPS source at 0.0 rather than trying to chase down the time packet offset so that I could see an “honest” offset value in the ntpq output:

 remote refid st t when poll reach delay offset jitter
LOCAL(0) .LOCL. 15 l 58m 64 0 0.000 0.000 0.000
*SHM(0) .GPS. 10 l 16 16 377 0.000 -106.45 1.145
oPPS(0) .PPS. 0 l 15 16 377 0.000 -0.001 0.001