Практикум по декодированию телеметрии

Обрабатываем данные с Геоскана-Эдельвейса

Все космические аппараты (КА) имеют в составе своей бортовой аппаратуры блок телеметрии, который собирает информацию о параметрах работы систем спутника и по радиоканалу отправляет полученные данные на Землю. Это могут быть данные о величине напряжения батарей, токе потребления, температуре на панелях и т.д.

Многие КА предоставляют возможность принимать телеметрию и декодировать её. Более того, большинство организаций-владельцев образовательных и радиолюбительских спутников заинтересовано в том, чтобы как можно большее число людей принимало, декодировало и отправляло владельцам телеметрию их аппаратов. И это не удивительно, так как зачастую владельцы этих космических аппаратов имеют только одну наземную станцию, соответственно связываться со своим аппаратом могут ограниченное количество раз (для орбит 400-600 км до 6 раз в сутки в течение примерно 10 минут).

Это приводит к тому, что организации не могут получить данные телеметрии, когда они находятся вне области видимости наземной станции. И если в какой-то момент спутник не вышел на связь, оператор даже не сможет узнать, в какой из систем произошёл сбой. 

Как раз для решения этой проблемы и создана сеть наземных станций приёма спутниковых данных. Теперь владельцы образовательных спутников в России могут присоединиться к сети, планировать наблюдения на своей и чужих станциях и следить за параметрами систем своих космических аппаратов. 

Для того, чтобы радиолюбители могли декодировать телеметрию, в открытый доступ выкладывают специальные протоколы. Некоторые из них уже учтены в сети и данные декодируются автоматически, а потом визуализируются в ЦУПе.

На практическом занятии вы научитесь самостоятельно декодировать телеметрию по примеру обработки пакета данных, полученных с аппарата Геоскан-Эдельвейс. После того, как телеметрия будет полностью вами декодирована, вы сможете сверить результаты с тем, что декодировала сама сеть.

Приступим к практикуму:

1) Загрузите и откройте Python3 (скачать можно по ссылке).

2) Откройте протокол передачи телеметрии.

Найдите в протоколе пункт 3. Структура пакета маяка в формате AX.25. Это структура пакета телеметрии.

Как вы видите, пакет начинается с 0x848a82869e9c.

– это приставка, которая обозначает, что данные представлены в 16-ричной системе счисления (также называемые HEX числа), в самом пакете с данными её нет, только в протоколе.

Зайдите на портал sonik.space в раздел Наблюдения и выберете любое хорошее наблюдение (без фотографии) с аппарата Геоскан-Эдельвейс. Откройте вкладку Данные и выберете любой пакет.

Каждый пакет данных на портале выделен в прямоугольник. В нашем примере мы будем декодировать первый пакет из этого наблюдения.

Шаг 1:

Создайте переменную data_string с данными из выбранного пакета и удалите все пробелы из этой строки. Это можно сделать с помощью функции replace(), которая позволяет произвести замену символов в строке. В данном случае замените символ пробела на его отсутствие (‘ ’,’’).

data_string = ("84 8A 82 86 9E 9C 60 A4 A6 64 60 A6 40 E1 03 F0 F6 01 C4 65 5A 03 4B 00 9D B1 07 B1 01 01 00 00 80 0B 0A 0A 0F 7F 1D F1 05 FA 53 4F 20 4C 4F 4E 47 21 20 54 48 58 20 34 20 41 4C 4C 20 37 33 21".replace(' ',''))

Теперь выведите данные в консоль:

print(data_string)
>>  848A82869E9C60A4A66460A640E103F0F601C4655A034B009DB107B101010000800B0A0A0F7F1DF105FA534F204C4F4E472120544858203420414C4C20373321

В данных пропали все пробелы, значит, код отработал правильно.

Шаг 2:

Для дальнейшего декодирования необходимо узнать, сколько байтов информации находится в принятом пакете. Для этого воспользуйтесь функцией len(), которая определяет количество символов в строке. Один байт – это 2 символа строки. Получается, чтобы узнать количество байт, нужно разделить количество символов на два.

print(len(data_string)/2)

>>> 64.0 – значит полная длина строки это 64 байт.

Шаг 3:

Для декодирования вам понадобится совершать битовые операции, а проводить их можно только в 10-ричной системе счисления. Поэтому вам необходимо перевести значения из HEX (16-ричной системы) в десятичную.

Переведём HEX строку данных в одно целое число с помощью такой команды: 

data_int = int(data_string, 16)

Здесь мы приводим строку HEX значений data_string к типу INT (целое число) с кодом 16, что означает, что строка data_string – это число в 16-ричной системе счисления. Для проверки выведете полученное число в консоль:

print(data_int)

>>> 6941738269909969197532881209783840985181172520039825433192101394276917838726221091367443884713764978247381149997768628194461380230723587409806637957329697 – это полученное значение из HEX (16-ричной) в десятичной.

Шаг 4:

Для дальнейшей обработки выделите телеметрию в отдельный массив. Для этого создайте пустой массив:

telemetry_data=bytearray()

Теперь необходимо наполнить массив байтами из переменной data_int с помощью команды extend (). Для этого необходимо предварительно перевести data_int (сейчас это целое число) в байты. Воспользуйтесь функцией to_bytes (кол-во байт,порядок). Количество байт для времени вы определили в шаге 2 (64), а порядок может быть 'big' (от самого старшего к младшему) либо 'little' (от младшего к старшему). В данном случае нужно поставить 'big', чтобы данные в пакете располагались в правильном порядке.

telemetry_data.extend((data_int).to_bytes(64,'big'))

