time
[
Пред. ] [ Содержание ] [
След. ]
time
Created Понедельник 23 Апрель 2018
Радиостанции стандартных частот и времени
кГц кВт Страна Позывной сигнал
2500 50 UZB УЛВ4 (Ташкент)
4996 50 RUS РВМ (Москва)
5000 50 UZB УЛВ4 (Ташкент)
5004 RUS РИД (Иркутск)
9996 50 RUS РВМ (Москва)
10000 RUS РТА (Новосибирск)
10000 50 UZB УЛВ4 (Ташкент)
10004 RUS РИД (Иркутск)
14996 50 RUS РВМ (Москва)
15000 RUS РТА (Новосибирск)
15004 RUS РИД (Иркутск)
(Источник : WRTH-2003)
2749 620РВМ-???
Декодирование сигнала
Загрузим файл с помощью 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()
Мы видим типичную амплитудную модуляцию:

Для упрощения декодирования возьмем огибающую сигнала с помощью преобразования Гильберта:
analytic_signal = signal.hilbert(data)
A = np.abs(analytic_signal)
plt.plot(A[:100000])Результат в увеличенном виде:

Сгладим выбросы от помех с помощью 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Результат (желтая линия): практически прямоугольный сигнал, который довольно легко анализировать.

Парсинг
Сначала нужно получить битовую последовательность. Сама структура сигнала очень проста.

Импульсы поделены на секундные интервалы. Если расстояние между импульсами составляет 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 бит, в которых закодировано достаточно много информации:

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

Для тех, кто захочет поэкспериментировать самостоятельно, код для декодирования приведен под спойлером.
Исходный кодЗапустив программу, мы увидим примерно такой вывод:
0011110110111000001011000001010000100110010101100010011000
Tuesday, 26.03.19, 21:41
0001111100110110001010100001010000100110010101100010011000
Tuesday, 26.03.19, 21:42Собственно, вот и вся магия. Плюс такой системы в том, что декодирование чрезвычайно простое, и может быть сделано на любом, самом несложном микроконтроллере. Просто считаем длину импульсов, накапливаем 60 бит, и в конце каждой минуты получаем точное время. По сравнению с другими способами синхронизации времени (GPS например, или не дай бог, Интернет:), такая радиосинхронизация практически не требует электроэнергии — для примера, обычная домашняя метеостанция работает около года от 2х батареек АА. Поэтому с радиосинхронизацией делают даже наручные часы, не говоря уже конечно, о настенных или об уличных вокзальных.
Удобство и простота DCF привлекают и любителей самоделок. Всего за 10-20$ можно купить готовый модуль из антенны с готовым приемником и TTL-выходом, который можно подключить к Arduino или другому контроллеру.

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

Найти такой можно на ebay по ключевым словам «Radio Controlled Movement».
И наконец, лайфхак для тех, кто дочитал досюда. Даже если в ближайших паре тысяч км нет ни одного передатчика радиосигнала, такой сигнал несложно сгенерировать самостоятельно. В Google Play есть программа с названием «DCF77 Emulator», которая выводит сигнал на наушники. По заверениям автора, если обмотать провод наушников вокруг часов, они поймают сигнал (интересно как, ведь обычные наушники не выдадут сигнал 77КГц, но вероятно прием идет за счет гармоник). У меня на Android 9 программа не заработала совсем — просто не было звука (а может я его не слышал — 77КГц ведь:), но может кому-то повезет больше. Некоторые впрочем, делают себе и полноценный генератор сигналов DCF, который несложно сделать на той же Arduino или ESP32:
(источник
sgfantasytoys.wordpress.com/2015/05/13/synchronize-radio-controlled-watch-without-access)
Содержание