Chrony NMEA/PPS offset

Hello, i made stratum-1 ntp server based on orangePI 3LTS + TOPGNSS GN803G GPS module.

Im using GPSD + Chrony to serve NTP.

And i cant figure out where to made offset for time.

refclock SHM 0 refid NMEA offset -0.15 precision 1e-3 poll 4 trust noselect
refclock PPS /dev/pps0 refid PPS poll 4 lock NMEA trust prefer

offset in refclock SHM 0 seems take no effect, but in server statistics pool.ntp.org: Statistics for 188.134.76.192 it seems like i need to made offset to -150ms

Also its strange that chrony telling that system time going aroud zero

System time     : 0.007656235 seconds slow of NTP time
System time     : 0.007686642 seconds fast of NTP time
System time     : 0.003670699 seconds slow of NTP time
System time     : 0.006554847 seconds fast of NTP time

chronyc sources && chronyc tracking

  .-- Source mode  '^' = server, '=' = peer, '#' = local clock.
 / .- Source state '*' = current best, '+' = combined, '-' = not combined,
| /             'x' = may be in error, '~' = too variable, '?' = unusable.
||                                                 .- xxxx [ yyyy ] +/- zzzz
||      Reachability register (octal) -.           |  xxxx = adjusted offset,
||      Log2(Polling interval) --.      |          |  yyyy = measured offset,
||                                \     |          |  zzzz = estimated error.
||                                 |    |           \
MS Name/IP address         Stratum Poll Reach LastRx Last sample
===============================================================================
#? NMEA                          0   4   377    16    -35ms[  -35ms] +/- 1000us
#* PPS                           0   4   376    30   +251ms[ +278ms] +/-  342us
^x 185.211.244.47                2  10   377   352    -54ms[  -16ms] +/-   48ms
^x svl2.ntp.netnod.se            1  10   377    33    -54ms[  -27ms] +/-   11ms
^x iotserv.ru                    2   6   377    44    -54ms[  -16ms] +/- 9394us
Reference ID    : 50505300 (PPS)
Stratum         : 1
Ref time (UTC)  : Sat Jan 11 17:16:55 2025
System time     : 0.012059166 seconds fast of NTP time
Last offset     : +0.027080629 seconds
RMS offset      : 0.017572170 seconds
Frequency       : 6.207 ppm fast
Residual freq   : +34.409 ppm
Skew            : 1.023 ppm
Root delay      : 0.000000001 seconds
Root dispersion : 0.049035851 seconds
Update interval : 16.0 seconds
Leap status     : Normal

Quick answer, but looking at the CSV log the monitors seem to think your server’s average offset is -41.66 ms (since Friday). Maybe try changing your refclock offset to -0.15+0.04166 = -0.10834 and see what happens.

(edit: fixed math)

Edit2: Changing the offset of NMEA refclock probably won’t help, as the refclock that is being used is PPS. Which shows an oddly large offset, for whatever reason.


What happened on Thursday evening? Did you change some settings? If not, this could be a case of bad asymmetric network routing.

Seeing how that GNSS puck is most likely using a serial to USB interface, jitter along with offset will be constantly fluctuating for its output. I’m not sure where you are getting the PPS signal from since most USB GNSS devices do not provide PPS over USB. Did it already come with the PPS output connected to the DCD/DSR pin of the serial to USB chip? I can’t find any information in regards to that. Either way, you’re not going to be able to get a stable and consistent time off it being its over USB.

Also, the product description on their website states it’s GPS+GLONASS. If you can, disable GLONASS. The timing provided by GLONASS is not very accurate, and can affect offset & jitter.

I’m not sure what chipset that module is using, but I do see some reference on some of their other models that they use Ublox GPS modules. However, I’m getting the impression that its more then likely either older model Ublox chips, or knockoffs which have dubious quality.

Hi,

This is how I did it (with advice from bas)

  • Set offset to 0.0 on NMEA/GPS
  • Let chrony run for 10-15 minutes then check the offset of NMEA with “chronyc sourcestats”
  • if, for example, it’s +/-35ms, set the offset for NMEA to +/-0.35
  • Set poll to 2 for NMEA
  • Set poll to 1 for PPS

Yep, a had try extremly high offset with no effect for NMEA.

Yep, for some reason (idk why) it was stratum 2+ and had sync from other servers from pool
There was some issues with noselect, NMEA and PPS was failing with error and chrony had switched to NTP from pool.

