A Meinberg PZF5xx NTP time standard is simulated with an Arduino
in conjunction with a cheap DCF77 receiver module to produce surprisingly
accurate internet independent time stamps.

A priori
In this post I elaborated on Udo’s magnificent work concerning decoding
DCF77 time stamps in noisy/suboptimal environments. Please read this first.

Last month I was in Germany /P at a camping site and decided for some JT65 on 40m.
Naively I started WSJT-X but soon discovered my laptop clock was way off time.

Believe it or not, I was in a situation with no internet access, nor 3G/4G. Now what?

Being in the process of building a DCF synced clock with large 7-segment displays
for the camper, my DCF clock had to be enriched with a reference clock option
for internet independent NTP time synchronisation. Yes, DCF not GPS.

Unfortunately most modern computers only have one type of hardware interface, USB.
This excludes e.g. connecting simple DCF77 receivers to a serial (RS232) port.
I remembered Udo published a Meinberg emulation sketch, so I digged further into this.

Reference clock
I added Udo’s Meinberg code to my sketch and after some fiddling I was able to
see the refclock in NTPD under Linux. Having experimented with DCF77 modules
a lot in the past, I was disappointed about the reported jitter.

Offset was/is not the issue, it can be tweaked with the fudge factor ‘time1′ in ntp.conf.
With DCF NTP refclocks this time1 fudge factor is normal because propagation delay
of the DCF transmitter in Mainflingen, Germany has to be compensated, as well as
latency of the hardware interface (RS232, USB).

Taking PLL options inside my clock sketch into account, I could hardly believe
the reported jitter. Did I overlook something?

Meinberg clocks output UTC epoch synced PPS with a datagram (‘describing string’).
The PPS creates NTP clock accuracy and the string clock Time (with a capital T).

Although my sketch -based on the dcf77.h library of Udo- has the option to output
a synced PPS, this PPS can’t be interfaced (directly/easily) with USB. Now what?

Reading more information on NTPD parse refclocks, it seems that Udo chose the
‘first’ option for his Meinberg emulator, i.e. ‘mode 2′.

In ‘mode 2′ there seems no relation between the (timing of the) datagram and UTC epochs.
When the datagram heeds the ‘University of Erlangen’ syntax, its burst
is assumed to be synchronised to UTC more precisely, i.e. ‘mode 0′ or ‘mode 1′ :

“The DCF77 PZF5xx variants provide higher accuracy and have a
pretty good relationship between RS232 time code and the PPS signal.”

Meinberg PZF511

Error/jitter relates to the datagram bitrate. For 9600 bits/s this amounts 1/9600 = 104 us.
This is also coded in the ntpd/refclock_parse.c source (download NTP source here) :

* Meinberg DCF PZF535/TCXO (FM/PZF) receiver
#define DCFPZF535_ROOTDELAY     0.0
#define DCFPZF535_BASEDELAY     0.001968  /* 1.968ms +- 104us (oscilloscope) – relative to start (end of STX) */
#define DCFPZF535_DESCRIPTION   “Meinberg DCF PZF 535/509 / TCXO”

In other words, fooling NTPD that my PLL locked Arduino is a Meinberg PZF5xx
should improve performance significantly?

I coded the ‘Uni Erlangen’ syntax in my sketch.
Despite lacking a ‘hard’ PPS, performance after convergence is suprisingly good.

Although I didn’t pay too much attention on timing issues inside the code,
it’s the best DCF NTP refclock I ever had!

Relevant ntp.conf entry for this refclock (Note: /dev/refclock-0 is linked to /dev/ttyUSB0) :

#PARSE clock for Meinberg , normal AM clock = mode 2, PZF5xx = mode 0 or 1
server mode 0
fudge time1 0.0277 stratum 0 refid DCFm

Note: fudge factor time1 here is 27.7 ms and I chose the TCXO version (mode 0)

