Todavía no he trabajado con filtros IIR, pero si solo necesitas calcular la ecuación dada
y[n] = y[n-1]*b1 + x[n]
una vez por ciclo de CPU, puede utilizar la canalización.
En un ciclo haces la multiplicación y en un ciclo necesitas hacer la suma para cada muestra de entrada. ¡Eso significa que su FPGA debe poder hacer la multiplicación en un ciclo cuando se cronometra a la frecuencia de muestreo dada!
Entonces solo tendrá que 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 constante en el procesamiento de 2 ciclos.
Bien, 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, por lo tanto, utiliza la salida del último ciclo de reloj.
No trabajé mucho con Verilog, por lo que la sintaxis de este código es muy 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
PS: Tal vez algún programador Verilog experimentado pueda editar este código y eliminar este comentario y el comentario sobre el código posterior. 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 toma una entrada escalar y calcula solo "veces b1".
Respuesta a: "Desafortunadamente, esto es realmente 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í, en realidad era lo correcto para la siguiente versión antigua (¡¡¡INCORRECTO !!!):
always @ (posedge clk or posedge reset)
if (reset) begin
t <= 0;
end else begin
y <= t + x;
t <= mult(y, b);
end
Ojalá haya corregido este error ahora al retrasar 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 disponibles valores de salida anteriores (por ejemplo, y [-1] == ??). 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 a partir de 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 con un "índice". Para ser más claros: los datos de salida retrasados son 2 ciclos, ya que se necesita un ciclo de reloj (normal) y se agrega 1 ciclo adicional (retraso l = 1) para la etapa intermedia.
Aquí hay un bosquejo para representar gráficamente cómo fluyen los datos:
PD: Gracias por mirar de cerca mi código. ¡Así que también aprendí algo! ;-) Avísame si esta versión es correcta o si ves más problemas.