yep, it is USB. It was a gift from friends (:
PPS interface appears after loading pps_ktimer kenel module
lsusb shows it as Bus 005 Device 002: ID 1546:01a8 U-Blox AG [u-blox 8]
I’ll grep documetation for changing modes.
thank you

made this changes, and will monitor it for some time, thanks.
But offset in NMEA seems like no effect

can you explain math please?

As for my math, you mentioned in your original message that you need to make offset to -150 ms. Although I don’t know where you got that -150 ms figure from, I think you estimated from the graph that the offset would be -150 ms. Do note, however, that the graph uses logarithmic scale, which may make determining actual values more difficult. I then had a look at your server’s CSV log and calculated the average offset since Friday, which was -41.66 ms. Therefore, I thought that if your current setting is -150 ms and you wanted to raise the average offset “up”, the needed offset adjustment would have been -108.34 ms instead of the current setting’s -150 ms.

However, that is a moot point, because your current score graphs looks quite wild and there’s something else going on than just setting some static offset.

The pps_ktimer kernel module does not relate to any real hardware PPS input. It uses a kernel timer to synthesize a dummy PPS source, and is intended for debugging purposes only.

After a evening of debugging:

Offset in refclock SHM 0 refid NMEA offset 0.25 precision 1e-3 poll 4 trust noselect
actually works.

It seems like pipeline in chrony for

refclock SHM 0 refid NMEA offset 0.25 precision 1e-3 poll 4 trust noselect
refclock PPS /dev/pps0 refid PPS poll 2 lock NMEA trust prefer

looks like

  • Adjust clock by NMEA
  • use PPS for clocking
  • repeat in some order

I have no idea what math behind
System time : 0.000015344 seconds slow of NTP time
of chronyc tracking, it seems like it not testing actual time from pool described in pool 2.debian.pool.ntp.org iburst maxsources 4 directive, idk whith which source it correlates. My guess is system time to current source. ( PPS in my case according to chronyc sources )

~# chronyc sources
MS Name/IP address         Stratum Poll Reach LastRx Last sample
===============================================================================
#? NMEA                          0   4   377    24   +373ms[  +70ms] +/- 1002us
#* PPS                           0   2   241     5  -6897us[ -310ms] +/-   43ms
^x sth2.ntp.netnod.se            1   9   377    29   +588ms[  -94ms] +/- 7320us
^? 92.118.113.24                 0  10     0     -     +0ns[   +0ns] +/-    0ns
^x 45.10.43.111                  2  10   377   667   +593ms[ +516ms] +/-   14ms
^x as57164-151-0-2-53.htel.>     2   9   377   124   +590ms[ +534ms] +/-   26ms

my actual chrony config:

port 123
confdir /etc/chrony/conf.d
pool 2.debian.pool.ntp.org iburst maxsources 4
refclock SHM 0 refid NMEA offset 0.25 precision 1e-3 poll 4 trust noselect
refclock PPS /dev/pps0 refid PPS poll 2 lock NMEA trust prefer
sourcedir /run/chrony-dhcp
sourcedir /etc/chrony/sources.d
keyfile /etc/chrony/chrony.keys
driftfile /var/lib/chrony/chrony.drift
ntsdumpdir /var/lib/chrony
log tracking measurements statistics
logdir /var/log/chrony
maxupdateskew 100.0
rtcsync
makestep 1 3
leapsectz right/UTC
hwtimestamp *
clientloglimit 100000000
allow

with poll 1 in PPS and NMEA it seems like there was some instability, but poll 4 for NMEA and poll 2 for PPS seems working. may be ill should play around it a little bit more.

Also a made google spreadsheet to monitor offset:

ah. ok. missed it out, will switch to NMEA for a time. Thank you.

1 Like

If this is the case, then that USB GPS is definitely not outputting a PPS signal. No point in even setting up a line for PPS in Chrony if the PPS is fake to begin with.

With that said, the OPs best course if they stick with that GPS puck, is to remove the code that enables PPS in thier OS. This will keep GPSD from trying to use and combine a fake PPS signal with the NMEA output of the GPS, and configure some other pools or server to use in addition to thier refclock, and just let Chrony work out the time. Without a real PPS signal, and being that GPS is going through USB, you’ll only be able to get within 10’s of ms variability/jitter (probably 70-90ms variability). But at least Chrony will know it’s on the correct UTC second, and can combine the refclock with internet servers to get down as accurate as possible.

If that is a real U-Blox 8 chipset, you can use the official U-blox U-center software to configure it to try and reduce that variability by disabling unnecessary message outputs. The only message you really need for time is the GxZDA message enabled. I forget the math, but every character of text transmitted takes time for it to be relayed, received, and processed, which can add up to a number of ms wasted, which can add into the variability. That GPS puck is probably configured to have every message enabled for general navigation purposes, and even though GPSD should configure the GPS itself if it identifies the chipset, I find that even GPSD enables too many messages if all you need is time. I disable GPSD ability to configure the GPS by setting GPSD to read only, so that it doesn’t keep changing my GPS configuration.

U-Blox 8 chipsets should also be able to enable not only US GNSS, but also EU Galileo constellations together. Using those 2 enabled, all other constellations disabled, will net you the most accurate time possible on that chipset, along with more satellite availability.

Yeah, thank you. i was misled by "pps":true in gpsmon

I`ll try to setup my gps puck some time later.
There is no actual datasheet on my model on topgnss site, but i think there is no much difference with other they models.

Now i`m aimed for switch to UART gps module with hardware UART/pps, or maybe make multiple stratum1-servers with different gps modules.

If you like to tinker with hardware, and are good with a soldering iron, you can probably open up that puck and access the U-Blox chip directly. If its the usual Neo chipset, it’s very easy to identify the PPS out on the chip, and you can solder a wire directly to it, and just attach that wire to one of the GPIO pins on your OrangePI to get real PPS.

Really daemons don’t need extremely NMEA offset precision settings to picoseconds. Problems can arise if NMEA is so far from the PPS pulse that the daemon cannot understand what PPS Pulse does NMEA refer to. (For example, if the offset is 500 ms, then it is not clear to which pulse the nmea refers - to the past or to the future?) By setting the offset we “move/attract” NMEA to the desired PPS pulse. Some modern receivers have a small offset, so even if you don’t set it, there is no problem for ntp daemon.

Disable NMEA and PPS sources, sync from another nearest good ntp (s1/2) servers or from pool. Wait when chronyc sources show minimal offset.
Then run gpsmon and look NxTOFF. You can use it as NMEA offset and that will be enough.

If you want more precision see gpsmon Archives - Austin's Nerdy Things article as example.

Thank you.

GPSmon NxTOFF offset seems like right metric, but i see there is large dispersion in measurements by judjes
Wouldn’t it be better to calculate the offset as the average of the last 100 measurements from all judges or something like that? In my mind it will supress network lag better? May be it will be worth for closer neibours, but better on average?