Oi Habr. Provavelmente todos que já conheceram ou acompanharam parentes ou amigos em um avião usaram o serviço gratuito Flightradar24. Essa é uma maneira muito conveniente de rastrear a posição da aeronave em tempo real.

A
primeira parte descreveu o princípio de operação de um serviço on-line. Agora iremos além, descobriremos quais dados são transmitidos e recebidos da aeronave para a estação receptora e decodificá-los independentemente usando Python.
A história
Obviamente, os dados sobre a aeronave não são transmitidos para que os usuários possam vê-los em seus smartphones. O sistema é chamado ADS - B (vigilância dependente automática - transmissão) e é usado para transmitir automaticamente informações da aeronave a um centro de controle - seu identificador, coordenadas, direção, velocidade, altitude e outros dados são transmitidos. Anteriormente, antes do advento de tais sistemas, o despachante via apenas um ponto no radar. Isso não foi suficiente quando havia muitos aviões.
Tecnicamente, o ADS-B consiste em um transmissor em uma aeronave que envia periodicamente pacotes com informações a uma frequência bastante alta de 1090 MHz (existem outros modos, mas eles não são tão interessantes para nós, porque as coordenadas são transmitidas apenas aqui). É claro que, além do transmissor, também há um receptor em algum lugar do aeroporto, mas para nós, assim como para os usuários, nosso próprio receptor é interessante.
A propósito, para comparação, o primeiro sistema desse tipo, o Airnav Radarbox, projetado para usuários comuns, apareceu em 2007 e custou cerca de US $ 900, cerca de US $ 250 por ano, valendo uma assinatura dos serviços de rede.

Você pode ler as resenhas desses primeiros proprietários russos no fórum do
radioscanner . Agora que os receptores RTL-SDR estão amplamente disponíveis, um dispositivo semelhante pode ser montado por US $ 30, mais sobre isso na
primeira parte . Vamos prosseguir para o próprio protocolo - vamos ver como ele funciona.
Recebendo sinais
Para começar, o sinal precisa ser gravado. Todo o sinal tem uma duração de apenas 120 microssegundos, portanto, para desmontar confortavelmente seus componentes, é desejável um receptor SDR com uma frequência de amostragem de pelo menos 5 MHz.

Após a gravação, obtemos um arquivo WAV com uma frequência de amostragem de 5.000.000 amostras / s, 30 segundos dessa gravação “pesam” cerca de 500 MB. Ouvi-lo com um media player é, obviamente, inútil - o arquivo não contém som, mas um sinal de rádio digitalizado diretamente - é assim que o Rádio Definido por Software funciona.
Vamos abrir e processar o arquivo usando Python. Aqueles que desejam experimentar por conta própria podem fazer o download da amostra de gravação
no link .
Baixe o arquivo e veja o que há 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 “pulsos” óbvios no contexto do ruído.

Cada "impulso" é um sinal cuja estrutura é claramente visível se você aumentar a resolução no gráfico.

Como você pode ver, a imagem é consistente com o descrito na descrição acima. Você pode começar a processar os dados.
Decodificação
Primeiro você precisa obter um fluxo de bits. O sinal em si é codificado usando a codificação manchester:

A partir da diferença de níveis em mordidelas, é fácil obter "0" e "1" reais.
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"
A estrutura do próprio sinal é a seguinte:

Vamos considerar os campos com mais detalhes.
DF (formato de downlink, 5 bits) - define o tipo de mensagem. Existem vários tipos deles:

(
origem da tabela )
Estamos interessados apenas no tipo DF17, como contém as coordenadas da aeronave.
ICAO (24 bits) é um código internacional exclusivo de aeronave. Você pode verificar a aeronave por seu código
no site (infelizmente, o autor parou de atualizar o banco de dados, mas ainda é relevante). Por exemplo, para o código 3c5ee2, temos as seguintes informações:

Editar: no
comentário do artigo, a descrição do código da ICAO é fornecida com mais detalhes; eu recomendo que você se familiarize com os interessados.
DADOS (56 ou 112 bits) - na verdade, os dados que iremos decodificar. Os primeiros 5 bits de dados são o campo
Código de tipo que contém o subtipo dos dados armazenados (não deve ser confundido com o DF). Existem alguns desses tipos:

(
origem da tabela )
Vejamos alguns exemplos de pacotes.
Identificação da aeronaveExemplo binário:
00100 011 000101 010111 000111 110111 110001 111000
Campos de dados:
+------+------+------+------+------+------+------+------+------+------+ | TC,5 | EC,3 | C1,6 | C2,6 | C3,6 | C4,6 | C5,6 | C6,6 | C7,6 | C8,6 | +------+------+------+------+------+------+------+------+------+------+
TC = 00100b = 4, cada caractere C1-C8 contém códigos correspondentes aos índices na sequência:
#ABCDEFGHIJKLMNOPQRSTUVWXYZ ##### _ ################# 0123456789 ######
Após decodificar a linha, é fácil obter o código do avião: 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('#', ''))
Posição no arSe o nome for simples, as coordenadas serão mais complicadas. Eles são transmitidos na forma de 2x, quadros pares e ímpares. Código do campo TC = 01011b = 11.

Exemplo de pacotes pares e ímpares:
01011 000 000101110110 00 10111000111001000 10000110101111001 01011 000 000110010000 01 10010011110000110 10000011110001000
O cálculo das coordenadas ocorre de acordo com uma fórmula bastante inteligente:

(
fonte )
Como não sou especialista em GIS, não sei de onde vem. Quem sabe, escreva nos comentários.
A altitude é considerada mais fácil - dependendo de um bit específico, ela pode aparecer como um múltiplo de 25 ou 100 pés.
Velocidade no arPacote com TC = 19. O interessante aqui é que a velocidade pode ser precisa, em relação ao solo (velocidade no solo) ou no ar, conforme medido por um sensor de avião (velocidade do ar). Muitos campos diferentes também são transmitidos:

(
fonte )
Conclusão
Como você pode ver, a tecnologia ADS-B se tornou uma simbiose interessante quando um padrão é útil não apenas para profissionais, mas também para usuários comuns. Mas é claro que o papel principal disso foi desempenhado pelo barateamento da tecnologia dos receptores digitais SDR, que permite que o dispositivo receba sinais com uma frequência acima de gigahertz literalmente "por um centavo".
No próprio padrão, é claro, muito mais que tudo. Os interessados podem ver o PDF na página da
ICAO ou visitar o
site já mencionado acima.
É improvável que muitos dos itens acima sejam úteis, mas pelo menos a idéia geral de como isso funciona, espero, permanece.
A propósito, já existe um decodificador pronto em Python, que pode ser estudado
aqui . E os proprietários dos receptores SDR podem montar e executar o decodificador ADS-B finalizado a
partir da página , mais sobre isso na
primeira parte .
O código-fonte do analisador descrito no artigo é fornecido sob o corte. Este é um exemplo de teste que não pretende ser produção, mas algo funciona nele, e você pode analisar o arquivo gravado acima.
Código-fonte (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 alguém esteja interessado, obrigado por sua atenção.