Наверное каждый, кто хоть раз встречал или провожал родственников или друзей на самолет, пользовался бесплатным сервисом Flightradar24. Это весьма удобный способ отслеживания положения самолета в реальном времени.
В первой части был описан принцип работы такого онлайн-сервиса. Сейчас мы пойдем дальше, и выясним, какие данные передаются и принимаются от воздушного судна к приемной станции, и декодируем их самостоятельно с помощью Python.
История
Очевидно, что данные о самолетах передаются не для того, чтобы пользователи видели их на своих смартфонах. Система называется ADS–B (Automatic dependent surveillance—broadcast), и служит для автоматической передачи информации о воздушном судне в диспетчерский центр — передаются его идентификатор, координаты, направление, скорость, высота и прочие данные. Ранее, до появления таких систем, диспетчер мог видеть лишь точку на радаре. Этого стало недостаточно, когда самолетов стало слишком много.
Технически, ADS-B состоит из передатчика на воздушном судне, который периодически посылает пакеты с информацией на достаточно высокой частоте 1090 МГц (есть и другие режимы, но нам они не так интересены, т.к. координаты передаются только здесь). Разумеется, кроме передатчика, есть и приемник где-то в аэропорту, но для нас, как для пользователей, интересен приемник наш собственный.
Кстати, для сравнения, первая такая система, Airnav Radarbox, расчитанная на обычных пользователей, появилась в 2007 году, и стоила около 900$, еще около 250$ в год стоила подписка на сетевые сервисы.
Отзывы тех первых российских владельцев можно почитать на форуме radioscanner. Сейчас, когда массово стали доступны RTL-SDR приемники, аналогичный девайс можно собрать за 30$, подробнее об этом было в первой части. Мы же перейдем собственно, к протоколу — посмотрим как это работает.
Прием сигналов
Для начала, сигнал нужно записать. Весь сигнал имеет длительность всего лишь 120 микросекунд, поэтому чтобы комфортно разобрать его компоненты, желателен SDR-приемник с частотой дискретизации не менее 5МГц.
После записи мы получаем WAV-файл с частотой дискретизации 5000000 семплов/сек, 30 секунд такой записи «весят» около 500Мб. Слушать её медиаплеером разумеется, бесполезно — файл содержит не звук, а непосредственно оцифрованный радиосигнал — именно так работает Software Defined Radio.
Открывать и обрабатывать файл мы будем с помощью Python. Желающие поэкспериментировать самостоятельно, могут скачать пример записи по ссылке.
Загрузим файл, и посмотрим что внутри.
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()
Результат: мы видим явные «импульсы» на фоне шума.
Каждый «импульс» — это и есть сигнал, структуру которого хорошо видно, если увеличить разрешение на графике.
Как можно видеть, картинка вполне соответствует тому, что приведено в описании выше. Можно приступать к обработке данных.
Декодирование
Для начала, нужно получить битовый поток. Сам сигнал закодирован с помощью manchester encoding:
Из разницы уровней в полубайтах легко получить реальные «0» и «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"
Структура самого сигнала имеет следующий вид:
Рассмотрим поля более подробно.
DF (Downlink Format, 5 бит) — определяет тип сообщения. Их несколько типов:
(источник таблицы — bibliotheek.knmi.nl/knmipubTR/TR336.pdf)
Нас интересует только тип DF17, т.к. именно он содержит координаты воздушного судна.
ICAO (24 бита) — международный уникальный код воздушного судна. Проверить самолет по его коду можно на сайте junzis.com/adb (к сожалению, автор перестал обновлять базу, но она еще актуальна). К примеру, для кода 3c5ee2 имеем следующую информацию:
DATA (56 или 112 бит) — собственно данные, которые мы и будем декодировать. Первые 5 бит данных — поле Type Code, содержащее описание хранящихся данных. Их также довольно много.
(источник таблицы — mode-s.org/decode/adsb/introduction.html)
Разберем несколько примеров пакетов.
Aircraft identification
Пример в бинарном виде:
00100 011 000101 010111 000111 110111 110001 111000
Поля данных:
+------+------+------+------+------+------+------+------+------+------+ | TC,5 | EC,3 | C1,6 | C2,6 | C3,6 | C4,6 | C5,6 | C6,6 | C7,6 | C8,6 | +------+------+------+------+------+------+------+------+------+------+
TC = 00100b = 4, каждый символ C1-C8 содержит коды, соответствующие индексам в строке:
#ABCDEFGHIJKLMNOPQRSTUVWXYZ#####_###############0123456789######
Раскодировав строку, несложно получить код самолета: 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('#', ''))
Airborne position
Если с названием все просто, то с координатами посложнее. Они передаются в виде 2х, четных и нечетных фреймов. Код поля TC = 01011b = 11.
Пример четного и нечетного пакетов:
01011 000 000101110110 00 10111000111001000 10000110101111001 01011 000 000110010000 01 10010011110000110 10000011110001000
Само вычисление координат происходит по достаточно хитрой формуле:
(источник — mode-s.org/decode/adsb/airborne-position.html)
Я не специалист по ГИС, так что откуда оно выводится, не знаю. Кто в курсе, напишите в комментариях.
Высота считается проще — в зависимости от определенного бита, она может представляться либо кратной 25, либо 100 футам.
Airborne Velocity
Пакет с TC=19. Интересно тут то, что скорость может быть как точная, относительно земли (Ground Speed), так и воздушная, измеряемая датчиком самолета (Airspeed). Еще передается множество разных полей:
(источник — mode-s.org/decode/adsb/airborne-velocity.html)
Заключение
Как можно видеть, технология ADS-B стала интересным симбиозом, когда какой-либо стандарт пригождается не только профессионалам, но и обычным пользователям. Но разумеется, ключевую роль в этом сыграло удешевление технологии цифровых SDR-приемников, позволяющим на девайсе буквально «за копейки» принимать сигналы с частотой выше гигагерца.
В самом стандарте разумеется, гораздо больше всего. Желающие могут посмотреть PDF на странице ICAO или посетить уже упомянутый выше сайт https://mode-s.org/decode/.
Вряд ли многим пригодится все вышенаписанное, но по крайней мере общая идея того, как это работает, надеюсь, осталась.
Кстати, готовый декодер на Python уже существует, его можно изучить здесь: https://github.com/junzis/pyModeS. А владельцы SDR-приемников могут собрать и запустить готовый ADS-B декодер со страницы https://github.com/antirez/dump1090.git, подробнее об этом рассказывалось в первой части.
Надеюсь, кому-то было интересно, спасибо за внимание.
Источник