Hei Habr.
Sannsynligvis har mange som kjøper en klokke eller en værstasjon sett radiokontrollert klokke eller til og med Atomic Clock-logoen på emballasjen. Dette er veldig praktisk, fordi det er nok å sette klokken på bordet, og etter en stund vil den automatisk justere seg til den nøyaktige tiden.

La oss finne ut hvordan det fungerer og skrive en dekoder i Python.
Det finnes forskjellige tidssynkroniseringssystemer. Det mest populære i Europa er det tyske systemet Japan har sitt eget system , i USA er det et system , og så videre. Videre vil historien handle om DCF77, som den mest relevante og tilgjengelige for mottak noen steder i den europeiske delen av Russland og nabolandene (innbyggerne i Fjernøsten kan ha motsatt oppfatning, men de kan på sin side motta og analysere det japanske signalet;).
Alt som er skrevet nedenfor vil handle om DCF77.
Signalmottak
DCF77 er en langbølgestasjon som opererer ved 77.5KHz og sender AM-signaler. Stasjonen med en kapasitet på 50 kW ligger 25 km fra Frankfurt, den begynte å jobbe i 1959, i 1973 ble informasjon om datoen lagt til det nøyaktige klokkeslettet. Bølgelengden ved en frekvens på 77 kHz er veldig stor, så dimensjonene til antennefeltet er også veldig anstendige (foto fra Wikipedia):

Med en slik antenne og inngangskraft dekker mottaksområdet nesten hele Europa, Hviterussland, Ukraina og deler av Russland.

Hvem som helst kan ta opp. For å gjøre dette, bare gå til nettmottakeren , velg en frekvens på 76.5KHz og USB-modulasjon der. Et bilde skal vises omtrent slik:

På samme sted trykker vi på nedlastingsknappen og tar opp et fragment som er noen minutter langt. Selvfølgelig, hvis du har en "ekte" mottaker som er i stand til å ta opp en frekvens på 77.5 kHz, kan du bruke den.
Når vi mottar nøyaktige tidsradiosignaler over Internett, vil vi selvfølgelig ikke få en virkelig nøyaktig tid - signalet overføres med en forsinkelse. Men målet vårt er bare å forstå strukturen til signalet, for dette er internettopptaket mer enn nok. I det virkelige liv brukes selvfølgelig spesialiserte enheter for mottak og dekoding, de vil bli diskutert nedenfor.
Så vi mottok posten, la oss begynne å behandle den.
Signalavkoding
La oss laste filen med Python og se strukturen:
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()
Vi ser en typisk amplitudemodulasjon:

For å forenkle dekodingen tar vi signalkonvolutten ved å bruke Hilbert-transformasjonen:
analytic_signal = signal.hilbert(data)
A = np.abs(analytic_signal)
plt.plot(A[:100000])
Utvidet resultat:

La oss jevne ut støyutslipp ved hjelp av et lavpassfilter, samtidig beregne gjennomsnittsverdien, det vil komme godt med senere for 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 (gul linje): et nesten rektangulært signal som er ganske enkelt å analysere.

Parsing
Først må du få bitsekvensen. Selve signalstrukturen er veldig enkel.

Pulsene er delt inn i andre intervaller. Hvis avstanden mellom pulsene er 0.1 s (dvs. lengden på selve pulsen er 0.9 s), legger vi til "0" til bitsekvensen, hvis avstanden er 0.2 s (dvs. lengden er 0.8 s), legger vi til "1". Slutten av hvert minutt indikeres med en "lang" puls, 2 s lang, bitsekvensen tilbakestilles til null, og fyllingen starter på nytt.
Ovenstående er lett å skrive i 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
Som et resultat får vi en sekvens av biter, i vårt eksempel i to sekunder ser det slik ut:
0011110110111000001011000001010000100110010101100010011000
0001111100110110001010100001010000100110010101100010011000
Forresten, det er interessant at det også er et "andre lag" med data i signalet. Bitsekvensen er også kodet med . Teoretisk sett burde dette gi mer robust dekoding selv ved et svekket signal.
Vårt siste trinn: få de faktiske dataene. Bits sendes en gang per sekund, så vi har bare 59 biter, der ganske mye informasjon er kodet:

