Я ще не працював з фільтрами IIR, але якщо вам потрібно лише обчислити задане рівняння
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
Щоб переконатися, що він працює правильно цього разу, давайте подивимося, що відбувається на перших кількох циклах. Зауважте, що перші два цикли створюють більше або менше (визначене) сміття, оскільки попередніх вихідних значень (наприклад, 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] затримується на відставання l = 1. Це означає, що вихідні дані еквівалентні, але затримуються на один "індекс". Для того, щоб бути більш зрозумілими: затримка вихідних даних складе 2 цикли, оскільки потрібен один (звичайний) тактовий цикл, а для проміжного етапу додається 1 додатковий (відставання l = 1) тактовий цикл.
Ось ескіз для графічного зображення способів потоку даних:
PS: Дякую, що уважно ознайомився з моїм кодом. Тож я і чомусь навчився! ;-) Повідомте мене, чи правильна ця версія чи ви бачите якісь проблеми.