Problemas con la implementación de un filtro de supresión de banda en una MCU (dsPIC) utilizando aritmética de punto fijo

Estoy tratando de implementar un filtro de parada de banda (muesca) en un microcontrolador dsPIC33EP64GS506para filtrar un 100 Hzcomponente de una señal de entrada. El problema aquí es que mi microcontrolador no tiene una unidad de punto flotante, así que tengo que usar una aritmética de punto fijo, pero para ser más preciso, uso aritmética de enteros. El tiempo de muestra del sistema es T s = 50   m s . Aquí explico mi problema en detalle, y las preguntas están al final de la publicación. Encuentre adjunto un código MATLAB para ejecutar simulaciones si lo desea: enlace de descarga en mi Dropbox . Tenga en cuenta que no tiene que ser un usuario registrado de Dropbox para poder descargar el archivo.

La resolución de ADC es 12b, a la que "aumento" 15b, no para aumentar la resolución de medición (que no se puede hacer), sino para aumentar la resolución del filtro:

v_in = ADCBUF0<<3;

La función de transferencia de filtro de muesca en el dominio s se da como:

GRAMO s ( s ) = s 2 + 2 ζ 1 ω norte s + ω norte 2 s 2 + 2 ζ 2 ω norte s + ω norte 2 ,

donde filtrar parámetros ζ 1 , ζ 2 , y ω norte determinar completamente el filtro. Si queremos filtrar un 100 Hzcomponente, entonces establecemos ω norte = 2 π 100   s 1 . En cuanto a otros parámetros, sin explicaciones detalladas, uso ζ 1 = 0.001 y ζ 2 = 1 . Para implementar este filtro en un sistema digital, necesitamos discretizar la función de transferencia en s-domain, y para eso utilizo un método de discretización de Tustin .

GRAMO z ( z ) = b 0 + b 1 z 1 + b 2 z 2 1 + a 1 z 1 + a 2 z 2 .

La ecuación recursiva correspondiente, implementada en un sistema digital, es:

y ( k ) = b 0 tu ( k ) + b 1 tu ( k 1 ) + b 2 tu ( k 2 ) a 1 y ( k 1 ) a 2 y ( k 2 ) .

Aquí está el código de MATLAB para obtener la función de transferencia en el dominio z:

Ts = 50e-6;
zeta1 = 0.001;
zeta2 = 1;
wn = 100*(2*pi);
Gs = tf([1 2*zeta1*wn wn^2], [1 2*zeta2*wn wn^2]);
Gz = c2d(Gs, Ts, 'tustin');
bodeplot(Gz);

Consulte a continuación las características de frecuencia del filtro en el dominio z generado por MATLAB. Como se puede ver, este tipo de filtro es muy sensible en términos de respuesta de frecuencia. Incluso los cambios más pequeños en los parámetros podrían causar un comportamiento completamente diferente, por ejemplo, una ganancia inesperada, cambio de fase, etc.

ingrese la descripción de la imagen aquí

Ahora, como no tengo una unidad de punto flotante a disposición, utilizo un método muy conocido llamado escalado binario. Cualquier número decimal d R se puede representar como d 2 r 2 r , dónde r norte , y es una función de redondeo al entero más cercano. El escalado binario es un método que se usa cuando queremos evitar el uso de una división, que es una operación muy costosa en términos de ciclos de CPU necesarios (normalmente 18 ciclos), ya que el desplazamiento binario puede producir los mismos resultados en muchos menos ciclos (normalmente 1 ciclo). Para este ejemplo usé r = 15 , que es la precisión más alta que podría usar considerando los bits disponibles para hacer una multiplicación (un resultado debe estar dentro de los 32 bits). La ecuación recursiva correspondiente usando aritmética de enteros se implementa de la siguiente manera:

yk0 = ( B0*uk0+B1*uk1+B2*uk2 - A1*yk1-A2*yk2 + (1<<14) ) >> 15;
uk2 = uk1; uk1 = uk0;
yk2 = yk1; yk1 = yk0;

