DCF77: як працює система передавання сигналів точного часу?

Привіт Хабр.

Напевно багато хто набуває годинника або метеостанції, бачили на упаковці логотип Radio Controlled Clock або навіть Atomic Clock. Це дуже зручно, адже достатньо поставити годинник на стіл, і вони через деякий час автоматично налаштуються на точний час.
DCF77: як працює система передавання сигналів точного часу?

Розберемося як це працює і напишемо декодер мовою Python.

Існують різні системи синхронізації часу. Найбільш популярна в Європі – німецька система DCF-77, у Японії є своя система JJY, у США є система WWVB, і так далі. Далі розповідь буде про DCF77, як про найбільш актуальну та доступну для прийому в деяких місцях європейську частину Росії та сусідні країни (у жителів Далекого Сходу може бути протилежна думка, втім вони у свою чергу можуть прийняти та проаналізувати японський сигнал;).

Все написане далі буде про DCF77.

Прийом сигналу

DCF77 це довгохвильова станція, що працює на частоті 77.5КГц, та передає сигнали в амплітудній модуляції. Станція потужністю 50КВт розташована в 25км від Франкфурта, вона розпочала роботу ще в 1959 році, в 1973 році до точного часу була додана інформація про дату. Довжина хвилі при частоті 77КГц дуже велика, тому розміри антенного поля теж дуже пристойні (фото з Вікіпедії):
DCF77: як працює система передавання сигналів точного часу?

За такої антени і потужності, що підводиться, зона прийому охоплює практично всю Європу, Білорусь, Україну і частину Росії.

DCF77: як працює система передавання сигналів точного часу?

Записати сигнал може кожен. Для цього достатньо зайти на онлайн-приймач http://websdr.ewi.utwente.nl:8901/, Вибрати там частоту 76.5КГц та USB-модуляцію. Повинна відкритися картинка приблизно такого типу:

DCF77: як працює система передавання сигналів точного часу?

Там же натискаємо кнопку download і записуємо фрагмент завдовжки кілька хвилин. Зрозуміло, за наявності «справжнього» приймача, здатного записати частоту 77.5КГц, можна використовувати його.

Звичайно, приймаючи радіосигнали точного часу через Інтернет, ми не отримаємо справді точний час – сигнал передається із затримкою. Але наша мета лише зрозуміти структуру сигналу, для цього інтернет-запису більш ніж достатньо. У реалі, звичайно, використовуються спеціалізовані пристрої для прийому та декодування, про них буде сказано нижче.

Отже, ми отримали запис, приступимо до її обробки.

Декодування сигналу

Завантажимо файл за допомогою Python та подивимося його структуру:

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

Ми бачимо типову амплітудну модуляцію:
DCF77: як працює система передавання сигналів точного часу?

Для спрощення декодування візьмемо огинаючу сигналу за допомогою перетворення Гільберта:

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

Результат у збільшеному вигляді:
DCF77: як працює система передавання сигналів точного часу?

Згладимо викиди від перешкод за допомогою low-pass фільтра, заодно обчислимо середнє значення, воно стане в нагоді потім для парсингу.

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

Результат (жовта лінія) практично прямокутний сигнал, який досить легко аналізувати.
DCF77: як працює система передавання сигналів точного часу?

Парсінг

Спочатку потрібно отримати бітову послідовність. Сама структура сигналу дуже проста.
DCF77: як працює система передавання сигналів точного часу?

Імпульси поділені на секундні інтервали. Якщо відстань між імпульсами становить 0.1с (тобто довжина самого імпульсу 0.9с), до бітової послідовності додаємо «0», якщо відстань становить 0.2с (тобто довжина 0.8с), додаємо «1». Кінець кожної хвилини позначається "довгим" імпульсом, довжиною 2с, бітова послідовність при цьому обнулюється, і заповнення починається наново.

Написане вище нескладно записати мовою 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

В результаті отримуємо послідовність біт, у нашому прикладі для двох секунд вона виглядає так:

0011110110111000001011000001010000100110010101100010011000
0001111100110110001010100001010000100110010101100010011000