Bitene er beskrevet i og de er ganske nysgjerrige. De første 15 bitene blir ikke brukt, selv om det var planer om å bruke dem til høyttaler- og sivilforsvarssystemer. Bit A1 indikerer at klokken vil skifte til sommertid i løpet av den neste timen. Bit A2 indikerer at neste time vil bli lagt til , som noen ganger brukes til å korrigere tiden i henhold til jordens rotasjon. De gjenværende bitene koder timer, minutter, sekunder og dato.

For de som ønsker å eksperimentere på egenhånd, er dekodingskoden gitt under spoileren.
Kildekode
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)
Når vi kjører programmet, vil vi se noe som denne utgangen:
0011110110111000001011000001010000100110010101100010011000
Tuesday, 26.03.19, 21:41
0001111100110110001010100001010000100110010101100010011000
Tuesday, 26.03.19, 21:42
Det er faktisk all magien. Fordelen med et slikt system er at dekodingen er ekstremt enkel, og kan gjøres på hvilken som helst, den mest ukompliserte mikrokontrolleren. Vi teller bare lengden på pulsene, akkumulerer 60 biter, og på slutten av hvert minutt får vi den nøyaktige tiden. Sammenlignet med andre metoder for tidssynkronisering (GPS, for eksempel, eller Gud forby, Internett :), krever slik radiosynkronisering praktisk talt ikke strøm - for eksempel fungerer en vanlig værstasjon i hjemmet i omtrent et år på 2 AA-batterier. Derfor er selv armbåndsur laget med radiosynkronisering, for ikke å snakke om, selvfølgelig, veggklokker eller gatestasjonsklokker.
Bekvemmeligheten og enkelheten til DCF tiltrekker også DIY-entusiaster. For kun $10-20 kan du kjøpe en ferdig antennemodul med en ferdig mottaker og en TTL-utgang som kan kobles til en Arduino eller annen kontroller.

For Arduino allerede skrevet og . Det er imidlertid allerede kjent at uansett hva du gjør på mikrokontrolleren, får du enten en klokke eller en værstasjon. Med en slik enhet er det veldig enkelt å få nøyaktig tid, med mindre du selvfølgelig er i resepsjonsområdet. Vel, du kan henge påskriften "Atomic Clock" på klokken, og samtidig forklare alle at enheten virkelig er synkronisert ved hjelp av en atomklokke.
De som ønsker det kan til og med oppgradere den gamle bestemorklokken ved å installere en ny mekanisme med radiosynkronisering:

Du kan finne en på ebay ved å bruke søkeordene "Radio Controlled Movement".
Og til slutt, et livshack for de som har lest så langt. Selv om det ikke er en eneste radiosender innenfor et par tusen kilometer, er det enkelt å generere en selv. Det finnes en app på Google Play som heter «DCF77 Emulator» som sender ut et signal til hodetelefoner. Forfatteren hevder at hvis du surrer hodetelefonkabelen rundt klokken, vil den plukke opp signalet (jeg lurer på hvordan, siden vanlige hodetelefoner ikke produserer et 77 kHz-signal, men det skyldes sannsynligvis harmoniske svingninger). På klokken min... Android Program 9 fungerte ikke i det hele tatt – det var rett og slett ingen lyd (eller kanskje jeg bare ikke kunne høre den – det er tross alt 77 kHz. :)), men kanskje noen andre har bedre hell. Noen bygger imidlertid sin egen fullverdige DCF-signalgenerator, som er enkel å lage ved hjelp av en Arduino eller ESP32:

(kilde )
Konklusjon
DCF-systemet viste seg å være ganske enkelt og praktisk. Ved hjelp av en enkel og billig mottaker kan du ha nøyaktig tid alltid og overalt, selvfølgelig i resepsjonsområdet. Det ser ut til at selv til tross for den utbredte digitaliseringen og «tingenes internett», vil slike enkle løsninger være etterspurt i lang tid fremover.
Kilde: www.habr.com
