Здраво Һабр.
Вероватно су многи који купују сат или метеоролошку станицу видели радио контролисани сат или чак логотип атомског сата на паковању. Ово је веома згодно, јер само треба да ставите сат на сто, а након неког времена ће се аутоматски прилагодити тачном времену.
Хајде да схватимо како то функционише и напишемо декодер у Питхон-у.
Постоје различити системи за синхронизацију времена. Најпопуларнији у Европи је немачки систем
Све што је доле написано биће о ДЦФ77.
Пријем сигнала
ДЦФ77 је дуготаласна станица која ради на фреквенцији од 77.5 кХз и емитује сигнале у амплитудној модулацији. Станица од 50КВ налази се 25 км од Франкфурта, почела је са радом 1959. године, а 1973. године је додат податак о тачном времену. Таласна дужина на фреквенцији од 77 КХз је веома дуга, тако да су и димензије антенског поља сасвим пристојне (фотографија са Википедије):
Са таквом антеном и улазом за напајање, пријемно подручје покрива скоро целу Европу, Белорусију, Украјину и део Русије.
Свако може да сними сигнал. Да бисте то урадили, само идите на мрежни пријемник
Тамо притиснемо дугме за преузимање и снимимо фрагмент дуг неколико минута. Наравно, ако имате „прави“ пријемник који може да снима фреквенцију од 77.5 КХз, можете то користити.
Наравно, примањем радио сигнала времена преко Интернета, нећемо добити заиста тачно време – сигнал се преноси са закашњењем. Али наш циљ је само да разумемо структуру сигнала, за то је више него довољан интернет снимак. У стварном животу, наравно, за пријем и декодирање се користе специјализовани уређаји, о њима ће бити речи у наставку.
Дакле, добили смо снимак, хајде да га обрадимо.
Сигнал Децодинг
Хајде да учитамо датотеку користећи Питхон и видимо њену структуру:
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()
Видимо типичну амплитудну модулацију:
Да бисмо поједноставили декодирање, узмимо омотач сигнала користећи Хилбертову трансформацију:
analytic_signal = signal.hilbert(data)
A = np.abs(analytic_signal)
plt.plot(A[:100000])
Увећани резултат:
Хајде да изгладимо емисије буке помоћу нископропусног филтера, а у исто време израчунамо просечну вредност, која ће касније бити корисна за рашчлањивање.
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
Резултат (жута линија): сигнал скоро квадратног таласа који је прилично лако анализирати.
Парсинг
Прво морате да добијете секвенцу битова. Сама структура сигнала је врло једноставна.
Импулси су подељени на секундарне интервале. Ако је растојање између импулса 0.1с (тј. дужина самог импулса је 0.9с), додајте „0“ секвенци битова; ако је растојање 0.2с (тј. дужина је 0.8с), додајте „1“. Крај сваког минута је означен „дугим“ импулсом, дугим 2 с, секвенца битова се ресетује на нулу и пуњење почиње поново.
Горе је лако написати у Питхон-у.
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
Као резултат, добијамо низ битова, у нашем примеру за две секунде то изгледа овако:
0011110110111000001011000001010000100110010101100010011000
0001111100110110001010100001010000100110010101100010011000
Иначе, занимљиво је да сигнал има и „други слој“ података. Битова секвенца се такође кодира помоћу
Наш последњи корак: добијање стварних података. Битови се преносе једном у секунди, тако да имамо укупно 59 битова, у којима је кодирано доста информација:
Битови су описани у
За оне који желе да експериментишу сами, код за декодирање је дат испод спојлера.
Извор
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)
Када покренемо програм, видећемо излаз сличан овоме:
0011110110111000001011000001010000100110010101100010011000
Tuesday, 26.03.19, 21:41
0001111100110110001010100001010000100110010101100010011000
Tuesday, 26.03.19, 21:42
У ствари, то је сва магија. Предност оваквог система је што је декодирање изузетно једноставно и може се обавити на било ком, па и најједноставнијем микроконтролеру. Једноставно бројимо дужину импулса, акумулирамо 60 бита и на крају сваког минута добијамо тачно време. У поређењу са другим методама временске синхронизације (ГПС, на пример, или не дај Боже, Интернет:), за такву радио синхронизацију није потребна буквално никаква струја – на пример, обична кућна метеоролошка станица ради око годину дана на 2 АА батерије. Због тога се чак и ручни сатови праве са радио синхронизацијом, да не помињемо, наравно, зидне сатове или сатове уличних станица.
Погодност и једноставност ДЦФ-а такође привлаче ентузијасте „уради сам“. За само 10-20 долара можете купити готов антенски модул са готовим пријемником и ТТЛ излазом, који се може повезати на Ардуино или други контролер.
Већ написано за Ардуино
Они који желе могу чак и да надограде свој стари бакин сат уградњом новог механизма са радио синхронизацијом:
Можете га пронаћи на еБаи-у користећи кључне речи „Радио Цонтроллед Мовемент“.
И на крају, лајф хак за оне који су читали до сада. Чак и ако у наредних неколико хиљада км нема ни једног предајника радио сигнала, није тешко сами генерисати такав сигнал. На Гоогле Плаи-у постоји програм под називом „ДЦФ77 Емулатор“ који емитује сигнал у слушалице. Према речима аутора, ако обмотате жицу слушалица око сата, оне ће ухватити сигнал (занимљиво је како, јер обичне слушалице неће производити сигнал од 77 кХз, али пријем је вероватно због хармоника). На Андроид-у 9 програм ми уопште није радио - једноставно није било звука (или га можда нисам чуо - ипак је 77КХз :)), али можда ће неко имати више среће. Неки, међутим, праве себи потпуни генератор ДЦФ сигнала, који је лако направити на истом Ардуину или ЕСП32:
(извор
Закључак
Испоставило се да је ДЦФ систем заиста прилично једноставан и згодан. Уз помоћ једноставног и јефтиног пријемника, увек и свуда можете имати тачно време, наравно у рецепцији. Чини се да ће и поред широко распрострањене дигитализације и Интернета ствари, оваква једноставна решења бити тражена још дуго.
Извор: ввв.хабр.цом