Warning: This is a long post. So fetch a coffee, beer or nice glass of wine ; -)

For a long time I want a UTC clock locked to DCF77 as a separate unit with six 7-segment LED displays.

Why? Perhaps because almost nobody has one, perhaps because it’s easier to make a UTC clock
with a GPS receiver.

The picture below displays a quick and dirty prototype of my UTC DCF77 clock (click to enlarge in a new tab).

DCF77 broadcasts Central European (Summer) Time (CE(S)T) which is one or two
hours ahead of UTC during wintertime or summertime respectively. Although very
cheap DCF clocks are available, I never found a DCF77 clock with a ‘UTC button’.

So the remedy for my desire was to build such a clock myself.
Nowadays this is relatively easy compared to a few decades ago.

Google found several DCF clock designs. However, a lot of them lack the seconds due to hardware restrictions,
like not enough I/O pins on a microcontroller chip to multiplex six 7-segment displays.

I had some Arduinos lying around and found out a very elegant solution for the displays: the MAX7219 multiplexer.
On Ebay I found cheap 8 digit displays with this chip. From my NTP experiments a while ago I discovered a
Conrad DCF77 receiver module in my junk box, so I had all the parts to start.

Google almost immediately led me to the site of Thijs Elenbaas. Thijs is the author of the popular
Arduino DCF77 library and states he added ‘UTC support’ in April 2012.
As I am not a skilled C++ programmer, this was exactly what I needed!

Thijs’ code was patched to drive the MAX7219 display multiplexer and in no time my UTC DCF77 clock
was up and running by calling the DCF.getUTCTime() routine. Looking at this routine I think there is a bug
concerning converting CE(S)T to UTC but I didn’t had the patience and time to verify.

Because …

After additional googling I stumbled upon the blog of Udo ‘Blinkenlight’ Klein. Udo did some magnificent and
complicated work on decoding DCF77 signals with low SNR’s and/or interference.

From earlier NTP experiments I remembered that e.g. when there was a thunderstorm in Europe my NTP
server had difficulties to decode DCF77 time stamps properly. Glitches on the signal resulted in losing lock.
So, Udo’s page was interesting for me and I examined his experiments.

Although DCF77 has a good signal here, I started to implement his exponential filter first.
This filter was integrated in a sketch based on Thijs’ DCF77 library. Udo states this filter results
in +15 dB (perceived) SNR. As the DCF77 signal arrives here strong enough, I had to decrease the perceived signal
strength by pointing the ferrite rod antenna in DCF’s direction and detune the receiver coil with a trimmer.

The result was indeed a better decode with lower signal strengths compared to Thijs’ original code. Promising!

In figure 1 (shamelessly stolen from Udo’s blog) the effect of the exponential filter is visualized when 60% noise is
super imposed on the DCF signal. Udo added a Schmitt trigger function to shape the signal.

Figure 1. Shaping a noisy DCF / pulse signal with exponential filter + Schmitt trigger (courtesy of Udo Klein).

The net result from this filtering is that it results in lower perceived band width, which means that signals
can be detected/demodulated better as (thermal) noise is directly proportional with band width (B): N = kTB

Although this approach results in cleaner pulses at lower SNR’s, there are a few side effects.

First, it can be seen that the pulse width after this filter highly depends on the Schmitt trigger threshold value.
In figure 1 this threshold amounts 50%, and magically results in suitable pulse lengths for a ‘normal’ DCF
interrupt driven decoder, like Thijs’ decoder. But when SNR’s become lower this kind of filtering, combined
with the Schmitt trigger option, may create wrong results.

Secondly, such a filter introduces additional phase delay… which is delay in Time (time with a capital T),
not considering the necessary time to execute the Arduino code.

Having read the DCF77 protocol a long time ago, I knew that DCF uses PSK on its signal as an additional
asset to increase the accuracy of the received time signal. However, in order to use this PSK option a
significant more complex (hardware) receiver is necessary. When around 2005 I used DCF77 for my NTP server
no home brew PSK receivers seemed publicly available. I just googled and found that in January 2012 such
a receiver was published in Elektor Magazine.

