Salutami Habr.
Probabilmente parechji chì acquistanu un orologio o una stazione meteorologica anu vistu u Clock Radio Controlled o ancu u logu di l'Orologio Atomicu nantu à l'imballu. Questu hè assai còmuda, perchè avete bisognu di mette u clock nantu à a tavula, è dopu un pocu tempu si aghjustà automaticamente à l'ora esatta.

Scupritemu cumu funziona è scrive un decodificatore in Python.
Ci sò diversi sistemi di sincronizazione di u tempu. U più populari in Europa hè u sistema tedescu , u Giappone hà u so propiu sistema , in i Stati Uniti ci hè un sistema , eccetera. In seguitu, a storia serà nantu à DCF77, cum'è u più pertinenti è accessibile per l'accolta in certi lochi in a parte europea di Russia è i paesi vicini (i residenti di l'Estremo Oriente ponu avè l'opinione opposta, però, à u turnu, ponu riceve. è analizà u signale giapponese;).
Tuttu ciò chì hè scrittu quì sottu serà nantu à u DCF77.
Ricezzione di signali
DCF77 hè una stazione d'onda longa chì opera à una frequenza di 77.5 kHz è trasmette segnali in modulazione di amplitude. A stazione 50KW hè situata à 25 km da Francoforte, hà cuminciatu à operare in u 1959, è in u 1973 l'infurmazione di data hè stata aghjunta à l'ora esatta. A lunghezza d'onda à una freccia di 77 KHz hè assai longa, cusì e dimensioni di u campu di l'antenna sò ancu abbastanza decentu (foto da Wikipedia):

Cù una tale antenna è input di putenza, a zona di ricezione copre quasi tutta l'Europa, Bielorussia, Ucraina è parte di Russia.

Qualchese pò arregistrà un signalu. Per fà questu, basta à andà à u ricevitore in linea , selezziunate a frequenza 76.5KHz è a modulazione USB quì. Una maghjina deve esse aperta chì pare cusì cusì:

Ci avemu appughjà u buttone di scaricamentu è arregistrà un fragmentu longu parechji minuti. Di sicuru, sè vo avete un "veru" receptore capace di registrà a freccia di 77.5KHz, pudete aduprà.
Di sicuru, ricevendu segnali di u tempu di radio via Internet, ùn riceveremu micca u tempu veramente precisu - u signale hè trasmessu cun ritardu. Ma u nostru scopu hè solu di capisce a struttura di u signale; per questu, a registrazione in Internet hè più chè abbastanza. In a vita reale, sicuru, i dispositi specializati sò usati per riceve è decodificà; seranu discututi quì sottu.
Dunque, avemu ricevutu a registrazione, cuminciamu à processà.
Decodificazione di signali
Caricà u schedariu cù Python è vede a so struttura:
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()
Avemu vistu a modulazione di amplitude tipica:

Per simplificà a decodificazione, pigliemu l'envelope di signale utilizendu a trasformazione di Hilbert:
analytic_signal = signal.hilbert(data)
A = np.abs(analytic_signal)
plt.plot(A[:100000])
Risultatu ingrandatu:

Lisciamu l'emissioni di rumore cù un filtru low-pass, è à u stessu tempu calcule u valore mediu, chì serà utile più tardi per l'analisi.
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
Risultatu (linea gialla): un signalu d'onda quasi quatratu chì hè abbastanza faciule da analizà.

Parsing
Prima avete bisognu di ottene a sequenza di bit. A struttura di u signale stessu hè assai simplice.

