Salam Habr.
Bəlkə də, saat və ya meteoroloji stansiya alarkən, boksda Radio Controlled Clock və ya hətta Atomic Clock loqosunu görən çoxdur. Bu, olduqca rahatdır, çünki saatı masaya qoymaq kifayətdir və bir müddət sonra əsl vaxtla avtomatik olaraq tənzimlənir.

Bu necə çalışır, onu anlamağa çalışaq və Python dilində bir dekoder yazaq.
Fərqli vaxtın sinxronizasiya sistemləri mövcuddur. Avropada ən məşhuru - alman sistemidir. , Yaponiyada öz sistemi var. , ABŞ-da isə sistem var. , və s. Daha sonra danışılacaq DCF77, bəzi yerlərdə qəbul üçün ən aktuallığa malik olan və müvafiq olanıdır, Rusiya Federasiyasının Avropa hissəsində və qonşu ölkələrdə (Uzaq Şərqdə yaşayanların əks fikri ola bilər, lakin onlar Yapon siqnalını qəbul edə və analiz edə bilərlər).
Aşağıda yazılanlar DCF77 barəsində olacaq.
Siqnalın qəbul edilməsi
DCF77, 77.5 kHz tezliyində işləyən uzun dalğa stansiyasıdır və amplituda modulyasiyası ilə siqnallar göndərir. 50 kVt gücündə stansiya Frankfurtdan 25 km məsafədə yerləşir, 1959-cu ildən fəaliyyətə başlayıb, 1973-cü ildən dəqiq vaxtın yanına tarix informasiya əlavə olunub. 77 kHz tezliyində dalğa uzunluğu olduqca böyükdür, buna görə də antena sahəsinin ölçüləri də olduqca əhəmiyyətlidir.

Belə bir antena və güclə maksimum qəbul sahəsi faktiki olaraq bütün Avropanı, Belarusiyanı, Ukraynaları və Rusiyanın bir hissəsini əhatə edir.

Siqnalı hər kəs yaza bilər. Bunun üçün sadəcə onlayn qəbul ediciyə daxil olub , orada 76.5 kHz tezliyini və USB modulyasiyasını seçmək lazımdır. Aşağıdakı tipdə bir şəkil açılmalıdır:

Orada da download düyməsini basıb bir neçə dəqiqəlik fraqmenti qeyd edirik. Əlbəttə, əgər 'gerçək' qəbul edici varsa, 77.5 kHz tezliyini qeyd etmək üçün onu da istifadə etmək olar.
Təbii ki, internet vasitəsilə dəqiq vaxtın radio siqnallarını qəbul edərkən, əslində dəqiq vaxt əldə etməyəcəyik - siqnal gecikmə ilə ötürülür. Lakin məqsədimiz yalnız siqnalın strukturunu anlamaqdır, buna görə də internet yazıları bunun üçün kifayət qədərdir. Həqiqətdə, mütəxəssislər tərəfindən qəbul və dekodasiya üçün xüsusi cihazlar istifadə olunur, yuxarıda qeyd ediləcək.
Beləliklə, biz qeyd etdik, onun işlənməsinə keçək.
Siqnalın dekodlaşdırılması
Faylı Python ilə yükləyək və onun strukturuna baxaq:
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()
Tipik amplituda modulyasiyasını görürük:

Dekodlaşdırmanı asanlaşdırmaq üçün Hilbert transformasiyası ilə siqnalın əhatəsini alaq:
analytic_signal = signal.hilbert(data)
A = np.abs(analytic_signal)
plt.plot(A[:100000]) Böyüdülmüş nəticə:

Xarici müdaxilələrdən yaranan həyəcanı sıxışdırmaq üçün low-pass filterdən istifadə edərək, ortalama dəyəri də hesablayacağıq, bu daha sonra parslama üçün lazım olacaq.
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 Nəticə (sarı xət): demək olar ki, düzbucaqlı siqnal, onu analiz etmək olduqca asandır.

Parslama
Öncə bit sırasını əldə etmək lazımdır. Siqnalın özü çox sadə quruluşa malikdir.

İmpulslar saniyəlik intervallara bölünür. Əgər impulslar arasındakı məsafə 0.1s-dirsə (yəni impulsun uzunluğu 0.9s-dirsə), bit sırasına "0" əlavə edirik, əgər məsafə 0.2s-dirsə (yəni uzunluğu 0.8s-dirsə), "1" əlavə edirik. Hər dəqiqənin sonu "uzun" impulsla göstərilir, bu impuls 2s-dir, bit sırası bu anda sıfırlanır və doldurma yenidən başlayır.
Yuxarıda yazılanları Python dilində yazmaq çətin deyil.
sig_start, sig_stop = 0, 0
pos = 0
bits_str = ""
while pos < cnt - 4:
if A[pos] avg:
# Siqnalın başlanğıcı
sig_start = pos
if A[pos] > avg and A[pos+1] < avg:
# Siqnalın sonu
sig_stop = pos
diff = sig_stop - sig_start
if diff 0.85*sample_rate and diff 1.5*sample_rate:
print(bits_str)
bits_str = ""
pos += 1
Nəticədə bit ardıcıllığı alırıq, bizim nümunəmiz üçün iki saniyə belə görünür:
0011110110111000001011000001010000100110010101100010011000
0001111100110110001010100001010000100110010101100010011000
Üstəlik, maraqlı bir şey var ki, siqnalda "ikinci təbəqə" məlumat da mövcuddur. Bit ardıcıllığı da . Teorik olaraq, bu, zəifləmiş siqnal vəziyyətində belə daha dayanıqlı dekodlaşdırma təmin etməlidir.
Sonuncu addımımız: məlumatları əldə etmək. Bitlər bir dəfə bir saniyədə göndərilir, beləliklə, 59 bitimiz var, burada kifayət qədər məlumat kodlaşdırılıb:

Bitlər ilə təsvir olunur və olduqca maraqlıdır. İlk 15 bit istifadə olunmur, baxmayaraq ki, xəbərdarlıq sistemləri və mülki müdafiə üçün istifadə edilmə planları var idi. A1 biti, növbəti saatda saatların yaz vaxtına keçirilməsini bildirir. A2 biti növbəti saatda əlavə olunduğunu bildirir ki, bu da bəzən Yer kürəsinin fırlanmasına uyğun vaxtı düzəltmək üçün istifadə olunur. Qalan bitlər saat, dəqiqə, saniyə və tarixi kodlaşdırır.

Özünüz mütəxəssis kimi eksperiment etmək istəyənlər üçün dekodlaşdırma kodu spoiler altında verilmişdir.
Mənbə kodu
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 = ('Bazar', 'Bazar ertəsi', 'Çərşənbə axşamı', 'Çərşənbə', 'Cümə axşamı', 'Cümə', 'Şənbə', 'Bazar')
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)
Proqramı başladanda, biz belə bir nəticə görəcəyik:
0011110110111000001011000001010000100110010101100010011000
Çərşənbə axşamı, 26.03.19, 21:41
0001111100110110001010100001010000100110010101100010011000
Çərşənbə axşamı, 26.03.19, 21:42
Düzü, bütün bu sehr budur. Bu sistemin üstünlüyü ondan ibarətdir ki, dekodlama çox sadədir və istənilən sadə mikrocontroller-də icra oluna bilər. Sadəcə impulsların uzunluğunu sayırıq, 60 bit yığırıq və hər dəqiqənin sonunda dəqiq vaxtı alırıq. Digər vaxt sinxronizasiya üsulları ilə (məsələn, GPS, ya da İnternet:) müqayisədə, belə radio sinxronizasiyası praktik olaraq elektrik enerjisi tələb etmir — misal üçün, adi ev meteoroloji stansiyası 2 ədəd AA batareyadan bir il işləyir. Buna görə, radio sinxronizasiya ilə hətta qol saatları düzəldilir, sözsüz ki, divar saatları və ya küçə stansiyaları haqqında danışdıqda.
DCF-nin rahatlığı və sadəliyi həm də DIY həvəskarlarını cəlb edir. Yalnız 10-20$ ətrafında hazır antena modulu satın ala bilərsiniz, bununla yanaşı TTL çıxışına sahib olan bir qəbul edici, hansı ki, Arduino ya da digər kontrolcü ilə qoşa bilərsiniz.

Arduino üçün artıq yazılmışdır və . Lakin bilinir ki, mikrocontroller-də nə edirsənsə, ya saat, ya da meteoroloji stansiya yaranır. Belə bir cihazla dəqiq vaxt almaq həqiqətən də mürəkkəb deyil, əlbəttə ki, qəbul zonasındaysanız. Və saatlarınızın üzərinə 'Atom Saatı' yazısını asıb, hər kəsə izah edə bilərsiniz ki, cihaz həqiqətən atom saatı ilə sinxronlaşdırılır.
İstəyənlər köhnə nənə saatlarını belə inkişaf etdirə bilər, onlara radio sinxronizasiya edən yeni mexanizm quraşdıra bilər:

Belə birini ebay-da 'Radio Controlled Movement' açar sözləri ilə tapa bilərsiniz.
Və nəhayət, bura qədər oxuyanlar üçün bir həyat hack'i. Yaxınlarda minlərlə kilometr məsafədə bir radio siqnal ötürücüsü olmasa da, belə siqnalı özünüz yaratmaq asandır. Google Play-də «DCF77 Emulator» adında bir proqram var, hansının siqnalı qulaqlara çıxarır. Müəllifin iddialarına görə, qulaqların kabellərini saatın ətrafında dolamaqla, siqnalı ala bilərlər (təəccüblüdür necə, çünki adi qulaqlar 77 kHz siqnalı verə bilmir, amma ehtimal ki, qəbul harmoniklər sayəsində baş verir). Android 9-da proqram tamamilə işləmədi - sadəcə səs yox idi (ya da bəlkə mən eşitmədim - 77 kHz-di:), amma bəlkə də kimlərsə daha çox şanslı olar. Bəziləri isə, Arduino və ya ESP32-də asanlıqla hazırlaya biləcəkləri tam siqnal generatorunu özlərinə düzəldirlər.

(kaynak )
Nəticə
DCF sistemi həqiqətən də sadə və rahatdır. Asan və ucuz bir qəbulqoyucu sayəsində hər zaman dəqiq vaxtı əldə edə bilərsiniz, əlbəttə ki, qəbul bölgəsində. Düşünürəm ki, ümumi rəqəmsallaşma və «əşyaların interneti» dövründə belə sadə həllərin tələbi uzun müddət davam edəcək.
Mənbə: habr.com
