📜 ⬆️ ⬇️

DCF77: how does the exact time signaling system work?

Hi Habr.

Probably many who buy a clock or weather station, saw on the package logo Radio Controlled Clock or even Atomic Clock. This is very convenient, because it is enough to put the clock on the table, and after some time they will automatically adjust to the exact time.


')
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 DCF-77 system , Japan has its own JJY system, the USA has the WWVB system, 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 (residents of the Far East may have the opposite opinion, although they, in turn, can receive and analyze the Japanese signal;).

Everything written further will be about DCF77.

Receive signal


DCF77 is a long-wave station operating at 77.5 kHz and transmitting signals in amplitude modulation. The station with a capacity of 50 kW is located 25 km from Frankfurt, it began work in 1959, in 1973 the date information was added to the exact time. The wavelength at 77KHz is quite large, so the dimensions of the antenna field are also quite decent (photo from Wikipedia):



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



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



In the same place we press the download button and record a fragment of several minutes in length. Of course, if you have a “real” receiver that can record a frequency of 77.5KHz, you can also use it.

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

So, we got a record, let's proceed to its processing.

Signal decoding


Load the file using 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 typical amplitude modulation:



To simplify decoding, let's take the signal envelope using the Hilbert transform:

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

Result in an enlarged form:



Smooth out emissions from noise using a low-pass filter, at the same time we calculate the average value, it is useful 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): almost square wave, which is fairly easy to analyze.



Parsing


First you need to get a bit sequence. The structure of the signal itself is very simple.



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

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 minutes it looks like this:

0011110110111000001011000001010000100110010101100010011000
0001111100110110001010100001010000100110010101100010011000


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

Our last step: get the actual data. Bits are transmitted once per second, so we have only 59 bits in which a lot of information is encoded:



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



For those who want to experiment on their own, the code for decoding 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:

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, very simple microcontroller. 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 time synchronization methods (GPS, for example, or, God forbid, the Internet :), this radio synchronization practically does not require electricity - for example, an ordinary home weather station works for about a year with 2 AA batteries. Therefore, even watches are made with radio synchronization, not to mention, of course, wall or street stations.

Convenience and simplicity DCF attract homemade lovers. For only $ 10-20, you can buy a ready-made module from an antenna with a ready-made receiver and a TTL output that can be connected to an Arduino or another controller.



For Arduino already written and ready libraries . However, and so it is known - whatever you do on the microcontroller, you get either a clock or a weather station. With such a device to get the exact time is really easy, if of course be 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 actually synchronized using an atomic clock.

Those interested can even upgrade the old grandmother's clock by installing a new mechanism with radio synchronization in them:



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

And finally, a life hack for those who read this far. Even if in the next couple of thousands of kilometers there is not a single radio signal transmitter, it’s easy to generate such a signal yourself. On Google Play, there is a program called “DCF77 Emulator” that outputs the signal to the headphones. According to the author, if you wind 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 reception comes at the expense of harmonics). The program did not work on my Android 9 at all - there was simply no sound (or maybe I didn’t hear it - 77KHz, after all :), but maybe someone will have better luck. Some, however, make themselves a full-fledged DCF signal generator, which is easy to do on the same Arduino or ESP32:


(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 a simple and cheap receiver, you can have the exact time anytime, anywhere, 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.

Source: https://habr.com/ru/post/445470/


All Articles