Udo’s second published experiment involves ‘phase detection’ of the DCF signal. At first glance I thought he
found a way to demodulate the pseudo-random phase (PSK) signal with cheap DCF77 receiver modules.
If this was true that would be wonderful and could result in 50 ns accuracy!

However, Udo has another perception of phase than I initially had. He considers ‘phase’ as relative to the
second epochs of DCF. On other words, he considers DCF77 as a PPS source, just like I did in 2008 with ntpd
in conjunction with the ATOM (22) and PARSE (8) driver. The latter driver is necessary to obtain Time.

Here and here are my posts from 2008 and 2011 respectively. Connecting the DCF signal to the DCD pin of a
RS232 interface resulted (and results) in ca. 50x lower PLL offset compared to the PARSE (8) driver alone.

What Udo basically programmed, is a software PLL where the time stamps of the Arduino are compared
with the second epochs of DCF. Another use of a PLL is that it can be used as a very effective filter,
depending on the perceived phase (time) difference and loop filter time constants.

When such system is in lock, band widths of fractions of a Hertz are achievable, resulting in detecting
lower and lower SNR’s. However, it takes some precision and time to get there.

Although Udo claims that running his code on an Arduino with a ceramic resonator is useless, I gave it a try
with an Arduino Nano … with a ceramic resonator.  I ran Udo’s DCF77 Scope and concluded quickly that the
clock source was not stable enough. Fiddling with the time constants in the software didn’t result in a lock.

I inspected the Nano and regarded the space around the resonator too small to insert a HC49(/U) crystal.

I was impatient and considered building an Arduino myself with a DIL28 ATMega328. Unfortunately one
of my nearby friends used his last DIL28 ATMega328 in one of his projects, so I looked on Ebay
and forecasted that my project would be delayed for at least two weeks…

At first glance my Ebay search seemed ‘polluted’ with Arduino Mini’s and I skipped them. Suddenly I saw a
picture of one of these Mini’s with a crystal and apparently I clicked on this particular link earlier!

It took me some time to realize I ordered some Mini’s from the same Ebay shop a while ago for ‘just in case’.
They were lying unopened in my shack as I planned to use the ‘old’ Mini’s first.

Presto! With great joy I saw that the last ordered Mini’s had a 16 MHz crystal clock source!

See picture below (click to enlarge and open in a new tab).

Immediately I rewired the Nano contraption to the Mini and ran DCF77 Scope. As you can see
below, the stability of the clock source is almost perfect for Udo’s software and/or library, albeit
that the signal may be ‘too clean’ to fully recognize the claimed capabilities of his DCF77 decoder.

32, +———+2XXXXXXXXX5——–+———+———+———+———+———+———+———
33, +———+8XXXXXXXXX7——–+———+———+———+———+———+———+———
34, +———+5XXXXXXXXX6——–+———+———+———+———+———+———+———
35, +———+6XXXXXXXXXXXXXXXXXXX2——–+———+———+———+———+———+———
36, +———+3XXXXXXXXX4——–+———+———+———+———+———+———+———
37, +———+4XXXXXXXXX2——–+———+———+———+———+———+———+———
38, +———+5XXXXXXXXXXXXXXXXXXX1——–+———+———+———+———+———+———
39, +———+9XXXXXXXXX6——–+———+———+———+———+———+———+———
40, +———+5XXXXXXXXXXXXXXXXXXX———+———+———+———+———+———+———
41, +———+3XXXXXXXXX5——–+———+———+———+———+———+———+———


2381, +———+—–5XXXXXXXXX3—+———+———+———+———+———+———+———
2382, +———+—–7XXXXXXXXXXXXXXXXXXX—-+———+———+———+———+———+———
2383, +———+—–6XXXXXXXXX—-+———+———+———+———+———+———+———
2384, +———+—–7XXXXXXXXXXXXXXXXXX8—-+———+———+———+———+———+———
2385, +———+—–5XXXXXXXXXXXXXXXXXX8—-+———+———+———+———+———+———
2386, +———+—–6XXXXXXXXXXXXXXXXXX8—-+———+———+———+———+———+———
2387, +———+—–5XXXXXXXXXXXXXXXXXX7—-+———+———+———+———+———+———
2388, +———+—–7XXXXXXXXXXXXXXXXXX5—-+———+———+———+———+———+———
2389, +———+—–7XXXXXXXXX—-+———+———+———+———+———+———+———
2390, +———+—–4XXXXXXXXX2—+———+———+———+———+———+———+———

