Je vais deviner et dire que tous ceux dont les amis ou la famille ont déjà pris l'avion ont utilisé Flightradar24 - un service gratuit et pratique pour suivre les vols en temps réel.

Dans la
première partie, les idées de fonctionnement de base ont été décrites. Allons maintenant plus loin et découvrons quelles données transmettent et reçoivent exactement entre l'avion et une station au sol. Nous allons également décoder ces données en utilisant Python.
L'histoire
Il devrait être évident que les données des avions ne sont pas destinées uniquement aux utilisateurs, qui souhaitent les voir sur leurs smartphones. Ce système est appelé ADS-B (surveillance dépendante automatique - diffusion) et a été conçu pour la transmission automatique des données d'informations de l'avion au centre de contrôle - différents paramètres, tels que les coordonnées, la vitesse, le cap, l'altitude et d'autres, sont envoyés. Auparavant, le répartiteur ne pouvait voir qu'un point sur l'écran radar. Et cela est devenu définitivement insuffisant lorsque le nombre d'avions a considérablement augmenté.
Techniquement, l'ADS-B se compose d'un émetteur à l'intérieur de l'avion, qui envoie périodiquement des trames de données d'information à une fréquence relativement élevée de 1090 MHz (il existe d'autres modes, mais ils ne nous intéressent pas tellement, car les coordonnées ne sont transmises qu'ici) ) Bien sûr, il y a aussi un récepteur quelque part à l'aéroport, mais pour nous, comme pour les utilisateurs, notre propre récepteur est plus intéressant.
À titre de comparaison, le premier système de ce type conçu pour les utilisateurs ordinaires, l'Airnav Radarbox, est apparu en 2007 et coûte environ 900 $, et environ 250 $ par an coûte un abonnement à leurs services réseau (l'idée principale de ce système est de collecter et partager les données de
nombreux récepteurs , un récepteur autonome est relativement inutile).

Maintenant, lorsque les récepteurs RTL-SDR sont devenus beaucoup plus disponibles, un appareil similaire peut être fabriqué pour 30 $. Il se trouve dans la
première partie de l'article , et nous irons plus loin et décrirons le protocole lui-même - voyons comment cela fonctionne.
Recevoir un signal
Tout d'abord, nous devons enregistrer un échantillon de signal. L'ensemble du signal n'a qu'une longueur de 120 microsecondes, et pour voir ses détails dans une bonne "résolution", il est préférable d'avoir une radio SDR avec une fréquence d'échantillonnage d'au moins 5 MHz.

Après l'enregistrement, nous obtenons un fichier WAV avec un taux d'échantillonnage de 5 000 000 d'échantillons / s, 30 secondes d'un tel enregistrement ont une taille d'environ 500 Mo. Bien sûr, il est inutile de l'écouter avec votre lecteur multimédia préféré - le fichier ne contient pas de son, mais un signal radio directement numérisé lui-même - c'est exactement ainsi que fonctionne la radio définie par logiciel.
Nous pouvons ouvrir et traiter ce fichier avec Python. Ceux qui souhaitent faire l'expérience par eux-mêmes peuvent télécharger un échantillon à partir de
ce lien .
Permet d'ouvrir un fichier et de voir ce qu'il contient.
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()
Résultat: on voit des «impulsions» sur le bruit.

Chaque "impulsion" est un signal, dont la structure est clairement visible si l'on augmente la résolution sur le graphique.

Comme nous pouvons le voir, l'image est entièrement cohérente avec sa description ci-dessus. Nous pouvons maintenant traiter ces données.
Décodage
Tout d'abord, nous devons avoir un flux de bits. Le signal lui-même est codé avec un codage manchester:

Grâce aux différences de demi-bouchée, nous pouvons facilement obtenir de vrais «0» et «1».
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"
La structure du signal lui-même ressemble à ceci:

Permet de voir les champs plus en détail.
DF (Downlink Format, 5 bits) - définit le type de message. Il en existe plusieurs types:

