DCF77: miten aikamerkinantojärjestelmä toimii?

Hei Habr.

Todennäköisesti monet kellon tai sääaseman ostajat ovat nähneet pakkauksessa radio-ohjattavan kellon tai jopa atomikellon logon. Tämä on erittäin kätevää, koska sinun tarvitsee vain laittaa kello pöydälle, ja hetken kuluttua se mukautuu automaattisesti tarkkaan aikaan.
DCF77: miten aikamerkinantojärjestelmä toimii?

Selvitetään kuinka se toimii ja kirjoitetaan dekooderi Pythonissa.

Aikasynkronointijärjestelmiä on erilaisia. Suosituin Euroopassa on saksalainen järjestelmä DCF-77, Japanilla on oma järjestelmänsä JJY, Yhdysvalloissa on järjestelmä wwvb, ja niin edelleen. Seuraavaksi tarina kertoo DCF77:stä, joka on olennaisin ja vastaanottokelpoisin paikoin Venäjän Euroopan osassa ja naapurimaissa (Kaukoidän asukkaat voivat olla päinvastaista mieltä, mutta he puolestaan ​​voivat vastaanottaa ja analysoida japanilaista signaalia;).

Kaikki alla kirjoitettu koskee DCF77:ää.

Signaalin vastaanotto

DCF77 on pitkän aallon asema, joka toimii 77.5 kHz:n taajuudella ja lähettää signaaleja amplitudimodulaatiolla. 50 kW:n asema sijaitsee 25 km:n päässä Frankfurtista, se aloitti toimintansa vuonna 1959, ja vuonna 1973 tarkkaan aikaan lisättiin päivämäärätiedot. Aallonpituus 77 KHz:n taajuudella on erittäin pitkä, joten antennikentän mitat ovat myös melko kunnolliset (kuva Wikipediasta):
DCF77: miten aikamerkinantojärjestelmä toimii?

Tällaisella antennilla ja tehotulolla vastaanottoalue kattaa lähes koko Euroopan, Valko-Venäjän, Ukrainan ja osan Venäjää.

DCF77: miten aikamerkinantojärjestelmä toimii?

Kuka tahansa voi tallentaa signaalin. Voit tehdä tämän siirtymällä online-vastaanottimeen http://websdr.ewi.utwente.nl:8901/, valitse taajuus 76.5KHz ja USB-modulaatio sieltä. Kuvan pitäisi avautua, joka näyttää tältä:

DCF77: miten aikamerkinantojärjestelmä toimii?

Siellä painamme latauspainiketta ja tallennamme muutaman minuutin pituisen fragmentin. Tietenkin, jos sinulla on "oikea" vastaanotin, joka pystyy tallentamaan 77.5 kHz:n taajuuden, voit käyttää sitä.

Vastaanottamalla radioaikasignaaleja Internetin kautta emme tietenkään saa todella tarkkaa aikaa - signaali lähetetään viiveellä. Mutta tavoitteemme on vain ymmärtää signaalin rakenne; tähän Internet-tallennus on enemmän kuin tarpeeksi. Todellisessa elämässä tietysti käytetään erikoislaitteita vastaanottamiseen ja dekoodaukseen; niitä käsitellään alla.

Joten, olemme vastaanottaneet tallenteen, aloitetaan sen käsittely.

Signaalin dekoodaus

Ladataan tiedosto Pythonilla ja katsotaan sen rakenne:

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()

Näemme tyypillisen amplitudimodulaation:
DCF77: miten aikamerkinantojärjestelmä toimii?

Dekoodauksen yksinkertaistamiseksi otetaan signaalin verhokäyrä Hilbert-muunnoksen avulla:

analytic_signal = signal.hilbert(data)
A = np.abs(analytic_signal)
plt.plot(A[:100000])

Laajennettu tulos:
DCF77: miten aikamerkinantojärjestelmä toimii?

Tasoitetaan melupäästöjä alipäästösuodattimella ja lasketaan samalla keskiarvo, josta on hyötyä myöhemmin jäsennyksessä.

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

Tulos (keltainen viiva): melkein neliöaaltosignaali, joka on melko helppo analysoida.
DCF77: miten aikamerkinantojärjestelmä toimii?

Jäsentäminen

Ensin sinun on hankittava bittisekvenssi. Itse signaalin rakenne on hyvin yksinkertainen.
DCF77: miten aikamerkinantojärjestelmä toimii?

Pulssit on jaettu kakkosjaksoihin. Jos pulssien välinen etäisyys on 0.1 s (eli itse pulssin pituus on 0.9 s), lisää bittijonoon "0"; jos etäisyys on 0.2 s (eli pituus on 0.8 s), lisää "1". Jokaisen minuutin päättymisen ilmaisee "pitkä" pulssi, 2s pitkä, bittisekvenssi nollataan ja täyttö alkaa uudelleen.

Yllä oleva on helppo kirjoittaa Pythonilla.

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

Tämän seurauksena saamme bittisarjan, esimerkissämme kahden sekunnin ajan se näyttää tältä:

0011110110111000001011000001010000100110010101100010011000
0001111100110110001010100001010000100110010101100010011000

