Использование модуля FFT совместно с NIOS

image
В этой статье я хочу рассказать про работу с аппаратным модулем FFT (БПФ). Используя этот модуль, можно получить спектр входного сигнала. Для обработки и отображения полученных от FFT данных используется SOPC с софтовым процессором NIOS II. Данный проект является продолжением предыдущего: Захват данных от АЦП с использованием NIOS II.



В данном проекте используется модуль FFT, входящий в состав Quartus. Для передачи данных в модуль и чтения из него обработанных данных используются шины Avalon-ST. Именно при помощи такой шины в предыдущем проекте шла передача данных от АЦП в SOPC. Таким образом, SOPC из предыдущей статьи хорошо стыкуется с модулем FFT, и не требует никаких модификаций. Модуль формирования управляющих сигналов «FFT_CTRL» оттуда также можно использовать для управления модулем FFT.

Настройки модуля FFT:

Как видно, модуль обрабатывает 512 выборок данных, разрядность входных и выходных данных — 16 бит.
Метод приема чтения и записи данных в модуль — Burst. При вводе настроек можно видеть, какие ресурсы ПЛИС будет использовать выбранная реализация модуля.

Режим работы FFT — Burst выбран по причине меньших требований к ресурсам ПЛИС, и простоты передачи данных.
Для того, чтобы загрузить данные в модуль FFT, источник данных должен дождаться от FFT сигнала готовности — sink_ready. После этого источник должен передать сигнал sop и 512 пар-выборок данных (у FFT два входа данных — для действительной и мнимой части). В конце источник передает сигнал eop. Полученные данные сохраняются в памяти модуля.
Далее модуль FFT начинает выполнение расчетов. Длительность расчета можно узнать при настройке параметров FFT — в графе Transform Calculation Cycles.
После завершения расчетов модуль начинает ждать от приемника (в нашем случае это SOPC) разрешения на передачу данных, при этом модуль проверяет состояние линии sourse_ready. После того, как приемник выставит на этой линии 1, модуль FFT начинает передачу данных. От так же передает 512 пар данных, и формирует сигналы sop, eop, ready, которыми управляет приемником.
При передаче данных приемнику, вначале предаются данные о положительной области спектра (N/2 выборок), затем данные об отрицательной области (оставшиеся N/2 выборок).

Данные выдаются в формате Block Floating Point, подробное описание которого есть здесь. Для того, чтобы расширить диапазон значений, выдаваемых FFT, кроме двух шин комплексных данных, используется специальная шина экспонент, значение которой указывает, на сколько бит нужно сдвинуть результаты преобразования в определенную сторону.
Так как данные могут сдвигаться влево, то разрядность результата увеличивается.

Так как меня интересовала форма спектра сигнала, подаваемого на АЦП, то для вычисления амплитуд точек спектра на Verilog был написан специальный модуль, вычисляющий корень из суммы квадратов действительной и комплексной части выходных данных FFT модуля. Этот модуль вошел в состав модуля «FFT_CONV», который выполняет сдвиг значений рассчитанной амплитуды на нужную величину. 32-битный выход этого модуля модуля напрямую связан со входом шины Avalon-ST SOPC.

Для проверки работы FFT в качестве источника данных был использован NCO — numerically controlled oscillators. Этот модуль, входящий в состав Quartus, предназначен для формирования гармонического сигнала нужной частоты. Модуль имеет вход тактовой частоты, и входную шину данных, значение на которой определяет частоту формируемого сигнала.
Настройки используемого NCO:

Как видно, используемый метод формирования сигнала — CORDIC, разрядность аккумулятора (совпадающая с шириной входной шины данных) — 24 бита, разрядность выходных данных — 16 бит. При частоте тактирования 50кГц для формирования частоты 5кГц на входной чине должно выть значение 1677722. На графике внизу показан спектр формируемого сигнала (при указанной частоте выходного сигнала).
NCO может выдавать данные со сдвигом в 90 градусов — на разные выходы, которые в моем случае подключены прямо к входу модуля FFT.

