DCF77: how does the time signaling system work?

Hello Habr.

Probably many who purchase a watch or a weather station have seen the Radio Controlled Clock or even Atomic Clock logo on the packaging. This is very convenient, because it is enough to put the clock on the table, and after a while it will automatically adjust to the exact time.
DCF77: how does the time signaling system work?

Let's figure out how it works and write a decoder in Python.

There are different time synchronization systems. The most popular in Europe is the German system DCF-77Japan has its own system JJY, in the USA there is a system WWVB, and so on. Further, the story will be about DCF77, as the most relevant and accessible for reception in some places of the European part of Russia and neighboring countries (the inhabitants of the Far East may have the opposite opinion, however, they, in turn, can receive and analyze the Japanese signal;).

Everything written below will be about DCF77.

Signal reception

The DCF77 is a longwave station operating at 77.5KHz and transmitting AM signals. The station with a capacity of 50 kW is located 25 km from Frankfurt, it began work in 1959, in 1973 information about the date was added to the exact time. The wavelength at a frequency of 77 kHz is very large, so the dimensions of the antenna field are also very decent (photo from Wikipedia):
DCF77: how does the time signaling system work?

With such an antenna and input power, the reception area covers almost the whole of Europe, Belarus, Ukraine and part of Russia.

DCF77: how does the time signaling system work?

Anyone can record. To do this, just go to the online receiver http://websdr.ewi.utwente.nl:8901/, select a frequency of 76.5KHz and USB modulation there. An image should appear something like this:

DCF77: how does the time signaling system work?

In the same place, we press the download button and record a fragment a few minutes long. Of course, if you have a "real" receiver capable of recording a frequency of 77.5 kHz, you can use it.

Of course, when receiving accurate time radio signals over the Internet, we will not get a really accurate time - the signal is transmitted with a delay. But our goal is only to understand the structure of the signal, for this the Internet recording is more than enough. In real life, of course, specialized devices are used for receiving and decoding, they will be discussed below.

So, we received the record, let's start processing it.

Signal decoding

Let's load the file with Python and see its structure:

from scipy.io import wavfile
from scipy import signal
import matplotlib.pyplot as plt
import numpy as np

sample_rate, data = wavfile.read("dcf_websdr_2019-03-26T20_25_34Z_76.6kHz.wav")
plt.plot(data[:100000])
plt.show()

We see a typical amplitude modulation:
DCF77: how does the time signaling system work?

To simplify decoding, we take the signal envelope using the Hilbert transform:

analytic_signal = signal.hilbert(data)
A = np.abs(analytic_signal)
plt.plot(A[:100000])

Expanded result:
DCF77: how does the time signaling system work?

Let's smooth out noise emissions using a low-pass filter, at the same time calculate the average value, it will come in handy later for parsing.

b, a = signal.butter(2, 20.0/sample_rate)
zi = signal.lfilter_zi(b, a)
A, _ = signal.lfilter(b, a, A, zi=zi*A[0])
avg = (np.amax(A) + np.amin(A))/2

Result (yellow line): an almost rectangular signal that is fairly easy to analyze.
DCF77: how does the time signaling system work?

Parsing

First you need to get the bit sequence. The signal structure itself is very simple.
DCF77: how does the time signaling system work?

The pulses are divided into second intervals. If the distance between pulses is 0.1s (i.e., the length of the pulse itself is 0.9s), we add “0” to the bit sequence, if the distance is 0.2s (i.e., the length is 0.8s), we add “1”. The end of each minute is indicated by a "long" pulse, 2 s long, the bit sequence is reset to zero, and the filling starts again.

The above is easy to write in Python.

sig_start, sig_stop = 0, 0
pos = 0
bits_str = ""
while pos < cnt - 4:
    if A[pos] < avg and A[pos+1] > avg:
        # Signal begin
        sig_start = pos
    if A[pos] > avg and A[pos+1] < avg:
        # Signal end
        sig_stop = pos

        diff = sig_stop - sig_start
    
        if diff < 0.85*sample_rate:
            bits_str += "1"
        if diff > 0.85*sample_rate and diff < 1.25*sample_rate:
            bits_str += "0"
        if diff > 1.5*sample_rate:
            print(bits_str)
            bits_str = ""

    pos += 1

As a result, we get a sequence of bits, in our example for two seconds it looks like this:

0011110110111000001011000001010000100110010101100010011000
0001111100110110001010100001010000100110010101100010011000

