Оптимизация приёма AX.25
Введение
Итак, после того, как измерена BER кривая для AX.25 декодера, можно попробовать её оптимизировать.
Оптимизация заранее известного заголовка
Просмотрев несколько десятков протоколов различных спутников от UNISAT-7 до FIREBIRD 4, я обнаружил, что они всегда шлют один и тот же AX.25 заголовок. Заранее зная такой заголовок, можно игнорировать его в принятом фрейме и попытаться исправить ошибки получения. Алгоритм тогда будет выглядеть следующим образом:
- найти флаги начала и окончания HDLC фрейма
- посчитать контрольную сумму
- если сумма совпала, то фрейм корректно получен
- если сумма не совпала, то подставить заранее известный заголовок в начало фрейма
- посчитать контрольную сумму ещё раз
- если сумма совпала, то фрейм удалось восстановить
- если не совпала, то ничего не поделаешь - фрейм утерян
При таком алгоритме спутник может слать как известные заголовки, так и нет. Вероятность исправления ошибок в известных заголовках будет выше.
Вообще такой подход работает отлично для приёма данных со спутников. Они часто шлют данные один ко многим и имеют один и тот же заголовок AX.25. Поскольку целью проекта r2cloud является получение как можно больше данных из космоса, то такую оптимизацию неплохо было бы иметь.
Использование синхрослова
Одним из слабых мест HDLC являются начальные и конечные тэги - 0b01111110. Если хотя бы один бит в принятом тэге неправильный, то весь фрейм будет отброшен. Даже если полезные данные не содержат ошибок. Декодер просто не сможет найти начало фрейма. В хорошо продуманных протоколах используется синхрослово, за которым идут полезные данные. Синхрослово - это заранее известная последовательность бит, которую отправляют перед каждым фреймом. Это слово позволяет:
- найти начало фрейма
- не выполнять дорогостоящих и сложных вычислений вроде коррекции ошибок или проверки контрольной суммы
- делать неточный поиск. Это позволяет найти начало фрейма даже если в принятом синхрослове есть несколько бит ошибок
Для HDLC таким синхрословом может быть начальный тэг 0b01111110. Проблема заключается в том, что большинство спутников использует G3RUH скремблер. Вообще скремблированые данных перед отправкой - полезная штука. Однако, в AX25 он применяется и к тэгам! Это значит, что каждый фрейм каждый раз будет иметь разные биты вместо 0b01111110. И это не очень подходит для приёма HDLC.
Однако, я не стал отчаиваться и придумал следующий алгоритм:
- взять реальный сигнал со спутника
- декодировать его старым алгоритмом
- собрать статистику для каждого успешно декодированного фрейма:
- внутреннее состояние дескремблера
- вывод демодулятора до того, как он будет пропущен через дескремблер
Зная такую статистику для каждого фрейма можно понять состояние скремблера в момент передачи данных со спутника. Если оно одно и то же, то принятые данные можно отмотать назад и получить синхрослово. Да, это звучит так же сложно, как и реализовано в jradio.
Однако, алгоритм на удивление работает и я могу искать начало HDLC фреймов даже если они были пропущены через скремблер!
Проверка
Я реализовал оба алгоритма и прогнал на искусственном тесте Ax24G3ruhBer:
В тесте отправляются фреймы размером 131 байт. Если учесть, что заголовок занимает 16 байт, то улучшить приём можно примерно на 12%. На графике видно улучшение, но небольшое. В среднем на 8%.
Если же использовать поиск синхрослова и заранее известный заголовок, то улучшить приём можно в среднем на 14% процентов. А при достаточно сильном сигнале вплоть до 50%.
Проверка оптимизаций на реальных сигналах
После тестирования оптимизаций на модели, я решил проверить работу на реальных сигналах со спутников. Вот пример сигнала со спутника UNISAT-7:
На спектрограмме отчётливо виден сигнал со спутника - он идёт вдоль зелёной линии. Однако, его мощности недостаточно, чтобы декодировать все пакеты. До оптимизаций мой декодер мог получить только 3 фрейма, после оптимизаций - 4.
Я также сравнил результаты с декодером из gr_satellites. Этот декодер лёг в основу моего до всех оптимизаций. Я запускал его следующей командой:
gr_satellites 47945 --rawfile output.raw.gz-doppler.cf32 --samp_rate 48000 --iq
В результате мне удалось получить только один фрейм.
Выводы
HDLC не так-то просто оптимизировать. Мне потребовалось несколько недель и действительно очень много кода, чтобы немного улучшить приём. Тем не менее мой метод нельзя сделать универсальным и декодер необходимо конфигурировать для каждого спутника отдельно.