# Stratum 0 GPS+PPS Time Source for $50

**URL:** <https://community.ntppool.org/t/stratum-0-gps-pps-time-source-for-50/3260>\
**Category:** Uncategorized\
**Created:** [February 28, 2024, 10:57am UTC](https://community.ntppool.org/t/stratum-0-gps-pps-time-source-for-50/3260 "2024-02-28T10:57:16Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![elvisimprsntr](https://avatars.discourse-cdn.com/v4/letter/e/43a26b/32.png) [@elvisimprsntr](https://community.ntppool.org/u/elvisimprsntr)\
**Post date:** [February 28, 2024, 10:57am UTC](https://community.ntppool.org/t/stratum-0-gps-pps-time-source-for-50/3260/1 "2024-02-28T10:57:16Z")

</div>

New amateur time nut here,

I thought it would be fun to add a GPS+PPS source to my pfSense firewall to serve time to clients. I tested three different Garmin GPS receivers connected via DE9 or RJ45 RS232 communication and the NTP package in [http://pfsense.org](http://pfsense.org)

- GPS 16X LVS
- GPS 18X LVC
- GPS 19X HVS

I am sure others with more experience will find faults with my NTP solution, but it seems to achieve less than 10-15 usec offset/jitter. Might not be good enough for a financial institution or high speed data acquisition, but good enough for homelab use.

> **[GitHub - elvisimprsntr/pfsense-ntp-gps: pfSense NTP GPS Server](https://github.com/elvisimprsntr/pfsense-ntp-gps)**
>
> pfSense NTP GPS Server. Contribute to elvisimprsntr/pfsense-ntp-gps development by creating an account on GitHub.

Comments welcome.

---

<div class="post-metadata">

**Author:** ![Kets\_One](https://avatars.discourse-cdn.com/v4/letter/k/46a35a/32.png) [@Kets\_One](https://community.ntppool.org/u/Kets_One)\
**Post date:** [February 28, 2024, 2:44pm UTC](https://community.ntppool.org/t/stratum-0-gps-pps-time-source-for-50/3260/2 "2024-02-28T14:44:03Z")

</div>

Welcome!  
Personally i don’t have any experience with Garmin gps receivers. Sorry 😊

---

<div class="post-metadata">

**Author:** ![Mpegger](https://avatars.discourse-cdn.com/v4/letter/m/e19adc/32.png) [@Mpegger](https://community.ntppool.org/u/Mpegger)\
**Post date:** [February 28, 2024, 9:25pm UTC](https://community.ntppool.org/t/stratum-0-gps-pps-time-source-for-50/3260/3 "2024-02-28T21:25:34Z")

</div>

uBlox based GPS modules from 7th to 9th gen, can be purchased for half that price, or even less, if a naked chip on a tiny board and possibly some soldering isn’t a problem. Pratically all support PPS, even if there is no dedicated PPS pad/pin on the board.

---

<div class="post-metadata">

**Author:** ![elvisimprsntr](https://avatars.discourse-cdn.com/v4/letter/e/43a26b/32.png) [@elvisimprsntr](https://community.ntppool.org/u/elvisimprsntr)\
**Post date:** [February 29, 2024, 9:42pm UTC](https://community.ntppool.org/t/stratum-0-gps-pps-time-source-for-50/3260/4 "2024-02-29T21:42:59Z")

</div>

Thanks. I preferred the COTS outdoor rated GPS receivers vs a Rube Goldberg option.

---

<div class="post-metadata">

**Author:** ![PoolMUC](https://sea2.discourse-cdn.com/flex016/user_avatar/community.ntppool.org/poolmuc/32/1473_2.png) [@PoolMUC](https://community.ntppool.org/u/PoolMUC)\
**Post date:** [February 29, 2024, 11:01pm UTC](https://community.ntppool.org/t/stratum-0-gps-pps-time-source-for-50/3260/5 "2024-02-29T23:01:13Z")

</div>

> [@elvisimprsntr](#):
>
> COTS outdoor rated GPS receivers vs a Rube Goldberg option

Hmm, I guess it lies in the eyes of the beholder as to whether to consider any option a Rube Goldberg one. E.g., due to the much better performance of the u-blox units, there _may_ be no need for an outdoor rating. Depending on circumstances, it may be possible to operate such a unit indoors and get reception good enough for timing (less so for positioning), as discussed in another recent thread.

Or, if that doesn’t work in particular circumstances, the receiver may reside indoors, and it’s only a COTS puck antenna with attached coaxial cable run that gets placed outdoors.

Either way, slightly different handiwork needed than what you did for your solution, but to me, it seems pretty much on par with what you did for your solution as far as Rube Goldberg worthiness is concerned. But the performance would arguably be better with a recent u-blox unit than with the slightly older Garmin units.

A bit pricier, but if reducing handiwork is a must, some vendors such as NaviSys and Navilock also offer outdoor rated units with PPS and serial (non-USB) interface based on u-blox chips, e.g., the NaviSys GR-801R.

---

<div class="post-metadata">

**Author:** ![Bas](https://sea2.discourse-cdn.com/flex016/user_avatar/community.ntppool.org/bas/32/465_2.png) [@Bas](https://community.ntppool.org/u/Bas)\
**Post date:** [March 2, 2024, 5:17pm UTC](https://community.ntppool.org/t/stratum-0-gps-pps-time-source-for-50/3260/6 "2024-03-02T17:17:27Z")

</div>

> [@elvisimprsntr](#):
>
> GPS 18X LVC

I use a couple of these receivers, but they are tricky to setup.  
And they need DB9 as well as USB (for 5V power).

There are various good sites on how to work with these.

It all depends on your situation, because if the roof of your building isn’t steel-enforced-concrete often indoor simple U-blox will work fine.

You can install a app on your mobile-phone and see how well it received and how many sat’s. That will give an idea what you need for good timekeeping.

Mine are under a wooden roof and do not need to be outdoors.

Bas.

---

<div class="post-metadata">

**Author:** ![elvisimprsntr](https://avatars.discourse-cdn.com/v4/letter/e/43a26b/32.png) [@elvisimprsntr](https://community.ntppool.org/u/elvisimprsntr)\
**Post date:** [March 3, 2024, 4:08am UTC](https://community.ntppool.org/t/stratum-0-gps-pps-time-source-for-50/3260/7 "2024-03-03T04:08:51Z")

</div>

@Bas

Thanks for the suggestion.

I already have them working as a stratum 0 time source. I was just sharing my solution.

 ![Screenshot 2024-03-02 at 11.00.26 PM](https://us1.discourse-cdn.com/flex016/uploads/ntppool/original/2X/6/6ce2eb8d63b1b924276298bbf8917d67d7901fb6.png)

Cabling was the easy part. Can be connected to DE9 (PPS on DCD) or RJ45 (PPS on CTS) RS232 ports.

The trick is enabling statistics logging and calculating the right fudge time 1 and time 2, but that applies to any GPS receiver with PPS.

```auto
[2.7.2-RELEASE][root@pfSense.[redacted].com]/root: ntpq -pn
     remote refid st t when poll reach delay offset jitter
==============================================================================
o127.127.20.0 .GPS. 0 l 16 16 377 0.000 +1.303 0.004
 time.nist.gov .POOL. 16 p - 64 0 0.000 +0.000 0.000
+132.163.96.4 .NIST. 1 u 58 64 377 53.366 +1.465 0.429
+132.163.96.6 .NIST. 1 u 63 64 377 53.155 +1.537 0.513
+132.163.97.6 .NIST. 1 u 61 64 377 56.764 +1.674 0.460
[2.7.2-RELEASE][root@pfSense.[redacted].com]/root: ntpq -c sysinfo
associd=0 status=041d leap_none, sync_uhf_radio, 1 event, kern,
system peer: GPS_NMEA(0)
system peer mode: client
leap indicator: 00
stratum: 1
log2 precision: -21
root delay: 0.000
root dispersion: 1.598
reference ID: GPS
reference time: e98e7294.6b78e6ce Sat, Mar 2 2024 22:52:52.419
system jitter: 0.002500
clock jitter: 0.002
clock wander: 0.014
broadcast delay: -50.000
symm. auth. delay: 0.000

```

---

<div class="post-metadata">

**Author:** ![Bas](https://sea2.discourse-cdn.com/flex016/user_avatar/community.ntppool.org/bas/32/465_2.png) [@Bas](https://community.ntppool.org/u/Bas)\
**Post date:** [March 3, 2024, 10:37am UTC](https://community.ntppool.org/t/stratum-0-gps-pps-time-source-for-50/3260/8 "2024-03-03T10:37:29Z")

</div>

> [@elvisimprsntr](#):
>
> ```auto
> o127.127.20.0 .GPS. 0 l 16 16 377 0.000 +1.303 0.004
> time.nist.gov .POOL. 16 p - 64 0 0.000 +0.000 0.000
> +132.163.96.4 .NIST. 1 u 58 64 377 53.366 +1.465 0.429
> +132.163.96.6 .NIST. 1 u 63 64 377 53.155 +1.537 0.513
> 
> ```

Sorry to say, but the PPS line doesn’t contrain time and date info.  
It only pulses and is normally locked to the normal NMEA driver to combine the two for correct time and date.

That is the reason there are always 2 lines in there.

If you don’t do that and the internet drops, it won’t know what to do with those pulses.

Bas.

---

<div class="post-metadata">

**Author:** ![elvisimprsntr](https://avatars.discourse-cdn.com/v4/letter/e/43a26b/32.png) [@elvisimprsntr](https://community.ntppool.org/u/elvisimprsntr)\
**Post date:** [March 3, 2024, 11:15am UTC](https://community.ntppool.org/t/stratum-0-gps-pps-time-source-for-50/3260/9 "2024-03-03T11:15:34Z")

</div>

> [@Bas](#):
>
> Sorry to say, but the PPS line doesn’t contrain time and date info.

I am by no means a NTPD algorithm expert, but I noticed if a source is marked as a valid PPS Peer o, NTPD uses that to sync and serve time to clients regardless if there a separate Active Peer \* used for time data. If a GPS is being used for both a PPS Peer o and source of time data, it will be marked as PPS Peer o and there will be no other Active Peers \* marked. The NTP Widget seems to display the Active Peer \* even when the PPS Peer o is actually being used to sync and serve time to clients. Which source is actually served to clients can be confirmed with “ntpq -c sysinfo”.

As a test, I removed the NIST pool and added a single NIST server and marked it as no select. Seems to be using GPS for both time and PPS.

```auto
[2.7.2-RELEASE][root@pfSense.[redacted].com]/root: ntptime 
ntp_gettime() returns code 0 (OK)
  time e98edb42.843b1d0c Sun, Mar 3 2024 6:19:30.516, (.516527909),
  maximum error 3633 us, estimated error 34 us, TAI offset 0
ntp_adjtime() returns code 0 (OK)
  modes 0x0 (),
  offset -861.970 us, frequency -33.804 ppm, interval 256 s,
  maximum error 3633 us, estimated error 34 us,
  status 0x2107 (PLL,PPSFREQ,PPSTIME,PPSSIGNAL,NANO),
  time constant 4, precision 0.001 us, tolerance 496 ppm,
  pps frequency -33.804 ppm, stability 0.024 ppm, jitter 8.414 us,
  intervals 7152, jitter exceeded 877, stability exceeded 0, errors 1.
[2.7.2-RELEASE][root@pfSense.[redacted].com]/root: ntpq -pn
     remote refid st t when poll reach delay offset jitter
==============================================================================
o127.127.20.0 .GPS. 0 l 14 16 377 0.000 +0.391 0.565
 132.163.96.4 .NIST. 1 u 13 64 3 53.417 +0.811 0.334
[2.7.2-RELEASE][root@pfSense.[redacted].com]/root: ntpq -c sysinfo
associd=0 status=041d leap_none, sync_uhf_radio, 1 event, kern,
system peer: GPS_NMEA(0)
system peer mode: client
leap indicator: 00
stratum: 1
log2 precision: -21
root delay: 0.000
root dispersion: 1.261
reference ID: GPS
reference time: e98edb4d.97dd5492 Sun, Mar 3 2024 6:19:41.593
system jitter: 0.392407
clock jitter: 0.007
clock wander: 0.000
broadcast delay: -50.000
symm. auth. delay: 0.000
[2.7.2-RELEASE][root@pfSense.[redacted].com]/root: 

```

---

<div class="post-metadata">

**Author:** ![PoolMUC](https://sea2.discourse-cdn.com/flex016/user_avatar/community.ntppool.org/poolmuc/32/1473_2.png) [@PoolMUC](https://community.ntppool.org/u/PoolMUC)\
**Post date:** [March 3, 2024, 11:23am UTC](https://community.ntppool.org/t/stratum-0-gps-pps-time-source-for-50/3260/10 "2024-03-03T11:23:56Z")

</div>

> [@Bas](#):
>
> normally locked to the normal NMEA driver to combine the two

My understanding would be that the NMEA driver (20) is used to get both the second numbering from the NMEA data stream as well as the PPS pulses from the same driver, as also discussed in [another recent thread](https://community.ntppool.org/t/choosing-an-ntp-driver-nmea-driver-20-vs-shm-plus-pps-28-22/1621). Note the server address, the RefID, and the lack of a star in front of any of the other servers on the billboard.

> [@elvisimprsntr](#):
>
> Can be connected to DE9 (PPS on DCD) or RJ45 (PPS on CTS) RS232 ports

Thanks for sharing your solution! Small item, but quite interesting to see that BSD natively supports both DCD and CTS lines to serve as PPS input for kernel PPS. Linux typically only uses DCD, like illustrated by Dan Drown adding PPS capability to the CDC USB-UART bridge driver, as shared in a [recent thread](https://community.ntppool.org/t/ordered-me-a-new-gps/3251/42). Avoids having to muck around with the cables/connectors if a GNSS unit natively provides PPS on the CTS pin, as various units do.

---

<div class="post-metadata">

**Author:** ![elvisimprsntr](https://avatars.discourse-cdn.com/v4/letter/e/43a26b/32.png) [@elvisimprsntr](https://community.ntppool.org/u/elvisimprsntr)\
**Post date:** [March 3, 2024, 11:55am UTC](https://community.ntppool.org/t/stratum-0-gps-pps-time-source-for-50/3260/11 "2024-03-03T11:55:17Z")

</div>

> [@PoolMUC](#):
>
> BSD natively supports both DCD and CTS lines to serve as PPS input for kernel PPS

Just have to set a tunable to use CTS line in a loader.conf.local file

Example

```auto
dev.uart.0.pps_mode="1"

```

---

<div class="post-metadata">

**Author:** ![Bas](https://sea2.discourse-cdn.com/flex016/user_avatar/community.ntppool.org/bas/32/465_2.png) [@Bas](https://community.ntppool.org/u/Bas)\
**Post date:** [March 3, 2024, 3:12pm UTC](https://community.ntppool.org/t/stratum-0-gps-pps-time-source-for-50/3260/12 "2024-03-03T15:12:41Z")

</div>

Normally you run it like this:

```auto
server 127.127.28.0 minpoll 4
fudge 127.127.28.0 time1 0.183 refid NMEA
server 127.127.28.1 minpoll 4 prefer
fudge 127.127.28.1 refid PPS

```

See here…

[https://rjsystems.nl/en/2100-ntpd-garmin-gps-18-lvc-gpsd.php](https://rjsystems.nl/en/2100-ntpd-garmin-gps-18-lvc-gpsd.php)

---

<div class="post-metadata">

**Author:** ![elvisimprsntr](https://avatars.discourse-cdn.com/v4/letter/e/43a26b/32.png) [@elvisimprsntr](https://community.ntppool.org/u/elvisimprsntr)\
**Post date:** [March 3, 2024, 4:04pm UTC](https://community.ntppool.org/t/stratum-0-gps-pps-time-source-for-50/3260/13 "2024-03-03T16:04:07Z")

</div>

@Bas

Thanks. I think that assumes you are using GPSD.

> **[Shared Memory Driver](https://www.ntp.org/documentation/drivers/driver28/)**
>
> The Shared Memory Driver receives its reference clock info from a shared memory segment.

> **NOTE:** The _GPSD_ client driver (type 46) uses the _GPSD_ client protocol to connect and talk to _GPSD_ , but using the SHM driver is the ancient way to have _GPSD_ talk to _NTPD_ . There are some tricky points when using the SHM interface to interface with _GPSD_ , because _GPSD_ will use two SHM clocks, one for the serial data stream and one for the PPS information when available. Receivers with a loose/sloppy timing between PPS and serial data can easily cause trouble here because _NTPD_ has no way to join the two data streams and correlate the serial data with the PPS events.

pfSense uses NTPD and the configuration GUI does not allow custom options.

Sure you can manually change the ntpd.conf file, but it will not persist on NTPD restart, reboot, or pfSense upgrade.

NTPD NMEA drivers support both NMEA messages and PPS in the same driver. I’ve had a Garmin GPS receiver connected to my pfSense firewall more than a year without issues.

---

<div class="post-metadata">

**Author:** ![Bas](https://sea2.discourse-cdn.com/flex016/user_avatar/community.ntppool.org/bas/32/465_2.png) [@Bas](https://community.ntppool.org/u/Bas)\
**Post date:** [March 3, 2024, 4:57pm UTC](https://community.ntppool.org/t/stratum-0-gps-pps-time-source-for-50/3260/14 "2024-03-03T16:57:36Z")

</div>

Yes I’m using GPSD and Chrony.

Not a fan of NTPD.

I also do not believe in firewalls as in seperate servers 🤣

---

<div class="post-metadata">

**Author:** ![elvisimprsntr](https://avatars.discourse-cdn.com/v4/letter/e/43a26b/32.png) [@elvisimprsntr](https://community.ntppool.org/u/elvisimprsntr)\
**Post date:** [March 4, 2024, 9:49am UTC](https://community.ntppool.org/t/stratum-0-gps-pps-time-source-for-50/3260/15 "2024-03-04T09:49:12Z")

</div>

For the record, this is the relevant section of the ntpd.conf for my pfSense GPS+PPS config.

```auto
# GPS Setup
server 127.127.20.0 mode 176 minpoll 3 maxpoll 3 prefer
fudge 127.127.20.0 time1 0.0013 time2 0.369 flag1 1 flag3 1

```

time1 PPS offset to account for any electrical or interrupt delay.  
time2 NMEA message offset from PPS, length, and baud rate.  
flag1 enable PPS.  
flag3 enable kernel PPS discipline.

---

<div class="post-metadata">

**Author:** ![elvisimprsntr](https://avatars.discourse-cdn.com/v4/letter/e/43a26b/32.png) [@elvisimprsntr](https://community.ntppool.org/u/elvisimprsntr)\
**Post date:** [March 24, 2024, 1:06pm UTC](https://community.ntppool.org/t/stratum-0-gps-pps-time-source-for-50/3260/16 "2024-03-24T13:06:46Z")

</div>

Plotted loopstats clock offset over 24 hour period. Garmin GPS 18x sitting on a an interior window ledge, so not getting full sky view. Seems good enough for my homelab.

 ![loopstats](https://us1.discourse-cdn.com/flex016/uploads/ntppool/original/2X/a/a819c8235e845fed0f115d80b7c0fe17e1b44dec.jpeg)

---

<div class="post-metadata">

**Author:** ![Bas](https://sea2.discourse-cdn.com/flex016/user_avatar/community.ntppool.org/bas/32/465_2.png) [@Bas](https://community.ntppool.org/u/Bas)\
**Post date:** [March 28, 2024, 5:25pm UTC](https://community.ntppool.org/t/stratum-0-gps-pps-time-source-for-50/3260/17 "2024-03-28T17:25:47Z")

</div>

I would min/max-poll at 1, there is no reason to let it poll at 2^4.  
Poll 1 is every 1~2 seconds, your computer has no problem doing that.

Every 16 seconds will fill the buffer with a lot of data and that takes time to collect and process.

I suggest you change 4 to 1 for better results.

Also, I would remove time1, the PPS is so fast, if you correct it you make it more in-accurate…in my opinion. As it’s typical in the nanosecond range already.

My 2 cents.

---

<div class="post-metadata">

**Author:** ![elvisimprsntr](https://avatars.discourse-cdn.com/v4/letter/e/43a26b/32.png) [@elvisimprsntr](https://community.ntppool.org/u/elvisimprsntr)\
**Post date:** [March 28, 2024, 7:45pm UTC](https://community.ntppool.org/t/stratum-0-gps-pps-time-source-for-50/3260/18 "2024-03-28T19:45:08Z")

</div>

@bas

Thanks.

pfSense WebGUI lowest poll setting is 3 (8 sec), default is 4 (16 sec).

If I set time1 to 0, NTPD will use a [time.nist.gov](http://time.nist.gov) pool source for time data, although it will still report GPS stratum 1 served to clients. (ntpq -c sysinfo)

```auto
[2.7.2-RELEASE][root@pfSense.[redacted].com]/root: ntpq -c sysinfo
associd=0 status=041d leap_none, sync_uhf_radio, 1 event, kern,
system peer: GPS_NMEA(0)
system peer mode: client
leap indicator: 00
stratum: 1
log2 precision: -21
root delay: 0.000
root dispersion: 1.542
reference ID: GPS
reference time: e9b0edd5.ce147334 Fri, Mar 29 2024 3:35:49.804
system jitter: 0.004529
clock jitter: 0.003
clock wander: 0.001
broadcast delay: -50.000
symm. auth. delay: 0.000

```

IMHO, it’s about low jitter and adding a firewall rule to force all clients to use the local NTP server vs reaching out to the internet for time which will have several orders of magnitude higher offset and jitter.

 ![Screenshot 2024-03-28 at 3.47.50 PM](https://us1.discourse-cdn.com/flex016/uploads/ntppool/original/2X/1/168418a93c1970b60c16ee9e06fa1d2d972bc13c.png)