Как упомянуто выше, для формирования сигналов sop, eop, valid используется модуль «FFT_CTRL» из предыдущего проекта. Для запуска захвата сигнала NIOS посылает на этот модуль стартовый сигнал.
Вид всей системы в Quartus:


Программа для NIOS не сильно отличается от программы из предыдущей статьи — захват данных происходит абсолютно таким же образом, изменения только в части вывода данных на экран.
Вид спектра сигнала от NCO:


Заметно, что спектр достаточно широкий, что не соответствует ожиданиям — на графике в настройках NCO спектр сигнала узкий. Это связано с краевыми эффектами в начале и конце обрабатываемой выборки данных. Для устранения этого эффекта приходится использовать умножать данные, подаваемые на вход FFT, на оконную функцию. Фактически, каждую выборку данных перед передачей на FFT нужно умножить на некое число, зависящее от номера выборки. Вычислить на ходу в ПЛИС оконную функцию достаточно сложно, намного проще вычислить ее на компьютере, и сформировать таблицу значений, которая далее будет использоваться для обработки данных.
Схема модуля, выполняющего умножение на оконную функцию:

Этот модуль, так же как и FFT, управляется сигналами от модуля «FFT_CTRL». 9-разрядый счетчик, входящий в него, используется для выборки из ROM нужного значения, на которое умножаются входные данные.
Для загрузки в ROM требуется набор чисел, соответствующий выбранной оконной функции. Я выбрал окно Ханна и посчитал значения этой функции в Mathcad:

После этого значения функции нужно преобразовать так, чтобы максимальным значением в таблице было 2^15.
Далее результат экспортировался в текстовый файл, который вручную переводился в файл стандарта mif: описание. В проекте этот файл называется «window_lut2.mif».
Так как на выход модуля передаются только старшие 16 бит данных из 32, получаемых после умножения, то в результате получается, что входной сигнал оказывается умножен на число в диапазоне от 0 до 1.

Вид системы в Quartus с использованием оконной функции:


Вид спектра сигнала от NCO с использованием оконной функции:


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

После этих проверок можно подключить к системе реальный АЦП. В данном случае, используется тот же модуль для работы со встроенным АЦП платы DE0-nano, что и в предыдущей статье. Так как нулевое напряжение за счет резисторного делителя напряжения смещается в середину диапазона АЦП, то для формирования правильного знакового результата приходится вычитать из данных АЦП 2048 единиц.

Пример спектра сигнала, формируемого аудиокартой компьютера, имеющего частоту ~2.5кГц и амплитуду 10 мВ.

На частоте ~18кГц имеется постоянная помеха, идущая от компьютера.

Видео работы (источник сигнала — аудиокарта):


Ссылка на проект: www.dropbox.com/s/6t2wa1ppkz9uph2/fft1_vga.zip?dl=0
  • +10
  • 21 августа 2014, 22:42
  • citizen

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

RSS свернуть / развернуть
А зачем нам отрицательные частоты? Зачем их видеть, если они зеркально отображают спектр в правой части?
0
Это образовательный момент…
0
Если сигнал комплексный, то отрицательные частоты имеют смысл — при работе с NCO это видно.
При работе с АЦП от отрицательной области действительно нет смысла, но программу я изменять не стал.
0
Автору респект, решил задачу, которую я тоже недавно решал: БПФ из Ниоса.
Но я решил немного по-другому. Дарю бесплатно: есть халявная корка bel_fft, которая цепляется как мастер шины авалон.
В Ниосе надо ей выделить память под результат, сказать откуда брать выборки и отдать команду на запуск. Сама вычитает из памяти выборки, сделает хардовый БПФ и положит в память результат. Очень удобно, и, главное, просто.

С оконными функциями я бы прикрутил к Ниосу Custom Instruction и через него бы прогнал все выборки. Или написал аналогичного мастера для авалона. Но если работать с выборками в памяти.
0
  • avatar
  • Ezhik
  • 27 августа 2014, 13:26
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.