Hallo Habr.
Wierskynlik hawwe in protte dy't in horloazje as waarstasjon keapje, it Radio Controlled Clock of sels Atomic Clock-logo op 'e ferpakking sjoen. Dit is heul handich, om't jo gewoan de klok op 'e tafel moatte sette, en nei in skoft sil it automatysk oanpasse oan' e krekte tiid.
Litte wy útfine hoe't it wurket en in dekoder skriuwe yn Python.
D'r binne ferskate tiidsyngronisaasjesystemen. De populêrste yn Jeropa is it Dútske systeem
Alles dat hjirûnder skreaun is sil oer de DCF77 gean.
Sinjaal ûntfangst
DCF77 is in lange-golfstasjon dat wurket op in frekwinsje fan 77.5 kHz en sinjalen útstjoert yn amplitudemodulaasje. It 50KW-stasjon leit 25 km fan Frankfurt, it begon te wurkjen yn 1959, en yn 1973 waard datumynformaasje tafoege oan 'e krekte tiid. De golflingte by in frekwinsje fan 77 KHz is tige lang, sadat de ôfmjittings fan it antennefjild ek aardich binne (foto fan Wikipedia):
Mei sa'n antenne en enerzjyynput beslacht it ûntfangstgebiet hast hiel Europa, Wyt-Ruslân, Oekraïne en in diel fan Ruslân.
Elkenien kin in sinjaal opnimme. Om dit te dwaan, gean gewoan nei de online ûntfanger
Dêr drukke wy op de downloadknop en registrearje in fragmint ferskate minuten lang. Fansels, as jo in "echte" ûntfanger hawwe dy't de frekwinsje fan 77.5KHz kin opnimme, kinne jo dat brûke.
Fansels, troch it ûntfangen fan radiotiidsinjalen fia it ynternet, sille wy gjin wirklik krekte tiid ûntfange - it sinjaal wurdt mei fertraging útstjoerd. Mar ús doel is allinich om de struktuer fan it sinjaal te begripen; hjirfoar is de ynternetopname mear dan genôch. Yn it echte libben wurde fansels spesjalisearre apparaten brûkt foar it ûntfangen en dekodearjen; se sille hjirûnder besprutsen wurde.
Dat, wy hawwe de opname ûntfongen, litte wy it begjinne te ferwurkjen.
Sinjaal Decoding
Litte wy it bestân laden mei Python en de struktuer sjen:
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()
Wy sjogge typyske amplitudemodulaasje:
Om it dekodearjen te ferienfâldigjen, litte wy de sinjaal-envelop nimme mei de Hilbert-transformaasje:
analytic_signal = signal.hilbert(data)
A = np.abs(analytic_signal)
plt.plot(A[:100000])
Fergrutte resultaat:
Litte wy de lûdsemissies glêdje mei in leechpassfilter, en tagelyk de gemiddelde wearde berekkenje, dy't letter nuttich sil wêze foar parsing.
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
Resultaat (giele line): in sinjaal fan hast fjouwerkante golf dat frij maklik te analysearjen is.
Parsing
Earst moatte jo de bitsekwinsje krije. De sinjaalstruktuer sels is heul ienfâldich.
De pulsen wurde ferdield yn twadde yntervallen. As de ôfstân tusken pulsen 0.1 s is (d.w.s. de lingte fan 'e puls sels is 0.9 s), foegje "0" ta oan de bitsekwinsje; as de ôfstân 0.2 s is (dus de lingte is 0.8 s), add "1". De ein fan elke minút wurdt oanjûn troch in "lange" pols, 2s lang, de bit folchoarder wurdt weromsette nei nul, en it filling begjint wer.
It boppesteande is maklik te skriuwen yn 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
As gefolch krije wy in sekwinsje fan bits, yn ús foarbyld foar twa sekonden sjocht it der sa út:
0011110110111000001011000001010000100110010101100010011000
0001111100110110001010100001010000100110010101100010011000
Troch de wei, it is nijsgjirrich dat it sinjaal ek hat in "twadde laach" fan gegevens. It bit folchoarder wurdt ek kodearre mei help
Us lêste stap: de eigentlike gegevens krije. Bits wurde ien kear per sekonde oerbrocht, dus wy hawwe in totaal fan 59 bits, wêryn in soad ynformaasje kodearre is:
De bits wurde beskreaun yn
Foar dyjingen dy't op har eigen wolle eksperimintearje, wurdt de dekodearringskoade jûn ûnder de spoiler.
Boarne
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)
As wy it programma útfiere, sille wy útfier sjen lykas dit:
0011110110111000001011000001010000100110010101100010011000
Tuesday, 26.03.19, 21:41
0001111100110110001010100001010000100110010101100010011000
Tuesday, 26.03.19, 21:42
Eins is dat al de magy. It foardiel fan sa'n systeem is dat dekodearjen ekstreem ienfâldich is en kin dien wurde op elke, sels de ienfâldichste mikrocontroller. Wy telle gewoan de lingte fan 'e pulsen, sammelje 60 bits, en oan' e ein fan elke minút krije wy de krekte tiid. Yn ferliking mei oare metoaden fan tiidsyngronisaasje (gps, bygelyks, of God ferbiede, it ynternet :)), fereasket sa'n radiosyngronisaasje frijwol gjin elektrisiteit - bygelyks in gewoan hûswaarstasjon draait sawat in jier op 2 AA-batterijen. Dêrom, sels polshorloazjes wurde makke mei radio syngronisaasje, net te hawwen oer, fansels, muorre horloazjes of strjitstasjon horloazjes.
It gemak en ienfâld fan DCF lûke ek DIY-entûsjasters oan. Foar mar $ 10-20 kinne jo in klear makke antennemodule keapje mei in klearmakke ûntfanger en TTL-útfier, dy't kin wurde ferbûn mei in Arduino of oare controller.
Al skreaun foar Arduino
Wa't wol, kin sels har âlde beppe's horloazje opwurdearje troch in nij meganisme te ynstallearjen mei radiosyngronisaasje:
Jo kinne ien fine op ebay mei de kaaiwurden "Radio Controlled Movement".
En as lêste, in libben hack foar dyjingen dy't hawwe lêzen sa fier. Sels as d'r de kommende pear tûzen km gjin inkele radiosinjaalstjoerder is, is it net dreech om sa'n sinjaal sels te generearjen. D'r is in programma op Google Play mei de namme "DCF77 Emulator" dat it sinjaal útstjoert nei koptelefoan. Neffens de skriuwer, as jo de draad fan 'e koptelefoan om it horloazje wikkelje, sille se it sinjaal opnimme (it is nijsgjirrich hoe, om't gewoane koptelefoan gjin 77KHz-sinjaal sil produsearje, mar ûntfangst is wierskynlik te tankjen oan harmonics). Op Android 9 wurke it programma hielendal net foar my - d'r wie gewoan gjin lûd (of miskien hearde ik it net - it is ommers 77KHz:), mar miskien sil immen better gelok hawwe. Guon meitsje harsels lykwols in folsleine DCF-sinjaalgenerator, dy't maklik te meitsjen is op deselde Arduino as ESP32:
(boarne
konklúzje
It DCF-systeem blykte echt frij ienfâldich en handich te wêzen. Mei help fan in ienfâldige en goedkeape ûntfanger kinne jo altyd en oeral de krekte tiid hawwe, fansels yn 'e resepsje. It liket derop dat sels nettsjinsteande wiidferspraat digitalisearring en it Internet of Things, sokke ienfâldige oplossingen foar in lange tiid yn fraach sille wêze.
Boarne: www.habr.com