(
source de la page )
Nous ne sommes intéressés que par le type DF17, car seul celui-ci contient les coordonnées de l'avion.
OACI (24 bits) - est un code d'avion international unique. Nous pouvons vérifier l'avion par son code
sur ce site (malheureusement, l'auteur a cessé de mettre à jour la base de données, mais elle est toujours pertinente). Par exemple, pour le code 3c5ee2, nous pouvons avoir les informations suivantes:
DONNÉES (56 ou 112 bits) - sont les données elles-mêmes, que nous allons décoder. Les 5 premiers bits de données sont le champ
Code de type , qui contient le sous-type des données stockées (à ne pas mélanger avec le champ
DF ). Il existe de nombreux types de ce type:

(
source du tableau )
Regardons quelques exemples.
Identification de l'aéronefUn exemple sous forme binaire:
00100 011 000101 010111 000111 110111 110001 111000
Champs de données:
+------+------+------+------+------+------+------+------+------+------+ | TC,5 | EC,3 | C1,6 | C2,6 | C3,6 | C4,6 | C5,6 | C6,6 | C7,6 | C8,6 | +------+------+------+------+------+------+------+------+------+------+
TC = 00100b = 4, et chaque symbole C1-C8 contient des codes, qui doivent correspondre aux index de cette chaîne:
#ABCDEFGHIJKLMNOPQRSTUVWXYZ ##### _ ################# 0123456789 ######
Après avoir décodé, il est facile d'obtenir le nom de l'avion: 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('#', ''))
Position aéroportéeLe décodage du nom était simple, mais les coordonnées sont plus compliquées. Ils sont transmis sous forme de 2 trames, paires et impaires. Le code de champ TC = 01011b = 11.

Exemple de trames de données paires et impaires:
01011 000 000101110110 00 10111000111001000 10000110101111001 01011 000 000110010000 01 10010011110000110 10000011110001000
Le calcul des coordonnées lui-même utilise une formule un peu délicate:

(
source )
Je ne suis pas un expert en SIG, donc je ne sais pas d'où il vient. Qui le sait mieux, veuillez écrire dans les commentaires.
Le calcul de l'altitude est plus simple - en fonction d'un bit spécifique, il peut être représenté comme un multiple de 25 ou 100 pieds.
Vitesse aéroportéeDataframe avec TC = 19. Ce qui est intéressant ici, c'est que la vitesse peut être relative au sol (plus précise, appelée Ground Speed) et à la vitesse, mesurée par le capteur d'air de l'avion (peut être moins précise à cause du vent). De nombreux autres domaines différents sont également transmis:

(
source )
Conclusion
Comme nous pouvons le voir, la technologie ADS-B est devenue une symbiose intéressante, lorsqu'un standard est largement utilisable non seulement pour les professionnels, mais aussi pour les utilisateurs ordinaires. Mais définitivement, le rôle clé dans cela a été fait par la réduction du coût de la technologie des récepteurs SDR numériques, qui permet de recevoir des signaux avec une fréquence supérieure à gigahertz sur un appareil très bon marché.
La norme elle-même, bien sûr, contient beaucoup plus de données. Les personnes intéressées peuvent consulter le PDF sur la page
OACI ou visiter le
site Web mode-s.org déjà mentionné ci-dessus. Il est peu probable que cet article soit réellement utilisé par la plupart des lecteurs, mais j'espère qu'au moins l'idée générale de son fonctionnement est désormais plus claire.
Par ailleurs, le décodeur ADS-B Python existe déjà, il peut être étudié
sur le github . Les propriétaires de récepteurs SDR peuvent également créer et exécuter un décodeur ADS-B prêt à l'emploi à
partir de cette page , et (je le répète) quelques détails que nous avons également dans
la première partie de cet article.
Le code source de l'analyseur, décrit ci-dessus, est donné sous le spoiler. Ce n'est qu'un exemple de test qui ne prétend pas à la qualité de la production, mais en général cela fonctionne, et il peut analyser le
fichier WAV , enregistré ci-dessus.
Code source (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
J'espère que cela a été utile, merci d'avoir lu.