El término (1<<14)se utiliza para garantizar que el resultado se redondee al entero más cercano después de la operación de cambio de bit. Tenga en cuenta que >>15es prácticamente una división entera por 32768, pero sabemos que no es completamente equivalente. El cambio de bit siempre redondea a menos infinito, mientras que la división de enteros siempre redondea a cero. Los valores de los parámetros de filtro son los siguientes: B0=31771, B1=-63509m B2=31769, A1=-63509, A2=30772. Esto también se puede encontrar en un código de MATLAB proporcionado.

Me sorprendió mucho cuando me di cuenta de que la variante entera del filtro no funciona en absoluto. Consulte a continuación las respuestas de tres filtros diferentes utilizados para eliminar un 100 Hzcomponente de la señal de entrada. De arriba a abajo: (1) filtro de muesca en la implementación de punto flotante, (2) filtro de muesca en la implementación aritmética de enteros usando r = 15 , (3) un filtro de promedio móvil simple.

ingrese la descripción de la imagen aquí

Así es como implementé un filtro de promedio móvil en C:

uk200 = window[ind];
window[ind] = uk0;
win_sum = win_sum - uk200 + uk0;
yk0 = (((win_sum+(1<<3))>>4)*5243+(1<<15))>>16;
ind++;
if (ind==200) ind=0;

Preguntas a la comunidad.

Como no tengo mucha experiencia en filtrado digital, ¿alguien puede confirmarme si se esperan estos resultados? ¿Es realmente problemático implementar un filtro de muesca en un sistema digital usando solo aritmética de enteros ? ¿Qué filtro digital se utiliza normalmente para eliminar una determinada frecuencia ? Como veo en estos resultados, el filtro de media móvil supera a las dos implementaciones de filtro de muesca. ¿Hay alguna desventaja para el filtro de promedio móvil que deba tener en cuenta, excepto por la demanda de memoria obviamente aumentada ?

La aritmética de enteros (o más bien, punto fijo) es generalmente preferida para DSP, los flotantes traen algunos problemas de redondeo difíciles de manejar. Y puedes construir muescas bastante buenas usando filtros FIR (que son una generalización del promedio móvil). Mi preferencia es usar un lenguaje que admita puntos fijos directamente, al menos para crear prototipos del filtro: la migración a enteros no es difícil.
¿Cuáles son los valores que usó para B0, B1, B2, A1 y A2 en el código C anterior? ¿Está escalando estos coeficientes en consecuencia? ¿También está escalando el valor del ADC (o la entrada)? Sin embargo, programar el DSPIC en ensamblador tiene algunas ventajas cuando se usa punto fijo, como el acceso a las instrucciones MAC y al acumulador de 40 bits. No tiene que portar todo el código, sino solo las funciones relacionadas con el filtro. Además, Microchip proporciona una biblioteca para operaciones DSP, incluso trabajando en C.
@DirceuRodriguesJr He actualizado mi pregunta con información adicional. Los valores de los parámetros se proporcionan inmediatamente después de su introducción. El ADC funciona en 12bla resolución, que "aumento" para 15baumentar la resolución del filtro.
Entonces, si está usando r = 15, el coeficiente original para -63509 será -1.93814... (no escalado). Creo que esto requeriría una representación Q1.14 de 32 bits. En otras palabras: 1 bit de signo, 1 bit para la parte entera y 14 bits para la parte fraccionaria (con r = 14). Pero recuerde que Q1.14 x Q1.14 conduce a un resultado con 2 bits de signo (repetidos), 2 bits para la parte entera y 28 bits para la parte fraccionaria; lo que requerirá turnos apropiados para su corrección.
No estoy usando una aritmética de punto fijo, sino una aritmética de enteros. En otras palabras, mantengo la posición de un punto en mi cabeza :) Intenté aumentar la resolución en 5 bits adicionales, pero no funcionó.
No. No aumenté la resolución, solo la disminuí, para que el producto quepa en 32 bits. Además, ¿qué es la representación de punto fijo si no se mantiene el punto binario en la "cabeza" del programador?
@MarkoGulin: el punto fijo significa permitir que el compilador realice un seguimiento del punto binario. Hace la vida mucho más fácil para los programadores y menos propensos a errores.
Brian Drummond escribió: "...punto fijo significa dejar que el compilador realice un seguimiento del punto binario...". ¿Quería referirse a "punto flotante" en su lugar? Usando el punto fijo, mantienes el punto binario alineado solo para sumas y restas. Al menos sin el soporte de bibliotecas dedicadas y tipos de datos como, por ejemplo, q31_t (Q0.31) para las bibliotecas ARM CMSIS DSP.

