سلام حبر.
احتمالاً بسیاری از کسانی که ساعت یا ایستگاه هواشناسی میخرند، لوگوی ساعت کنترلشده رادیویی یا حتی ساعت اتمی را روی بستهبندی آن دیدهاند. این بسیار راحت است، زیرا فقط باید ساعت را روی میز بگذارید و پس از مدتی به طور خودکار با زمان دقیق تنظیم می شود.
بیایید بفهمیم که چگونه کار می کند و یک رمزگشا در پایتون بنویسیم.
سیستم های همگام سازی زمانی مختلفی وجود دارد. محبوب ترین در اروپا سیستم آلمان است
همه چیزهایی که در زیر نوشته شده در مورد DCF77 خواهد بود.
دریافت سیگنال
DCF77 یک ایستگاه موج بلند است که در فرکانس 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 بیت جمع می کنیم و در پایان هر دقیقه زمان دقیق را بدست می آوریم. در مقایسه با سایر روشهای همگامسازی زمانی (مثلاً GPS یا خدای ناکرده اینترنت :)، چنین همگامسازی رادیویی عملاً به برق نیاز ندارد - برای مثال، یک ایستگاه هواشناسی معمولی در خانه حدود یک سال با 2 باتری AA کار میکند. بنابراین، حتی ساعتهای مچی با هماهنگسازی رادیویی ساخته میشوند، البته به ساعتهای دیواری یا ساعتهای ایستگاه خیابانی اشاره نمیشود.
راحتی و سادگی DCF نیز علاقه مندان به DIY را جذب می کند. فقط با 10-20 دلار می توانید یک ماژول آنتن آماده با یک گیرنده آماده و خروجی TTL خریداری کنید که می تواند به یک آردوینو یا کنترلر دیگر متصل شود.
قبلاً برای آردوینو نوشته شده است
کسانی که مایلند حتی می توانند ساعت مادربزرگ قدیمی خود را با نصب مکانیزم جدید با همگام سازی رادیویی ارتقا دهند:
می توانید یکی از آنها را در ebay با استفاده از کلمات کلیدی "حرکت کنترل شده رادیویی" پیدا کنید.
و در نهایت یک هک زندگی برای کسانی که تا اینجا خوانده اند. حتی اگر در چند هزار کیلومتر بعدی یک فرستنده سیگنال رادیویی وجود نداشته باشد، تولید چنین سیگنالی خودتان دشوار نیست. برنامه ای در گوگل پلی به نام “DCF77 Emulator” وجود دارد که سیگنال را به هدفون ارسال می کند. به گفته نویسنده، اگر سیم هدفون را به دور ساعت بپیچید، سیگنال را دریافت می کند (جالب است که چگونه، زیرا هدفون های معمولی سیگنال 77 کیلوهرتز تولید نمی کنند، اما دریافت احتمالاً به دلیل هارمونیک است). در اندروید 9، این برنامه اصلا برای من کار نمی کرد - به سادگی هیچ صدایی وجود نداشت (یا شاید من آن را نشنیدم - بالاخره 77 کیلوهرتز است:)، اما شاید کسی شانس بیشتری داشته باشد. با این حال، برخی از آنها خود را یک ژنراتور سیگنال DCF کامل میسازند که ساخت آن در همان آردوینو یا ESP32 آسان است:
(منبع
نتیجه
معلوم شد که سیستم DCF بسیار ساده و راحت است. با کمک یک گیرنده ساده و ارزان می توانید زمان دقیق را همیشه و همه جا، البته در قسمت پذیرش داشته باشید. به نظر می رسد حتی با وجود دیجیتالی شدن گسترده و اینترنت اشیا، چنین راه حل های ساده ای برای مدت طولانی مورد تقاضا خواهد بود.
منبع: www.habr.com