[/home/user@li]> ntpq -p
remote           refid      st t when poll reach   delay   offset  jitter
*GENERIC(0)      .DCFm.      0 l    9   64  377    0.000    0.291   0.070
+aardbei         .GPS.       1 u   47   64  377    0.698   -0.211   0.183
+ntp.nmi.nl      .PPS.       1 u    7   64  377   19.924   -1.240   0.203

[/home/user]> ntpdc -nc kern
pll offset:           -1.128e-05 s
pll frequency:        21.402 ppm
maximum error:        0.000749 s
estimated error:      0.000133 s
status:               2001  pll nano
pll time constant:    6
precision:            1e-09 s
frequency tolerance:  500 ppm

Relying on the quality of the dcf77.h library there may be room for further improvement.

More experiments
From the original perspective the above information is somewhat ‘cheating’.
NTPD is configured as connected to the internet with several active remote NTP servers.

To simulate a real standalone situation, i.e. no internet connection, I rebooted my
computer and started ntpd with only one refclock entry in /etc/ntp.conf:

#PARSE clock for Arduino/fake Meinberg PZF5xx –> mode 0
server mode 0
fudge time1 0.0259  stratum 0 refid DCFp #DCFp because refclock is phase locked : -)

During the reboot process ntpd was started with ntpd -I lo -I eth0 to peek into this
‘standalone’ running ntpd from another machine to compare its performance with other NTP servers.
The ‘-I’ options are necessary because ntpd does not open e.g. the eth0 interface when no remote
(internet) time servers are configured in /etc/ntp.conf.

While (re)booting I fetched a cup of coffee, fed my cats, and returned after 15 minutes.

At my location the Arduino takes around six minutes for a DCF lock, after which it produces timestamps.

Ntpq -p delivered the following output:

[/home/user@li]> ntpq -p
remote           refid      st t when poll reach   delay   offset  jitter
*GENERIC(0)      .DCFp.      0 l   39   64  377    0.000    0.003   0.014

Although the above result may be considered Kafkaesque, it’s suspiciously good : -)

Subsequent queries gave often offsets in the usec range and jitters < 200 usec. Very good.

In order to peek into this Kafkaesque situation I queried this NTPD instance from a remote
machine on my LAN (remember, I started ntpd with the options -I lo and -I eth0):

[/home/user@he]> ntpq -p
remote           refid      st t when poll reach   delay   offset  jitter
*lithium .DCFp.      1 u   64   64  377    0.309   -0.332   0.084
+aardbei .GPS.       1 u   41   64  377    0.615    2.048   0.199
+ntp.nmi.nl      .PPS.       1 u   29   64  377   19.643   -0.123  0.362
-ntp3.vniiftri.r .MRS.       1 u   17   64  377   70.189    3.363  0.652

Aardbei‘ is my very popular Motorola Oncore GPS disciplined NTP server ntp.remco.org and has
a local accuracy and jitter of a few micro seconds:

[/home/user@li]> ntpq -p aardbei
remote           refid      st t when poll reach   delay   offset  jitter
oGPS_ONCORE(0)   .GPS.       0 l    5   16  377    0.000    0.000   0.002
+2001:610:1:80be .PPS.       1 u   12   64  377   18.528   -2.012   0.172
+ntp.nmi.nl      .PPS.       1 u   31   64  377   20.002   -2.147   0.357
*ntp1.nl.uu.net  .PPS.       1 u   93   64  376   18.475   -2.040   0.368

Lithium‘ is the ntpd instance running ‘standalone’ with the DCF disciplined Arduino/fake Meinberg PZF5xx.
Other entries are remote benchmarks.

After some monitoring I discovered that lithium (DCF locked) and aardbei (GPS locked) were
competitive stratum 1 servers (from heliums perspective) !

I reckon when the Arduino interfaced to a real RS232 interface (using DCD for the PPSAPI)
may outperform a real DCF based Meinberg !
Edit: I did some early experiments with PPS (atom driver 22) and indeed, this looks promising ; -)

Anyway, for the time being it’s fine for me. The fake Meinberg will not be used as a reference for a
NTP server but only to sync my laptop (which also has to run NTPD then) for weak signal usage.

The current active Meinberg refclock sketch can be downloaded here.