Γεια σου Χαμπρ.
Πιθανώς πολλοί που αγοράζουν ένα ρολόι ή μετεωρολογικό σταθμό έχουν δει το λογότυπο με ραδιοελεγχόμενο ρολόι ή ακόμα και το λογότυπο Atomic Clock στη συσκευασία. Αυτό είναι πολύ βολικό, γιατί απλά πρέπει να βάλετε το ρολόι στο τραπέζι και μετά από λίγο θα προσαρμοστεί αυτόματα στην ακριβή ώρα.
Ας καταλάβουμε πώς λειτουργεί και ας γράψουμε έναν αποκωδικοποιητή στην Python.
Υπάρχουν διαφορετικά συστήματα συγχρονισμού χρόνου. Το πιο δημοφιλές στην Ευρώπη είναι το γερμανικό σύστημα
Όλα όσα γράφονται παρακάτω θα αφορούν το DCF77.
Λήψη σήματος
Ο DCF77 είναι ένας σταθμός μεγάλων κυμάτων που λειτουργεί σε συχνότητα 77.5 kHz και εκπέμπει σήματα σε διαμόρφωση πλάτους. Ο σταθμός 50 KW βρίσκεται 25 χλμ. από τη Φρανκφούρτη, ξεκίνησε τη λειτουργία του το 1959 και το 1973 προστέθηκαν πληροφορίες ημερομηνίας στην ακριβή ώρα. Το μήκος κύματος σε συχνότητα 77 KHz είναι πολύ μεγάλο, επομένως οι διαστάσεις του πεδίου της κεραίας είναι επίσης αρκετά αξιοπρεπείς (φωτογραφία από τη Wikipedia):
Με μια τέτοια είσοδο κεραίας και ισχύος, ο χώρος λήψης καλύπτει σχεδόν όλη την Ευρώπη, τη Λευκορωσία, την Ουκρανία και μέρος της Ρωσίας.
Οποιοσδήποτε μπορεί να ηχογραφήσει ένα σήμα. Για να το κάνετε αυτό, απλώς μεταβείτε στον διαδικτυακό δέκτη
Εκεί πατάμε το κουμπί λήψης και καταγράφουμε ένα κομμάτι πολλών λεπτών. Φυσικά, εάν έχετε έναν «πραγματικό» δέκτη ικανό να καταγράφει τη συχνότητα των 77.5 KHz, μπορείτε να τον χρησιμοποιήσετε.
Φυσικά, με τη λήψη σημάτων ώρας ραδιοφώνου μέσω του Διαδικτύου, δεν θα λάβουμε πραγματικά ακριβή χρόνο - το σήμα μεταδίδεται με καθυστέρηση. Αλλά ο στόχος μας είναι μόνο να κατανοήσουμε τη δομή του σήματος· γι' αυτό, η εγγραφή στο Διαδίκτυο είναι υπεραρκετή. Στην πραγματική ζωή, φυσικά, χρησιμοποιούνται εξειδικευμένες συσκευές για τη λήψη και την αποκωδικοποίηση· θα συζητηθούν παρακάτω.
Λοιπόν, λάβαμε την ηχογράφηση, ας ξεκινήσουμε την επεξεργασία της.
Αποκωδικοποίηση σήματος
Ας φορτώσουμε το αρχείο χρησιμοποιώντας 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()
Βλέπουμε τυπική διαμόρφωση πλάτους:
Για να απλοποιήσουμε την αποκωδικοποίηση, ας πάρουμε το φάκελο του σήματος χρησιμοποιώντας τον μετασχηματισμό Hilbert:
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
Αποτέλεσμα (κίτρινη γραμμή): ένα σχεδόν τετράγωνο σήμα κύματος που είναι αρκετά εύκολο να αναλυθεί.
Πάρσινγκ
Πρώτα πρέπει να λάβετε την ακολουθία bit. Η ίδια η δομή του σήματος είναι πολύ απλή.
Οι παλμοί χωρίζονται σε δεύτερα διαστήματα. Εάν η απόσταση μεταξύ των παλμών είναι 0.1 δευτ. (δηλαδή το μήκος του ίδιου του παλμού είναι 0.9 δευτ.), προσθέστε "0" στην ακολουθία δυαδικών ψηφίων· εάν η απόσταση είναι 0.2 δευτ. (δηλαδή το μήκος είναι 0.8 δευτ.), προσθέστε "1". Το τέλος κάθε λεπτού υποδεικνύεται με έναν «μακρύ» παλμό, διάρκειας 2 δευτερολέπτων, η ακολουθία bit μηδενίζεται και η πλήρωση ξεκινά ξανά.
Τα παραπάνω είναι εύκολο να γραφτούν σε 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
Ως αποτέλεσμα, παίρνουμε μια ακολουθία bit, στο παράδειγμά μας για δύο δευτερόλεπτα μοιάζει με αυτό:
0011110110111000001011000001010000100110010101100010011000
0001111100110110001010100001010000100110010101100010011000
Παρεμπιπτόντως, είναι ενδιαφέρον ότι το σήμα έχει επίσης ένα "δεύτερο επίπεδο" δεδομένων. Η ακολουθία bit κωδικοποιείται επίσης χρησιμοποιώντας
Το τελευταίο μας βήμα: λήψη των πραγματικών δεδομένων. Τα bit μεταδίδονται μία φορά το δευτερόλεπτο, επομένως έχουμε συνολικά 59 bit, στα οποία κωδικοποιούνται πολλές πληροφορίες:
Τα bit περιγράφονται στο
Για όσους θέλουν να πειραματιστούν μόνοι τους, ο κωδικός αποκωδικοποίησης δίνεται κάτω από το spoiler.
Κωδικός πηγής
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 bit και στο τέλος κάθε λεπτού παίρνουμε τον ακριβή χρόνο. Σε σύγκριση με άλλες μεθόδους συγχρονισμού χρόνου (GPS, για παράδειγμα, ή Θεός φυλάξοι, το Διαδίκτυο:), αυτός ο συγχρονισμός ραδιοφώνου δεν απαιτεί σχεδόν καθόλου ηλεκτρισμό - για παράδειγμα, ένας κανονικός μετεωρολογικός σταθμός στο σπίτι λειτουργεί για περίπου ένα χρόνο με 2 μπαταρίες AA. Επομένως, ακόμη και τα ρολόγια χειρός κατασκευάζονται με συγχρονισμό ραδιοφώνου, για να μην αναφέρουμε, φυσικά, τα ρολόγια τοίχου ή τα ρολόγια σταθμών δρόμου.
Η ευκολία και η απλότητα του DCF προσελκύει επίσης τους λάτρεις των DIY. Με μόλις 10-20 $ μπορείτε να αγοράσετε μια έτοιμη μονάδα κεραίας με έτοιμο δέκτη και έξοδο TTL, η οποία μπορεί να συνδεθεί σε ένα Arduino ή άλλο ελεγκτή.
Έχει ήδη γραφτεί για το Arduino
Όσοι επιθυμούν μπορούν ακόμη και να αναβαθμίσουν το ρολόι της παλιάς γιαγιάς τους εγκαθιστώντας έναν νέο μηχανισμό με ραδιοσυγχρονισμό:
Μπορείτε να βρείτε ένα στο ebay χρησιμοποιώντας τις λέξεις-κλειδιά "Radio Controlled Movement".
Και τέλος, ένα life hack για όσους έχουν διαβάσει ως εδώ. Ακόμα κι αν δεν υπάρχει ούτε ένας πομπός ραδιοφωνικού σήματος στα επόμενα δύο χιλιάδες χιλιόμετρα, δεν είναι δύσκολο να δημιουργήσετε μόνοι σας ένα τέτοιο σήμα. Υπάρχει ένα πρόγραμμα στο Google Play που ονομάζεται "DCF77 Emulator" που εξάγει το σήμα στα ακουστικά. Σύμφωνα με τον συγγραφέα, αν τυλίξετε το καλώδιο των ακουστικών γύρω από το ρολόι, θα πάρουν το σήμα (είναι ενδιαφέρον πώς, γιατί τα συνηθισμένα ακουστικά δεν θα παράγουν σήμα 77KHz, αλλά η λήψη οφείλεται πιθανώς σε αρμονικές). Στο Android 9, το πρόγραμμα δεν λειτούργησε καθόλου για μένα - απλά δεν υπήρχε ήχος (ή ίσως δεν τον άκουσα - είναι 77KHz, τελικά :), αλλά ίσως κάποιος θα έχει καλύτερη τύχη. Ορισμένοι, ωστόσο, κάνουν τον εαυτό τους μια πλήρη γεννήτρια σήματος DCF, η οποία είναι εύκολο να κατασκευαστεί στο ίδιο Arduino ή ESP32:
(πηγή
Συμπέρασμα
Το σύστημα DCF αποδείχθηκε πολύ απλό και βολικό. Με τη βοήθεια ενός απλού και φθηνού δέκτη, μπορείτε να έχετε την ακριβή ώρα πάντα και παντού, φυσικά στον χώρο της ρεσεψιόν. Φαίνεται ότι ακόμη και παρά την εκτεταμένη ψηφιοποίηση και το Διαδίκτυο των Πραγμάτων, τέτοιες απλές λύσεις θα είναι περιζήτητες για πολύ καιρό.
Πηγή: www.habr.com