Respuestas (1)

Hay dos problemas con los filtros digitales, uno es el rango dinámico (capacidad de representar un rango de números), el otro es el ruido de cuantificación del redondeo.

Los filtros de enteros tienen un rango dinámico mucho más reducido que los filtros de punto flotante y también tienen más ruido de cuantificación.

Es necesario comprobar el filtro para asegurarse de que no satura los registros. (El filtro siempre está multiplicando un número grande por una constante grande, el multiplicador se desbordará y esto provocará inestabilidad en el filtro o ruido). Hay formas de superar esto, los coeficientes se pueden ajustar para obtener la misma respuesta pero evitando.

Consulte este recurso para obtener más información.

Una cosa que puede intentar (si es posible con su compilador/hardware) es aumentar el tamaño de las variables de 32 a 64 y ver si eso ayuda.

Otra cosa que querrá verificar (y aún no lo he hecho, necesito averiguar qué forma tiene su filtro antes de poder convertirlo a una forma diferente) es el orden y la forma del filtro. Diferentes formas tienen diferentes resultados. El orden de filtro que tiene es un filtro de segundo orden. El formulario parece una sección de segundo orden de algún tipo, pero no estoy seguro (ahora mismo)

Los filtros digitales pueden tener un orden superior, se puede diseñar un filtro de muesca (o paso alto o paso bajo, lo que sea) filtrar con un filtro de segundo orden o más, a mayor orden más constantes, y multiplica y suma (más recursos computacionales) pero el mejor el filtro es aproximado.

Probablemente sea mejor diseñar el filtro a través de métodos digitales, hay documentos que describen cómo calcular los coeficientes, pero también hay calculadoras en línea y, por supuesto, matlab, pero use la herramienta de diseño de filtros. Asegúrese de que cualquiera que sea el método que utilice, sus constantes calculadas coincidan con la forma (secciones bicuadráticas de segundo orden, forma directa 1, forma directa II, etc.)

De hecho, he emulado la implementación de la aritmética de enteros en MATLAB mediante el uso de la aritmética de punto flotante con redondeo. Por eso, puedo descartar posibles desbordamientos. No puedo aumentar el tamaño a 64b, ya que mi compilador (para MCU) no lo admite. Lo que quería saber: ¿puedo usar el filtro de promedio móvil, es decir, es esta práctica común eliminar un determinado componente de frecuencia? Gracias por el recurso proporcionado, ¡lo revisaré!
Por promedio móvil, te refieres a filtros FIR, entonces sí. Hay muchas realizaciones diferentes de filtros. Dependiendo de cómo diseñe su filtro (puede diseñar filtros con más coeficientes, cuantos más coeficientes tenga, mejor se aproximará al filtro) Este es un buen recurso Hay diferentes estructuras, cada estructura tiene sus ventajas y desventajas (algunas son más computacionalmente caros, siendo algunos menos precisos en su filtrado)
He actualizado mi publicación para incluir también una implementación de filtro de promedio móvil. Puede encontrar mi implementación justo antes de las preguntas (al final de la publicación).
Si no necesita las frecuencias más altas, un filtro de promedio móvil funcionará bien, tienen respuestas de frecuencia similares a un filtro de paso bajo. gaussianwaves.com/2010/11/moving-average-filter-ma-filter-2