Moien Habr.
Wahrscheinlech vill déi eng Auer oder Wiederstatioun kafen, hunn de Radio Controlled Clock oder souguer Atomic Clock Logo op der Verpackung gesinn. Dëst ass ganz bequem, well Dir musst just d'Auer op den Dësch setzen, a no enger Zäit gëtt se automatesch un déi exakt Zäit ugepasst.
Loosst eis erausfannen wéi et funktionnéiert a schreift en Decoder am Python.
Et gi verschidde Zäitsynchroniséierungssystemer. De stäerkste populär an Europa ass den däitsche System
Alles wat hei drënner geschriwwe gëtt, wäert iwwer den DCF77 sinn.
Signal Empfang
DCF77 ass eng laangwelle Statioun, déi mat enger Frequenz vu 77.5 kHz funktionnéiert a Signaler an der Amplitudemodulatioun iwwerdréit. D'50KW Gare läit 25 km vu Frankfurt, et huet 1959 ugefaang, an 1973 gouf d'Datuminformatioun un déi exakt Zäit bäigefüügt. D'Wellelängt bei enger Frequenz vu 77 KHz ass ganz laang, sou datt d'Dimensioune vum Antennefeld och zimlech anstänneg sinn (Foto vu Wikipedia):
Mat esou enger Antenne a Strouminput deckt den Empfangsberäich bal ganz Europa, Belarus, Ukraine an en Deel vu Russland.
Jiddereen kann e Signal ophuelen. Fir dëst ze maachen, gitt einfach op den Online Empfänger
Do drécke mir op den Download Knäppchen an notéieren e Fragment e puer Minutten laang. Natierlech, wann Dir e "richtegen" Empfänger hutt, deen fäeg ass d'77.5KHz Frequenz opzehuelen, kënnt Dir dat benotzen.
Natierlech, andeems mir Radio Zäit Signaler iwwer den Internet kréien, kréie mir net wierklech richteg Zäit - d'Signal gëtt mat enger Retard iwwerdroen. Awer eist Zil ass nëmmen d'Struktur vum Signal ze verstoen; dofir ass d'Internetopnam méi wéi genuch. Am richtege Liewen, natierlech, spezialiséiert Apparater sinn fir Empfang an Decodéierung benotzt; si wäert ënnert diskutéiert ginn.
Also, mir hunn den Opnahmen kritt, loosst eis ufänken ze veraarbecht.
Signal Decodéierung
Loosst eis d'Datei mat Python lueden a seng Struktur kucken:
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()
Mir gesinn typesch Amplitudemodulatioun:
Fir d'Dekodéierung ze vereinfachen, loosst eis d'Signal Enveloppe mat der Hilbert Transform huelen:
analytic_signal = signal.hilbert(data)
A = np.abs(analytic_signal)
plt.plot(A[:100000])
Erweidert Resultat:
Loosst eis d'Geräischer Emissioune mat engem Low-Pass-Filter glat maachen, a gläichzäiteg den Duerchschnëttswäert berechnen, wat spéider nëtzlech ass fir d'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
Resultat (giel Linn): e bal Quadratwellensignal dat ganz einfach ze analyséieren ass.
Parsing
Als éischt musst Dir d'Bit Sequenz kréien. D'Signalstruktur selwer ass ganz einfach.
D'Puls ginn an zweet Intervalle opgedeelt. Wann d'Distanz tëscht Impulser 0.1s ass (dh d'Längt vum Puls selwer ass 0.9s), füügt "0" un d'Bitssequenz; wann d'Distanz 0.2s ass (dh d'Längt ass 0.8s), add "1". D'Enn vun all Minutt gëtt mat engem "laange" Puls uginn, 2s laang, d'Bitssequenz gëtt op Null zréckgesat, an d'Füllung fänkt erëm un.
Dat hei uewen ass einfach am Python ze schreiwen.
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
Als Resultat kréie mir eng Sequenz vu Bits, an eisem Beispill fir zwou Sekonnen gesäit et esou aus:
0011110110111000001011000001010000100110010101100010011000
0001111100110110001010100001010000100110010101100010011000
Iwwregens ass et interessant datt d'Signal och eng "zweet Schicht" vun Daten huet. D'Bit Sequenz ass och kodéiert mat
Eise leschte Schrëtt: déi aktuell Donnéeën ze kréien. Bits ginn eemol pro Sekonn iwwerdroen, also hu mir insgesamt 59 Bits, an deenen zimlech vill Informatioun kodéiert ass:
D'Bits sinn beschriwwen an
Fir déi, déi eleng experimentéiere wëllen, gëtt den Dekodéierungscode ënner dem Spoiler uginn.
Quelltext
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)
Wa mir de Programm lafen, gesi mir d'Ausgab ähnlech wéi dëst:
0011110110111000001011000001010000100110010101100010011000
Tuesday, 26.03.19, 21:41
0001111100110110001010100001010000100110010101100010011000
Tuesday, 26.03.19, 21:42
Eigentlech ass dat all d'Magie. De Virdeel vun esou engem System ass datt d'Dekodéierung extrem einfach ass a kann op all, och den einfachsten Mikrokontroller gemaach ginn. Mir zielen einfach d'Längt vun den Impulsen, sammelen 60 Bits, a mir kréien um Enn vun all Minutt déi exakt Zäit. Am Verglach mat anere Methoden vun der Zäitsynchroniséierung (GPS, zum Beispill, oder Gott verbidd, den Internet:), erfuerdert esou Radiosynchroniséierung praktesch kee Stroum - zum Beispill, eng normal Heemwiederstatioun leeft ongeféier ee Joer op 2 AA Batterien. Dofir gi souguer Armbanduhren mat Radiosynchroniséierung gemaach, net ze soen, natierlech, Wanduhren oder Stroossestatiounsaueren.
D'Bequemlechkeet an d'Einfachheet vun DCF lackele och DIY-Enthusiaster un. Fir just $ 10-20 kënnt Dir e fäerdege Antennemodul mat engem fäerdege Receiver an TTL Output kafen, deen mat engem Arduino oder anere Controller verbonne ka ginn.
Scho fir Arduino geschriwwen
Déi, déi wëllen, kënnen hir al Bomi-Auer souguer upgraden andeems en neie Mechanismus mat Radiosynchroniséierung installéiert:
Dir fannt een op eBay mat de Schlësselwieder "Radio Controlled Movement".
A schliisslech e Liewenshack fir déi, déi bis elo gelies hunn. Och wann et an den nächste puer dausend Kilometer keen eenzege Radiosignalsender ass, ass et net schwéier esou e Signal selwer ze generéieren. Et gëtt e Programm op Google Play mam Numm "DCF77 Emulator" deen d'Signal op d'Kopfhörer ausginn. Laut dem Auteur, wann Dir den Drot vun den Kopfhörer ëm d'Auer wéckelt, wäerte se d'Signal ophuelen (et ass interessant wéi, well gewéinlech Kopfhörer net e 77KHz Signal produzéieren, awer d'Empfang ass wahrscheinlech wéinst der Harmonie). Op Android 9 huet de Programm guer net fir mech geschafft - et war einfach keen Toun (oder vläicht hunn ech et net héieren - et ass 77KHz, schliisslech:), awer vläicht wäert iergendeen besser Gléck hunn. E puer maachen sech awer e vollwäertege DCF Signalgenerator, deen einfach op deemselwechten Arduino oder ESP32 ze maachen ass:
(Quell
Konklusioun
Den DCF System huet sech als wierklech ganz einfach a praktesch erausgestallt. Mat der Hëllef vun engem einfachen a bëllegen Empfänger kënnt Dir déi exakt Zäit ëmmer an iwwerall hunn, natierlech am Empfangsberäich. Et schéngt, datt och trotz der verbreeter Digitaliséierung an dem Internet vun de Saachen, esou einfach Léisunge fir eng laang Zäit gefuerdert sinn.
Source: will.com