Voy a adivinar y decir que todas las personas cuyos amigos o familiares han volado en un avión, han usado Flightradar24, un servicio gratuito y conveniente para rastrear vuelos en tiempo real.

En la
primera parte se describieron las ideas básicas de operación. Ahora vamos más allá y descubramos qué datos se transmiten y reciben exactamente entre el avión y una estación terrestre. También decodificaremos estos datos usando Python.
Historia
Debería ser obvio que los datos de los aviones no están destinados solo a los usuarios, que desean verlos en sus teléfonos inteligentes. Este sistema se llama ADS - B (vigilancia dependiente automática - transmisión), y fue diseñado para la transmisión automática de los datos de información de la aeronave al centro de control: se envían diferentes parámetros, como coordenadas, velocidad, rumbo, altitud y otros. Anteriormente, el despachador solo podía ver un punto en la pantalla del radar. Y definitivamente no fue suficiente cuando el número de aviones aumentó drásticamente.
Técnicamente, ADS-B consiste en un transmisor dentro de la aeronave, que envía periódicamente cuadros de datos de información a una frecuencia relativamente alta de 1090 MHz (hay algunos otros modos, pero no son tan interesantes para nosotros, porque las coordenadas se transmiten solo aquí ) Por supuesto, también hay un receptor en algún lugar del aeropuerto, pero para nosotros, como para los usuarios, nuestro propio receptor es más interesante.
Solo para comparar, el primer sistema diseñado para usuarios comunes, el Airnav Radarbox, apareció en 2007 y costó alrededor de $ 900, y alrededor de $ 250 por año costaba una suscripción a sus servicios de red (la idea principal de este sistema es recopilar y compartir datos de
muchos receptores , un receptor independiente es relativamente inútil).

Ahora, cuando los receptores RTL-SDR están mucho más disponibles, se puede hacer un dispositivo similar por $ 30. Se puede encontrar en la
primera parte del artículo , e iremos más allá y describiremos el protocolo en sí, veamos cómo funciona.
Recibiendo una señal
Primero, necesitamos registrar una muestra de señal. Toda la señal tiene solo 120 microsegundos de longitud, y para ver sus detalles en una buena "resolución", es mejor tener radio SDR con una frecuencia de muestreo de al menos 5 MHz.

Después de la grabación, estamos obteniendo un archivo WAV con una tasa de muestreo de 5,000,000 muestras / seg, 30 segundos de tal registro tiene un tamaño de aproximadamente 500MB. Por supuesto, es inútil escucharlo con su reproductor multimedia favorito: el archivo no contiene sonido, sino una señal de radio digitalizada directamente, así es exactamente cómo funciona la Radio definida por software.
Podemos abrir y procesar este archivo con Python. Aquellos que deseen realizar el experimento por su cuenta, pueden descargar una muestra desde
este enlace .
Vamos a abrir un archivo y ver qué hay dentro.
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()
Resultado: vemos algunos 'impulsos' sobre el ruido.

Cada "impulso" es una señal, cuya estructura es claramente visible si aumentamos la resolución en el gráfico.

Como podemos ver, la imagen es totalmente coherente con su descripción anterior. Ahora podemos procesar estos datos.
Decodificación
Primero, necesitamos tener un poco de flujo. La señal en sí está codificada con una codificación de Manchester:

De las diferencias de mordida podemos obtener fácilmente "0" y "1" reales.
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 estructura de la señal en sí se ve así:

Veamos los campos con más detalle.
DF (Formato de enlace descendente, 5 bits): define el tipo de mensaje. Hay varios tipos de ellos:

(
fuente de la página )
Solo estamos interesados en el tipo DF17, porque solo este contiene las coordenadas del avión.
OACI (24 bits): es un código internacional único de aeronave. Podemos verificar el avión por su código
en este sitio web (desafortunadamente, el autor ha dejado de actualizar la base de datos, pero aún es relevante). Por ejemplo, para el código 3c5ee2 podemos tener la siguiente información:
DATOS (56 o 112 bits): son los datos en sí, que decodificaremos. Los primeros 5 bits de datos son el campo
Código de tipo , que contiene el subtipo de los datos que se almacenan (no se mezclarán con el campo
DF ). Hay muchos tipos de este tipo:

(
fuente de la tabla )
Veamos algunos ejemplos.
Identificación de la aeronaveUn ejemplo en forma binaria:
00100 011 000101 010111 000111 110111 110001 111000
Campos de datos:
+------+------+------+------+------+------+------+------+------+------+ | TC,5 | EC,3 | C1,6 | C2,6 | C3,6 | C4,6 | C5,6 | C6,6 | C7,6 | C8,6 | +------+------+------+------+------+------+------+------+------+------+
TC = 00100b = 4, y cada símbolo C1-C8 contiene códigos que deben coincidir con los índices en esta cadena:
#ABCDEFGHIJKLMNOPQRSTUVWXYZ ##### _ ################# 0123456789 ######
Después de decodificar, es fácil obtener el nombre del avión: 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('#', ''))
Posición en el aireLa decodificación del nombre era simple, pero las coordenadas son más complicadas. Se transmiten en forma de 2 cuadros, pares e impares. El código de campo TC = 01011b = 11.

Ejemplo de marcos de datos pares e impares:
01011 000 000101110110 00 10111000111001000 10000110101111001 01011 000 000110010000 01 10010011110000110 10000011110001000
El cálculo de las coordenadas en sí usa una fórmula un poco complicada:

(
fuente )
No soy un experto en SIG, así que no sé de dónde viene. Quién lo sabe mejor, por favor escriba en los comentarios.
El cálculo de altitud es más simple: dependiendo de un bit específico, se puede representar como un múltiplo de 25 o 100 pies.
Velocidad en el aireMarco de datos con TC = 19. Lo interesante aquí es que la velocidad puede ser relativa al suelo (más precisa, llamada Velocidad de avance) y Velocidad aérea, medida por el sensor de aire de la aeronave (puede ser menos precisa debido al viento). También se transmiten muchos otros campos diferentes:

(
fuente )
Conclusión
Como podemos ver, la tecnología ADS-B se ha convertido en una simbiosis interesante, cuando un estándar es ampliamente utilizable no solo para profesionales, sino también para usuarios comunes. Pero definitivamente, el papel clave en esto fue hecho por el abaratamiento de la tecnología de los receptores digitales SDR, que permite recibir señales con una frecuencia superior a gigahercios en un dispositivo muy barato.
El estándar en sí, por supuesto, tiene muchos más datos. Los interesados pueden ver el PDF en la página de la
OACI o visitar el
sitio web mode-s.org ya mencionado anteriormente. Es poco probable que este artículo sea realmente utilizado por la mayoría de los lectores, pero espero que, al menos la idea general de cómo funciona, ahora sea más clara.
Por cierto, el decodificador Python ADS-B ya existe, puede investigarse
en el github . Los propietarios de receptores SDR también pueden construir y ejecutar un decodificador ADS-B listo para usar
desde esta página , y (repetiré de nuevo) algunos detalles que también en
la primera parte de este artículo.
El código fuente del analizador, descrito anteriormente, se proporciona bajo el spoiler. Este es solo un ejemplo de prueba que no pretende la calidad de producción, pero en general funciona, y puede analizar el
archivo WAV , registrado anteriormente.
Código fuente (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
Espero que haya sido útil, gracias por leer.