Todavía no he trabajado con filtros IIR, pero si solo necesita calcular la ecuación dada
y[n] = y[n-1]*b1 + x[n]
una vez por ciclo de CPU, puede usar la canalización.
En un ciclo, haces la multiplicación y en un ciclo necesitas hacer la suma de cada muestra de entrada. ¡Eso significa que su FPGA debe poder multiplicar en un ciclo cuando se registra a la frecuencia de muestreo dada! Entonces solo necesitará hacer la multiplicación de la muestra actual Y la suma del resultado de la multiplicación de la última muestra en paralelo. Esto provocará un retraso de procesamiento constante de 2 ciclos.
Ok, echemos un vistazo a la fórmula y diseñemos una tubería:
y[n] = y[n-1]*b1 + x[n]
Su código de canalización podría verse así:
output <= last_output_times_b1 + last_input
last_output_times_b1 <= output * b1;
last_input <= input
¡Tenga en cuenta que los tres comandos deben ejecutarse en paralelo y que la "salida" en la segunda línea utiliza la salida del último ciclo de reloj!
No trabajé mucho con Verilog, por lo que la sintaxis de este código es posiblemente incorrecta (por ejemplo, falta el ancho de bits de las señales de entrada / salida; sintaxis de ejecución para la multiplicación). Sin embargo, deberías tener la idea:
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
PD: Tal vez algún programador experimentado de Verilog podría editar este código y eliminar este comentario y el comentario sobre el código después. ¡Gracias!
PPS: en caso de que su factor "b1" sea una constante fija, es posible que pueda optimizar el diseño implementando un multiplicador especial que solo tome una entrada escalar y calcule "veces b1" solamente.
Respuesta a: "Desafortunadamente, esto en realidad es equivalente a y [n] = y [n-2] * b1 + x [n]. Esto se debe a la etapa de canalización adicional". como comentario a la versión anterior de la respuesta
Sí, eso era realmente correcto para la siguiente versión antigua (¡INCORRECTA!):
always @ (posedge clk or posedge reset)
if (reset) begin
t <= 0;
end else begin
y <= t + x;
t <= mult(y, b);
end
Espero haber corregido este error ahora retrasando los valores de entrada, también en un segundo registro:
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
Para asegurarnos de que funcione correctamente esta vez, veamos qué sucede en los primeros ciclos. Tenga en cuenta que los primeros 2 ciclos producen más o menos basura (definida), ya que no hay valores de salida anteriores (por ejemplo, y [-1] == ??) están disponibles. El registro y se inicializa con 0, lo que equivale a suponer y [-1] == 0.
Primer ciclo (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
Segundo ciclo (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]
Tercer ciclo (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]
Cuarto ciclo (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]
Podemos ver que comenzando con cylce n = 2 obtenemos el siguiente resultado:
y[2]=y[0]*b+x[1]
y[3]=y[1]*b+x[2]
que es equivalente a
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
Como se mencionó anteriormente, introducimos un retraso adicional de l = 1 ciclos. Eso significa que su salida y [n] se retrasa por el retraso l = 1. Eso significa que los datos de salida son equivalentes pero se retrasan en un "índice". Para ser más claro: los datos de salida retrasados son 2 ciclos, ya que se necesita un ciclo de reloj (normal) y se agrega 1 ciclo de reloj adicional (retraso 1 = 1) para la etapa intermedia.
Aquí hay un boceto para representar gráficamente cómo fluyen los datos:
PD: Gracias por mirar mi código de cerca. ¡Así que también aprendí algo! ;-) Avíseme si esta versión es correcta o si ve más problemas.