Ahoj Habr.
Pravdepodobne mnohí, ktorí si kúpia hodinky alebo meteorologickú stanicu, videli na obale logo rádiom riadených hodín alebo dokonca atómových hodín. Je to veľmi výhodné, pretože hodiny stačí položiť na stôl a po chvíli sa automaticky nastavia na presný čas.
Poďme zistiť, ako to funguje, a napíšme dekodér v Pythone.
Existujú rôzne systémy synchronizácie času. Najpopulárnejší v Európe je nemecký systém
Všetko napísané nižšie bude o DCF77.
Príjem signálu
DCF77 je stanica s dlhými vlnami, ktorá pracuje na frekvencii 77.5 kHz a vysiela signály v amplitúdovej modulácii. Stanica s výkonom 50 kW sa nachádza 25 km od Frankfurtu, začala svoju prevádzku v roku 1959 a v roku 1973 bola k presnému času pridaná informácia o dátume. Vlnová dĺžka pri frekvencii 77 KHz je veľmi dlhá, takže aj rozmery anténneho poľa sú celkom slušné (foto z Wikipédie):
S takouto anténou a príkonom pokrýva oblasť príjmu takmer celú Európu, Bielorusko, Ukrajinu a časť Ruska.
Každý môže zaznamenať signál. Ak to chcete urobiť, prejdite do online prijímača
Tam stlačíme tlačidlo sťahovania a nahráme niekoľkominútový fragment. Samozrejme, ak máte „skutočný“ prijímač schopný zaznamenať frekvenciu 77.5 kHz, môžete ho použiť.
Prijímaním rádiových časových signálov cez internet samozrejme nezískame skutočne presný čas – signál sa prenáša s oneskorením. Naším cieľom je však iba porozumieť štruktúre signálu, na to je záznam z internetu viac než dostatočný. V reálnom živote sa, samozrejme, na príjem a dekódovanie používajú špecializované zariadenia, o ktorých sa bude diskutovať nižšie.
Nahrávku sme teda dostali, začnime ju spracovávať.
Dekódovanie signálu
Načítajme súbor pomocou Pythonu a uvidíme jeho štruktúru:
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()
Vidíme typickú amplitúdovú moduláciu:
Aby sme zjednodušili dekódovanie, zoberme si obálku signálu pomocou Hilbertovej transformácie:
analytic_signal = signal.hilbert(data)
A = np.abs(analytic_signal)
plt.plot(A[:100000])
Zväčšený výsledok:
Vyhladzme emisie hluku pomocou dolnopriepustného filtra a zároveň vypočítajme priemernú hodnotu, ktorá sa nám bude hodiť neskôr pri analýze.
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
Výsledok (žltá čiara): takmer štvorcový signál, ktorý sa dá celkom ľahko analyzovať.
Analýza
Najprv musíte získať bitovú sekvenciu. Samotná štruktúra signálu je veľmi jednoduchá.
Impulzy sú rozdelené do sekundových intervalov. Ak je vzdialenosť medzi impulzmi 0.1 s (t. j. dĺžka samotného impulzu je 0.9 s), pridajte k sekvencii bitov „0“; ak je vzdialenosť 0.2 s (t. j. dĺžka je 0.8 s), pridajte „1“. Koniec každej minúty je indikovaný „dlhým“ impulzom v dĺžke 2 s, sekvencia bitov sa vynuluje a plnenie začne znova.
Vyššie uvedené je ľahké napísať v Pythone.
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
V dôsledku toho dostaneme sekvenciu bitov, v našom príklade to na dve sekundy vyzerá takto:
0011110110111000001011000001010000100110010101100010011000
0001111100110110001010100001010000100110010101100010011000
Mimochodom, je zaujímavé, že signál má aj „druhú vrstvu“ údajov. Bitová sekvencia je tiež kódovaná pomocou
Náš posledný krok: získanie skutočných údajov. Bity sa prenášajú raz za sekundu, takže máme spolu 59 bitov, v ktorých je zakódovaných pomerne veľa informácií:
Bity sú popísané v
Pre tých, ktorí chcú experimentovať sami, je dekódovací kód uvedený pod spojlerom.
Zdrojový kód
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)
Keď spustíme program, uvidíme výstup podobný tomuto:
0011110110111000001011000001010000100110010101100010011000
Tuesday, 26.03.19, 21:41
0001111100110110001010100001010000100110010101100010011000
Tuesday, 26.03.19, 21:42
V skutočnosti je to celé kúzlo. Výhodou takéhoto systému je, že dekódovanie je mimoriadne jednoduché a možno ho vykonať na akomkoľvek, aj na tom najjednoduchšom mikrokontroléri. Jednoducho spočítame dĺžku impulzov, nazbierame 60 bitov a na konci každej minúty dostaneme presný čas. V porovnaní s inými spôsobmi synchronizácie času (napr. GPS alebo nedajbože internet:) takáto rádiová synchronizácia nevyžaduje prakticky žiadnu elektrinu – napríklad bežná domáca meteostanica beží približne rok na 2 AA batérie. Preto sa aj náramkové hodinky vyrábajú s rádiovou synchronizáciou, nehovoriac, samozrejme, o nástenných či pouličných staničných.
Pohodlie a jednoduchosť DCF priťahuje aj domácich majstrov. Len za 10-20 dolárov si môžete kúpiť hotový anténny modul s hotovým prijímačom a TTL výstupom, ktorý je možné pripojiť k Arduinu alebo inému ovládaču.
Už napísané pre Arduino
Tí, ktorí chcú, môžu dokonca upgradovať hodinky svojej starej babičky inštaláciou nového mechanizmu s rádiovou synchronizáciou:
Môžete ho nájsť na eBay pomocou kľúčových slov „Rádio ovládaný pohyb“.
A na záver life hack pre tých, ktorí sa dočítali až sem. Aj keď sa v najbližších niekoľkých tisícoch km nenachádza ani jeden vysielač rádiového signálu, nie je ťažké si takýto signál vygenerovať sami. Na Google Play je program s názvom „DCF77 Emulator“, ktorý vysiela signál do slúchadiel. Podľa autora, ak omotáte kábel slúchadiel okolo hodiniek, zachytia signál (je zaujímavé, ako, pretože bežné slúchadlá nevytvoria signál 77 kHz, ale príjem je pravdepodobne spôsobený harmonickými). V systéme Android 9 mi program vôbec nefungoval - jednoducho tam nebol žiadny zvuk (alebo som ho možno nepočul - koniec koncov je to 77 kHz:), ale možno bude mať niekto viac šťastia. Niektorí si však robia plnohodnotný generátor signálu DCF, ktorý sa dá ľahko vyrobiť na rovnakom Arduine alebo ESP32:
(zdroj
Záver
Systém DCF sa ukázal byť skutočne celkom jednoduchý a pohodlný. Pomocou jednoduchého a lacného prijímača môžete mať presný čas vždy a všade, samozrejme v priestoroch recepcie. Zdá sa, že aj napriek rozšírenej digitalizácii a internetu vecí budú takéto jednoduché riešenia ešte dlho žiadané.
Zdroj: hab.com