Pozdrav, Habr.
Vjerojatno su mnogi, koji kupuju satove ili meteorološke stanice, vidjeli na ambalaži logotip Radio Controlled Clock ili čak Atomic Clock. To je vrlo zgodno, jer je dovoljno staviti sat na stol, i on će se nakon nekog vremena automatski namjestiti na točno vrijeme.

Razjasnimo kako to funkcionira i napisat ćemo dekoder na programskom jeziku Python.
Postoje različiti sustavi za sinkronizaciju vremena. Najpopularniji u Europi je njemački sustav , u Japanu postoji vlastiti sustav , u SAD-u postoji sustav , i tako dalje. Dalje će biti riječi o DCF77, kao najaktualnijem i dostupnom za prijem na nekim mjestima europskog dijela Rusije i susjednim zemljama (stanovnici Dalekog Istoka mogu imati suprotno mišljenje, iako oni sami mogu primati i analizirati japanski signal;).
Sve što slijedi bit će o DCF77.
Prijem signala
DCF77 je dugovalovna stanica koja radi na frekvenciji 77,5 kHz i prenosi signale u amplitudnoj modulaciji. Stanica snage 50 kW smještena je 25 km od Frankfurta, počela je s radom još 1959. godine, a 1973. godini točnom vremenu dodane su informacije o datumu. Duljina valne duljine pri frekvenciji 77 kHz vrlo je velika, stoga su dimenzije antene također prilično značajne (slika s Wikipedije):

S takvom antenom i dovodnom snagom, zona prijema pokriva gotovo cijelu Europu, Bjelorusiju, Ukrajinu i dio Rusije.

Signal može snimiti svatko. Za to je dovoljno ući na online prijemnik , odabrati frekvenciju 76,5 kHz i USB modulaciju. Trebala bi se otvoriti slika otprilike ovakve vrste:

Tamo pritiskamo gumb za preuzimanje i snimamo fragment koji traje nekoliko minuta. Naravno, ako imamo 'pravi' prijemnik sposoban snimiti frekvenciju 77,5 kHz, možemo koristiti i njega.
Naravno, primajući radio signale točnog vremena putem Interneta, nećemo dobiti doista točno vrijeme — signal se prenosi s kašnjenjem. No, naš cilj je samo razumjeti strukturu signala, za to su internet zapisi više nego dovoljni. U stvarnosti se, naravno, koriste specijalizirani uređaji za prijem i dekodiranje, o kojima će biti riječi u nastavku.
Dakle, dobili smo snimku, krenimo na njenu obradu.
Dekodiranje signala
Učit ćemo datoteku pomoću Pythona i pogledati njenu strukturu:
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()
Vidimo tipičnu amplitudsku modulaciju:

Za pojednostavljenje dekodiranja, uzmimo omotnicu signala pomoću Hilbertove transformacije:
analytic_signal = signal.hilbert(data)
A = np.abs(analytic_signal)
plt.plot(A[:100000]) Rezultat u uvećanom izdanju:

Izgladit ćemo izbočenja od smetnji pomoću low-pass filtra, a istovremeno ćemo izračunati prosječnu vrijednost koja će nam kasnije zatrebati za parsiranje.
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 Rezultat (žuta linija): praktički pravokutni signal koji je prilično lako analizirati.

Parsiranje
Prvo trebamo dobiti bitnu sekvencu. Sama struktura signala je vrlo jednostavna.

Impulsi su podijeljeni u sekunde. Ako je razdaljina između impulsa 0.1s (tj. duljina samog impulsa 0.9s), dodajemo „0“ u bitnu sekvencu, ako je razdaljina 0.2s (tj. duljina 0.8s), dodajemo „1“. Kraj svake minute označen je „dugim“ impulsom, duljim od 2s, pri čemu se bitna sekvenca resetira i novo punjenje počinje ispočetka.
Ovo prethodno nije teško zapisati u Pythonu.
sig_start, sig_stop = 0, 0
pos = 0
bits_str = ""
while pos < cnt - 4:
if A[pos] avg:
# Početak signala
sig_start = pos
if A[pos] > avg and A[pos+1] < avg:
# Kraj signala
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
Kao rezultat dobivamo sekvencu bitova, u našem primjeru za dvije sekunde ona izgleda ovako:
0011110110111000001011000001010000100110010101100010011000
0001111100110110001010100001010000100110010101100010011000
Usput, zanimljivo je da signal uključuje i „drugi sloj“ podataka. Sekvenca bitova također je kodirana putem . Teoretski, to bi trebalo osigurati otpornije dekodiranje čak i u slučajevima oslabljene signala.
Naš posljednji korak: dobiti zapravo podatke. Bitovi se šalju jednom u sekundi, tako da imamo ukupno 59 bitova, u kojima je kodirano dovoljno informacija:

