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
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
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
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ļÄ
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
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, dzÄ«ves hack tiem, kas ir izlasÄ«juÅ”i lÄ«dz Å”im. Pat ja tuvÄko pÄris tÅ«kstoÅ”u km laikÄ nav neviena radiosignÄla raidÄ«tÄja, paÅ”am Å”Ädu signÄlu Ä£enerÄt nav grÅ«ti. PakalpojumÄ Google Play ir programma ar nosaukumu āDCF77 Emulatorā, kas izvada signÄlu austiÅÄs. PÄc autora domÄm, aptinot austiÅu vadu ap pulksteni, tÄs uztvers signÄlu (interesanti, kÄ, jo parastÄs austiÅas neradÄ«s 77KHz signÄlu, bet uztverÅ”ana, iespÄjams, ir harmonikas dÄļ). OperÄtÄjsistÄmÄ Android 9 programma man vispÄr nedarbojÄs - vienkÄrÅ”i nebija skaÅas (vai varbÅ«t es to nedzirdÄju - galu galÄ tas ir 77KHz :), bet varbÅ«t kÄdam paveiksies labÄk. TomÄr daži veido sevi par pilnvÄrtÄ«gu DCF signÄlu Ä£eneratoru, ko ir viegli izveidot tajÄ paÅ”Ä 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