Ich werde raten und sagen, dass jeder, dessen Freunde oder Familie jemals in einem Flugzeug geflogen sind, Flightradar24 verwendet hat - einen kostenlosen und bequemen Service zur Verfolgung von Flügen in Echtzeit.

Im
ersten Teil wurden die Grundideen des Betriebs beschrieben. Lassen Sie uns nun weiter gehen und herausfinden, welche Daten genau zwischen dem Flugzeug und einer Bodenstation senden und empfangen. Wir werden diese Daten auch mit Python dekodieren.
Geschichte
Es sollte offensichtlich sein, dass Flugzeugdaten nicht nur für Benutzer bestimmt sind, die sie auf ihren Smartphones sehen möchten. Dieses System heißt ADS-B (Automatic Dependent Monitoring - Broadcast) und wurde für die automatische Übertragung der Flugzeuginformationsdaten an die Zentrale entwickelt. Verschiedene Parameter wie Koordinaten, Geschwindigkeit, Kurs, Höhe und andere werden gesendet. Bisher konnte der Dispatcher nur einen Punkt auf dem Radarbildschirm sehen. Und es wurde definitiv nicht genug, als die Anzahl der Flugzeuge drastisch zunahm.
Technisch gesehen besteht ADS-B aus einem Sender im Flugzeug, der regelmäßig Informationsdatenrahmen mit einer relativ hohen Frequenz von 1090 MHz sendet (es gibt einige andere Modi, die für uns jedoch nicht so interessant sind, da die Koordinaten nur hier übertragen werden ) Natürlich gibt es auch irgendwo am Flughafen einen Empfänger, aber für uns wie für Benutzer ist unser eigener Empfänger interessanter.
Nur zum Vergleich: Das erste derartige System, das für normale Benutzer entwickelt wurde, die Airnav Radarbox, erschien 2007 und kostete etwa 900 US-Dollar, und etwa 250 US-Dollar pro Jahr kosteten ein Abonnement für ihre Netzwerkdienste (die Hauptidee dieses Systems ist das Sammeln und Daten von
vielen Empfängern teilen, ein Standalone-Empfänger ist relativ nutzlos).

Wenn RTL-SDR-Empfänger jetzt viel verfügbarer sind, kann ein ähnliches Gerät für 30 US-Dollar hergestellt werden. Es ist im
ersten Teil des Artikels zu finden , und wir werden weiter gehen und das Protokoll selbst beschreiben - mal sehen, wie es funktioniert.
Ein Signal empfangen
Zuerst müssen wir eine Signalprobe aufnehmen. Das gesamte Signal hat nur eine Länge von 120 Mikrosekunden. Um seine Details in einer guten "Auflösung" zu sehen, ist es besser, SDR-Radio mit einer Abtastrate von mindestens 5 MHz zu haben.

Nach der Aufnahme erhalten wir eine WAV-Datei mit einer Abtastrate von 5.000.000 Abtastungen / s. 30 Sekunden einer solchen Aufnahme haben eine Größe von etwa 500 MB. Natürlich ist es sinnlos, es mit Ihrem Lieblings-Mediaplayer anzuhören - die Datei enthält keinen Ton, sondern ein direkt digitalisiertes Funksignal selbst - genau so funktioniert Software Defined Radio.
Wir können diese Datei mit Python öffnen und verarbeiten. Wer das Experiment alleine durchführen möchte, kann unter
diesem Link ein Beispiel herunterladen.
Öffnen wir eine Datei und sehen, was sich darin befindet.
from scipy.io import wavfile import matplotlib.pyplot as plt import numpy as np fs, data = wavfile.read("adsb_20190311_191728Z_1090000kHz_RF.wav") data = data.astype(float) I, Q = data[:, 0], data[:, 1] A = np.sqrt(I*I + Q*Q) plt.plot(A) plt.show()
Ergebnis: Wir sehen einige "Impulse" über das Rauschen.

Jeder "Impuls" ist ein Signal, dessen Struktur deutlich sichtbar ist, wenn wir die Auflösung im Diagramm erhöhen.

Wie wir sehen können, stimmt das Bild vollständig mit der obigen Beschreibung überein. Wir können diese Daten jetzt verarbeiten.
Dekodierung
Zuerst müssen wir ein bisschen Stream haben. Das Signal selbst wird mit einer Manchester-Codierung codiert:

Aus den Halbbissunterschieden können wir leicht echte "0" und "1" erhalten.
bits_str = "" for p in range(8): pos = start_data + bit_len*p p1, p2 = A[pos: pos + bit_len/2], A[pos + bit_len/2: pos + bit_len] avg1, avg2 = np.average(p1), np.average(p2) if avg1 < avg2: bits_str += "0" elif avg1 > avg2: bits_str += "1"
Die Struktur des Signals selbst sieht folgendermaßen aus:

Sehen wir uns die Felder genauer an.
DF (Downlink Format, 5 Bit) - Definiert den Nachrichtentyp. Es gibt verschiedene Arten von ihnen:

(
Seitenquelle )
Wir interessieren uns nur für den Typ DF17, da nur dieser die Flugzeugkoordinaten enthält.
ICAO (24 Bit) - ist ein einzigartiger internationaler Flugzeugcode. Wir können das Flugzeug anhand seines Codes
auf dieser Website überprüfen (leider hat der Autor die Aktualisierung der Datenbank eingestellt, sie ist jedoch weiterhin relevant). Für den 3c5ee2-Code können wir beispielsweise die folgenden Informationen haben:
DATA (56 oder 112 Bit) - sind die Daten selbst, die wir dekodieren werden. Die ersten 5 Datenbits sind das Feld
Typcode , das den Subtyp der gespeicherten Daten enthält (nicht mit dem
DF- Feld zu mischen). Es gibt viele solcher Typen:

(
Tabellenquelle )
Schauen wir uns einige Beispiele an.
FlugzeugidentifikationEin Beispiel in binärer Form:
00100 011 000101 010111 000111 110111 110001 111000
Datenfelder:
+------+------+------+------+------+------+------+------+------+------+ | TC,5 | EC,3 | C1,6 | C2,6 | C3,6 | C4,6 | C5,6 | C6,6 | C7,6 | C8,6 | +------+------+------+------+------+------+------+------+------+------+
TC = 00100b = 4, und jedes Symbol C1-C8 enthält Codes, die mit den Indizes in dieser Zeichenfolge übereinstimmen sollten:
#ABCDEFGHIJKLMNOPQRSTUVWXYZ ##### _ ################# 0123456789 ######
Nach dem Entschlüsseln ist es einfach, den Flugzeugnamen zu erhalten: EWG7184
symbols = "#ABCDEFGHIJKLMNOPQRSTUVWXYZ#####_###############0123456789######" code_str = "" for p in range(8): c = int(bits_str[8 + 6*p:8 + 6*(p + 1)], 2) code_str += symbols[c] print("Aircraft Identification:", code_str.replace('#', ''))
LuftpositionDie Namensdecodierung war einfach, aber die Koordinaten sind komplizierter. Sie werden in Form von 2 geraden und ungeraden Frames übertragen. Der Feldcode TC = 01011b = 11.

Beispiel für gerade und ungerade Datenrahmen:
01011 000 000101110110 00 10111000111001000 10000110101111001 01011 000 000110010000 01 10010011110000110 10000011110001000
Die Berechnung der Koordinaten selbst verwendet eine etwas knifflige Formel:

(
Quelle )
Ich bin kein GIS-Experte, daher weiß ich nicht, woher es kommt. Wer weiß es besser, bitte in Kommentare schreiben.
Die Höhenberechnung ist einfacher - abhängig von einem bestimmten Bit kann sie entweder als Vielfaches von 25 oder 100 Fuß dargestellt werden.
LuftgeschwindigkeitDatenrahmen mit TC = 19. Das Interessante dabei ist, dass die Geschwindigkeit relativ zum Boden (genauer, Bodengeschwindigkeit genannt) und die vom Flugzeugluftsensor gemessene Fluggeschwindigkeit (aufgrund des Windes weniger genau) sein kann. Viele andere verschiedene Felder werden ebenfalls übertragen:

(
Quelle )
Fazit
Wie wir sehen können, ist die ADS-B-Technologie zu einer interessanten Symbiose geworden, wenn ein Standard nicht nur für Profis, sondern auch für normale Benutzer weit verbreitet ist. Die Schlüsselrolle dabei spielte jedoch definitiv die Verbilligung der digitalen SDR-Empfängertechnologie, mit der Signale mit einer Frequenz von mehr als Gigahertz auf einem sehr billigen Gerät empfangen werden können.
Der Standard selbst enthält natürlich viel mehr Daten. Interessenten können das PDF auf der Seite
ICAO einsehen oder die
oben bereits erwähnte
Website mode-s.org besuchen. Es ist unwahrscheinlich, dass dieser Artikel von den meisten Lesern wirklich verwendet wird, aber ich hoffe, dass zumindest die allgemeine Vorstellung davon, wie er funktioniert, jetzt klarer ist.
Übrigens existiert der ADS-B Python-Decoder bereits, er kann
auf dem Github untersucht werden . Besitzer von SDR-Empfängern können auf
dieser Seite auch gebrauchsfertige ADS-B-Decoder erstellen und ausführen. (Ich werde es noch einmal wiederholen) einige Details finden Sie auch im
ersten Teil dieses Artikels.
Der oben beschriebene Parser-Quellcode wird unter dem Spoiler angegeben. Dies ist nur ein Testbeispiel, das nicht die Produktionsqualität vorgibt, aber im Allgemeinen funktioniert und die oben aufgezeichnete
WAV-Datei analysieren kann.
Quellcode (Python) from __future__ import print_function from scipy.io import wavfile from scipy import signal import matplotlib.pyplot as plt import numpy as np import math import sys def parse_message(data, start, bit_len): max_len = bit_len*128 A = data[start:start + max_len] A = signal.resample(A, 10*max_len) bits = np.zeros(10*max_len) bit_len *= 10 start_data = bit_len*8
Ich hoffe es war nützlich, danke fürs Lesen.