Necesito computar atan2(x,y)
en un FPGA con un flujo continuo de datos de entrada / salida. Logré implementarlo usando núcleos CORDIC enrollados y canalizados, pero para obtener la precisión que necesitaba, tuve que realizar 32 iteraciones. Esto llevó a que se dedicara una gran cantidad de LUT a esta tarea. Intenté cambiar el flujo para usar núcleos CORDIC parcialmente desenrollados, pero luego necesitaba una frecuencia de reloj multiplicada para ejecutar bucles repetidos mientras mantenía un flujo continuo de entrada / salida. Con esto, no pude cumplir con el tiempo.
Así que ahora estoy buscando formas alternativas de computación atan2(x,y)
.
Pensé en usar tablas de búsqueda de RAM en bloque con interpolación, pero dado que hay 2 variables, necesitaría 2 dimensiones de las tablas de búsqueda, y esto requiere muchos recursos en términos de uso de RAM en bloque.
Luego pensé en usar el hecho que atan2(x,y)
está relacionado atan(x/y)
con el ajuste del cuadrante. El problema con esto es que x/y
necesita una verdadera división ya y
que no es una constante, y las divisiones en FPGAs requieren muchos recursos.
¿Hay más formas novedosas de implementar atan2(x,y)
en un FPGA que resulten en un menor uso de LUT, pero que aún así proporcionen una buena precisión?
fuente
atan2
. Sin embargo, no estoy seguro de poder sobrevivir sin una división.atan2
. Sin embargo, aún necesitarás una división.Respuestas:
Puedes usar logaritmos para deshacerte de la división. Para(x,y) en el primer cuadrante:
Figura 1. Parcela deatan(2z)
Figura 2. Gráfico dellog2(c)
Para referencia posterior, aquí está el script torpe de Python que usé para calcular los errores de aproximación:
donde es la segunda derivada de y está en un máximo local del error absoluto. Con lo anterior obtenemos las aproximaciones:f′′(x) f(x) x
Debido a que las funciones son cóncavas y las muestras coinciden con la función, el error siempre es en una dirección. El error absoluto máximo local podría reducirse a la mitad si el signo del error se alternara una y otra vez cada intervalo de muestreo. Con la interpolación lineal, se pueden lograr resultados casi óptimos filtrando previamente cada tabla de la siguiente manera:
donde e son la tabla original y la filtrada que abarcan y los pesos son . El acondicionamiento final (primera y última fila en la ecuación anterior) reduce el error en los extremos de la tabla en comparación con el uso de muestras de la función fuera de la tabla, porque la primera y la última muestra no necesitan ajustarse para reducir el error de la interpolación entre él y una muestra justo afuera de la mesa. Las subtablas con diferentes intervalos de muestreo deben prefiltrarse por separado. Los valores de los pesos se encontraron minimizando secuencialmente para aumentar el exponentex y 0≤k≤N c0=98,c1=−116,b0=1516,b1=18,b2=−116 c0,c1 N El valor absoluto máximo del error aproximado:
para las posiciones de interpolación entre muestras , con una función cóncava o convexa (por ejemplo ). Con esos pesos resueltos, los valores de los pesos de acondicionamiento final se encontraron minimizando de manera similar el valor absoluto máximo de:0≤a<1 f(x) f(x)=ex b0,b1,b2
para . El uso del prefiltro acerca de la mitad del error de aproximación y es más fácil de hacer que la optimización completa de las tablas.0≤a<1
Figura 4. Error de aproximación de de 11 muestras, con y sin prefiltro y con y sin acondicionamiento final. Sin el acondicionamiento final, el prefiltro tiene acceso a los valores de la función justo fuera de la tabla.log2(a)
Este artículo probablemente presenta un algoritmo muy similar: R. Gutiérrez, V. Torres y J. Valls, " Implementación FPGA de atan (Y / X) basada en transformación logarítmica y técnicas basadas en LUT " , Journal of Systems Architecture , vol . 56, 2010. El resumen dice que su implementación supera los algoritmos anteriores basados en CORDIC en velocidad y los algoritmos basados en LUT en tamaño de huella.
fuente