Zdravo Habr.
Vjerovatno su mnogi koji kupuju sat ili meteorološku stanicu vidjeli radio kontrolirani sat ili čak logotip atomskog sata na pakovanju. Ovo je vrlo zgodno, jer samo treba da stavite sat na sto, a nakon nekog vremena on će se automatski prilagoditi tačnom vremenu.

Hajde da shvatimo kako to radi i napišemo dekoder u Pythonu.
Postoje različiti sistemi za sinhronizaciju vremena. Najpopularniji u Evropi je njemački sistem , Japan ima svoj sistem , u SAD postoji sistem , i tako dalje. Dalje, priča će biti o DCF77, kao najrelevantnijem i najpristupačnijem za prijem u nekim mjestima u evropskom dijelu Rusije i susjednih zemalja (stanovnici Dalekog istoka mogu imati suprotno mišljenje, međutim, oni zauzvrat mogu primiti i analizirati japanski signal;).
Sve napisano u nastavku bit će o DCF77.
Prijem signala
DCF77 je dugovalna stanica koja radi na frekvenciji od 77.5 kHz i emituje signale u amplitudnoj modulaciji. Stanica od 50KW nalazi se 25 km od Frankfurta, počela je sa radom 1959. godine, a 1973. godine dodana je informacija o tačnom vremenu. Talasna dužina na frekvenciji od 77 KHz je veoma duga, tako da su i dimenzije antenskog polja sasvim pristojne (fotografija sa Wikipedije):

Sa takvom antenom i ulazom za napajanje, prijemno područje pokriva gotovo cijelu Evropu, Bjelorusiju, Ukrajinu i dio Rusije.

Svako može snimiti signal. Da biste to učinili, samo idite na mrežni prijemnik , tamo odaberite frekvenciju 76.5KHz i USB modulaciju. Trebalo bi da se otvori slika koja izgleda otprilike ovako:

Tamo pritisnemo dugme za preuzimanje i snimimo fragment dug nekoliko minuta. Naravno, ako imate “pravi” prijemnik koji može snimiti frekvenciju od 77.5 KHz, možete to koristiti.
Naravno, primanjem radio signala vremena putem interneta, nećemo dobiti istinski tačno vrijeme - signal se prenosi sa zakašnjenjem. Ali naš cilj je samo razumjeti strukturu signala, za to je više nego dovoljan internet snimak. U stvarnom životu, naravno, za prijem i dekodiranje koriste se specijalizirani uređaji, o njima će biti riječi u nastavku.
Dakle, primili smo snimak, hajde da ga obradimo.
Signal Decoding
Učitajmo datoteku koristeći Python i vidimo 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 amplitudnu modulaciju:

Da pojednostavimo dekodiranje, uzmimo omotnicu signala koristeći Hilbertovu transformaciju:
analytic_signal = signal.hilbert(data)
A = np.abs(analytic_signal)
plt.plot(A[:100000]) Uvećani rezultat:

Hajde da izgladimo emisije buke pomoću niskopropusnog filtera, a u isto vrijeme izračunamo prosječnu vrijednost, što će nam kasnije biti od koristi za raščlanjivanje.
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): signal gotovo pravokutnog talasa koji je prilično lako analizirati.

Parsing
Prvo morate dobiti sekvencu bitova. Sama struktura signala je vrlo jednostavna.

Impulsi su podijeljeni u sekundarne intervale. Ako je razmak između impulsa 0.1s (tj. dužina samog impulsa je 0.9s), dodajte "0" sekvenci bitova; ako je udaljenost 0.2s (tj. dužina je 0.8s), dodajte "1". Kraj svake minute je označen “dugim” impulsom, dugim 2s, sekvenca bitova se resetuje na nulu i punjenje počinje ponovo.
Gore je lako napisati u Pythonu.
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
Kao rezultat, dobijamo niz bitova, u našem primjeru za dvije sekunde to izgleda ovako:
0011110110111000001011000001010000100110010101100010011000
0001111100110110001010100001010000100110010101100010011000
Inače, zanimljivo je da signal ima i "drugi sloj" podataka. Slijed bitova je također kodiran pomoću . U teoriji, ovo bi trebalo da obezbedi robusnije dekodiranje čak i u slučaju oslabljenog signala.
Naš posljednji korak: dobivanje stvarnih podataka. Bitovi se prenose jednom u sekundi, tako da imamo ukupno 59 bitova, u kojima je kodirano dosta informacija:

