Сәлем Хабр.
Сағат немесе ауа-райы станциясын сатып алатындардың көпшілігі қаптамада радиомен басқарылатын сағатты немесе тіпті атом сағатының логотипін көрген болуы мүмкін. Бұл өте ыңғайлы, өйткені сағатты үстелге қою жеткілікті, ал біраз уақыттан кейін ол автоматты түрде дәл уақытты реттейді.
Оның қалай жұмыс істейтінін анықтап алайық және Python тілінде декодерді жазайық.
Әр түрлі уақытты синхрондау жүйелері бар. Еуропадағы ең танымал неміс жүйесі
Төменде жазылғанның бәрі DCF77 туралы болады.
Сигнал қабылдау
DCF77 – 77.5 кГц жиілікте жұмыс істейтін және амплитудалық модуляцияда сигналдарды беретін ұзын толқынды станция. 50 кВт станция Франкфурттен 25 км қашықтықта орналасқан, ол 1959 жылы жұмысын бастады, ал 1973 жылы нақты уақыт туралы ақпарат қосылды. 77 кГц жиіліктегі толқын ұзындығы өте ұзын, сондықтан антенна өрісінің өлшемдері де өте лайықты (Википедиядан алынған фото):
Мұндай антенна мен қуат көзі арқылы қабылдау аймағы бүкіл Еуропаны, Беларусьті, Украинаны және Ресейдің бір бөлігін дерлік қамтиды.
Кез келген адам сигнал жаза алады. Мұны істеу үшін онлайн ресиверге өтіңіз
Онда біз жүктеу түймесін басып, бірнеше минуттық фрагментті жазамыз. Әрине, егер сізде 77.5 кГц жиілігін жаза алатын «нақты» қабылдағыш болса, оны пайдалануға болады.
Әрине, Интернет арқылы радиоуақыт сигналдарын алу арқылы біз нақты уақытты алмаймыз - сигнал кідіріспен беріледі. Бірақ біздің мақсатымыз - сигналдың құрылымын түсіну, бұл үшін Интернеттегі жазба жеткілікті. Шынайы өмірде, әрине, қабылдау және декодтау үшін арнайы құрылғылар пайдаланылады, олар төменде талқыланады.
Сонымен, біз жазбаны алдық, оны өңдеуді бастайық.
Сигналдарды декодтау
Файлды Python арқылы жүктеп, оның құрылымын көрейік:
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 секунд, разряд тізбегі нөлге орнатылады және толтыру қайтадан басталады.
Жоғарыда айтылғандарды 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
Нәтижесінде біз биттердің тізбегін аламыз, біздің мысалда екі секунд ішінде ол келесідей көрінеді:
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 бит жинаймыз және әр минуттың соңында біз нақты уақытты аламыз. Уақытты синхрондаудың басқа әдістерімен салыстырғанда (мысалы, GPS, немесе Құдай сақтасын, Интернет :)), мұндай радио синхрондау іс жүзінде электр қуатын қажет етпейді - мысалы, әдеттегі үй метеостанциясы 2 AA батареясында шамамен бір жыл жұмыс істейді. Сондықтан, тіпті қол сағаттары, әрине, қабырға сағаттары немесе көше станцияларының сағаттары туралы айтпағанда, радио синхрондауымен жасалады.
DCF ыңғайлылығы мен қарапайымдылығы да DIY энтузиастарын тартады. Бар болғаны 10-20 долларға сіз Arduino немесе басқа контроллерге қосылуға болатын дайын қабылдағыш пен TTL шығысы бар дайын антенна модулін сатып ала аласыз.
Arduino үшін қазірдің өзінде жазылған
Қалаушылар тіпті радио синхронизациясы бар жаңа механизмді орнату арқылы ескі әжесінің сағатын жаңарта алады:
Сіз оны ebay сайтында «Радиомен басқарылатын қозғалыс» кілт сөздерін пайдаланып таба аласыз.
Ақырында, осы уақытқа дейін оқығандар үшін лайфхак. Тіпті келесі екі мың шақырымда бір радио сигнал таратқышы болмаса да, мұндай сигналды өзіңіз жасау қиын емес. Google Play-де құлаққапқа сигнал беретін «DCF77 эмуляторы» атты бағдарлама бар. Автордың айтуынша, құлаққаптың сымын сағаттың айналасына орап алсаңыз, олар сигналды қабылдайды (қызық, өйткені қарапайым құлаққаптар 77 кГц сигнал шығармайды, бірақ қабылдау гармоникаға байланысты болуы мүмкін). Android 9-де бағдарлама мен үшін мүлдем жұмыс істемеді - дыбыс жоқ (немесе мен оны естімедім - бұл 77 кГц, ақыр соңында :)), бірақ біреудің сәттілікке жетуі мүмкін. Алайда кейбіреулер өздерін бірдей Arduino немесе ESP32-де оңай жасауға болатын толыққанды DCF сигнал генераторын жасайды:
(дереккөз
қорытынды
DCF жүйесі өте қарапайым және ыңғайлы болып шықты. Қарапайым және арзан қабылдағыштың көмегімен сіз әрқашан және барлық жерде, әрине, қабылдау бөлімінде нақты уақытты ала аласыз. Кең таралған цифрландыру мен заттар интернетіне қарамастан, мұндай қарапайым шешімдер ұзақ уақыт бойы сұранысқа ие болатын сияқты.
Ақпарат көзі: www.habr.com