Hola Habr.
Probablement, molts dels que compren un rellotge o una estació meteorològica han vist el rellotge radiocontrolat o fins i tot el logotip del rellotge atòmic a l'embalatge. Això és molt convenient, perquè només cal posar el rellotge a la taula i, al cap d'un temps, s'ajustarà automàticament a l'hora exacta.
Descobrim com funciona i escrivim un descodificador en Python.
Hi ha diferents sistemes de sincronització horària. El més popular a Europa és el sistema alemany
Tot el que s'escriu a continuació tractarà sobre el DCF77.
Recepció del senyal
DCF77 és una estació d'ona llarga que funciona a una freqüència de 77.5 kHz i transmet senyals en modulació d'amplitud. L'estació de 50KW es troba a 25 km de Frankfurt, va començar a funcionar l'any 1959 i l'any 1973 es va afegir informació de la data a l'hora exacta. La longitud d'ona a una freqüència de 77 KHz és molt llarga, de manera que les dimensions del camp de l'antena també són força decents (foto de la Viquipèdia):
Amb aquesta antena i entrada d'energia, l'àrea de recepció cobreix gairebé tota Europa, Bielorússia, Ucraïna i part de Rússia.
Qualsevol pot gravar un senyal. Per fer-ho, només cal que aneu al receptor en línia
Allà premem el botó de descàrrega i enregistrem un fragment de diversos minuts. Per descomptat, si teniu un receptor "real" capaç d'enregistrar la freqüència de 77.5 KHz, podeu utilitzar-lo.
Per descomptat, en rebre senyals de temps de ràdio a través d'Internet, no rebrem l'hora realment precisa: el senyal es transmet amb retard. Però el nostre objectiu és només entendre l'estructura del senyal; per això, la gravació d'Internet és més que suficient. A la vida real, per descomptat, s'utilitzen dispositius especialitzats per rebre i descodificar; es tractaran a continuació.
Així doncs, hem rebut la gravació, comencem a processar-la.
Descodificació del senyal
Carreguem el fitxer amb Python i veiem la seva estructura:
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()
Veiem una modulació d'amplitud típica:
Per simplificar la descodificació, prenem l'embolcall del senyal utilitzant la transformada de Hilbert:
analytic_signal = signal.hilbert(data)
A = np.abs(analytic_signal)
plt.plot(A[:100000])
Resultat ampliat:
Suavitzem les emissions de soroll mitjançant un filtre de pas baix i, al mateix temps, calculem el valor mitjà, que serà útil més endavant per analitzar.
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
Resultat (línia groga): un senyal d'ona gairebé quadrada que és bastant fàcil d'analitzar.
Anàlisi
Primer cal obtenir la seqüència de bits. L'estructura del senyal en si és molt senzilla.
Els polsos es divideixen en intervals de segons. Si la distància entre polsos és de 0.1 s (és a dir, la durada del pols en si és de 0.9 s), afegiu "0" a la seqüència de bits; si la distància és de 0.2 s (és a dir, la durada és de 0.8 s), afegiu "1". El final de cada minut s'indica amb un pols "llarg", de 2 segons, la seqüència de bits es reinicia a zero i l'ompliment comença de nou.
L'anterior és fàcil d'escriure en 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
Com a resultat, obtenim una seqüència de bits, en el nostre exemple durant dos segons es veu així:
0011110110111000001011000001010000100110010101100010011000
0001111100110110001010100001010000100110010101100010011000
Per cert, és interessant que el senyal també tingui una "segona capa" de dades. La seqüència de bits també es codifica utilitzant
El nostre últim pas: obtenir les dades reals. Els bits es transmeten una vegada per segon, de manera que tenim un total de 59 bits, en els quals es codifica força informació:
Els bits es descriuen a
Per a aquells que vulguin experimentar pel seu compte, el codi de descodificació es dóna sota l'spoiler.
Codi font
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)
Quan executem el programa, veurem una sortida semblant a aquesta:
0011110110111000001011000001010000100110010101100010011000
Tuesday, 26.03.19, 21:41
0001111100110110001010100001010000100110010101100010011000
Tuesday, 26.03.19, 21:42
De fet, això és tota la màgia. L'avantatge d'aquest sistema és que la descodificació és extremadament senzilla i es pot fer en qualsevol, fins i tot en el microcontrolador més senzill. Simplement comptem la durada dels polsos, acumulem 60 bits i al final de cada minut obtenim el temps exacte. En comparació amb altres mètodes de sincronització de l'hora (GPS, per exemple, o Déu n'hi do, Internet:), aquesta sincronització de ràdio pràcticament no requereix electricitat; per exemple, una estació meteorològica normal funciona durant un any amb 2 piles AA. Per tant, fins i tot els rellotges de polsera es fabriquen amb sincronització de ràdio, sense oblidar, és clar, els rellotges de paret o les estacions de carrer.
La comoditat i la senzillesa de DCF també atrauen els entusiastes del bricolatge. Per només 10-20 dòlars, podeu comprar un mòdul d'antena ja fet amb un receptor preparat i sortida TTL, que es pot connectar a un Arduino o un altre controlador.
Ja està escrit per a Arduino
Aquells que ho desitgin poden fins i tot actualitzar el rellotge de la seva vella àvia instal·lant un nou mecanisme amb sincronització de ràdio:
Podeu trobar-ne un a ebay amb les paraules clau "Moviment radiocontrolat".
I, finalment, un truc de vida per a aquells que han llegit fins aquí. Fins i tot si no hi ha un únic transmissor de senyal de ràdio en els propers dos mil quilòmetres, no és difícil generar aquest senyal. Hi ha un programa a Google Play anomenat "DCF77 Emulator" que envia el senyal als auriculars. Segons l'autor, si enrotlleu el cable dels auriculars al voltant del rellotge, recolliran el senyal (és interessant com, perquè els auriculars normals no produiran un senyal de 77 KHz, però probablement la recepció es deu als harmònics). A Android 9, el programa no va funcionar gens per a mi: simplement no hi havia so (o potser no el vaig escoltar; al cap i a la fi, és de 77KHz), però potser algú tindrà més sort. Alguns, però, es converteixen en un generador de senyal DCF complet, que és fàcil de fer amb el mateix Arduino o ESP32:
(font
Conclusió
El sistema DCF va resultar ser molt senzill i còmode. Amb l'ajuda d'un receptor senzill i econòmic, podeu tenir l'hora exacta sempre i a tot arreu, per descomptat a la zona de recepció. Sembla que fins i tot malgrat la digitalització generalitzada i l'Internet de les coses, solucions tan senzilles seran demandades durant molt de temps.
Font: www.habr.com