DCF77: jak działa system przesyłania sygnałów dokładnego czasu?

Cześć Habr.

Prawdopodobnie wielu z tych, którzy kupują zegary lub stacje pogodowe, widziało na opakowaniu logo Radio Controlled Clock lub nawet Atomic Clock. To bardzo wygodne, ponieważ wystarczy postawić zegar na stole, a on po chwili automatycznie dostosuje się do dokładnego czasu.
DCF77: jak działa system przesyłania sygnałów dokładnego czasu?

Zobaczmy, jak to działa i napiszemy dekoder w języku Python.

Istnieją różne systemy synchronizacji czasu. Najbardziej popularny w Europie to niemiecki system DCF-77, w Japonii mamy swój system JJY, w USA istnieje system WWVB, i tak dalej. Dalej opowieść będzie o DCF77, jako o najbardziej aktualnym i dostępnym do odbioru w niektórych miejscach europejskiej części Rosji i sąsiednich krajach (mieszkańcy Dalekiego Wschodu mogą mieć odmienne zdanie, aczkolwiek mogą czytać i analizować również sygnał japoński;).

Wszystko, co będzie napisane dalej, będzie o DCF77.

Odbieranie sygnału

DCF77 to stacja długofalowa działająca na częstotliwości 77,5 kHz, która przesyła sygnały w amplitudowej modulacji. Stacja o mocy 50 kW znajduje się 25 km od Frankfurtu, rozpoczęła działalność już w 1959 roku, a w 1973 roku do dokładnego czasu dodano informację o dacie. Długość fali przy częstotliwości 77 kHz jest dość duża, dlatego rozmiary pola antenowego są również dość duże (zdjęcie z Wikipedii):
DCF77: jak działa system przesyłania sygnałów dokładnego czasu?

Przy takiej antenie i dostarczanej mocy, strefa odbioru obejmuje praktycznie całą Europę, Białoruś, Ukrainę i część Rosji.

DCF77: jak działa system przesyłania sygnałów dokładnego czasu?

Każdy może nagrać sygnał. Wystarczy wejść na odbiornik online http://websdr.ewi.utwente.nl:8901/, wybrać tam częstotliwość 76,5 kHz i modulację USB. Powinno się otworzyć zdjęcie w mniej więcej takim stylu:

DCF77: jak działa system przesyłania sygnałów dokładnego czasu?

Tam także naciskamy przycisk download i nagrywamy fragment trwający kilka minut. Oczywiście, gdy mamy 'prawdziwy' odbiornik, zdolny nagrać częstotliwość 77,5 kHz, można go również użyć.

Oczywiście, odbierając sygnały radiowe dokładnego czasu przez Internet, nie uzyskamy naprawdę dokładnego czasu — sygnał jest przesyłany z opóźnieniem. Ale naszym celem jest tylko zrozumieć strukturę sygnału, do tego internetowe nagrania są więcej niż wystarczające. W rzeczywistości oczywiście używa się specjalistycznych urządzeń do odbioru i dekodowania, o nich będzie mowa poniżej.

Zatem otrzymamy nagranie, przejdźmy do jego obróbki.

Dekodowanie sygnału

Załadujemy plik za pomocą Pythona i przyjrzymy się jego strukturze:

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()

Widzimy typową modulację amplitudy:
DCF77: jak działa system przesyłania sygnałów dokładnego czasu?

Aby uprościć dekodowanie, weźmy obwiednię sygnału za pomocą transformacji Hilberta:

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

Wynik w powiększeniu:
DCF77: jak działa system przesyłania sygnałów dokładnego czasu?

Wygładzimy szumy przy pomocy filtru dolnoprzepustowego, jednocześnie obliczając średnią, która przyda się później do parsowania.

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

Wynik (żółta linia): praktycznie prostokątny sygnał, który jest dość łatwy do analizy.
DCF77: jak działa system przesyłania sygnałów dokładnego czasu?

Parsowanie

Najpierw musimy uzyskać sekwencję bitów. Sama struktura sygnału jest bardzo prosta.
DCF77: jak działa system przesyłania sygnałów dokładnego czasu?

Impulsy są podzielone na sekundy. Jeśli odległość między impulsami wynosi 0.1 s (tzn. długość samego impulsu 0.9 s), do sekwencji bitów dodajemy „0”, jeśli odległość wynosi 0.2 s (tzn. długość 0.8 s), dodajemy „1”. Koniec każdej minuty oznaczany jest „długim” impulsem, trwającym 2 s, sekwencja bitów przy tym jest zerowana, a wypełnianie zaczyna się od nowa.

To, co zostało napisane wyżej, nie jest trudne do zapisania w języku Python.

sig_start, sig_stop = 0, 0
pos = 0
bits_str = ""
while pos < cnt - 4:
    if A[pos]  avg:
        # Początek sygnału
        sig_start = pos
    if A[pos] > avg and A[pos+1] < avg:
        # Koniec sygnału
        sig_stop = pos

        diff = sig_stop - sig_start
    
        if diff  0.85*sample_rate and diff  1.5*sample_rate:
            print(bits_str)
            bits_str = ""

    pos += 1

