Esta pregunta se trata de implementar un filtro IIR en un FPGA con cortes DSP, con criterios muy específicos.
Digamos que está haciendo un filtro sin toques hacia adelante y solo 1 toque hacia atrás, con esta ecuación:
(ver imagen)
Tome el segmento DSP48A1 de Xilinx como ejemplo: la mayoría de los segmentos IP DSP duros son similares.
Digamos que tiene datos analógicos entrantes a 1 muestra por reloj. Me gustaría diseñar un filtro IIR que se ejecute sincrónicamente en el reloj de muestra.
El problema es que para ejecutar el segmento DSP a la velocidad máxima, no puede multiplicar Y agregar en el mismo ciclo. Debe tener un registro de canalización entre estos componentes.
Entonces, si tiene 1 nueva muestra cada reloj, necesitará producir 1 salida por reloj. Sin embargo, necesita la salida anterior 2 relojes antes de poder producir uno nuevo en este diseño.
La solución obvia es procesar los datos a una velocidad de reloj doble o deshabilitar el registro de canalización para poder multiplicar y agregar en el mismo ciclo.
Desafortunadamente, si dice que está muestreando a la frecuencia de reloj máxima del segmento DSP totalmente canalizado, ninguna de esas soluciones es posible. ¿Hay alguna otra forma de construir esto?
(Puntos de bonificación si puede diseñar un filtro IIR que funcione a la mitad de la frecuencia de muestreo, utilizando cualquier número de cortes DSP)
El objetivo sería ejecutar un filtro de compensación para un ADC de 1 GSPS en un FPGA Xilinx Artix. Sus divisiones DSP pueden ejecutar un poco más de 500 MHz cuando están totalmente canalizadas. Si hay una solución para 1 muestra por reloj, me gustaría probar y escalar la solución para 2 muestras por reloj. Todo esto es muy fácil con un filtro FIR.
Respuestas:
Todavía no he trabajado con filtros IIR, pero si solo necesita calcular la ecuación dada
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:
Su código de canalización podría verse así:
¡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:
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!):
Espero haber corregido este error ahora retrasando los valores de entrada, también en un segundo registro:
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):
Segundo ciclo (n = 1):
Tercer ciclo (n = 2):
Cuarto ciclo (n = 3):
Podemos ver que comenzando con cylce n = 2 obtenemos el siguiente resultado:
que es equivalente a
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.
fuente
y[n+l] = y[n-1] * b + x[n]
un valor fijo para el retrasol
que puede reescribirsey[n] = y[n-1-l] * b + x[n-l]
y para l = 1 esto esy[n] = y[n-2] * b + x[n-1]
.y[n+l] = x[n] * b0 + x[n-1] * b1 - y[n-1] * a1 - y[n-2] * a2
=>y[n] = x[n-l]*b0 + x[n-1-l] * b1 - y[n-1-l] * a1 - y[n-2-l]*a2
. Suponiendo que puede hacer las tres multiplicaciones en paralelo (1. etapa / 1 ciclo) y necesita hacer lo mismo para agregar los productos, necesita 2 ciclos (1 ciclo: agregar / sub los dos primeros resultados del producto, 1 ciclo: agregar / sub el resultado de esos dos add / subs), necesitará 2 ciclos adicionales. Entonces l = (3-1) = 2 dándotey[n]=x[n-2]*b0+x[n-1-2]*b1-y[n-1-2]*a1-y[n-2-2]*a2
=>y[n]=x[n-2]*b0+x[n-3]*b1-y[n-3]*a1-y[n-4]*a2
Sí, puedes ver la frecuencia de la muestra.
Una solución a este problema es manipular la expresión original para que se puedan insertar registros de canalización, mientras se mantiene la secuencia de salida deseada.
Dado: y [n] = y [n-1] * b1 + x [n];
esto se puede manipular en: y [n] = y [n-2] * b1 * b1 + x [n-1] * b1 + x [n].
Para verificar que esta es la misma secuencia, considere lo que sucede con las primeras muestras x [0], x [1], x [2], etc., donde antes de x [0] todas las muestras x, y eran cero.
Para la expresión original, la secuencia es:
Está claro que es necesario que b1 <1, de lo contrario, esto crecerá sin límite.
Ahora considere la expresión manipulada:
Esta es la misma secuencia.
Una solución de hardware en las primitivas de la biblioteca Xilinx necesitaría dos DSP48E en cascada. Consulte la figura 1-1 en UG193 v3.6 para conocer el puerto y los nombres de registro a continuación. La primera primitiva es multiplicar por b1 y agregar un reloj más tarde; el segundo se multiplica por b1 * b1 y se agrega un reloj más tarde. Hay una latencia de canalización de 4 relojes para esta lógica.
- DSP48E # 1
a_port1: = b1; - coeficiente constante, establecer AREG = 1
b_port1: = x; - establecer atributo BREG = 1
c_port1: = x; - establecer CREG = 1
- interno a DSP48E # 1
reg_a1 <= a_port1;
reg_b1 <= b_port1;
reg_c1 <= c_port1;
reg_m1 <= reg_a1 * reg_b1;
reg_p1 <= reg_m1 + reg_c1; - salida del primer DSP48E
- fin de DSP48E # 1
- DSP48E # 2
a_port2: = reg_p2; - establecer atributo AREG = 0
b_port2: = b1 * b1; - constante, establecer BREG = 1
c_port2: = reg_p1; - establecer CREG = 1
- interno a DSP48E # 2
reg_b2 <= b_port2;
reg_c2 <= c_port2;
reg_m2 <= a_port2 * reg_b2;
reg_p2 <= reg_m2 + reg_c2;
- fin de DSP48E # 2
La secuencia en reg_p1:
x [0],
x [1] + x [0] * b1,
x [2] + x [1] * b1,
x [3] + x [2] * b1,
etc.
La secuencia en reg_p2 es el resultado deseado. Interna al segundo DSP48E, el registro reg_m2 tiene una secuencia:
x [0] * b1 * b1,
x [1] * b1 * b1 + x [0] * b1 * b1 * b1,
x [2] * b1 * b1 + x [1] * b1 * b1 * b1 + x [0] * b1 * b1 * b1 * b1
Hay una bonita elegancia en este resultado. Claramente, el DSP48E no se multiplica y agrega en el mismo reloj, sin embargo, eso es lo que requiere la ecuación de diferencia. La ecuación de diferencia manipulada nos permite tolerar los registros M y P en el DSP48E y el reloj a toda velocidad.
fuente