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

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

Просто приобрести готовый SDR‐USB — это не интересно, а вот реализовать что‐то подобное (Простой SDR приёмник на ПЛИС), только для FM диапазона, мне уже по душе.

В дополнение ко всему, в моих руках оказалась отладочная плата DE10‐Standart с ПЛИС на борту — излишне мощная и громадная для этой задачи игрушка. 

Нет смысла описывать все её возможности — кто знает тот знает, кому интересно — тот найдёт. Лучше опишу то, что пригодится в проекте мне:

  • ПЛИС собственной персоной

  • Параллельный внешний интерфейс GPIO на 36 контактов

  • Аудиовыход

Используемые возможности DE10
Используемые возможности DE10

Также, в процессе пришлось слегка использовать HPS ядро, но не залезая в него (об этом позднее).

Вероятно, для кого‐то информация будет не нова и где‐то весьма не корректна, но, всё равно, поделюсь некоторыми возможностями, которые я для себя обнаружил.

«Техническое» задание

Цель: Познакомиться с обработкой сигналов на практике и разработать «нечто», позволяющее услышать хотя бы намек на принятую радиостанцию.

Задачи:

  • Подготовить сигнал ФМ диапазона (98‐108 МГц) для оцифровки

  • Оцифровать сигнал для ПЛИС

  • Произвести цифровую обработку

  • Насладиться результатом

Проработка структуры проекта

Так как для прямой обработки сигнала мне необходима частота дискретизации от 216 МГц и выше, то сперва была мысль перенести спектр входного сигнала на нулевую частоту, потом податься в аналоговую схемотехнику, поэкспериментировать с фильтрами, смесителями, усилителями и прочей аналоговой шелухой. Но за неимением хорошего осциллографа, мне не захотелось вслепую возиться с этим.

Было бы проще использовать высокоскоростной АЦП с параллельным интерфейсом, но сколько бы я не искал дешевый, доступный, не требующий какойто сложной топологии платы. Я такой не нашёл. Максимально удовлетворяющий мне по цене, но не по частоте дискретизации, оказался 8‐ми битный AD9057 на 80 MSPS.

Немного расстроившись, я стал размышлять над двумя путями:

  • либо работать в третьей зоне Найквиста 

  • либо придумать метод как взять отсчеты сигнала чаще чем получается.

АЦП с чередованием во времени
АЦП с чередованием во времени

Не знаю какие злые силы меня навели на следующую цепочку мыслей. Если АЦП берет отсчеты 80 млн раз в секунду, то почему бы не взять три АЦП, которые будут работать параллельно, но каждая запустится чуть позже. Да и, тем более, ПЛИС позволяет довольно точно настраивать тактовые сигналы. Что может пойти не так? В крайнем случае, если не получится, я всегда смогу использовать только один АЦП и работать в третьей зоне Найквиста.

Оказалось

Довольно поздно я обнаружил, что изобрел велосипед и имя ему «timeinterleaved adc» или «АЦП с чередованием во времени». Им иногда пользуются, хотя он и имеет свои недостатки.

Структура АЦП
Структура АЦП

Таким образом, блок схема платы аналогоцифрового преобразования выглядит до безобразия просто.

Преобразования структуры приемника

Разработка платы

Рецепт принципиальной схемы максимально прост. На порцию для трёх АЦП режем входной сигнал с помощью разветвителя из резисторов, разделяем аналоговое и цифровое питание по вкусу, посыпаем обильным количеством конденсаторов, раскладываем цифровые интерфейсы по разъемам PBD.

Схема подключения АЦП
Схема подключения АЦП

Смещение сигнала обеспечивается внутренним резистором АЦП. Больше здесь сказать нечего :)

Фото платы
3D модель платы
3D модель платы
Изготовленная плата
Изготовленная плата

Позаботься о тестовом сигнале

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

Аудиосигнал

Пустить под модуляцию обычную синусоиду — скучно. Поэтому, чтобы было веселее страдать, я принял решение синтезировать мелодию.

Примерный алгоритм действий:

  1. Определил перечисляемым типом ноты от «ля» малой октавы до «си» второй октавы и для каждой ноты свой делитель опорной частоты;

  2. Записал два массива: первый — с последовательностью нот в мелодии, второй — с длительностью нот;

  3. Запустил счетчик от 0 до N−1 количества нот и проходил по всем массивам;

  4. В зависимости от ноты на выход подавался сигнал с определенной частотой.

Генерация мелодии
Генерация мелодии

Частотная модуляция

Сперва была реализация «в лоб» и звуковой сигнал генерировался путем деления частоты тактового генератора.

Для частотного, в данном случае, манипулирования я создал с помощью PLL два тактовых сигнала на 99,96 МГц и 100,04 МГц. Таким образом, если в звуковом сигнале логическая единица, то на выходе частота 100,04 МГц, если логический ноль — то 99,96 МГц. Этот сигнал был выведен через обычный разъем GPIO к которому подключен провод ~70 см длиной.

Радио в смартфоне, настроенное на частоту 100 МГц, прекрасно принимало сигнал на расстоянии до 10 метров.

Визуализация ЧМ
Визуализация ЧМ

Улучшенный синтезатор

После этого я приступил ко второй реализации чуть более грамотнее.

В качестве генерирования чистых нот (синусоид) использовал встроенное IP‐ядро NCO, благодаря чему, у меня было от 10 бит качественного звука. Для желаемой частоты ноты мне достаточно было менять только значение приращения фазы. Прослушивание синтезируемой мелодии я выполнил через встроенный в отладочную плату разъём Jack.

Как?

Для этого я взял файл из демонстрационного проекта, который работает с данным кодеком, и «прикрутил» к нему простой интерфейс Avalon‐ST Sink. Только не забываем добавить в проект модули настройки аудио кодека по I2C.

Сама частотная модуляция теперь уже не выходила за границы отладочной платы и реализовывалась с помощью второго NCO ядра, настроенного на частоту 100 МГц, и дополнительной галочки Frequency Modulation Input. Ко входу значения приращения фазы добавляются дополнительные младшие биты для модулирующего (звукового) сигнала.

Улучшенный синтезатор
Улучшенный синтезатор

Полезности

Поделюсь информацией, которую я обнаружил в процессе разработки, и, которая помогла в настройке, но в конце исключил из реализации. Вдруг комуто пригодится и поможет.

Анализ сигнала в матлаб

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

Конечно, это можно было бы попробовать реализовать внутри ПЛИС, либо перенести данные в Линукс, но я пошёл по более костыльному методу, и решил его как то вытащить на компьютер

Так как я уже более менее был знаком с цифровой обработкой в среде MATLAB, то начал копать в эту сторону. Да и сам MATLAB везде кричит что он самый мощный инструмент для всего. И (о пламя!) я нашёл очень, как мне кажется, полезный инструмент AXI Master Read (и Writer).

Matlab позволяет синтезировать специальные IP‐ядра, которые можно подключать в проекте ПЛИС и считывать данные с памяти по интерфейсу Ethernet или JTAG. Кстати, последнему не нужно назначать сигналы в Assignment Editor, он сам всё знает и подключится без посторонней помощи.

На стороне ПК в Simulink используется блок AXI Master Read, в котором нужно указать сколько и с какого адреса хочешь считать данные. Конечно, скоростей больших с JTAG не добьешься, но хоть что‐то. Вполне доступное описание есть на официальном сайте.

AXI Master Read
AXI Master Read

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

С аудиосигналом попроще — мне удалось считывать данные с частотой дискретизации 200 кГц. Правда, есть нюанс с синхронизацией и данные приходят «рваные» — с этим придётся ещё повозиться.

Увеличение пропускной способности

На имеющейся отладочной плате со стороны ПЛИС подключена SDRAM, работать с которой я смог на максимальной частоте лишь ~130 МГц. При работе с видеосигналом такой частоты не хватает для больших разрешений.

С другой стороны, на отладочной плате присутствует довольно мощное HPS ядро с 1GB памяти DDR3, но, как я уже говорил, в Linux мне лезть не хотелось, и какова же была моя радость что мне не пришлось.

Оказалось, что ПЛИС тоже может воспользоваться этой памятью. Нет,  я конечно это знал, но не понимал каким образом. По простому, для этого можно взять ядро hps процессора из демонстрационного проекта GHRD отладочной платы, выкинуть всё ненужное и использовать его как ядро памяти.

Единственное, что для настройки проекта пришлось сделать следующие танцы с бубном:  я оставил сигналы reset; перед компиляцией пришлось с генерировать tcl‐скрипты hps; после компиляции файл прошивки переконвертировать в rbf (конвертер также имеется в демонстрационном проекте); закинуть на flash с образом Linux и установить MSEL на запуск HPS. (читаем My_First_hps)

Схема использования DDR3
Схема использования DDR3

В своё время мне не хватало этой информации и я не знал что всё так просто.

Собственно, сам цифровой приемник

Фильтрация на ПЛИС

Глубокой теории  я расписывать не буду, так как её описывали все кому не лень, и сравнений фильтров тоже великое множество. Жестких требований к фильтрации я себе не ставил, просто было интересно их практическое применение. 

Сперва я перепробовал фильтры в Simulink через Filter Designer, пытался сгенерировать из него сразу в Verilog код (мне не понравилось). Тогда, всё таки, сдался и использовал ядро от Altera FIR, разобрался как туда экспортировать коэффициенты из MATLAB.

Скрытое негодование

Ну вот могли бы уже добавить функцию в Matlab — создавать коэффициенты сразу через запятую, в одну строчку, как надо для ядра Altera!

Тысячу и один раз прочитал и выучил на dsplib статьи по CIC фильтрам и дециматорам. Вроде разобрался, но сомневаюсь. 

Из всех манипуляций, проб и ошибок я пришел к следующей структуре приемника (его половине).

Так как на входе три параллельных шины данных, то необходимо их преобразовать в последовательные данные на частоте 240 МГц, но я беспокоился что ПЛИС не будет успевать при таких частотах выполнять математические действия (поправьте если не так). Поэтому, для переноса спектра на нулевую частоту, последовательные данные с гетеродина (синус и косинус), также преобразовываются в три параллельных и умножаются с входным оцифрованным сигналом. Результаты произведения просто суммируются и частота дискретизации сигнала становится 80 МГц.

Вероятно правильное решение

Если честно, я пробовал интегрировать вместо сумматора самописный CIC фильтр с децимацией R=3, но, вероятно, его простая реализация была некорректна, так что я оставил идею его отработки до лучших времён.

Структура фильтрации
Структура фильтрации

Следующими каскадами идут две пары CIC фильтра с порядком N=2, задержкой D=2, и с децимацией  25 и 16, соответственно. От корректирующего фильтра решил принципиально отказаться, предполагая что сильных искажений я не получу. 

В итоге, на выходе фильтров имеются данные с частотой дискретизации 200 кГц.

Чистосердечное

Наверное, стоит признаться, что в конечной реализации приемника я снизил частоту дискретизации до 90 МГц, и работаю в третьей зоне Найквиста. При этом второй фильтр имеет децимацию R=6, но также используются все три АЦП на 30 МГц (вдруг мне, всё таки, бракованные приехали и не выносят высоких частот).

Реальная структура фильтрации
Реальная структура фильтрации

Демодуляция

Это оказалось самой больной темой. Не изза сложности, а изза множества структурных схем в разных источниках. Все они одинаковые и разные одновременно. Я проверил их в Simulink и в теории они работали, но в теории всегда всё работает, а на практике…

Такие одинаковые, но такие разные

Для реализации «Only FPGA» желательно избегать делителей и тригонометрических функций, поэтому схему демодулятора я выбрал самую простейшую.

Выбранный демодулятор
Выбранный демодулятор

В реализации «FPGA‐PC» квадратурные составляющие принимаемого сигнала передаются в Simulink, в котором имеется готовый блок демодуляции. После него стоит фильтр низких частот чтобы уменьшить шум.

Модель Simulink
Модель Simulink

Результаты

Результаты более‐менее удовлетворительные. 

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

С реальными сигналами всё хуже, но(!), самое главное, я смог поймать некоторые радиостанции, хоть и с плохим звуком (честно я отчаялся хоть чтото услышать). Лучше всего различимы станции только с речью.

Звук очень зашумленный, и в реализации, где данные передаются на ПК, хоть и можно поставить фильтр, подавляющий большинство шумов, но, как я и говорил, изза рассинхронизации передачи данных, звук дополнительно искажается.

При попытке записать результат с аудио разъема Jack в аудиофайл, я снова случайно использовал Simulink, где могу принять звук с микрофона, слегка его обработать, установить фильтр для подавления высокочастотных шумов и удобно записать аудиосигнал в файл.

Запись в файл
Запись в файл

Впечатления

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

Конечный результат
Конечный результат

Интересно будет почитать комментарии и о технических ошибках, замеченных в ходе действий над проектом. Только не сильно строго, а то я брошу электронику и уйду в монастырь художником :) (Шучу, кто‐то же должен вам подпекать).

Ссылка на кусочки ip‐ядер из проекта

Ссылка на аудио принятых радиостанций

По поводу аудио

К сожалению, записи с лучшим звуком я не могу выложить из–за их содержания.

Домашнее задание

  1. Если у вас имеются несложные Linux проекты для платы DE10‐Standart (или подобных), то поделитесь пожалуйста. Хотелось бы уметь обрабатывать данные, записанные в память, или хотя бы передавать по Ethernet на ПК (по‐любому же есть простые реализации).

  2. Если у кого‐то завалялась в тумбочке мощная нейросеть и нормальный АЦП на частотах от 220 МГц, не хотите ли поэкспериментировать и научить нейросеть самой принимать,  фильтровать и демодулировать сигнал. Я понимаю, что её основной принцип это классифицировать, но вдруг :) Либо можете развернуто в комментариях описать почему это невозможно (но вы еще даже не пробовали).

Используемая литература

  1. Лайонс Р. Цифровая обработка сигналов

  2. Implementation of a software defined FM mixed demodulator on FPGA November 2015

  3. FPGA Implementation of an IF Sampled FM Receiver

  4. Демодуляция сигналов с угловой модуляцией. PM и FM демодуляторы

  5. Interleaved ADCs Through the Ages. Ken Poulton. Keysight Laboratories

Комментарии (25)


  1. engine9
    10.12.2023 07:27

    Мне кажется, что ЧМ сигнал УКВ диапазона довольно просто получается из схемы передатчика на одном КТ315 + источника аудиосигнала, типа переносного MP3 плеера.


    1. johnfound
      10.12.2023 07:27

      И принимается тоже прекрасно на приемнике из еще двух-трех KT315.

      Автор нагородил такое, что я думал хочет супер приемник с ИИ и автоматическое распознавание голоса. А получилось:

      я доволен любому словечку и звуку принятых радиостанций.


      1. pz4k
        10.12.2023 07:27

        Разумеется можно собрать простейшие передатчик и приёмник. Либо приобрести готовый SDR USB-свисток и играться с ним.

        Но целью было попробовать обработку сигналов на ПЛИС, а не собрать устройство, реализация которого пойдёт в народ.


        1. Alyoshka1976
          10.12.2023 07:27

          Есть еще и сверхдлинноволновый диапазон. Там сигнал не модулирует несущую частоту, а передается как есть. На приемной стороне рамочная антенна, простейший усилитель ЗВУКОВОЙ (!) частоты (один/два каскада), а дальше ЦОС. Можно попытаться и без усилителя, но там будут микровольты, АЦП может не вытянуть. ЦОС - от спектрального анализа (ведь принята будет смесь всех-всех сигналов, даже от молний) до интегрирования сигнала на известной частоте (это если пытаться совсем слабый сигнал принять, от любителя из-за океана, например). Морзянку можно в текст переводить (там азбука Морзе до сих пор в ходу). Но понятным, чаще всего, будет только позывной, OTP как говорится rulezzz :-)


    1. leshabirukov
      10.12.2023 07:27

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


    1. Serge78rus
      10.12.2023 07:27

      Только в таком простейшем передатчике модуляция будет скорее всего представлять смесь ЧМ и АМ. Это вполне сносно для того, чтобы услышать что-либо на ЧМ приемник. Но для исследовательских целей, преследуемых автором, необходимо иметь источник сигнала с "правильной" модуляцией.


  1. semennikov
    10.12.2023 07:27

    Не совсем понял Вашу схему с несколькими АЦП, там же должны стоять на каждом канале устройства выборки-хранения, иначе будет сильный шум из-за времени преобразования АЦП и плохой синхронизации начала преобразования. Или я чего то не понял в Вашей схеме?


    1. AndronNSK
      10.12.2023 07:27

      Все так.

      Такие схемы раньше применялись, но на высоких частотах.


    1. pz4k
      10.12.2023 07:27

      Я подозревал, что будут проблемы в синхронизации преобразования АЦП, но пренебрёг ими слегка :)


    1. VT100
      10.12.2023 07:27

      УВХ уже встроен в АЦП: https://doc.mymsk.cloud/analog.com.datasheet/ad9057/AD9057.pdf

      А вот питание входа через резисторы (какого номинала?) - первый шаг к GIGO. @pz4k , плату AFE надо переделывать!


  1. semennikov
    10.12.2023 07:27

    И еще - перенести на нулевую частоту очень просто если у Вас есть хороший генератор(а он есть в FPGA), да и осциллограф написать в FPGA совсем не трудно. Да и вообще там настолько примитивные аналоговые решения что и отлаживать не надо, сами заработают. :-)


    1. pz4k
      10.12.2023 07:27

      Перенос на нулевую частоту с помощью генератора от ПЛИС — было моей самой первой идеей. Было несколько черновых вариантов, которые я немного запорол, и пошёл пути максимального отказа от аналоговой части.

      Осциллограф на FPGA — может быть когда нибудь :)


  1. HardWrMan
    10.12.2023 07:27

    Разнесение АЦП во времени для повышения эффективной частоты преобразования давно применяется в цифровых осциллографах.


    1. ABRogov
      10.12.2023 07:27

      Да что там в осциллографах, даже в простых контроллерах STM32 такой режим есть из коробки.


  1. Iustinianus
    10.12.2023 07:27

    Приветствую!

    Как разработчик аналоговых СВЧ устройств могу порекомендовать Вам собрать RF-front-end (называю этим термином участок тракта от антенного разъема до входа АЦП демодулятора) на широко известной микросхеме SA676. Это приемник ЧМ-сигнала со смесителем и усилителем-ограничителем, с переносом спектра на 455 кГц и последующим аналоговым демодулятором. Вот узел демодулятора Вам не нужен, выход ПЧ 455 кГц отправите на АЦП с частотой до 1 MSps, а дальше будете заниматься чистым ЦОС на ПЛИС без всякой аналоговой бесовщины. :) На неё есть подробная спецификация, с примером топологии печатной платы. Чувствительность на уровне на минус 110 дБмВт.

    Если интересно - могу написать подробнее или вообще сделать пост.


    1. pz4k
      10.12.2023 07:27

      Спасибо за наводку)

      Я думаю если есть вдохновение на подробный пост/гайд, который может помочь кому-то в работе, то почему бы и не написать? :)


      1. Iustinianus
        10.12.2023 07:27

        Хм... Извините, я Вам дал слишком сложный путь для движения.

        Вам нужна микросхема AD608 (есть в Чип-Дипе). У Вас получится супергетеродинный приемник с одним преобразованием частоты. Схема электрическая принципиальная - рисунок 24 спецификации на микросхему. Из, возможно, непонятных компонентов:

        1. "10.7 MHz BPF" - керамический фильтр на 10.7 МГЦ с полосой пропускания 150 кГц (для broadcast FM приложений, есть целая куча в Чип-Дипе); отвечает за фильтрацию помех (коими, в данном случае, являются все радиостанции кроме нужной).

        2. На значок "полярности" у конденсаторов не обращайте внимания, нужны обычные керамические.

        3. RF input - к антенне.

        4. "LO input" - вход гетеродина первой ПЧ, как раз пригодится Ваша разработка синтезатора частот на ПЛИС. Частоту, соответственно, ставите равной частоте принимаемой радиостанции минус 10.7 МГц. Фильтрацию из прямоугольника в синус можно не делать, пострадает избирательность по побочным каналам приема, для задачи "поиграться с ЦОС" неважно.

        5. "Limiter Out" - выход ПЧ частотой 10.7 МГц, с отфильтрованными помехами, отправляете на АЦП.

        6. RSSI - выход логарифмического детектора принятого сигнала, оценивает в шкале некоторых условных "попугаев" мощность радиочастотного сигнала на входе антенны (уровень шумов - условно ноль - сигнал слабый, менее минус 80 дБмВт, с ростом сигнала растет RSSI; максимальное значение зависит от питания).

        Печатную плату для аналоговой части (AD608) нужно спроектировать со сплошным полигоном "земли" на слое "bottom", соединение "земель" цифровой части и аналоговой чсти сделайте небольшой узкой "шейкой", у Вас этого будет достаточно для минимизации шумов.

        На отдельный пост не тянет. :)


  1. iggr63
    10.12.2023 07:27

    Автор молодец! И ничего себе самоделки пошли - на Cyclone 5+ARM. и даже с интерливингом и мултиплексированием. Имею в виду цифровые. Аналоговые приемники совсем другая тема. На HackRF и GNUradio не смотрели? Вот например На Хабре


  1. NutsUnderline
    10.12.2023 07:27

    велосипед, красивый. это уже почти полноценный sdr где АЦП все таки побыстрее, но ПЛИС хорошо находят в себя. можно взять готовое железо типа HackRF/portapack и сосредоточиться только на программировании ПЛИС


    1. iggr63
      10.12.2023 07:27

      Точно. Я на ZCU102 c мезонинным модулем АЦП залил с гитхаба битстрим анализатора спектра и оно заработало!


  1. Victor_Panic
    10.12.2023 07:27

    А не желаете попробовать совместный проект на эту же тему, но потенциально с практически применением впоследствии?


  1. dmitriyrudnev
    10.12.2023 07:27

    Ради интереса попробовал принять что-нибудь в диапазоне FM на плату из своего проекта Selenite Lite с отключенным диапазонным полосовым фильтром, естественно

    Вот так она принимает в Перми Маяк на обыкновенный "детектор Тэйло"

    Схема, для справки, в этом файле: https://github.com/dmitrii-rudnev/selenite-lite/blob/main/_documents/Selenite Lite User Manual.pdf


  1. Gudd-Head
    10.12.2023 07:27

    я беспокоился что ПЛИС не будет успевать при таких частотах выполнять математические действия (поправьте если не так)

    По моей практике в основном всё упирается в быстродействие встроенных умножителей. Частоты и разрядность для них указаны в даташите.


    1. iggr63
      10.12.2023 07:27

      И Quartus вам скажет "timing criteria not met" .


  1. supermaxus
    10.12.2023 07:27

    >режем входной сигнал с помощью разветвителя из резисторов

    с помощью резистров изменить фазу не получится. возможны варианты только с помощью конденсаторов и индуктивностей.

    без осциллографа разрабатывать электронные схемы вообще не имеет смысла. потому что реальные радиодетали не всегда ведут себя так, как в программе эмуляции.

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