Новая жизнь старого GPS-приёмника
Эта статья во многом посвящена теории работы GPS приемников, при том я не буду погружаться в формулы и нюансы, а приведу практическое описание применения теории.
Сигнал, передаваемый со спутника
Я думаю, большинство читателей и так знают, что метод определения координат в системе GPS основан на измерении моментов времени приёма синхронизированного сигнала от навигационных спутников антенной приемника. Приемник, зная координаты спутников, по измеренным задержкам может вычислить расстояния до спутников, и далее - свою позицию в пространстве. Но что именно предает спутник?
В системе GPS наиболее широко известным является сигнал C/A-code, передаваемый на частоте L1 (1575.42 МГц). Частота L1 одинакова для всех спутников GPS.
C/A - это сигнал гражданского назначения, также на этой же частоте передается P(Y)-code, декодирование которого доступно только военным. С точки зрения гражданских приемников, P(Y)-code является просто шумом, и его существование можно не учитывать.
Самое интересное тут - именно сам C/A-код, представляющий собой поток бит, формируемый со скоростью 1.023 Mbit/s. Этот поток данных представляет собой псевдослучайный шумоподобный код (PRN), который формируется по специальной формуле, уникальной для каждого спутника.
Поток данных состоит из 1023 бит (называемых chips/чипами), то есть через каждые 1023 чипа (1 мс) данные повторяются. Также этот поток данных называют дальномерным кодом, так как именно моменты повторения этого кода привязаны на спутнике к времени UTC.
Также спутник формирует поток навигационных данных, который имеет скорость 50 бит/с. Этот поток содержит в себе полную информацию о текущем времени, точную информацию об орбите спутника (эфимериды), и некоторую другую информацию.
Навигационные данные перемножаются с C/A-кодом при помощи операции XOR, и далее сформированный поток данных используется для управления модуляцией несущей частоты L1. Используемая модуляция - BPSK ( двоичная фазовая манипуляция), то есть при изменении двоичного значения данных формируемая синусоида несущей частоты меняет фазу на 180 градусов, а по сути - инвертируется.
Замечу, что фазы всех вышеупомянутых сигналов синхронизированы друг с другом, к примеру, смена битов навигационных данных четко привязана к периодам C/A-кода.
Прием данных со спутника для последующей обработки
Каким образом можно получить и обработать сигнал GPS на ПК? Первое, что приходит в голову - использовать SDR-приемник.
Задача приемника - усилить принятый сигнал, перенести его на более низкую частоту, оцифровать и передать на ПК. Для приема GPS сигнала приемник должен уметь принимать сигнал на частоте 1575 МГц и иметь полосу пропускания более 2 МГц.
Достаточно даже такого простого приемника, как RTL-SDR. Вот тут есть подробная инструкция, использовать такой приемник для приема GPS.
Я попробовал повторить описанную инструкцию, и у меня это получилось. Именно этот эксперимент и послужил основой для написания этой статьи, и дальше я буду рассказывать именно про Open Source программу "GNSS-SDRLIB", упомянутую в этой инструкции.
На что стоит обратить внимание при повторении инструкции:
Я использовал довольно старый приемник RTL-SDR, без всяких радиолюбительских улучшений. Как и упомянуто в инструкции, при работе на частоте 1575 МГц в нем очень быстро (секунд за 30-50) перегревается микросхема тюнера и прием сигнала нарушается. Так что мне пришлось вынуть плату из приемника и обдувать вентилятором - за счет этого приемник нормально работает длительное время.
Важно установить в настройках "GNSS-SDRLIB" значение "Clock Error" - отклонение частоты кварцевого резонатора приемника в ppm (его нужно предварительно измерить). Для обработки данных от GPS довольно важно точно знать точную частоту кварца, при наличии большой ошибки алгоритмы просто не обнаружат сигналы GPS.
Лучше не выбирать все спутники в программе (в окне справа), а выбрать только те, что реально присутствуют над приемником. Программа довольно требовательна к CPU.
Ранее, до широкого распространения дешевых приемников GNSS, энтузиасты использовали специализированные GNSS-приёмники.
Примером могут являться:
Или: PocketSDR
Достоинствами таки приемников могут являться: возможность приема сигналов сразу с двух далеких друг от друга диапазонов, возможность синхронного приема сигналов сразу с двух антенн, наличие точного кварцевого генератора TCXO, специализированные аппаратные полосовые фильтры сигнала; так что и сейчас в определенных случаях такие приемники не потеряли актуальности.
В большинстве своем в таких приемниках для приема и оцифровки сигналов GNSS используются специализированные микросхемы (GNSS RF front-end). Сейчас, в эпоху, когда весь GPS приемник может быть сделан на единственной микросхеме или может быть даже частью большого SoC, такие микросхемы встречается в основном в профессиональном GNSS-оборудовании. Посмотрим же, как дела обстояли раньше.
Исследование старого GPS приемника
Пора, наконец, перейти к приемнику, упомянутому в заголовке)
С давних пор у меня имеется GPS-приемник Globalsat BT-318.
Это довольно типичный представитель своего класса - GPS приемник с Bluetooth интерфейсом. Приемник имеет встроенный аккумулятор и предназначен для подключения к КПК, не имеющих встроенного GPS-приемника.
В продажу поступил в далеком 2004 году - 19 лет назад.
Построен он на чипсете SiRF StarIIe.
Однажды этот приемник попался мне на глаза в очередной раз, и я подумал: "Можно ли использовать его, чтобы принять "сырые" GPS данные и обработать их на ПК"?
К тому моменту у меня уже был опыт работы с RTL-SDR, и я знал, что программа GNSS-SDRLIB умеет работать со специализированными GNSS приемниками. Именно тогда я решил разобраться с приемником поглубже.
Структурная схема этого чипсета:
Можно видеть, что приемник построен на двух основных микросхемах - GRF2i/LP и GSP2e/LP. Первая - собственно, вышеупомянутый GNSS RF front-end, вторая - "мозг" приемника, именно она занимается обработкой принятого оцифрованного сигнала и выдает результат в виде NMEA пакетов по UART. Если не ошибаюсь, разделение на две микросхемы нужно потому, что они изготовлены по разным техпроцессам, кроме того, таким образом можно надежно отделить аналоговую часть приемника от цифровой.
Из схемы можно видеть, что данные от микросхемы GRF2i/LP идут в цифровом виде, их можно попробовать перехватить и передать на ПК.
К сожалению, у меня не осталось хороших фотографий разобранного приемника, так что придется довольствоваться фотографиями из FCC.ID:
Справа вверху - микросхема GRF2i/LP и ее обвязка, включая TCXO, справа внизу - микросхема GSP2e/LP и Flash-память. Они размещены на отдельной плате, фактически образуя модуль GPS-приемника.
Слева - модуль Bluetooth.
Все три узла закрыты металлическими крышками-экранами, снимать их непросто.
К сожалению, никакой документации на микросхему GRF2i/LP мне найти не удалось. А вот для GSP2e/LP есть такой документ от 2000 года: SiRF Application Note GSP2e Hardware Implementation (APNT0012).
В нем есть кое-какие подробности работы чипа GRF2i/LP.
Еще нашлась вот эта презентация, которая, к сожалению, несколько сбила меня с толку в дальнейшем.
Фактически, микросхема с обвязкой работает довольно просто - подаем на нее высокочастотный сигнал, она усиливает его (LNA) и переносит его на более низкую частоту (промежуточная частота - IF) ~9.45 МГц, полученный сигнал внутри микросхемы еще раз усиливается и оцифровывается двухбитным АЦП, оцифрованный сигнал микросхема выдает наружу.
Фраза "двухбитный АЦП" звучит несколько необычно, когда речь идет про радиоприем, но для приема сигналов GNSS можно использовать и однобитный АЦП!
В данном случае АЦП имеет два выхода - SIGN и MAG (magnitude). Первый - знак аналогового сигнала, второй - признак повышенного уровня сигнала. Также микросхема выдает сигнал ACQCLK, по нарастающему фронту которого приёмник цифровых данных должен захватывать данные от АЦП. Частота сигнала тактирования довольно высокая - ~38МГц.
Также микросхема имеет вход управления усилением AGCDATA, в чипсете он подключён к GSP2e/LP, которая, анализируя данные от АЦП, переключает усиление. Так как я не собирался отключать GSP2e, то про эту линию можно не думать.
Осциллограф показал вот такие сигналы на линиях ACQCLK/SIGN:
В итоге выходит, что этот GPS-приемник вполне можно использовать для получения "сырых" данных GPS - достаточно захватить данные с линий SIGN/MAG и передать их на ПК, где их можно будет обработать в GNSS-SDRLIB. Честно говоря, я думал, что это займет не очень много времени, но ошибся...
Получение цифровых данных от GPS RF Front-end
Как я уже писал выше, микросхема GRF2i/LP имеет две линии данных и одну линию тактирования. Однако просто так подключить эти линии к какой-то распространенной цифровой логике не выйдет - все три линии имеют тип PECL (Pseudo Emitter Coupled Logic), размах сигнала там маленький (около 700мВ) и имеется постоянная составляющая около 1.5В. У микросхемы имеется специальный выход PECLREF, на котором присутствует как раз это напряжение смещения. Таким образом, чтобы получить цифровые данные в привычного типа CMOS 3.3V, нужно иметь три компаратора, причем быстрых (напомню, что скорость данных - 38 MSPS).
Для преобразования сигналов я изготовил специальную плату, на которой размещена микросхема MAX964EEE+ - счетверенный компаратор.
Площадки P1,P2,P4 подключаются к линиям ACQCLK/SIGN/MAG приемника, площадки P9, P10, P11 - выходы. Для тестов на плате есть два U.FL разъема - с их помощью можно подключить плату напрямую к осциллографу. На осциллографе получается такой сигнал:
Видно, что сигналы имеют крутые фронты и приличную амплитуду.
Получившаяся конструкция выглядит так:
Как видно, плата компараторов подключена к линиям GRF2i тонкими проволочками. Это подключение не влияет на работу приемника - к нему все еще можно подключится по Bluetooth и посмотреть, какие спутники он принимает.
Внутри приемника была встроенная активная антенна, я отпаял ее и припаял разъем для более крупной антенны с длинным проводом.
Питание платы компараторов - внешнее.
Передача оцифрованных данных в ПК
Как я уже писал выше, частота выборок - 38 MSPS, что соответствует потоку данных 76 Mbit/s. Это довольно много, поэтому для передачи данных я решил использовать специализированную микросхему cy7c68013a, которая может работать в режиме конвертера "USB-параллельная шина". Эта микросхема программируется, возможно, ее можно было бы настроить для приема данных по двухбитной шине, но я решил использовать готовый софт и восьмибитную шину.
Если попробовать завести двухбитную шину на восьмибитную, то это создаст огромную нагрузку на USB и ПК - получившийся поток данных будет иметь скорость 304 Mbit/s, и я даже не уверен, что USB HS справится. Как же преобразовать двухбитный поток данных в восьмибитный? Можно собрать преобразователь на микросхемах сдвиговых регистров и триггерах, но я пошел более простым путем, и использовал отладочную плату ПЛИС DE0-Nano. Так так задача довольно простая, то и код на Verilog получается простейший. В результате на 4 такта ACQCLK ПЛИС выдает один байт данных (8 выходов). В них четыре старших бита - SIGN, четыре младших - MAG. Также имеется выход синхронизации. Таким образом мы получаем поток данных 9.5 Мбайт/с.
У меня была дешевя отладочная плата для микросхемы CY7C68013a, которую я и собирался использовать для захвата данных от ПЛИС:
Когда я планировал использовать ее для захвата данных, я рассчитывал использовать Open Source проект sigrok - у них были примеры использования таких плат для создания логических анализаторов сигнала. Однако, как оказалось, прошивки sigrok не поддерживают внешнее тактирование.
Далее я смог найти проект fx2pipe для Linux. Проект обещал возможность захватывать данные с параллельной шины по внешнему тактированию, но был довольно старым, основанным на libusb-0.1, что мешало запустить его в современном Linux.
В дальнейшем я смог найти современную модификацию этого проекта: Cannelloni (небольшое обсуждение). Тут, как водится, классика Linux - нужно все собирать самому (включая прошивку CY7C68013a), инструкции неполные... В итоге все же удалось собрать проект - и он не заработал.
Еще немного поисков - в недрах сайта проекта fx2pipe находится упоминание:
Before running this firmware, you need to manually do the following wiring:
Connect to HIGH (3.3V): PA2/SLOE, PA5/FIFOADR1, RDY0/SLRD
Connect to LOW (GND): PA4/FIFOADR0, RDY1/SLWR
Накинул на палату кучу соединений - не помогает, программа на ПК не принимает никаких данных. Хотя видно, что программа с ПК успешно загружает прошивку в микросхему, при помощи ключей командной строки можно запустить захват данных по тактированию "изнутри" микросхемы.
Прошивки sigrok на этой отладочной плате работают нормально.
Потратил кучу времени, разбираясь с этой проблемой, и в итоге решил заказать новую отладочную плату - вдруг вход IFCLK микросхемы пробило. Новая плата ничего не изменила, вела себя абсолютно также, как и предыдущая, только микросхема на ней немного отличалась внешне от первой, и грелась намного меньше. Тут уже у меня возникло ощущение - "а может обе микросхемы контрафактные?".
Вспомнил, что у меня завалялась недоделанная отладочная плата на такой же микросхеме CY7C68013-128A. Эту микросхему я выпаял их ненужного тв-тюнера, и она была заведомо рабочей. Опять потратил кучу времени на оживление этой платы (а она была сделана по технологии ЛУТ, и некоторые дорожки перетравились), допаял определенное количество перемычек, которые требовались fx2pipe (некоторые пришлось припаивать прямо к ножкам микросхемы) и, в итоге, захват данных заработал! Так что, судя по всему, все же с китайскими микросхемами было что-то не так.
Вдруг кому-то пригодится, пример команды для захвата 81920 выборок с использованием cannelloni:
./cannelloni -f fx2pipe.ihx -t fx2lp -i -8 -b 8192 -n 81920 -c x -v > test.bin
На всякий случай замечу, что тактовая частота сигнала, подаваемого на вход IFCLK, должна быть больше 5 МГц, а сигнал нужно начинать подавать на микросхему до того, как ПК начинает загружать в нее прошивку.
В итоге получилась вот такая странноватая конструкция:
Думаю, у читателя сразу возникает вопрос - зачем тут стрелочный миллиамперметр (1957г выпуска)?
Как я уже писал выше, по началу плата CY7C68013A работала нестабильно из-за плохого качества платы. По амперметру можно контролировать ток, потребляемый платой, и таким образом определять режим работы микросхемы. При стабильной работе платы можно выделить состояния - прошивка не загружена/загружена/передача данных запущена.
Плата DC-DC преобразователя (под амперметром) нужна для питания CY7C68013A. Ток тут достаточно большой, и линейного преобразователя явно не хватит.
Можно видеть, что на плату CY7C68013A не установлена EEPROM. Для cannelloni она не нужна - программа сама загружает в микросхему прошивку при запуске.
Обработка захваченных данных
В итоге, я меня появилась возможность при помощи программы cannelloni захватывать довольно большие объёмы данных в файл на ПК. Программа GNSS-SDRLIB имеет возможность обрабатывать данные из файлов. Таким образом, сделав конвертер файлов, я мог проанализировать свои данные в GNSS-SDRLIB. К сожалению, формат файлов, поддерживаемых GNSS-SDRLIB, нигде толком не описан (честно сказать, с документацией на эту программу все плохо). В итоге, покопавшись в исходном коде, я выяснил, что лучше всего подходит формат приемника GN3Sv3. Формат очень прост - это последовательно идущие результаты АЦП типа int8_t, в этом приемнике тоже использован 2-битный АЦП, так что допустимые значения данных тут - [-3,-1, 1, 3].
Я быстро написал на C# конвертер своих файлов в формат GN3Sv3, записал 40 сек данных, в GUI GNSS-SDRLIB указал характеристики своего приемника ("Sampling Freq" - частота дискретизации АЦП, ACQCLK и "Intermediate Freq." - промежуточная частота, ее я тоже упоминал выше). И ничего не заработало, опять...
Программа не смогла захватить сигнал от спутников.
Замечу, что в программе есть возможность отображения гистограммы входных данных и спектра сигнала. С моими данными они выглядели достаточно адекватно:
Что представляет из себя захват (acquisition) сигнала?
Как я уже писал выше, основа GPS сигнала - псевдослучайный код длинной 1023 бита. Обнаружить этот код в принятом сигнале можно, вычисляя взаимную корреляцию между принятым сигналом, и сгенерированном на приемнике. При этом придется имеются следующие неизвестные:
Номер спутника. Он нужен для генерирования PRN кода. При "холодном старте" приемник ничего не знает про орбиты спутников, свои координаты и время, так что приемнику нужно либо перебирать номера спутников, проверяя наличие сигнала, либо (если приемник обладает нужными аппаратными ресурсами) - анализировать параллельно все существующие номера. В программе GNSS-SDRLIB номера спутников выбирает сам пользователь.
Частота сигнала, на которой нужно искать поток данных. Спутники постоянно движутся по небу, в результате чего принимаемый на Земле сигнал имеет доплеровское смещение частоты. При "холодном старте" приемник опять же ничего не знает про спутник, так что ему приходится определять истинную частоту перебором. Очевидно, что у каждого спутника, от которого мы принимаем сигнал, частота будет своя. Обычно зона поиска находится в диапазоне ±10 кГц.
Фаза сигнала. Фактически, это положение одного периода PRN кода в принятых данных. Именно по разнице фаз между сигналами разных спутников и происходит вычисление расстояния до них.
Как видно, даже если номер спутника известен, вычислений для обнаружения сигнала от спутника нужно много - нужно перебрать все 1023 вариантов фазы и десятки частот, каждый раз вычисляя корреляцию. Если приемник имеет аппаратные корреляторы, то задача не займет много времени, а вот на ПК она выйдет довольно медленной. В случае GNSS-SDRLIB автор программы использовал метод поиска с использованием БПФ (FFT), то есть перенеся данные из временной области в частотную.
Схема используемого алгоритма:
"Local oscillator" - формирует сигнал промежуточной частоты (IF), смещенный на X Гц (это значение перебирается в процессе поиска). Перемножая входные данные с данными этого генератора, мы получаем данные, перенесенные на нулевую частоту в комплексной форме. Далее при помощи FFT приемник переносит эти данные в частотную область, т.е. по сути, вычисляет спектр входного сигнала на анализируемой частоте.
"PRN code generator" вычисляет данные PRN для заданного спутника, по ним тоже выполняется FFT преобразование, а затем - для найденных значений вычисляются комплексно сопряженные значения. Замечу, что так как PRN зависит только от номера спутника, то эту часть операций можно выполнить один раз - при старте приемника. В итоге получаем спектр PRN кода.
После этого оба спектра поэлементно перемножаются, и для полученных данных вычисляется обратное преобразование Фурье (IFFT), то есть выполняется перенос данных обратно во временную область.
Зачем нужно было делать все вышеперечисленное? Теорема свертки утверждает, что свертка во временной области эквивалентна умножению в частотной области. Таким образом, в результате вышеперечисленных операций мы получаем значения корреляции для каждого варианта фазы PRN кода. Проанализировав, в какой месте получившегося массива значение превышает определенный порог, мы получаем значение фазы. Или не получаем, что означает, что на данной частоте нет сигнала от данного спутника.
GNSS-SDRLIB может формировать вот такие визуализации результатов acquisition:
На изображении приведены результаты N вышеприведенных вычислений для N перебираемых частот, для одного спутника.
Offset - это как раз фаза в выборках, а вот частота здесь подписана неверно, в действительности значения - не Hz, это просто значение индекса среди N перебираемых частот.
В программе алгоритм захвата находится в файле sdracq.c.
Я долго разбирался, что же не так с моими данными, в отладчике все выглядело адекватно.
Единственная остававшаяся проблема - неверно выставленные частоты в программе.
В презентации выше упомянуты частоты: ACQCLK=38.192 MHz и IF=9.548 MHz (1/4 ACQCLK). Такие же частоты упоминаются в книге [1].
А вот в Application Note APNT0012 упомянуты другие частоты: ACQCLK=38.194 и IF=9.45MHz.
Правда, если проанализировать структурную схему, можно определить коэффициенты деления и формулы, связывающие все частоты в микросхеме RF frontend. По ним первые частоты подходят, вторые - нет. Но есть явное ощущение, что тут что-то не так.
Чтобы вычислить истинные значения частот, нужно знать только частоту TCXO кварцевого генератора, использованного в моем приемнике. И с этим есть проблема - маркировка R2141 Y439 не находится в интернете, точного частотомера у меня нет (уже позже я выяснил, что это может быть Rakon Part 2141-24.5535MHZ). Покопавшись в интернете, я смог найди одну схему GPS приемника на таком же чипсете, и выяснил, что другие производители использовали с этим чипсетом TCXO на частоту 24.5535MHz.
Если по вышеупомянутым формулам вычислить частоты, то выходят неудобные дробные величины: ACQCLK=38.19433(3) MHz и IF=9.452333(3) MHz. Отношение ACQCLK/IF тоже становится здоровой дробью. Зато эти числа похожи на те, что в APNT0012, только там они, вероятно, округлены.
С новыми значениями частот программа смогла обнаружить сигнал от спутников в захваченных данных, что уже было серьезным прогрессом. А вот приема данных не было, опять проблема...
Теперь проблема связана со слежением (tracking) за данными со спутника.
Что представляет из себя трекинг? После захвата сигнала приемнику уже не нужно искать частоту сигнала со спутника и перебирать огромного количество возможных фаз PRN - эти значения он уже определил. Однако, частота в процессе захвата определяется грубо, плюс она будет меняться по мере движения спутника по небу. Скорость формирования кода PRN в приемнике тоже нужно подстраивать, также, как и фазу.
Источником данных о приеме служат результаты корреляции, только теперь число вычислений корреляции значительно меньше. В данном случае используется распространённый подход (Early, Prompt, Late), в котором принятые данные сравниваются со сгенерированным потоком PRN, сдвинутым на (-1/2;0;+1/2) чипа. Откуда дробные значения? Частота дискретизации АЦП значительно выше частоты PRN данных. Сравнивая результаты корреляции, можно оценить состояние трекинга.
В результате получается вот такой алгоритм трекинга:
В данном случае "NCO carrier generator" - программный генератор промежуточной частоты, его частоту подстраивает алгоритм PLL (phase locked loop).Перемножая входные данные с данными этого генератора, мы получаем данные, перенесенные на нулевую частоту в комплексной форме.
"E-P-L" - корреляторы, "PRN code generator" - формирователь кода PRN. Скорость формирования кода регулирует алгоритм DLL (delay lock loop).
Результаты работы корреляторов интегрируются и используются в дискриминаторах для определения коэффициентов коррекции. Дискриминаторы описываются довольно несложными математическими выражениями.
Замечу, что алгоритм трекинга анализирует входные данные блоками по одному периоду PRN-кода, то есть все вышеописанные операции нужно успеть выполнить за 1мс, причем для всех анализируемых спутников. Результаты трекинга (текущий результат корреляции) используется для выделения навигационных данных.
Программа GNSS-SDRLIB может выдавать результаты работы корреляторов для каждого спутника в виде графиков:
Откуда столько точек, если выше сказано, что корреляторов всего шесть?
В описании программы [2] сказано, что ней реализовано большее число корреляторов для исследовательских целей, для целей трекинга используются только три пары.
Число корреляторов, шаг между ними можно настраивать в GUI.
А вот в в моем случае на этих графиках был просто шум.
Также программа GNSS-SDRLIB может сохранять логи трекинга. Там присутствуют много данных, включая результаты корреляций, величины вычисленных коррекций. Построив график колонки IP, можно увидеть байты навигационных данных:
Хорошо видно в начале процесс выхода обратных связей алгоритмов трекинга на истинные значения от грубых, найденных во время acquisition.
В моем случае по такому же графику было видно, что небольшое время трекинг есть, но потом он "срывается":
Я довольно долго разбирался, в чем же тут проблема, и в итоге выяснил, что она была связана со слишком малым размером промежуточного буфера в cannelloni. Судя по всему, иногда в записанных данных возникали пропуски, а это приводило к сбою трекинга (так как нарушалась синхронизация). В итоге остановился на размере буфера - 131072 байта. Замечу, что отключение антенны от приемника на несколько секунд не приводит к нарушению трекинга.
Дальнейшие эксперименты
К этому этапу, у меня был софт, способный адекватно анализировать данные, записанные в файл. Работать в таком режиме с программой было неудобно (данные занимают очень много места), и я добавил в GNSS-SDRLIB поддержку своего приемника - то есть получение данных с него в реальном времени. Так как у меня уже были исходные коды cannelloni, это было не очень сложно.
Однако, как оказалось, скорость данных в 38 MSPS оказалась высоковата для GNSS-SDRLIB, так что мне пришлось в ПЛИС поделить входной тактовый сигнал на два.
В итоге прием данных заработал, как и ожидалось, однако периодически (раз в минуту или реже) трекниг терялся, причем для всех спутников сразу.
Для проверки я добавил в программу для ПЛИС формирование небольших последовательностей байт — маркеров, которые раз в 10 000 передаваемых байт подменяли данные с АЦП. Эти последовательности можно легко находить при анализе данных на ПК, с точки зрения обрабатывающего софта они являются просто слабыми помехами. Как оказалось, периодически данные все равно терялись, что нарушало синхронизацию. Найти причину, почему это происходит, я не смог, так что просто доработал анализ данных в GNSS‑SDRLIB — благодаря маркерам можно обнаружить потерю данных и не допустить потерю синхронизации.
В итоге удалось добиться полноценной работы приемника в режиме реального времени.
Таким образом я получил программу для ПК, которая может анализировать "сырые" данные, принимаемые GPS-приемником, определять фазы принятых сигналов с каждого спутника и выделять из потока данных навигационную информацию. Все полученные данные GNSS-SDRLIB может передать в более высокоуровневый софт для последующего анализа по протоколу RTCM через TCP. Именно этот высокоуровневый софт занимается вычислением координат приемника. Пример такого софта: RTKLIB.
Используя свой приемник, я смог успешно запустить RTKLIB:
Честно сказать, качество определения координат вышло так себе, из картинки выше видно, что разброс значений координат за несколько минут доходит до ±20м, и это - при 6 используемых спутниках.
Для сравнения, разброс координат, полученный при помощи приемника u-blox M8T (сырые данные от него тоже обработаны в RTKLIB):
Тут разброс координат около ±5м, и это при 5 используемых спутниках. Антенна использовалась та же самая.
Также я заметил, что программа GNSS-SDRLIB явно требует высокого уровня принимаемого сигнала для того, чтобы acquisition прошел успешно. То есть, к примеру, GNSS-SDRLIB адекватно захватывает сигналы только с 4 спутников, а сам приемник BT-318 (его микросхема GSP2e) в это же время захватывает данные уже с 6 спутников.
Во всех экспериментах я использовал активную антенну, установленную на подоконнике. Это приводит к тому, что принимать сигналы можно только с части неба, и соответственно, набрать в GNSS-SDRLIB 6 спутников с высоким уровнем сигнала можно не всегда.
Также для другого эксперимента я собрал небольшую плату с GNSS RF front-end MAX2769:
Эта микросхема удобна тем, что имеет специальный режим - Preconfigured Device State, в который ее можно переключить, подав единицу на вход PGM. Таким образом можно получить данные с микросхемы, не конфигурируя ее по SPI.
Я подключил эту плату вместо BT-318, отключил деление частоты на 2 в ПЛИС, поменял настройки частот в GNSS-SDRLIB - и конструкция успешно заработала. По моим ощущениям, MAX2769 имеет явно лучшую чувствительность, чем GRF2i (хотя MAX2769 тоже не молодая - времен 2007 года). Точность определения координат получилась аналогичная.
В GNSS-SDRLIB была заявлена поддержка спутников Galileo (они передают сигнал на той же частоте, что и GPS), но мне пришлось немного доработать программу, чтобы она начала обрабатывать и пересылать данные Galileo, однако по какой-то причине, нормально сигналы от них удалось обработать только в RTKLIB 2.4.2 p13.
В ходе экспериментов я внеc много разных доработок в GNSS-SDRLIB, результат выложен здесь: https://github.com/iliasam/GNSS-SDRLIB
Дополнительные ссылки:
Книга про построение программных GNSS приемников [1]: A Software-Defined GPS and Galileo Receiver: A Single-Frequency Approach
Описание программы [2]: GNSS-SDRLIB: An Open-Source and Real-Time GNSS Software Defined Radio Library, также есть презентация
Про то, как устроен C/A-код: Generating GPS L1 C/A pseudo-random noise (PRN) code with MATLAB and C/C++
Очень крутой проект GPS приемника из 90-х, собранного на аналоговых микросхемах, распространенных цифровых микросхемах и MC68010 в качестве CPU: A homemade receiver for GPS & GLONASS satellites. Также тут подробно описана теория работы GNSS систем.
Проект самодельного GPS приемника на ПЛИС, тоже неплохо описана теория: Homemade GPS Receiver