Этот вопрос касается реализации фильтра БИХ в ПЛИС со срезами DSP, с очень конкретными критериями.
Допустим, вы делаете фильтр без прямых нажатий и только с одним обратным касанием, с этим уравнением:
(см. изображение)
В качестве примера возьмем срез DSP48A1 от Xilinx - большинство жестких срезов IP DSP схожи.
Допустим, у вас есть аналоговые данные, поступающие на 1 выборке за такт. Я хотел бы разработать БИХ-фильтр, который работает синхронно на тактовой частоте.
Проблема в том, что для запуска среза DSP с максимальной скоростью вы не можете умножать И добавлять в одном цикле. Вы должны иметь конвейерный регистр между этими компонентами.
Таким образом, если у вас есть 1 новый семпл на такт, вам нужно будет генерировать 1 выход за такт. Тем не менее, вам нужны предыдущие выходные 2 такта, прежде чем вы сможете создать новый в этом проекте.
Очевидным решением является либо обработка данных с двойной тактовой частотой, либо отключение конвейерного регистра, чтобы вы могли умножать и добавлять в одном цикле.
К сожалению, если, скажем, вы производите выборку с максимальной тактовой частотой полностью конвейерного среза DSP, ни одно из этих решений невозможно. Есть ли другой способ построить это?
(Бонусные баллы, если вы можете создать БИХ-фильтр, который работает на половине частоты дискретизации, используя любое количество срезов DSP)
Цель состоит в том, чтобы запустить компенсационный фильтр для АЦП 1 GSPS в FPGA Xilinx Artix. Их срезы DSP могут работать на частоте чуть более 500 МГц при полной конвейеризации. Если есть решение для 1 выборки за такт, я хотел бы попробовать масштабировать решение для 2 выборок за такт. Это все очень просто с помощью фильтра FIR.
Ответы:
Я еще не работал с фильтрами БИХ, но если вам нужно только рассчитать данное уравнение
один раз за цикл процессора, вы можете использовать конвейерную обработку.
В одном цикле вы выполняете умножение, а в одном цикле вам необходимо выполнить суммирование для каждой входной выборки. Это означает, что ваша FPGA должна быть способна выполнять умножение за один такт при тактировании с заданной частотой дискретизации! Тогда вам нужно будет только выполнить умножение текущего сэмпла И суммирование результата умножения последнего сэмпла параллельно. Это приведет к постоянной задержке обработки в 2 цикла.
Хорошо, давайте посмотрим на формулу и спроектируем конвейер:
Код вашего конвейера может выглядеть так:
Обратите внимание, что все три команды должны выполняться параллельно и что «выходные данные» во второй строке, следовательно, используют выходные данные из последнего тактового цикла!
Я мало работал с Verilog, поэтому синтаксис этого кода, скорее всего, неверен (например, отсутствует битовая ширина входных / выходных сигналов; синтаксис выполнения для умножения). Однако вы должны понять:
PS: Может быть, какой-нибудь опытный программист Verilog мог бы отредактировать этот код и впоследствии удалить этот комментарий и комментарий над кодом. Спасибо!
PPS: В случае, если ваш коэффициент «b1» является фиксированной константой, вы можете оптимизировать проект, внедрив специальный множитель, который принимает только один скалярный вход и рассчитывает только «времена b1».
Ответ: «К сожалению, это на самом деле эквивалентно y [n] = y [n-2] * b1 + x [n]. Это из-за дополнительной стадии конвейера». как комментарий к старой версии ответа
Да, это было действительно правильно для следующей старой (НЕПРАВИЛЬНОЙ !!!) версии:
Надеюсь, теперь я исправил эту ошибку, задержав входные значения во втором регистре:
Чтобы убедиться, что на этот раз все работает правильно, давайте посмотрим, что происходит в первые несколько циклов. Обратите внимание, что первые 2 цикла производят более или менее (определенный) мусор, так как предыдущие выходные значения (например, y [-1] == ??) недоступны. Регистр y инициализируется 0, что эквивалентно предположению y [-1] == 0.
Первый цикл (n = 0):
Второй цикл (n = 1):
Третий цикл (n = 2):
Четвертый цикл (n = 3):
Мы можем видеть, что, начиная с cylce n = 2, мы получаем следующий вывод:
что эквивалентно
Как уже упоминалось выше, мы вводим дополнительный лаг из l = 1 циклов. Это означает, что ваш вывод y [n] задерживается на lag l = 1. Это означает, что выходные данные эквивалентны, но задерживаются на один «индекс». Чтобы быть более понятным: выходные данные задерживаются на 2 цикла, так как необходим один (нормальный) тактовый цикл и добавляется 1 дополнительный (lag l = 1) тактовый цикл для промежуточной ступени.
Вот эскиз, чтобы графически изобразить поток данных:
PS: Спасибо, что внимательно ознакомились с моим кодом. Так что я тоже кое-чему научился! ;-) Дайте мне знать, если эта версия верна или вы видите какие-либо проблемы.
источник
y[n+l] = y[n-1] * b + x[n]
фиксированное значение для задержки,l
которую можно переписать,y[n] = y[n-1-l] * b + x[n-l]
и для l = 1 это такy[n] = y[n-2] * b + x[n-1]
.y[n+l] = x[n] * b0 + x[n-1] * b1 - y[n-1] * a1 - y[n-2] * a2
=>y[n] = x[n-l]*b0 + x[n-1-l] * b1 - y[n-1-l] * a1 - y[n-2-l]*a2
. Предполагая, что вы можете делать все три умножения параллельно (1. этап / 1 цикл) и вам нужно сделать то, чтобы сложить продукты вместе, вам нужно 2 цикла (1 цикл: добавление / подстановка первых двух результатов продукта, 1 цикл: сложение / добавление) результат этих двух дополнений / сабов), вам потребуется 2 дополнительных цикла. Итак, l = (3-1) = 2 дает вамy[n]=x[n-2]*b0+x[n-1-2]*b1-y[n-1-2]*a1-y[n-2-2]*a2
=>y[n]=x[n-2]*b0+x[n-3]*b1-y[n-3]*a1-y[n-4]*a2
Да, вы можете часы на частоте дискретизации.
Решением этой проблемы является манипулирование исходным выражением, чтобы можно было вставить конвейерные регистры, сохраняя при этом требуемую выходную последовательность.
Дано: y [n] = y [n-1] * b1 + x [n];
этим можно манипулировать следующим образом: y [n] = y [n-2] * b1 * b1 + x [n-1] * b1 + x [n].
Чтобы убедиться, что это та же последовательность, рассмотрим, что происходит с первыми несколькими выборками x [0], x [1], x [2] и т. Д., Где до x [0] все x, y выборок были нулевыми.
Для исходного выражения последовательность:
Понятно, что необходимо, чтобы b1 <1, иначе это будет расти без границ.
Теперь рассмотрим манипулируемое выражение:
Это та же последовательность.
Аппаратное решение в примитивах библиотеки Xilinx потребовало бы двух DSP48E в каскаде. Обратитесь к рисунку 1-1 в UG193 v3.6 для порта и имен регистра ниже. Первый примитив умножается на b1 и добавляет один такт позже; вторая умножается на b1 * b1 и добавляет один такт позже. Для этой логики существует задержка конвейера в 4 такта.
- DSP48E # 1
a_port1: = b1; - постоянный коэффициент, установите AREG = 1
b_port1: = x; - установить атрибут BREG = 1
c_port1: = x; - установить CREG = 1
- внутренний для DSP48E # 1
reg_a1 <= a_port1;
reg_b1 <= b_port1;
reg_c1 <= c_port1;
reg_m1 <= reg_a1 * reg_b1;
reg_p1 <= reg_m1 + reg_c1; - выход 1-го DSP48E
- конец DSP48E # 1
- DSP48E # 2
a_port2: = reg_p2; - установить атрибут AREG = 0
b_port2: = b1 * b1; - постоянная, установите BREG = 1
c_port2: = reg_p1; - установить CREG = 1
- внутренний для DSP48E # 2
reg_b2 <= b_port2;
reg_c2 <= c_port2;
reg_m2 <= a_port2 * reg_b2;
reg_p2 <= reg_m2 + reg_c2;
- конец DSP48E # 2
Последовательность в reg_p1:
х [0],
х [1] + х [0] * b1,
х [2] + х [1] * b1,
х [3] + х [2] * b1,
и т.п.
Последовательность в reg_p2 является желаемым результатом. Внутри второго DSP48E регистр reg_m2 имеет последовательность:
х [0] * b1 * b1,
x [1] * b1 * b1 + x [0] * b1 * b1 * b1,
x [2] * b1 * b1 + x [1] * b1 * b1 * b1 + x [0] * b1 * b1 * b1 * b1
В этом результате есть хорошая элегантность. Понятно, что DSP48E не умножает и не добавляет одни и те же часы, но это то, чего требует уравнение разностей. Управляемое разностное уравнение позволяет нам допускать регистры M и P в DSP48E и тактовую частоту на полной скорости.
источник