Bitovi su opisani u , i prilično su zanimljivi. Prvih 15 bita se ne koristi, iako je bilo planova za korištenje za sustave upozorenja i građanske obrane. Bit A1 označava da će satovi sljedeći sat biti pomjereni na ljetno računanje vremena. Bit A2 označava da će sljedeći sat biti dodana , koja se ponekad koristi za ispravak vremena u skladu s rotacijom Zemlje. Ostali bitovi kodiraju sate, minute, sekunde i datum.

Za one koji žele eksperimentirati samostalno, kod za dekodiranje je naveden ispod spoiler-a.
Izvorni kod
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 = ('Nedjelja', 'Ponedejak', 'Utorak', 'Srijeda', 'Četvrtak', 'Petak', 'Subota', 'Nedjelja')
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)
Pokretanjem programa, vidjet ćemo otprilike ovakav ishod:
0011110110111000001011000001010000100110010101100010011000
Utorak, 26.03.19, 21:41
0001111100110110001010100001010000100110010101100010011000
Utorak, 26.03.19, 21:42
U suštini, to je sva magija. Prednost ovakvog sustava je u tome što je dekodiranje krajnje jednostavno i može se izvršiti na bilo kojem, najjednostavnijem mikrokontroleru. Jednostavno mjerimo dužinu impulsa, akumuliramo 60 bita, i na kraju svake minute dobijemo točno vrijeme. U usporedbi s drugim metodama sinkronizacije vremena (npr. GPS, ili ne daj Bože, Internet :), takva radijska sinkronizacija praktički ne troši energiju — primjerice, obična kućna meteorološka stanica radi oko godine na 2 AA baterije. Zato se radijska sinkronizacija koristi čak i u ručnim satovima, a kamoli o zidnim ili vanjskim stanicama.
Pogodnost i jednostavnost DCF privlače i ljubitelje samogradnje. Za svega 10-20$ može se kupiti gotovi modul antene s gotovim prijemnikom i TTL izlazom, koji se može povezati s Arduino-om ili drugim kontrolerom.

Za Arduino su već napisane i . U svakom slučaju, poznato je — šta god radili s mikrokontrolerom, dobijate ili sat ili meteorološku stanicu. Sa ovim uređajem, dobijanje tačnog vremena zaista nije teško, naravno, ako se nalazite u zoni prijema. Takođe, možete staviti natpis „Atomic Clock“ na sat, i objasniti svim zainteresovanima da se uređaj zaista sinhronizuje pomoću atomskih sati.
Zainteresovani mogu čak i nadograditi stari bakin sat tako što će u njega ugraditi novi mehanizam sa radio sinhronizacijom:

Takav se može naći na eBayu pretraživanjem ključnih reči „Radio Controlled Movement“.
I na kraju, savjet za one koji su do ovde pročitali. Čak i ako u narednih nekoliko hiljada kilometara nema nijednog predajnika radio signala, takav signal se lako može generisati samostalno. U Google Play-u postoji aplikacija pod nazivom „DCF77 Emulator“ koja šalje signal na slušalice. Prema tvrdnjama autora, ako obavijete žicu slušalica oko sata, oni će uhvatiti signal (zanimljivo kako, jer obične slušalice ne mogu predavati signal od 77KHz, ali verovatno prijem ide zahvaljujući harmonijskim frekvencijama). Na mom Android 9 uređaju aplikacija nije radila uopšte — jednostavno nije bilo zvuka (možda ga nisam čuo — 77KHz, zar ne:), ali možda će nekome biti sreće više. Neki, međutim, prave i potpuno funkcionalni DCF generator signala, koji se lako može napraviti na istom Arduino ili ESP32:

(izvor )
Zaključak
DCF sistem se pokazao biti zaista prilično jednostavan i praktičan. Sa jednostavnim i jeftinim prijemnikom, možete imati tačno vreme uvek i svuda, naravno, u zoni prijema. Mislim da će, čak i uprkos sveprisutnoj digitalizaciji i „internet stvari“, ovakva jednostavna rešenja biti tražena još dugo.
Izvor: habr.com