This particular Arduino Mini deviates 50 ms in 2390 seconds, which is 0.05/2390 = 21 ppm or 335 Hz @16 MHz during the test period.

The estimated 16 MHz clock source offset is used for -what Udo calls- ‘auto tune’ the internal clock of the Arduino.
Normally you would adjust the frequency of an oscillator with the outcome of a phase loop but that is not possible here because the
Arduino 16 MHz clock source has no external means (e.g. a varicap or VCO pin) to adjust its frequency.

Udo used a ‘software varicap’ by manipulating internal timer (CTC) prescaler and division constants. Knowing that the DCF epochs are
1s or 1000 ms by definition, and knowing that the local clock source is approx. 16 MHz one can simply count cycles with a CTC.
In his interpretation one of the internal CTC’s is prescaled with 64, resulting in 16E6/64 = 250000 counts (needed for interrupts).

When 1ms resolution is required, these 250000 counts can be divided inside the CTC with 250. During a certain period the amount of
counts is collected. If this amount exceeds or deceeds the theoretical value, the CTC division factor is (temporary) in- or decreased.

In other words, it’s a PLL the other way round: not changing the oscillator frequency with a fixed division number (N), but change
N in relation to the oscillator frequency, similar what dual modulus prescalers do.

The reason to ‘tune’ the internal clock source is when the Arduino loses its DCF lock, the clock must run on its internal clock
as accurate as possible. This accuracy is important to retrieve DCF lock, especially in noisy or interfering environments.

The next thing Udo did to obtain Time is using a mechanism known as convolution.
Convolution is known for several years in programs as JT65 and WSPR, brought into the HAM radio community by K1JT.
As far as I could ascertain Udo is the first to deploy convolution for DCF77 signals.

I try to explain it in my own words. When the local clock source is locked with DCF a few things ‘happen’.
The software starts searching for a known a bit sequence. Udo selected some bits of which the ‘sync mark’ during
the last second is a member.

During the sync mark the DCF carrier is not reduced, which means full DCF carrier for at least 1 second.
This occurs only once every 60 seconds, except when a leap second is inserted (which is very rare).
Combined with other known bits, like ‘start of second bit’ = DCF bit20, the (noisy/distorted) signal is convoluted
with the known bit sequence to -summarizing- produce Time.

In the figure below (shamelessly stolen from Wikipedia) the mechanism behind convolution is depicted.

What clearly can be seen is that the ‘overlap integral’ is maximal when two identical bit patterns are in sync. In order to
determine this overlap integral properly the local clock source has to be as accurate as possible. Using more bits and
reward the outcome of a convolution process with a quality indicator gives a measure concerning the prediction skill.
In my own words, a sort of pattern recognition which is a PLL, based on the data itself!

After a long story … the result is I now have a VERY accurate DCF77 UTC clock with truly remarkable DCF signal acquisition performance!

At my location the clock needs around 5 minutes to reach the ‘synced’ state:

Decoded time: 15-03-16 1 13:06:48 CET ..
Quality (p,s,m,h,wd,d,m,y,st,tz,ls,pm): 2 (9746-0:255)(71-8:10)(56-42:2)(49-35:2)(21-14:1)(42-35:1)(30-24:1)(24-18:1)14,7,7,255
Clock state: synced
Tick: 14
confirmed_precision ?? adjustment, deviation, elapsed
0 Hz @+ , -335 Hz, 0 ticks, 0 min, 4303 cs mod 60000

Here is my preliminary Arduino sketch. It’s a somewhat patched ‘Superfilter’ sketch.

I did some simple tests. It is important to obtain a lock or sync. Once locked or synced it’s almost
impossible here to let the clock run in ‘free’ mode, except when disconnecting the DCF receiving module.