Я еще не работал с фильтрами БИХ, но если вам нужно только рассчитать данное уравнение
y[n] = y[n-1]*b1 + x[n]
один раз за цикл процессора, вы можете использовать конвейерную обработку.
В одном цикле вы выполняете умножение, а в одном цикле вам необходимо выполнить суммирование для каждой входной выборки. Это означает, что ваша FPGA должна быть способна выполнять умножение за один такт при тактировании с заданной частотой дискретизации! Тогда вам нужно будет только выполнить умножение текущего сэмпла И суммирование результата умножения последнего сэмпла параллельно. Это приведет к постоянной задержке обработки в 2 цикла.
Хорошо, давайте посмотрим на формулу и спроектируем конвейер:
y[n] = y[n-1]*b1 + x[n]
Код вашего конвейера может выглядеть так:
output <= last_output_times_b1 + last_input
last_output_times_b1 <= output * b1;
last_input <= input
Обратите внимание, что все три команды должны выполняться параллельно и что «выходные данные» во второй строке, следовательно, используют выходные данные из последнего тактового цикла!
Я мало работал с Verilog, поэтому синтаксис этого кода, скорее всего, неверен (например, отсутствует битовая ширина входных / выходных сигналов; синтаксис выполнения для умножения). Однако вы должны понять:
module IIRFilter( clk, reset, x, b, y );
input clk, reset, x, b;
output y;
reg y, t, t2;
wire clk, reset, x, b;
always @ (posedge clk or posedge reset)
if (reset) begin
y <= 0;
t <= 0;
t2 <= 0;
end else begin
y <= t + t2;
t <= mult(y, b);
t2 <= x
end
endmodule
PS: Может быть, какой-нибудь опытный программист Verilog мог бы отредактировать этот код и впоследствии удалить этот комментарий и комментарий над кодом. Спасибо!
PPS: В случае, если ваш коэффициент «b1» является фиксированной константой, вы можете оптимизировать проект, внедрив специальный множитель, который принимает только один скалярный вход и рассчитывает только «времена b1».
Ответ: «К сожалению, это на самом деле эквивалентно y [n] = y [n-2] * b1 + x [n]. Это из-за дополнительной стадии конвейера». как комментарий к старой версии ответа
Да, это было действительно правильно для следующей старой (НЕПРАВИЛЬНОЙ !!!) версии:
always @ (posedge clk or posedge reset)
if (reset) begin
t <= 0;
end else begin
y <= t + x;
t <= mult(y, b);
end
Надеюсь, теперь я исправил эту ошибку, задержав входные значения во втором регистре:
always @ (posedge clk or posedge reset)
if (reset) begin
y <= 0;
t <= 0;
t2 <= 0;
end else begin
y <= t + t2;
t <= mult(y, b);
t2 <= x
end
Чтобы убедиться, что на этот раз все работает правильно, давайте посмотрим, что происходит в первые несколько циклов. Обратите внимание, что первые 2 цикла производят более или менее (определенный) мусор, так как предыдущие выходные значения (например, y [-1] == ??) недоступны. Регистр y инициализируется 0, что эквивалентно предположению y [-1] == 0.
Первый цикл (n = 0):
BEFORE: INPUT (x=x[0], b); REGISTERS (t=0, t2=0, y=0)
y <= t + t2; == 0
t <= mult(y, b); == y[-1] * b = 0
t2 <= x == x[0]
AFTERWARDS: REGISTERS (t=0, t2=x[0], y=0), OUTPUT: y[0]=0
Второй цикл (n = 1):
BEFORE: INPUT (x=x[1], b); REGISTERS (t=0, t2=x[0], y=y[0])
y <= t + t2; == 0 + x[0]
t <= mult(y, b); == y[0] * b
t2 <= x == x[1]
AFTERWARDS: REGISTERS (t=y[0]*b, t2=x[1], y=x[0]), OUTPUT: y[1]=x[0]
Третий цикл (n = 2):
BEFORE: INPUT (x=x[2], b); REGISTERS (t=y[0]*b, t2=x[1], y=y[1])
y <= t + t2; == y[0]*b + x[1]
t <= mult(y, b); == y[1] * b
t2 <= x == x[2]
AFTERWARDS: REGISTERS (t=y[1]*b, t2=x[2], y=y[0]*b+x[1]), OUTPUT: y[2]=y[0]*b+x[1]
Четвертый цикл (n = 3):
BEFORE: INPUT (x=x[3], b); REGISTERS (t=y[1]*b, t2=x[2], y=y[2])
y <= t + t2; == y[1]*b + x[2]
t <= mult(y, b); == y[2] * b
t2 <= x == x[3]
AFTERWARDS: REGISTERS (t=y[2]*b, t2=x[3], y=y[1]*b+x[2]), OUTPUT: y[3]=y[1]*b+x[2]
Мы можем видеть, что, начиная с cylce n = 2, мы получаем следующий вывод:
y[2]=y[0]*b+x[1]
y[3]=y[1]*b+x[2]
что эквивалентно
y[n]=y[n-2]*b + x[n-1]
y[n]=y[n-1-l]*b1 + x[n-l], where l = 1
y[n+l]=y[n-1]*b1 + x[n], where l = 1
Как уже упоминалось выше, мы вводим дополнительный лаг из l = 1 циклов. Это означает, что ваш вывод y [n] задерживается на lag l = 1. Это означает, что выходные данные эквивалентны, но задерживаются на один «индекс». Чтобы быть более понятным: выходные данные задерживаются на 2 цикла, так как необходим один (нормальный) тактовый цикл и добавляется 1 дополнительный (lag l = 1) тактовый цикл для промежуточной ступени.
Вот эскиз, чтобы графически изобразить поток данных:
PS: Спасибо, что внимательно ознакомились с моим кодом. Так что я тоже кое-чему научился! ;-) Дайте мне знать, если эта версия верна или вы видите какие-либо проблемы.