By the way, it is interesting that there is also a “second layer” of data in the signal. The bit sequence is also encoded with phase modulation. Theoretically, this should provide more robust decoding even in the case of a weakened signal.

Our last step: get the actual data. Bits are transmitted once per second, so we have only 59 bits, in which quite a lot of information is encoded:
DCF77: how does the time signaling system work?

The bits are described in Wikipediaand they are quite curious. The first 15 bits are not used, although there were plans to use them for public address and civil defense systems. Bit A1 indicates that the clock will change to daylight saving time in the next hour. Bit A2 indicates that the next hour will be added leap second, which is sometimes used to correct the time according to the rotation of the Earth. The remaining bits encode hours, minutes, seconds, and date.

DCF77: how does the time signaling system work?

For those who want to experiment on their own, the decoding code is given under the spoiler.
Source

def decode(bits):
    if bits[0] != '0' or bits[20] != '1':
        return
    
    minutes, hours, day_of_month, weekday, month, year = map(convert_block,
                                                             (bits[21:28], bits[29:35], bits[36:42], bits[42:45],
                                                              bits[45:50], bits[50:58]))
    days = ('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday')
    print('{dow}, {dom:02}.{mon:02}.{y}, {h:02}:{m:02}'.format(h=hours, m=minutes, dow=days[weekday],
                                                               dom=day_of_month, mon=month, y=year))


def convert_ones(bits):
    return sum(2**i for i, bit in enumerate(bits) if bit == '1')


def convert_tens(bits):
    return 10*convert_ones(bits)


def right_parity(bits, parity_bit):
    num_of_ones = sum(int(bit) for bit in bits)
    return num_of_ones % 2 == int(parity_bit)


def convert_block(bits, parity=False):
    if parity and not right_parity(bits[:-1], bits[-1]):
        return -1
    
    ones = bits[:4]
    tens = bits[4:]
    return convert_tens(tens) + convert_ones(ones)

Running the program, we will see something like this output:

0011110110111000001011000001010000100110010101100010011000
Tuesday, 26.03.19, 21:41
0001111100110110001010100001010000100110010101100010011000
Tuesday, 26.03.19, 21:42

Actually, that's all the magic. The advantage of such a system is that decoding is extremely simple, and can be done on any, the most uncomplicated microcontroller. We just count the length of the pulses, accumulate 60 bits, and at the end of each minute we get the exact time. Compared to other methods of time synchronization (GPS, for example, or God forbid, the Internet :), such radio synchronization practically does not require electricity - for example, an ordinary home weather station works for about a year on 2 AA batteries. Therefore, even wristwatches are made with radio synchronization, not to mention, of course, wall clocks or street station clocks.

The convenience and simplicity of the DCF also attract DIY enthusiasts. For only $10-20, you can buy a ready-made antenna module with a ready-made receiver and a TTL output that can be connected to an Arduino or other controller.
DCF77: how does the time signaling system work?

For Arduino already written and ready-made libraries. However, it is already known that whatever you do on the microcontroller, you get either a clock or a weather station. With such a device, getting the exact time is really easy, unless of course you are in the reception area. Well, you can hang the inscription “Atomic Clock” on the clock, and at the same time explain to everyone that the device is really synchronized using an atomic clock.

Those who wish can even upgrade the old grandmother's watch by installing a new mechanism with radio synchronization:

DCF77: how does the time signaling system work?

You can find one on ebay using the keywords "Radio Controlled Movement".

And finally, a life hack for those who have read this far. Even if there is not a single radio signal transmitter in the next couple of thousand kilometers, such a signal is easy to generate on your own. There is a program on Google Play called "DCF77 Emulator" that outputs a signal to the headphones. According to the author, if you wrap the headphone wire around the clock, they will catch the signal (I wonder how, because ordinary headphones will not give out a 77KHz signal, but probably the reception is due to harmonics). The program didn’t work for me on Android 9 at all - there was simply no sound (or maybe I didn’t hear it - 77KHz, after all :), but maybe someone will be more lucky. Some, however, make themselves a full-fledged DCF signal generator, which is easy to do on the same Arduino or ESP32:

DCF77: how does the time signaling system work?
(a source sgfantasytoys.wordpress.com/2015/05/13/synchronize-radio-controlled-watch-without-access)

Conclusion

The DCF system turned out to be really quite simple and convenient. With the help of a simple and cheap receiver, you can have the exact time always and everywhere, of course in the reception area. It seems that even despite the widespread digitalization and the “Internet of Things”, such simple solutions will be in demand for a long time to come.

Source: habr.com

Add a comment