До речі, цікаво, що в сигналі є і «другий шар» даних. Послідовність біт також закодована за допомогою фазової модуляції. Теоретично, це має забезпечувати стійкіше декодування навіть у разі ослабленого сигналу.

Наш останній крок: отримати власні дані. Біти передаються раз на секунду, тому ми маємо всього 59 біт, у яких закодовано досить багато інформації:
DCF77: як працює система передавання сигналів точного часу?

Біти описані в Вікіпедії, І вони досить цікаві. Перші 15 біт не використовуються, хоча плани були використані для систем оповіщення та цивільної оборони. Біт A1 вказує на те, що наступної години години будуть переведені на літній час. Біт А2 вказує, що наступної години буде додано додаткова секунда, яка іноді використовується для корекції часу відповідно до обертання Землі. Інші біти кодують годинник, хвилину, секунду і дату.

DCF77: як працює система передавання сигналів точного часу?

Для тих, хто захоче експериментувати самостійно, код для декодування наведений під спойлером.
Вихідний код

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)

Запустивши програму, ми побачимо приблизно такий висновок:

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

Власне, ось і вся магія. Плюс такої системи в тому, що декодування надзвичайно просте, і може бути зроблено на будь-якому, найпростішому мікроконтролері. Просто рахуємо довжину імпульсів, накопичуємо 60 біт, і наприкінці кожної хвилини отримуємо точний час. У порівнянні з іншими способами синхронізації часу (GPS наприклад, або не дай боже, Інтернет:), така радіосинхронізація практично не вимагає електроенергії — для прикладу, звичайна домашня метеостанція працює близько року від 2 батарей АА. Тому з радіосинхронізацією роблять навіть наручний годинник, не кажучи вже звичайно, про настінний або про вуличні вокзальні.

Зручність та простота DCF приваблюють і любителів саморобок. Всього за 10-20 $ можна купити готовий модуль з антени з готовим приймачем та TTL-виходом, який можна підключити до Arduino або іншого контролера.
DCF77: як працює система передавання сигналів точного часу?

Для Arduino вже написані та готові бібліотеки. Втім, і так відомо — що не роби на мікроконтролері, виходить годинник або метеостанція. З таким пристроєм отримувати точний час дійсно нескладно, якщо перебувати в зоні прийому. Ну і можна повісити на годинник напис «Atomic Clock», і заразом пояснювати всім бажаючим, що пристрій дійсно синхронізується за допомогою атомного годинника.

Бажаючі можуть навіть проапгрейдить старий бабусиний годинник, встановивши в них новий механізм з радіосинхронізацією:

DCF77: як працює система передавання сигналів точного часу?

Знайти такий можна на ebay за ключовими словами "Radio Controlled Movement".

І нарешті, лайфхак для тих, хто дочитав до сюди. Навіть якщо в найближчих кількох тисячах кілометрів немає жодного передавача радіосигналу, такий сигнал нескладно згенерувати самостійно. У Google Play є програма під назвою «DCF77 Emulator», яка виводить сигнал на навушники. За словами автора, якщо обмотати провід навушників навколо годинника, вони зловлять сигнал (цікаво як, адже звичайні навушники не видадуть сигнал 77КГц, але ймовірно прийом йде за рахунок гармонік). У мене на Android 9 програма не запрацювала зовсім - просто не було звуку (а може я його не чув - адже 77КГц:), але може комусь пощастить більше. Деякі втім роблять собі і повноцінний генератор сигналів DCF, який нескладно зробити на тій же Arduino або ESP32:

DCF77: як працює система передавання сигналів точного часу?
(джерело sgfantasytoys.wordpress.com/2015/05/13/synchronize-radio-controlled-watch-without-access)

Висновок

Система DCF, виявилася дійсно цілком простою та зручною. За допомогою простого і недорогого приймача можна мати точний час завжди і скрізь, очевидно в зоні прийому. Здається, навіть незважаючи на повсюдну цифровізацію та «інтернет речей», такі прості рішення будуть затребувані ще довго.

Джерело: habr.com

Додати коментар або відгук