Sveiki, Habr.
Droši vien daudzi, kas iegādājas pulksteni vai meteoroloģisko staciju, uz iepakojuma ir redzējuši radio vadāmo pulksteni vai pat atompulksteņa logotipu. Tas ir ļoti ērti, jo vienkārši jānoliek pulkstenis uz galda, un pēc kāda laika tas automātiski pielāgosies precīzam laikam.

Izdomāsim, kā tas darbojas, un uzrakstīsim dekodētāju programmā Python.
Ir dažādas laika sinhronizācijas sistēmas. Vispopulārākā Eiropā ir vācu sistēma , Japānai ir sava sistēma , ASV ir sistēma , un tā tālāk. Tālāk sižets būs par DCF77, kā aktuālāko un uzņemšanai pieejamāko vietām Krievijas Eiropas daļā un kaimiņvalstīs (Tālo Austrumu iedzīvotājiem var būt pretējs viedoklis, taču viņi, savukārt, var saņemt un analizēt japāņu signālu;).
Viss, kas rakstīts zemāk, būs par DCF77.
Signāla uztveršana
DCF77 ir garo viļņu stacija, kas darbojas ar frekvenci 77.5 kHz un pārraida signālus amplitūdas modulācijā. 50KW stacija atrodas 25 km attālumā no Frankfurtes, tā sāka darboties 1959. gadā, un 1973. gadā datuma informācija tika pievienota precīzam laikam. Viļņa garums 77 KHz frekvencē ir ļoti garš, tāpēc arī antenas lauka izmēri ir diezgan pieklājīgi (foto no Wikipedia):

Ar šādu antenu un strāvas ievadi uztveršanas zona aptver gandrīz visu Eiropu, Baltkrieviju, Ukrainu un daļu Krievijas.

Ikviens var ierakstīt signālu. Lai to izdarītu, vienkārši dodieties uz tiešsaistes uztvērēju , izvēlieties frekvenci 76.5KHz un tur USB modulāciju. Jāatveras attēlam, kas izskatās apmēram šādi:

Tur mēs nospiežam lejupielādes pogu un ierakstām vairākas minūtes garu fragmentu. Protams, ja jums ir "īsts" uztvērējs, kas spēj ierakstīt 77.5 kHz frekvenci, varat to izmantot.
Protams, saņemot radio laika signālus caur internetu, mēs nesaņemsim patiesi precīzu laiku – signāls tiek pārraidīts ar kavēšanos. Bet mūsu mērķis ir tikai izprast signāla struktūru; šim nolūkam ar interneta ierakstu ir vairāk nekā pietiekami. Reālajā dzīvē, protams, saņemšanai un dekodēšanai tiek izmantotas specializētas ierīces, tās tiks apskatītas tālāk.
Tātad, esam saņēmuši ierakstu, sāksim tā apstrādi.
Signāla dekodēšana
Ielādēsim failu, izmantojot Python, un apskatīsim tā struktū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()
Mēs redzam tipisku amplitūdas modulāciju:

Lai vienkāršotu dekodēšanu, ņemsim signāla aploksni, izmantojot Hilberta transformāciju:
analytic_signal = signal.hilbert(data)
A = np.abs(analytic_signal)
plt.plot(A[:100000])
Palielināts rezultāts:

Izlīdzināsim trokšņu emisijas, izmantojot zemas caurlaidības filtru, un tajā pašā laikā aprēķināsim vidējo vērtību, kas vēlāk noderēs parsēšanai.
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
Rezultāts (dzeltena līnija): gandrīz kvadrātveida viļņu signāls, ko ir diezgan viegli analizēt.

Parsēšana
Vispirms jums jāiegūst bitu secība. Pati signāla struktūra ir ļoti vienkārša.

Impulsi ir sadalīti otrajās intervālos. Ja attālums starp impulsiem ir 0.1 s (t.i., paša impulsa garums ir 0.9 s), pievienojiet bitu secībai “0”, ja attālums ir 0.2 s (t.i., garums ir 0.8 s), pievienojiet “1”. Katras minūtes beigas tiek norādītas ar “garu” impulsu, 2 s garš, bitu secība tiek atiestatīta uz nulli, un aizpildīšana sākas no jauna.
Iepriekš minēto ir viegli uzrakstīt 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
Rezultātā mēs iegūstam bitu secību, mūsu piemērā divas sekundes tas izskatās šādi:
0011110110111000001011000001010000100110010101100010011000
0001111100110110001010100001010000100110010101100010011000
Starp citu, interesanti, ka signālam ir arī datu “otrais slānis”. Bitu secība tiek kodēta arī izmantojot . Teorētiski tam vajadzētu nodrošināt spēcīgāku dekodēšanu pat novājināta signāla gadījumā.
Mūsu pēdējais solis: faktisko datu iegūšana. Biti tiek pārraidīti reizi sekundē, tāpēc mums kopā ir 59 biti, kuros tiek iekodēts diezgan daudz informācijas:

Biti ir aprakstīti sadaļā , un viņi ir diezgan ziņkārīgi. Pirmie 15 biti netiek izmantoti, lai gan bija plāni tos izmantot brīdināšanas sistēmām un civilajai aizsardzībai. Bits A1 norāda, ka pulkstenis nākamajā stundā pārslēgsies uz vasaras laiku. Bits A2 norāda, ka papildu , ko dažreiz izmanto, lai pielāgotu laiku atbilstoši Zemes rotācijai. Atlikušie biti kodē stundas, minūtes, sekundes un datumu.

Tiem, kas vēlas eksperimentēt paši, dekodēšanas kods ir norādīts zem spoilera.
Pirmkods
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)
Palaižot programmu, mēs redzēsim līdzīgu izvadi:
0011110110111000001011000001010000100110010101100010011000
Tuesday, 26.03.19, 21:41
0001111100110110001010100001010000100110010101100010011000
Tuesday, 26.03.19, 21:42
Patiesībā tā ir visa burvība. Šādas sistēmas priekšrocība ir tā, ka dekodēšana ir ārkārtīgi vienkārša un to var veikt uz jebkura, pat visvienkāršākā mikrokontrollera. Mēs vienkārši saskaitām impulsu garumu, uzkrājam 60 bitus un katras minūtes beigās iegūstam precīzu laiku. Salīdzinot ar citiem laika sinhronizācijas paņēmieniem (GPS, piemēram, vai nedod Dievs, internets:), šādai radio sinhronizācijai praktiski nav nepieciešama elektrība – piemēram, parasta mājas meteoroloģiskā stacija aptuveni gadu darbojas ar 2 AA baterijām. Tāpēc pat rokas pulksteņi tiek izgatavoti ar radio sinhronizāciju, nemaz nerunājot, protams, sienas pulksteņi vai ielu stacijas pulksteņi.
DCF ērtības un vienkāršība piesaista arī DIY entuziastus. Tikai par 10-20 dolāriem var iegādāties gatavu antenas moduli ar gatavu uztvērēju un TTL izeju, ko var savienot ar Arduino vai citu kontrolieri.

Jau rakstīts priekš Arduino . Tomēr jau ir zināms, ka neatkarīgi no tā, ko jūs darāt ar mikrokontrolleru, jūs saņemat vai nu pulksteni, vai meteoroloģisko staciju. Ar šādu ierīci precīza laika iegūšana ir patiešām vienkārša, protams, ja atrodaties reģistratūras zonā. Nu, jūs varat pakārt pulkstenim uzrakstu “Atompulkstenis” un tajā pašā laikā visiem paskaidrot, ka ierīce patiešām tiek sinhronizēta, izmantojot atompulksteni.
Tie, kas vēlas, var pat uzlabot savu veco vecmāmiņas pulksteni, uzstādot jaunu mehānismu ar radio sinhronizāciju:

Jūs varat to atrast vietnē ebay, izmantojot atslēgvārdus “Radio Controlled Movement”.
Un visbeidzot, neliels praktisks padoms tiem, kas ir izlasījuši tik tālu. Pat ja pāris tūkstošu kilometru rādiusā nav neviena radio raidītāja, to ir viegli ģenerēt pašam. Google Play ir lietotne ar nosaukumu "DCF77 Emulator", kas izvada signālu uz austiņām. Autors apgalvo, ka, aptinot austiņu vadu ap pulksteni, tas uztvers signālu (es brīnos, kā, jo parastās austiņas neradīs 77 kHz signālu, bet tas droši vien ir saistīts ar harmonikām). Manā pulkstenī... Android 9. programma vispār nedarbojās — vienkārši nebija skaņas (vai varbūt es to vienkārši nedzirdēju — galu galā tā ir 77 kHz. :)), bet varbūt kādam citam veiksies labāk. Tomēr daži cilvēki paši izveido pilnvērtīgu DCF signāla ģeneratoru, ko ir viegli izveidot, izmantojot Arduino vai ESP32:

(avots )
Secinājums
DCF sistēma izrādījās patiešām diezgan vienkārša un ērta. Izmantojot vienkāršu un lētu uztvērēju, vienmēr un visur var atrast precīzu laiku, protams, reģistratūras zonā. Šķiet, pat neskatoties uz plaši izplatīto digitalizāciju un lietu internetu, šādi vienkārši risinājumi būs pieprasīti vēl ilgi.
Avots: www.habr.com