I pulsati sò spartuti in secunni intervalli. Se a distanza trà i pulsazioni hè 0.1 s (vale à dì a durata di l'impulsu stessu hè 0.9 s), aghjunghje "0" à a sequenza di bit; se a distanza hè 0.2 s (vale à dì a durata hè 0.8 s), aghjunghje "1". A fine di ogni minutu hè indicatu da un impulsu "longu", 2s longu, a sequenza di bit hè resettata à zero, è u riempimentu principia di novu.
U sopra hè faciule da scrive 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
In u risultatu, avemu una sequenza di bits, in u nostru esempiu per dui seconde pare cusì:
0011110110111000001011000001010000100110010101100010011000
0001111100110110001010100001010000100110010101100010011000
In modu, hè interessante chì u signale hà ancu una "seconda capa" di dati. A sequenza di bit hè ancu codificata usendu . In teoria, questu deve furnisce una decodificazione più robusta ancu in u casu di un signalu debilitatu.
U nostru ultimu passu: uttene e dati attuali. Bits sò trasmessi una volta per seconda, cusì avemu un totale di 59 bits, in quale assai infurmazione hè codificata:

I pezzi sò descritti in , è sò abbastanza curiosi. I primi 15 bits ùn sò micca utilizati, ancu s'ellu ci sò stati piani di usà per i sistemi d'avvertimentu è a difesa civile. Bit A1 indica chì u clock cambierà à l'ora d'estate in l'ora dopu. Bit A2 indica chì un supplementu , chì hè qualchì volta usatu per aghjustà u tempu secondu a rotazione di a Terra. I bits restante codificanu ore, minuti, seconde è data.

Per quelli chì volenu sperimentà per sè stessu, u codice di decodificazione hè datu sottu u spoiler.
Codice fonte
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)
Quandu eseguimu u prugramma, vedemu un output simile à questu:
0011110110111000001011000001010000100110010101100010011000
Tuesday, 26.03.19, 21:41
0001111100110110001010100001010000100110010101100010011000
Tuesday, 26.03.19, 21:42
In fatti, hè tutta a magia. U vantaghju di un tali sistema hè chì a decodificazione hè assai simplice è pò esse fatta nantu à qualsiasi, ancu u microcontroller più simplice. Contemu simpricimenti a durata di l'impulsi, accumule 60 bits, è à a fine di ogni minutu avemu u tempu esatta. In cunfrontu cù altri metudi di sincronizazione di u tempu (GPS, per esempiu, o Diu ùn ci vole, Internet :), una tale sincronizazione di a radiu ùn hà micca bisognu di elettricità - per esempiu, una stazione meteorologica regulare di casa funziona per circa un annu nantu à 2 batterie AA. Per quessa, ancu i wristwatches sò fatti cù a sincronizazione di radiu, per ùn dì, di sicuru, orologio di muru o orologio di stazione di strada.
A cunvenzione è a simplicità di DCF attrae ancu i dilettanti di DIY. Per solu $ 10-20 pudete cumprà un modulu d'antenna pronta cù un ricevitore prontu è un output TTL, chì pò esse cunnessu à un Arduino o un altru controller.

Già scrittu per Arduino . In ogni casu, hè digià cunnisciutu chì ùn importa ciò chì fate nantu à un microcontroller, finiscinu cù un clock o una stazione meteorologica. Cù un tali dispusitivu, uttene l'ora esatta hè veramente faciule, basta, sicuru, chì site in l'area di ricezione. Ebbè, pudete appiccà l'inscription "Atomic Clock" in u vostru sguardu, è à u stessu tempu spiegà à tutti chì u dispusitivu hè veramente sincronizatu cù un clock atomicu.
Quelli chì vulianu ponu ancu aghjurnà l'orologio di a so vechja nanna installendu un novu mecanismu cù sincronizazione radio:

Pudete truvà unu in ebay utilizendu e parolle chjave "Movimentu Radio Controlled".
È infine, un truccu di vita per quelli chì anu lettu finu à quì. Ancu s'ellu ùn ci hè micca un solu trasmettitore radio in un paru di millaie di chilometri, hè faciule di generà unu voi stessu. Ci hè una applicazione in Google Play chjamata "DCF77 Emulator" chì emette un signale à l'auricolari. L'autore afferma chì se avvolgete u cavu di l'auricolari intornu à l'orologio, riceverà u signale (mi dumandu cumu, postu chì l'auricolari regulari ùn producenu micca un signale di 77 kHz, ma hè probabilmente per via di l'armoniche). Nant'à u mo orologio... Android U prugramma 9 ùn hà micca funziunatu - ùn ci era micca sonu (o forse ùn pudia micca sentelu - hè 77 kHz, dopu tuttu. :)), ma forse qualchissia altru averà più furtuna. Certi persone, però, custruiscenu u so propiu generatore di signali DCF cumpletu, chì hè faciule da fà cù un Arduino o ESP32:

(surghjente )
cunchiusioni
U sistema DCF hè diventatu veramente abbastanza simplice è cunvene. Cù l'aiutu di un ricevitore simplice è prezzu, pudete avè l'ora esatta sempre è in ogni locu, sicuru in l'area di ricezione. Sembra chì ancu malgradu a digitalizazione diffusa è l'Internet di e Cose, tali suluzioni simplici seranu dumandate per un bellu pezzu.
Source: www.habr.com