W rezultacie otrzymujemy sekwencję bitów, w naszym przykładzie dla dwóch sekund wygląda ona tak:

0011110110111000001011000001010000100110010101100010011000
0001111100110110001010100001010000100110010101100010011000

Ciekawostką jest to, że w sygnale istnieje i "druga warstwa" danych. Sekwencja bitów jest również zakodowana za pomocą modulacji fazowej. Teoretycznie powinno to zapewnić bardziej stabilne dekodowanie nawet w przypadku osłabionego sygnału.

Nasz ostatni krok: uzyskanie właściwych danych. Bity przesyłane są raz na sekundę, więc mamy łącznie 59 bitów, w których zakodowane jest wystarczająco dużo informacji:
DCF77: jak działa system przesyłania sygnałów dokładnego czasu?

Bity są opisane w Wikipedii, i są dość ciekawe. Pierwsze 15 bitów nie jest używanych, chociaż były plany wykorzystania ich do systemów alarmowych i obrony cywilnej. Bit A1 wskazuje, że w następnym godzinie zegary będą przestawione na czas letni. Bit A2 wskazuje, że w następnym godzinie będzie dodana dodatkowa sekunda, która czasami jest używana do dostosowywania czasu do obrotu Ziemi. Pozostałe bity kodują godziny, minuty, sekundy i datę.

DCF77: jak działa system przesyłania sygnałów dokładnego czasu?

Dla tych, którzy chcą eksperymentować samodzielnie, kod do dekodowania jest pod spoylerem.
Kod źródłowy

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 = ('Niedziela', 'Poniedziałek', 'Wtorek', 'Środa', 'Czwartek', 'Piątek', 'Sobota', 'Niedziela')
    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)

Uruchamiając program, zobaczymy mniej więcej taki wynik:

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

Właściwie, to cała magia. Zaleta tego systemu polega na tym, że dekodowanie jest niezwykle proste i może być zrealizowane na dowolnym, najmniej skomplikowanym mikrokontrolerze. Po prostu liczymy długość impulsów, zbieramy 60 bitów, a na końcu każdej minuty otrzymujemy dokładny czas. W porównaniu do innych metod synchronizacji czasu (np. GPS, albo, nie daj Boże, Internet:), taka radiowa synchronizacja wymaga praktycznie żadnej energii — na przykład, zwykła domowa stacja meteorologiczna działa przez około rok na dwóch bateriaach AA. Dlatego z radiową synchronizacją robią nawet zegarki na rękę, nie mówiąc już o zegarach ściennych czy na dworcach.

Wygoda i prostota DCF przyciągają także amatorów DIY. Za 10-20$ można kupić gotowy moduł z anteną z gotowym odbiornikiem i wyjściem TTL, który można podłączyć do Arduino lub innego kontrolera.
DCF77: jak działa system przesyłania sygnałów dokładnego czasu?

Dla Arduino już zostały napisane i gotowe biblioteki. Jednak wiadomo, że cokolwiek by robić na mikrokontrolerze, zawsze kończy się to na zegarku lub stacji meteorologicznej. Z takim urządzeniem uzyskanie dokładnego czasu naprawdę nie jest trudne, o ile oczywiście znajduje się w zasięgu sygnału. Można też powiesić na zegarze napis „Atomic Clock” i tłumaczyć wszystkim, że urządzenie rzeczywiście synchronizuje się z atomowymi zegarami.

Chętni mogą nawet zmodernizować stare zegarki babci, instalując w nich nowy mechanizm z radiową synchronizacją:

DCF77: jak działa system przesyłania sygnałów dokładnego czasu?

Można go znaleźć na eBayu, korzystając z hasła „Radio Controlled Movement”.

I na koniec, wskazówka dla tych, którzy dotarli aż tutaj. Nawet jeśli w najbliższych kilku tysiącach kilometrów nie ma żadnego nadajnika radiowego, sygnał można łatwo wygenerować samodzielnie. W Google Play jest program o nazwie „DCF77 Emulator”, który emituje sygnał na słuchawki. Według zapewnień autora, jeśli okręcić przewód słuchawek wokół zegarka, złapią one sygnał (ciekawe jak, bo zwykłe słuchawki nie wygenerują sygnału 77 kHz, ale prawdopodobnie odbiór odbywa się dzięki harmonicznym). U mnie na Androidzie 9 program w ogóle nie zadziałał - po prostu nie było dźwięku (a może go nie słyszałem - 77 kHz przecież :), ale może komuś pójdzie lepiej. Niektórzy zresztą budują sobie pełnoprawny generator sygnałów DCF, który można łatwo zrobić na tej samej Arduino lub ESP32:

DCF77: jak działa system przesyłania sygnałów dokładnego czasu?
(źródło sgfantasytoys.wordpress.com/2015/05/13/synchronize-radio-controlled-watch-without-access)

Podsumowanie

System DCF okazał się naprawdę dość prosty i wygodny. Przy pomocy prostego i taniego odbiornika można mieć dokładny czas zawsze i wszędzie, oczywiście w zasięgu sygnału. Myślę, że nawet pomimo powszechnej cyfryzacji i „Internetu rzeczy” takie proste rozwiązania będą pożądane jeszcze przez długi czas.

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster