DCF77: Hur fungerar tidssignalsystemet?

Hej Habr.

Förmodligen har många som köper en klocka eller väderstation sett Radio Controlled Clock eller till och med Atomic Clock-logotypen på förpackningen. Detta är väldigt bekvämt, eftersom du bara behöver lägga klockan på bordet, och efter ett tag kommer den automatiskt att anpassa sig till den exakta tiden.
DCF77: Hur fungerar tidssignalsystemet?

Låt oss ta reda på hur det fungerar och skriva en avkodare i Python.

Det finns olika tidssynkroniseringssystem. Det mest populära i Europa är det tyska systemet DCF-77, Japan har sitt eget system JJY, i USA finns ett system WWVB, och så vidare. Därefter kommer historien att handla om DCF77, som den mest relevanta och tillgängliga för mottagning på vissa platser i den europeiska delen av Ryssland och grannländerna (invånare i Fjärran Östern kan ha motsatt uppfattning, men de kan i sin tur ta emot och analysera den japanska signalen ;).

Allt som skrivs nedan kommer att handla om DCF77.

Signalmottagning

DCF77 är en långvågsstation som arbetar med en frekvens på 77.5 kHz och sänder signaler i amplitudmodulering. 50KW-stationen ligger 25 km från Frankfurt, den började fungera 1959 och 1973 lades datuminformation till den exakta tiden. Våglängden vid en frekvens på 77 KHz är mycket lång, så dimensionerna på antennfältet är också ganska anständiga (foto från Wikipedia):
DCF77: Hur fungerar tidssignalsystemet?

Med en sådan antenn och strömingång täcker mottagningsområdet nästan hela Europa, Vitryssland, Ukraina och en del av Ryssland.

DCF77: Hur fungerar tidssignalsystemet?

Vem som helst kan spela in en signal. För att göra detta, gå bara till online-mottagaren http://websdr.ewi.utwente.nl:8901/, välj frekvensen 76.5KHz och USB-modulering där. En bild bör öppnas som ser ut ungefär så här:

DCF77: Hur fungerar tidssignalsystemet?

Där trycker vi på nedladdningsknappen och spelar in ett flera minuter långt fragment. Naturligtvis, om du har en "riktig" mottagare som kan spela in 77.5KHz-frekvensen, kan du använda den.

Genom att ta emot radiotidssignaler via Internet kommer vi naturligtvis inte att få riktigt exakt tid - signalen sänds med en fördröjning. Men vårt mål är bara att förstå strukturen på signalen, för detta räcker internetinspelningen mer än nog. I verkliga livet används naturligtvis specialiserade enheter för att ta emot och avkoda; de kommer att diskuteras nedan.

Så vi har fått inspelningen, låt oss börja bearbeta den.

Signalavkodning

Låt oss ladda filen med Python och se dess struktur:

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 typisk amplitudmodulering:
DCF77: Hur fungerar tidssignalsystemet?

För att förenkla avkodningen, låt oss ta signalenveloppen med hjälp av Hilbert-transformen:

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

Förstorat resultat:
DCF77: Hur fungerar tidssignalsystemet?

Låt oss jämna ut brusemissioner med ett lågpassfilter och samtidigt beräkna medelvärdet, vilket kommer att vara användbart senare för analys.

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): en nästan fyrkantsvågsignal som är ganska lätt att analysera.
DCF77: Hur fungerar tidssignalsystemet?

Parsing

Först måste du få bitsekvensen. Signalstrukturen i sig är väldigt enkel.
DCF77: Hur fungerar tidssignalsystemet?

Pulserna är uppdelade i andra intervall. Om avståndet mellan pulserna är 0.1 s (dvs längden på själva pulsen är 0.9 s), lägg till "0" till bitsekvensen; om avståndet är 0.2 s (dvs längden är 0.8 s), lägg till "1". Slutet av varje minut indikeras av en "lång" puls, 2s lång, bitsekvensen nollställs och fyllningen börjar igen.

Ovanstående är lätt att skriva 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 ett resultat får vi en sekvens av bitar, i vårt exempel under två sekunder ser det ut så här:

0011110110111000001011000001010000100110010101100010011000
0001111100110110001010100001010000100110010101100010011000