Как вы видите по протоколу, в пакете телеметрия смещена на 16 байт. Поэтому необходимо удалить первые 16 символов:

telemetry_data=telemetry_data[16:]

Теперь в переменной telemetry_data находится вся принятая телеметрия и вы можете дальше с ней работать.

Шаг 5:

Ознакомьтесь с таблицей 2, где представлены значения телеметрии. Первое значение – это время. Оно хранится в формате unix

В графе Тип стоит значение uint32, где Uint – это беззнаковое целое число, а 32 – это количество бит.  Для одного байта это диапазон значений 0-255. Здесь 32 бит, а значит 32/8=4 байт, то есть данные о времени занимают 4 байта. Для начала импортируйте встроенный модуль для работы с временем datetime в свою программу и обратитесь к функции datetime.

from datetime import datetime

Мы уже выяснили, что информация о времени занимает 4 байта. Поэтому вам необходимо выделить из массива первые 4 байта и перевести их обратно в целое число. Создайте новую переменную (в нашем примере int_time) и сделайте это с помощью функции int.from_bytes(переменная[диапазон]). Используйте порядок 'little', так как это указано в протоколе:

литл.png

int_time=int.from_bytes(telemetry_data[:4],'little')

Теперь переведите это целое число во временную метку с помощью функции datetime.utcfromtimestamp и выведете в нужном формате “год-месяц-день час:мин:сек”. Чтобы определить вид вывода данных, воспользуйтесь функцией strftime()

print(datetime.utcfromtimestamp(int_time).strftime('%Y-%m-%d %H:%M:%S'))

>>> 2024-02-07 22:19:34

Шаг 6:

Теперь декодируйте следующее значение в таблице – это мгновенный ток потребления. 

В столбце Ед.измерения указаны Амперы и в скобках константа, на которую нужно умножить полученное значение. 

В столбце Тип вы видите значение Uint16. Значит, оно занимает 16 бит= 2 байта. 

Составьте строку команд. В данном случае рассматриваемый диапазон – [4:6], так как первые 4 байта были выделены под время и вы их уже декодировали, а 4+2=6. И после этого умножьте его на константу, указанную в документации. (Константы используются, чтобы данные занимали меньше места.)

print(int.from_bytes(telemetry_data[4:6],'little')*0.0000766)

>>> 0.0657228 А (примерно 65 мА)

Шаг 7:

Теперь декодируйте ток с панелей:

print(int.from_bytes(telemetry_data[6:8],'little')*0.00003076)

>>> 0.0023069999999999996 А (примерно 2.3мА)

Далее вы можете декодировать телеметрию до конца похожим образом согласно документации.

! Помните, что каждому значению соответствует свой тип, соответственно разное количество байтов. 

Примечание:

В пункте, где указано Значение - число, надо отнять эту константу.

В последнем пункте после 'little' добавьте ,signed=True), чтобы формат числа был от-127 до 128 (так как там значение с минусом).

Шаг 8:

После того, как вы декодировали всю телеметрию, сверьте результаты с тем, что декодировала сеть. Для этого зайдите на страницу спутника в ЦУПе.

Выберете удобный промежуток времени (опираясь на время декодированного вами пакета). Чем меньше будет промежуток, тем проще будет найти ваше наблюдение.

На графиках проверяем значения. Когда наводишь на точку, отображается точное время. Так же время ты знаешь по тому, что декодировано.

Учитывайте, что скорее всего время, которое вы получили при декодировании, будет отличаться от времени у этого наблюдения на сайте на несколько секунд. Это происходит из-за несовпадения времени на компьютере и на спутнике. Поэтому для проверки выбирайте ближайшее время и проверяйте, на какую станцию было принято наблюдение.

Дополнительно:

Для некоторых задач, где предполагается обработка большого количества пакетов данных, сначала может быть необходимо убедиться, что данный пакет данных – это телеметрия. Можно сравнить данные и значение из протокола визуально (как вы сделали это в начале задания), но для большого количества это неудобно и можно сделать это с помощью программной строки. 

Обратимся к документации (Рисунок 1). Адрес получателя – это первые 6 байт. Для телеметрии он обозначается BEACON (маяк). Соответственно, вам нужно определить, соответствует ли этот адрес тому, что в принятом пакете. 

Для начала нужно сдвинуть данные вправо на 64 (общее количество байт в пакете) - 6 (столько байт занимает адрес получателя) = 58 байт с помощью знаков >>. Так как с помощью этих знаков можно сдвигать только биты, количество байт нужно умножить на 8. 

После этого приведите данные к формату HEX с помощью соответствующей команды hex и дальше можно сравнивать полученные данные удобным вам образом.

Учтите, что возвращаемая шестнадцатеричная строка начинается с префикса 0x, указывающего, что она в шестнадцатеричной форме.

Для примера, вы можете добавить в выполненном задании после шага 2 следующую программную строку, чтобы вывести на экран адрес получателя: 

print(hex((data_int >> int((64-6)*8)))[2:].upper())

В этой программной строке конструкция [2:] удаляет приставку , а метод upper преобразует все символы в верхний регистр. Полученный вывод в консоль:

>>> 848A82869E9C – обратимся к документации. Это и есть BEACON.


На основе такого протокола радиолюбители делают свои декодеры. Например, такие программы сделали радиолюбители Александр SA2KNG geoscan-tools и Егор UB1QBJ Geoscan-Edelveis-Decoder.

Новинки в энциклопедии
и самые актуальные новости.

Мы будем писать вам только когда появится что-то интересное,
никакого космического мусора