สวัสดีฮับ
หลายๆ คนที่ซื้อนาฬิกาหรือสถานีตรวจอากาศอาจเคยเห็นนาฬิกาควบคุมด้วยวิทยุ หรือแม้แต่โลโก้นาฬิกาอะตอมบนบรรจุภัณฑ์ สะดวกมากเพราะคุณเพียงแค่ต้องวางนาฬิกาไว้บนโต๊ะแล้วหลังจากนั้นไม่นานนาฬิกาก็จะปรับตามเวลาที่แน่นอนโดยอัตโนมัติ
เรามาดูกันว่ามันทำงานอย่างไรและเขียนตัวถอดรหัสใน Python
มีระบบการซิงโครไนซ์เวลาที่แตกต่างกัน ที่ได้รับความนิยมมากที่สุดในยุโรปคือระบบเยอรมัน
ทุกอย่างที่เขียนด้านล่างนี้จะเกี่ยวกับ DCF77
การรับสัญญาณ
DCF77 เป็นสถานีคลื่นยาวที่ทำงานที่ความถี่ 77.5 kHz และส่งสัญญาณในรูปแบบมอดูเลตแอมพลิจูด สถานี 50KW ตั้งอยู่ห่างจากแฟรงก์เฟิร์ต 25 กม. เริ่มดำเนินการในปี 1959 และในปี 1973 มีการเพิ่มข้อมูลวันที่ลงในเวลาที่แน่นอน ความยาวคลื่นที่ความถี่ 77 KHz นั้นยาวมาก ดังนั้นขนาดของสนามเสาอากาศจึงค่อนข้างดีเช่นกัน (ภาพถ่ายจาก Wikipedia):
ด้วยเสาอากาศและกำลังไฟฟ้าเข้า บริเวณแผนกต้อนรับจึงครอบคลุมเกือบทั้งหมดของยุโรป เบลารุส ยูเครน และส่วนหนึ่งของรัสเซีย
ใครๆ ก็สามารถบันทึกสัญญาณได้ ในการดำเนินการนี้เพียงไปที่ผู้รับออนไลน์
ที่นั่นเรากดปุ่มดาวน์โหลดและบันทึกส่วนความยาวหลายนาที แน่นอน หากคุณมีเครื่องรับ "ของจริง" ที่สามารถบันทึกความถี่ 77.5KHz ได้ คุณก็สามารถใช้เครื่องรับนั้นได้
แน่นอนว่าการรับสัญญาณเวลาวิทยุผ่านอินเทอร์เน็ตเราจะไม่ได้รับเวลาที่แม่นยำอย่างแท้จริง - สัญญาณจะถูกส่งด้วยความล่าช้า แต่เป้าหมายของเราคือการเข้าใจโครงสร้างของสัญญาณเท่านั้น ด้วยเหตุนี้ การบันทึกทางอินเทอร์เน็ตจึงเกินพอ แน่นอนว่าในชีวิตจริง มีการใช้อุปกรณ์พิเศษในการรับและถอดรหัส ซึ่งจะกล่าวถึงด้านล่าง
เราได้รับการบันทึกแล้ว มาเริ่มประมวลผลกันดีกว่า
การถอดรหัสสัญญาณ
มาโหลดไฟล์โดยใช้ 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 หรือ God Forbid อินเทอร์เน็ต :) การซิงโครไนซ์วิทยุดังกล่าวไม่จำเป็นต้องใช้ไฟฟ้าเลย - ตัวอย่างเช่น สถานีตรวจอากาศในบ้านทั่วไปใช้งานได้ประมาณหนึ่งปีโดยใช้แบตเตอรี่ AA 2 ก้อน ดังนั้นแม้แต่นาฬิกาข้อมือก็ยังทำด้วยการซิงโครไนซ์ด้วยวิทยุ แน่นอนว่าไม่ต้องพูดถึงนาฬิกาติดผนังหรือนาฬิกาตามสถานีตามท้องถนน
ความสะดวกสบายและความเรียบง่ายของ DCF ยังดึงดูดผู้ที่ชื่นชอบการ DIY อีกด้วย คุณสามารถซื้อโมดูลเสาอากาศสำเร็จรูปพร้อมตัวรับสัญญาณสำเร็จรูปและเอาต์พุต TTL ในราคาเพียง 10-20 ดอลลาร์ ซึ่งสามารถเชื่อมต่อกับ Arduino หรือตัวควบคุมอื่น ๆ ได้
เขียนแล้วสำหรับ Arduino
ผู้ที่ต้องการสามารถอัพเกรดนาฬิกาของคุณยายเก่าได้โดยติดตั้งกลไกใหม่พร้อมการซิงโครไนซ์วิทยุ:
คุณสามารถค้นหาได้บน eBay โดยใช้คำหลัก "Radio Controlled Movement"
และสุดท้าย แฮ็คชีวิตสำหรับผู้ที่อ่านมาจนถึงตอนนี้ แม้ว่าจะไม่มีเครื่องส่งสัญญาณวิทยุเครื่องเดียวในอีกสองสามพันกิโลเมตรข้างหน้า แต่ก็ไม่ใช่เรื่องยากที่จะสร้างสัญญาณดังกล่าวด้วยตัวเอง มีโปรแกรมบน Google Play ชื่อ “DCF77 Emulator” ที่จะส่งสัญญาณเอาท์พุตไปยังหูฟัง ตามที่ผู้เขียนกล่าวไว้ หากคุณพันสายหูฟังไว้รอบนาฬิกา พวกเขาจะรับสัญญาณได้ (น่าสนใจว่าทำอย่างไร เพราะหูฟังธรรมดาจะไม่สร้างสัญญาณ 77KHz แต่การรับสัญญาณอาจเนื่องมาจากฮาร์โมนิกส์) บน Android 9 โปรแกรมใช้งานไม่ได้สำหรับฉันเลย - ไม่มีเสียงเลย (หรือบางทีฉันไม่ได้ยินเลย - มันคือ 77KHz เลย :) แต่อาจมีบางคนโชคดีกว่า อย่างไรก็ตาม บางตัวทำให้ตัวเองกลายเป็นเครื่องกำเนิดสัญญาณ DCF เต็มรูปแบบซึ่งสร้างได้ง่ายบน Arduino หรือ ESP32 เดียวกัน:
(ที่มา
ข้อสรุป
ระบบ DCF กลายเป็นระบบที่ค่อนข้างง่ายและสะดวกจริงๆ ด้วยความช่วยเหลือของเครื่องรับที่เรียบง่ายและราคาถูก คุณสามารถมีเวลาที่แน่นอนทุกที่ทุกเวลาในบริเวณแผนกต้อนรับส่วนหน้า ดูเหมือนว่าแม้จะมีการเปลี่ยนแปลงทางดิจิทัลอย่างกว้างขวางและ Internet of Things แต่โซลูชันง่ายๆ ดังกล่าวยังคงเป็นที่ต้องการมาเป็นเวลานาน
ที่มา: will.com