Förresten, det är intressant att signalen också har ett "andra lager" av data. Bitsekvensen kodas också med hjälp av fasmodulering. I teorin bör detta ge en mer robust avkodning även i fallet med en försvagad signal.

Vårt sista steg: få de faktiska uppgifterna. Bitar sänds en gång per sekund, så vi har totalt 59 bitar, där ganska mycket information är kodad:
DCF77: Hur fungerar tidssignalsystemet?

Bitarna beskrivs i Wikipedia, och de är ganska nyfikna. De första 15 bitarna används inte, även om det fanns planer på att använda dem för varningssystem och civilförsvar. Bit A1 indikerar att klockan kommer att ändras till sommartid under nästa timme. Bit A2 indikerar att ytterligare en språngsekund, som ibland används för att anpassa tiden efter jordens rotation. De återstående bitarna kodar timmar, minuter, sekunder och datum.

DCF77: Hur fungerar tidssignalsystemet?

För den som vill experimentera på egen hand ges avkodningskoden under spoilern.
Källkod

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 kör programmet kommer vi att se utdata som liknar detta:

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

Det är faktiskt allt som är magin. Fördelen med ett sådant system är att avkodningen är extremt enkel och kan göras på vilken som helst, även den enklaste mikrokontrollern. Vi räknar helt enkelt längden på pulserna, ackumulerar 60 bitar, och i slutet av varje minut får vi den exakta tiden. Jämfört med andra metoder för tidssynkronisering (GPS, till exempel, eller gud förbjude, internet:) kräver sådan radiosynkronisering praktiskt taget ingen elektricitet - till exempel går en vanlig väderstation för hemmabruk i ungefär ett år på 2 AA-batterier. Därför är även armbandsur gjorda med radiosynkronisering, för att förstås inte tala om väggur eller gatustationsklockor.

Bekvämligheten och enkelheten hos DCF lockar också gör-det-själv-entusiaster. För bara $10-20 kan du köpa en färdig antennmodul med färdig mottagare och TTL-utgång, som kan kopplas till en Arduino eller annan styrenhet.
DCF77: Hur fungerar tidssignalsystemet?

Redan skriven för Arduino färdiga bibliotek. Det är dock redan känt att oavsett vad du gör på en mikrokontroller så får du antingen en klocka eller en väderstation. Med en sådan enhet är det väldigt enkelt att få den exakta tiden, givetvis förutsatt att du är i receptionen. Tja, du kan hänga inskriptionen "Atomic Clock" på din klocka, och samtidigt förklara för alla att enheten verkligen är synkroniserad med en atomklocka.

De som önskar kan till och med uppgradera sin gamla mormors klocka genom att installera en ny mekanism med radiosynkronisering:

DCF77: Hur fungerar tidssignalsystemet?

Du kan hitta en på ebay med nyckelorden "Radio Controlled Movement".

Och till sist, ett life hack för dem som har läst så här långt. Även om det inte finns en enda radiosignalsändare inom de närmaste tusentals km, är det inte svårt att själv generera en sådan signal. Det finns ett program på Google Play som heter "DCF77 Emulator" som matar ut signalen till hörlurar. Enligt författaren, om du lindar hörlurarnas tråd runt klockan, kommer de att fånga upp signalen (det är intressant hur, eftersom vanliga hörlurar inte kommer att producera en 77KHz-signal, men mottagningen beror förmodligen på övertoner). På Android 9 fungerade programmet inte alls för mig - det fanns helt enkelt inget ljud (eller jag kanske inte hörde det - det är trots allt 77KHz:), men kanske någon har bättre tur. Vissa gör sig dock till en fullfjädrad DCF-signalgenerator, som är lätt att göra på samma Arduino eller ESP32:

DCF77: Hur fungerar tidssignalsystemet?
(källa sgfantasytoys.wordpress.com/2015/05/13/synchronize-radio-controlled-watch-without-access)

Slutsats

DCF-systemet visade sig egentligen vara ganska enkelt och bekvämt. Med hjälp av en enkel och billig mottagare kan du ha den exakta tiden alltid och överallt, givetvis i receptionen. Det verkar som att även trots utbredd digitalisering och Internet of Things kommer sådana enkla lösningar att efterfrågas under lång tid.

Källa: will.com

Lägg en kommentar