Muuten, on mielenkiintoista, että signaalilla on myös "toinen kerros" dataa. Bittisekvenssi koodataan myös käyttämällä vaihemodulaatio. Teoriassa tämän pitäisi tarjota tehokkaampi dekoodaus jopa heikentyneen signaalin tapauksessa.

Viimeinen vaiheemme: todellisten tietojen saaminen. Bittejä lähetetään kerran sekunnissa, joten meillä on yhteensä 59 bittiä, joihin on koodattu melko paljon tietoa:
DCF77: miten aikamerkinantojärjestelmä toimii?

Bitit on kuvattu kohdassa wikipedia, ja he ovat melko uteliaita. Ensimmäiset 15 bittiä eivät ole käytössä, vaikka niitä suunniteltiin käyttää varoitusjärjestelmiin ja väestönsuojeluun. Bitti A1 osoittaa, että kello siirtyy kesäaikaan seuraavan tunnin aikana. Bitti A2 osoittaa, että ylimääräinen harppaus toinen, jota käytetään joskus säätämään aikaa maan pyörimisen mukaan. Loput bitit koodaavat tunteja, minuutteja, sekunteja ja päivämäärää.

DCF77: miten aikamerkinantojärjestelmä toimii?

Niille, jotka haluavat kokeilla itse, dekoodauskoodi annetaan spoilerin alla.
Lähdekoodi

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)

Kun suoritamme ohjelman, näemme tämän kaltaisen tulosteen:

0011110110111000001011000001010000100110010101100010011000
Tuesday, 26.03.19, 21:41
0001111100110110001010100001010000100110010101100010011000
Tuesday, 26.03.19, 21:42

Itse asiassa se on kaikki taika. Tällaisen järjestelmän etuna on, että dekoodaus on erittäin yksinkertaista ja se voidaan tehdä millä tahansa, jopa yksinkertaisimmalla mikro-ohjaimella. Laskemme yksinkertaisesti pulssien pituuden, keräämme 60 bittiä ja jokaisen minuutin lopussa saamme tarkan ajan. Verrattuna muihin aikasynkronointimenetelmiin (esim. GPS tai varjelkoon Internet:), tällainen radiosynkronointi ei vaadi käytännössä sähköä - esimerkiksi tavallinen kotisääasema toimii noin vuoden kahdella AA-paristolla. Siksi jopa rannekellot valmistetaan radiosynkronoinnilla, puhumattakaan tietysti seinäkelloista tai katuasemakelloista.

DCF:n mukavuus ja yksinkertaisuus houkuttelevat myös tee-se-itse-harrastajia. Vain 10-20 dollarilla voit ostaa valmiin antennimoduulin valmiilla vastaanottimella ja TTL-lähdöllä, joka voidaan liittää Arduinoon tai muuhun ohjaimeen.
DCF77: miten aikamerkinantojärjestelmä toimii?

Kirjoitettu jo Arduinolle valmiita kirjastoja. On kuitenkin jo tiedossa, että riippumatta siitä, mitä teet mikro-ohjaimella, saat joko kellon tai sääaseman. Tällaisella laitteella tarkan ajan saaminen on todella helppoa, edellyttäen tietysti, että olet vastaanottoalueella. No, voit ripustaa kelloon merkinnän "Atomic Clock" ja samalla selittää kaikille, että laite on todella synkronoitu atomikellolla.

Halukkaat voivat jopa päivittää vanhan isoäitikellonsa asentamalla uuden mekanismin radiosynkronoinnilla:

DCF77: miten aikamerkinantojärjestelmä toimii?

Löydät sellaisen eBaysta avainsanoilla "Radio Controlled Movement".

Ja lopuksi elämänhack niille, jotka ovat lukeneet tähän asti. Vaikka seuraavan parin tuhannen km:n sisällä ei olisi yhtään radiosignaalilähetintä, sellaisen signaalin luominen itse ei ole vaikeaa. Google Playssa on ohjelma nimeltä "DCF77 Emulator", joka lähettää signaalin kuulokkeisiin. Kirjoittajan mukaan, jos kiedät kuulokkeiden langan kellon ympärille, ne poimivat signaalin (mielenkiintoista miten, koska tavalliset kuulokkeet eivät tuota 77KHz signaalia, mutta vastaanotto johtuu luultavasti harmonisista). Android 9:ssä ohjelma ei toiminut ollenkaan minulle - ääntä ei yksinkertaisesti kuulunut (tai ehkä en kuullut sitä - se on loppujen lopuksi 77KHz:), mutta ehkä jollain on parempi onni. Jotkut kuitenkin tekevät itsestään täysimittaisen DCF-signaaligeneraattorin, joka on helppo tehdä samalla Arduinolla tai ESP32:lla:

DCF77: miten aikamerkinantojärjestelmä toimii?
(lähde sgfantasytoys.wordpress.com/2015/05/13/synchronize-radio-controlled-watch-without-access)

Johtopäätös

DCF-järjestelmä osoittautui todella yksinkertaiseksi ja käteväksi. Yksinkertaisen ja halvan vastaanottimen avulla saat tarkan ajan aina ja kaikkialla, tietysti vastaanottoalueella. Vaikuttaa siltä, ​​että laajasta digitalisaatiosta ja esineiden internetistä huolimatta tällaisille yksinkertaisille ratkaisuille on kysyntää vielä pitkään.

Lähde: will.com

Lisää kommentti