Bitovi su opisani u , i prilično su radoznali. Prvih 15 bitova se ne koristi, iako je bilo planova da se koriste za sisteme upozorenja i civilnu odbranu. Bit A1 označava da će se sat promijeniti na ljetno računanje vremena u sljedećem satu. Bit A2 označava da je dodatni , koji se ponekad koristi za podešavanje vremena prema Zemljinoj rotaciji. Preostali bitovi kodiraju sate, minute, sekunde i datum.

Za one koji žele sami eksperimentirati, kod za dekodiranje je dat ispod spojlera.
Izvor
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)
Kada pokrenemo program, vidjet ćemo izlaz sličan ovome:
0011110110111000001011000001010000100110010101100010011000
Tuesday, 26.03.19, 21:41
0001111100110110001010100001010000100110010101100010011000
Tuesday, 26.03.19, 21:42
Zapravo, to je sva magija. Prednost ovakvog sistema je što je dekodiranje izuzetno jednostavno i može se obaviti na bilo kom, pa i najjednostavnijem mikrokontroleru. Jednostavno brojimo dužinu impulsa, akumuliramo 60 bita i na kraju svake minute dobijamo tačno vrijeme. U poređenju sa drugim metodama vremenske sinhronizacije (GPS, na primer, ili ne daj Bože, Internet:), za takvu radio sinhronizaciju nije potrebna praktički nikakva struja - na primer, obična kućna meteorološka stanica radi oko godinu dana na 2 AA baterije. Stoga se čak i ručni satovi prave sa radio sinhronizacijom, a da ne spominjemo, naravno, zidne satove ili satove uličnih stanica.
Pogodnost i jednostavnost DCF-a također privlače DIY entuzijaste. Za samo 10-20 dolara možete kupiti gotov antenski modul sa gotovim prijemnikom i TTL izlazom, koji se može spojiti na Arduino ili drugi kontroler.

Već napisano za Arduino . Međutim, već je poznato da bez obzira šta radite na mikrokontroleru, na kraju imate ili sat ili meteorološku stanicu. Sa takvim uređajem je zaista lako doći do tačnog vremena, pod uslovom, naravno, da se nalazite u zoni recepcije. Pa, možete okačiti natpis "Atomski sat" na svoj sat, i istovremeno svima objasniti da je uređaj zaista sinhronizovan pomoću atomskog sata.
Oni koji žele mogu čak i nadograditi stari bakin sat ugradnjom novog mehanizma sa radio sinhronizacijom:

Možete ga pronaći na ebayu koristeći ključne riječi “Radio Controlled Movement”.
I na kraju, trik za one koji su pročitali dovde. Čak i ako nema nijednog radio predajnika u krugu od nekoliko hiljada kilometara, lako ga je sami generirati. Na Google Playu postoji aplikacija pod nazivom "DCF77 Emulator" koja šalje signal na slušalice. Autor tvrdi da ako omotate kabel slušalica oko sata, on će uhvatiti signal (pitam se kako, budući da obične slušalice neće proizvesti signal od 77 kHz, ali to je vjerovatno zbog harmonika). Na mom satu... Android Program 9 uopće nije radio—jednostavno nije bilo zvuka (ili ga možda ja jednostavno nisam mogao čuti—uostalom je 77 kHz. :)), ali možda će neko drugi imati više sreće. Neki ljudi, međutim, sami grade svoj potpuni generator DCF signala, što je lako napraviti pomoću Arduina ili ESP32:

(izvor )
zaključak
Pokazalo se da je DCF sistem zaista prilično jednostavan i praktičan. Uz pomoć jednostavnog i jeftinog prijemnika možete imati tačno vrijeme uvijek i svugdje, naravno na recepciji. Čini se da će čak i uprkos raširenoj digitalizaciji i Internetu stvari, ovakva jednostavna rješenja biti tražena još dugo.
izvor: www.habr.com
