Todavía no he trabajado con filtros IIR, pero si sólo necesitas calcular la ecuación dada
y[n] = y[n-1]*b1 + x[n]
una vez por ciclo de CPU, se puede utilizar el pipelining.
En un ciclo se hace la multiplicación y en un ciclo hay que hacer la suma para cada muestra de entrada. Esto significa que tu FPGA debe ser capaz de hacer la multiplicación en un ciclo cuando se sincroniza a la velocidad de muestreo dada. Entonces sólo tendrás 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 de procesamiento constante 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]
El código de su canalización podría ser el siguiente:
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" de la segunda línea utiliza por tanto la salida del último ciclo de reloj.
No he trabajado mucho con Verilog, así que la sintaxis de este código es muy posiblemente errónea (por ejemplo, falta el ancho de bits de las señales de entrada/salida; la sintaxis de ejecución para la multiplicación). Sin embargo, usted debe obtener 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 de Verilog con experiencia podría editar este código y eliminar este comentario y el que está encima del código después. Gracias.
PPS: En caso de que tu factor "b1" sea una constante fija, podrías optimizar el diseño implementando un multiplicador especial que sólo tome una entrada escalar y calcule "veces b1" solamente.
Respuesta a: "Desgraciadamente, esto equivale en realidad a y[n] = y[n-2] * b1 + x[n]. Esto se debe a la etapa extra de la tubería" como comentario a la versión antigua de la respuesta
Sí, en realidad era 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 esta vez funciona correctamente, veamos qué ocurre en los primeros ciclos. Observa que los primeros 2 ciclos producen más o menos basura (definida), ya que no hay valores de salida anteriores (por ejemplo y[-1] == ??). El registro y se inicializa con 0, lo que equivale a asumir que 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 el cilindro n=2 obtenemos la siguiente salida:
y[2]=y[0]*b+x[1]
y[3]=y[1]*b+x[2]
lo que equivale 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 ha mencionado anteriormente, introducimos un retraso adicional de l=1 ciclos. Eso significa que su salida y[n] se retrasa en el lag l=1. Esto significa que los datos de salida son equivalentes pero están retrasados en un "índice". Para ser más claros: Los datos de salida se retrasan 2 ciclos, ya que se necesita un ciclo de reloj (normal) y se añade 1 ciclo de reloj adicional (lag l=1) para la etapa intermedia.
A continuación se muestra un esquema para representar gráficamente cómo fluyen los datos:
P.D.: Gracias por mirar de cerca mi código. Yo también he aprendido algo ;-) Hazme saber si esta versión es correcta o si ves algún otro problema.
1 votos
Sólo para aclarar, no hay ninguna razón por la que no tendrías una salida por ciclo de reloj con el método de la tubería, ¿verdad? Usted está tratando de minimizar la latencia a un ciclo de reloj en lugar de dos, ¿verdad? Dependiendo de tu situación, si estás usando un entero para b1, entonces podrías convertir la multiplicación en una suma gigante incluyendo x[n].
0 votos
Correcto - ya que hay una entrada por reloj, tiene que haber una salida por reloj. la latencia tampoco es un problema. la rebanada de DSP sólo tiene un sumador de 2 entradas, y las derivaciones suelen ser números bastante grandes, por lo que no se podría sumar b1 veces en 1 ciclo de reloj. el principal límite es que la salida tiene que retroalimentarse en 1 reloj, pero tarda 2 relojes en producirse.
1 votos
Creo que sigues sin entender cómo funciona una tubería. Un pipeline aumenta potencialmente la latencia, pero te permite obtener 1 salida por cada entrada en cada ciclo de reloj. Es sólo que el resultado es ahora 2 relojes después en lugar de la ideal 1 reloj después. La entrada sería la secuencia así: x[0],x[1],x[2],x[3],x[4] mientras que la salida sería en ese mismo intervalo de tiempo y[-2],y[-1],y[0],y[1],y[2]. No estás perdiendo ninguna muestra. Además, estás en una FPGA, así que si quieres hacer más trabajo del que los pipelines DSP están diseñados, utiliza la fpga para paralelizar la carga de trabajo.
0 votos
Ese DSP es capaz de hacer una acumulación de multiplicación fusionada en un ciclo. Sin embargo, no me queda claro si la salida de un trozo de DSP puede conectarse a su propia entrada con retroalimentación en un solo ciclo.
0 votos
Horta - tienes razón sobre el pipelining en general, pero el problema es que la pestaña b1 en este caso tiene retroalimentación - lo que significa que una etapa en el pipeline depende de la salida del valor anterior. si siempre tarda 2 relojes en producir la siguiente salida a partir de la salida anterior, no hay manera de producir 1 salida por reloj, independientemente de la latencia que hayas añadido. jbarlow - tienes razón, el slice DSP tiene una opción de fundido de 1 ciclo. Sin embargo no puede correr lo suficientemente rápido en este caso. añadiendo el registro M (ver hoja de datos) puedes alcanzar los 500 MHz.Sin embargo entonces no puedes multiplicar y sumar en el mismo clk.
0 votos
Ah, ahora entiendo lo que dices Marcus. Estoy pensando que la única solución ahora es que crees tu propia lógica en la parte fpga que te permita realizar una suma múltiple en un solo ciclo de reloj mientras alimentas la salida directamente de vuelta a la entrada de este bloque lógico.
0 votos
Mi respuesta habitual a este tipo de preguntas en el trabajo es: "Tienes una implementación muy definida en mente... dime la especificación real del procesamiento que estás tratando de hacer, veamos si podemos hacerlo de otra manera".
0 votos
Tienes razón, y ya estoy trabajando en otras opciones que son significativamente diferentes. el objetivo es construir un osciloscopio de 1 GSPS a partir de una FPGA Artix-7. El filtro IIR es principalmente para compensar la banda de paso, en caso de que no sea plana. Sin embargo, dado que el osciloscopio funcionará con buffers de captura cortos, no es un problema filtrar los datos a posteriori a una velocidad más baja - no hay necesidad de transmitir continuamente. hacer el filtrado de compensación por adelantado es sólo una idea que deja más opciones abiertas. Este es también un buen ejercicio de rendimiento para ver exactamente cómo la velocidad y IIR puede correr, así que me alegro de haber preguntado.