Merhaba Habr.
Muhtemelen bir saat veya hava durumu istasyonu satın alan birçok kişi, ambalajın üzerinde Radyo Kontrollü Saat ve hatta Atomik Saat logosunu görmüştür. Bu çok kullanışlıdır, çünkü saati masanın üzerine koymanız yeterlidir ve bir süre sonra otomatik olarak tam zamanı ayarlayacaktır.
Nasıl çalıştığını anlayalım ve Python'da bir kod çözücü yazalım.
Farklı zaman senkronizasyon sistemleri vardır. Avrupa'da en popüler olanı Alman sistemidir
Aşağıda yazılanların hepsi DCF77 ile ilgili olacaktır.
Sinyal alımı
DCF77, 77.5 kHz frekansında çalışan ve genlik modülasyonlu sinyaller ileten uzun dalga istasyonudur. 50KW'lık istasyon Frankfurt'a 25 km uzaklıkta olup 1959 yılında faaliyete geçmiş ve 1973 yılında kesin saate tarih bilgisi eklenmiştir. 77 KHz frekansındaki dalga boyu çok uzun olduğundan anten alanının boyutları da oldukça iyidir (Wikipedia'dan fotoğraf):
Böyle bir anten ve güç girişi ile alım alanı neredeyse tüm Avrupa'yı, Beyaz Rusya'yı, Ukrayna'yı ve Rusya'nın bir kısmını kapsıyor.
Herkes bir sinyali kaydedebilir. Bunu yapmak için çevrimiçi alıcıya gitmeniz yeterlidir
Orada indirme düğmesine basıyoruz ve birkaç dakika uzunluğunda bir parça kaydediyoruz. Elbette 77.5KHz frekansını kaydedebilen “gerçek” bir alıcınız varsa onu kullanabilirsiniz.
Elbette, İnternet üzerinden radyo zaman sinyallerini alarak, gerçekten doğru zamanı alamayacağız - sinyal gecikmeli olarak iletilir. Ama amacımız sadece sinyalin yapısını anlamak, bunun için internet kaydı fazlasıyla yeterli. Gerçek hayatta, elbette, alma ve kod çözme için özel cihazlar kullanılır; bunlar aşağıda tartışılacaktır.
Kaydı aldık, işlemeye başlayalım.
Sinyal Kod Çözme
Dosyayı Python kullanarak yükleyelim ve yapısını görelim:
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 genlik modülasyonunu görüyoruz:
Kod çözmeyi basitleştirmek için Hilbert dönüşümünü kullanarak sinyal zarfını alalım:
analytic_signal = signal.hilbert(data)
A = np.abs(analytic_signal)
plt.plot(A[:100000])
Büyütülmüş sonuç:
Alçak geçiren bir filtre kullanarak gürültü emisyonlarını düzeltelim ve aynı zamanda daha sonra ayrıştırma için faydalı olacak ortalama değeri hesaplayalım.
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
Sonuç (sarı çizgi): Analiz edilmesi oldukça kolay, neredeyse kare dalga sinyali.
Ayrıştırma
İlk önce bit dizisini almanız gerekir. Sinyal yapısının kendisi çok basittir.
Darbeler ikinci aralıklara bölünür. Darbeler arasındaki mesafe 0.1s ise (yani darbenin uzunluğu 0.9s ise), bit dizisine “0” ekleyin; mesafe 0.2s ise (yani uzunluk 0.8s ise) “1” ekleyin. Her dakikanın sonu, 2 saniye uzunluğundaki "uzun" bir darbeyle gösterilir, bit dizisi sıfırlanır ve doldurma yeniden başlar.
Yukarıdakileri Python'da yazmak kolaydır.
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
Sonuç olarak, bir dizi bit elde ediyoruz, örneğimizde iki saniye boyunca şöyle görünüyor:
0011110110111000001011000001010000100110010101100010011000
0001111100110110001010100001010000100110010101100010011000
Bu arada, sinyalin aynı zamanda "ikinci bir veri katmanına" sahip olması ilginçtir. Bit dizisi ayrıca kullanılarak kodlanır.
Son adımımız: gerçek verileri elde etmek. Bitler saniyede bir kez iletilir, dolayısıyla oldukça fazla bilginin kodlandığı toplam 59 bitimiz var:
Bitler şurada açıklanmıştır:
Kendi başına denemek isteyenler için şifre çözme kodu spoiler altında verilmiştir.
Kaynak 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 = ('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)
Programı çalıştırdığımızda aşağıdakine benzer bir çıktı göreceğiz:
0011110110111000001011000001010000100110010101100010011000
Tuesday, 26.03.19, 21:41
0001111100110110001010100001010000100110010101100010011000
Tuesday, 26.03.19, 21:42
Aslında tüm sihir bu. Böyle bir sistemin avantajı, kod çözmenin son derece basit olması ve herhangi bir hatta en basit mikro denetleyicide bile yapılabilmesidir. Basitçe darbelerin uzunluğunu sayarız, 60 bit biriktiririz ve her dakikanın sonunda tam zamanı elde ederiz. Diğer zaman senkronizasyon yöntemleriyle karşılaştırıldığında (örneğin GPS veya Tanrı korusun İnternet :)), bu tür radyo senkronizasyonu neredeyse hiç elektrik gerektirmez - örneğin, normal bir ev hava durumu istasyonu 2 AA pille yaklaşık bir yıl boyunca çalışır. Bu nedenle kol saatleri bile radyo senkronizasyonu ile yapılır, elbette duvar saatleri veya sokak istasyonu saatlerinden bahsetmeye bile gerek yok.
DCF'nin rahatlığı ve basitliği aynı zamanda Kendin Yap meraklılarının da ilgisini çekmektedir. Yalnızca 10-20 $ karşılığında, Arduino'ya veya başka bir denetleyiciye bağlanabilen, hazır alıcısı ve TTL çıkışı olan hazır bir anten modülü satın alabilirsiniz.
Zaten Arduino için yazılmış
Dileyenler, radyo senkronizasyonlu yeni bir mekanizma kurarak eski büyükannelerinin saatini bile yükseltebilirler:
"Radyo Kontrollü Hareket" anahtar kelimesini kullanarak ebay'de bir tane bulabilirsiniz.
Ve son olarak buraya kadar okuyanlar için bir hayat tüyosu. Önümüzdeki birkaç bin km'de tek bir radyo sinyali vericisi olmasa bile, böyle bir sinyali kendiniz üretmeniz zor değildir. Google Play'de “DCF77 Emulator” adında kulaklığa sinyal gönderen bir program var. Yazara göre, kulaklıkların telini saatin etrafına sararsanız sinyali alacaklardır (bu ilginç çünkü sıradan kulaklıklar 77KHz sinyal üretmez, ancak alım muhtemelen harmoniklerden kaynaklanmaktadır). Android 9'da program benim için hiç işe yaramadı - hiç ses yoktu (ya da belki duymadım - sonuçta 77KHz :), ama belki birisinin şansı daha iyi olabilir. Ancak bazıları kendilerini aynı Arduino veya ESP32'de yapılması kolay olan tam teşekküllü bir DCF sinyal üreteci haline getiriyor:
(bir kaynak
Sonuç
DCF sisteminin gerçekten oldukça basit ve kullanışlı olduğu ortaya çıktı. Basit ve ucuz bir alıcının yardımıyla her zaman ve her yerde, tabii ki resepsiyon alanında, tam zamanı görebilirsiniz. Yaygın dijitalleşmeye ve Nesnelerin İnterneti'ne rağmen bu kadar basit çözümler uzun süre talep görecek gibi görünüyor.
Kaynak: habr.com