Hola habr Probablemente, todos los que alguna vez conocieron o acompañaron a familiares o amigos en un avión utilizaron el servicio gratuito Flightradar24. Esta es una forma muy conveniente de rastrear la posición de la aeronave en tiempo real.

La
primera parte describe el principio de funcionamiento de dicho servicio en línea. Ahora iremos más allá, y descubriremos qué datos se transmiten y reciben del avión a la estación receptora, y los decodificamos independientemente usando Python.
La historia
Obviamente, los datos sobre el avión no se transmiten para que los usuarios puedan verlos en sus teléfonos inteligentes. El sistema se denomina ADS - B (vigilancia dependiente automática - transmisión), y se utiliza para transmitir automáticamente información de la aeronave a un centro de control: se transmiten su identificador, coordenadas, dirección, velocidad, altitud y otros datos. Anteriormente, antes del advenimiento de tales sistemas, el despachador solo podía ver un punto en el radar. Esto no fue suficiente cuando había demasiados aviones.
Técnicamente, ADS-B consiste en un transmisor en una aeronave que envía periódicamente paquetes con información a una frecuencia bastante alta de 1090 MHz (hay otros modos, pero no son tan interesantes para nosotros, porque las coordenadas se transmiten solo aquí). Por supuesto, además del transmisor, también hay un receptor en algún lugar del aeropuerto, pero para nosotros, como para los usuarios, nuestro propio receptor es interesante.
Por cierto, en comparación, el primer sistema de este tipo, Airnav Radarbox, diseñado para usuarios comunes, apareció en 2007 y costó alrededor de $ 900, alrededor de $ 250 al año valía una suscripción a los servicios de red.

Puedes leer los comentarios de esos primeros propietarios rusos en el foro de
radioscanner . Ahora que los receptores RTL-SDR se han vuelto ampliamente disponibles, se puede ensamblar un dispositivo similar por $ 30, más sobre esto en la
primera parte . Procederemos al protocolo en sí, veamos cómo funciona.
Recepción de señales
Para comenzar, la señal necesita ser grabada. Toda la señal tiene una duración de solo 120 microsegundos, por lo tanto, para desarmar cómodamente sus componentes, es deseable un receptor SDR con una frecuencia de muestreo de al menos 5 MHz.

Después de la grabación, obtenemos un archivo WAV con una frecuencia de muestreo de 5,000,000 muestras / seg, 30 segundos de tal grabación "pesan" aproximadamente 500 MB. Escucharlo con un reproductor multimedia es, por supuesto, inútil: el archivo no contiene sonido, sino una señal de radio digitalizada directamente: así es como funciona la Radio definida por software.
Abriremos y procesaremos el archivo usando Python. Aquellos que deseen experimentar por su cuenta pueden descargar la grabación de muestra
desde el enlace .
Descargue el archivo y vea lo que 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 "impulsos" obvios en el contexto del ruido.

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

Como puede ver, la imagen es consistente con lo que se describe en la descripción anterior. Puede comenzar a procesar los datos.
Decodificación
Primero necesitas obtener un flujo de bits. La señal en sí misma se codifica utilizando la codificación manchester:

A partir de la diferencia en los niveles de mordiscos, es fácil obtener "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í es la siguiente:

Consideremos 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 tabla )
Solo nos interesa el tipo DF17, como Contiene las coordenadas de la aeronave.
La OACI (24 bits) es un código internacional único de aeronave. Puede verificar el avión por su código
en el sitio web (desafortunadamente, el autor ha dejado de actualizar la base de datos, pero sigue siendo relevante). Por ejemplo, para el código 3c5ee2 tenemos la siguiente información:

Editar: en el
comentario sobre el artículo, la descripción del código de la OACI se da con más detalle; le recomiendo que la lea a los interesados.
DATOS (56 o 112 bits): en realidad, los datos que decodificaremos. Los primeros 5 bits de datos son el campo
Código de tipo que contiene el subtipo de los datos almacenados (que no debe confundirse con DF). Hay bastantes de estos tipos:

(
fuente de la tabla )
Veamos algunos paquetes de muestra.
Identificación de la aeronaveEjemplo binario:
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, cada carácter C1-C8 contiene códigos correspondientes a los índices en la cadena:
#ABCDEFGHIJKLMNOPQRSTUVWXYZ ##### _ ################# 0123456789 ######
Una vez decodificada la línea, es fácil obtener el código 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 aireSi el nombre es simple, entonces las coordenadas son más complicadas. Se transmiten en forma de tramas 2x, pares e impares. Código de campo TC = 01011b = 11.

Ejemplo de paquetes pares e impares:
01011 000 000101110110 00 10111000111001000 10000110101111001 01011 000 000110010000 01 10010011110000110 10000011110001000
El cálculo de las coordenadas se realiza de acuerdo con una fórmula bastante inteligente:

(
fuente )
No soy un especialista en SIG, así que no sé de dónde viene. Quién sabe, escribe en los comentarios.
La altitud se considera más fácil: dependiendo de un bit en particular, puede aparecer como un múltiplo de 25 o 100 pies.
Velocidad en el airePaquete con TC = 19. Lo interesante aquí es que la velocidad puede ser precisa, en relación con el suelo (Velocidad de avance) o el aire, según lo medido por un sensor de avión (Velocidad aérea). También se transmiten muchos campos diferentes:

(
fuente )
Conclusión
Como puede ver, la tecnología ADS-B se ha convertido en una simbiosis interesante cuando un estándar es útil no solo para profesionales, sino también para usuarios comunes. Pero, por supuesto, el papel clave en esto fue desempeñado por el abaratamiento de la tecnología de los receptores SDR digitales, que permite que el dispositivo reciba señales con una frecuencia superior a gigahercios, literalmente "por un centavo".
En el estándar mismo, por supuesto, mucho más que nada. Los interesados pueden ver el PDF en la página de la
OACI o visitar el
sitio ya mencionado anteriormente.
Es poco probable que muchos de los anteriores sean útiles, pero al menos la idea general de cómo funciona esto, espero.
Por cierto, ya existe un decodificador listo para usar en Python, puede estudiarse
aquí . Y los propietarios de los receptores SDR pueden ensamblar y ejecutar el decodificador ADS-B terminado
desde la página , más sobre esto en la
primera parte .
El código fuente del analizador descrito en el artículo se proporciona debajo del corte. Este es un ejemplo de prueba que no pretende ser producción, pero algo funciona en él, y puede analizar el archivo grabado 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 alguien esté interesado, gracias por su atención.