¿Cómo funcionan las secciones biquad en cascada para filtros de orden superior?

20

Estoy tratando de implementar un filtro IIR de octavo orden y cada nota de aplicación y libro de texto que he leído dice que es mejor implementar cualquier filtro de orden de más de 2 como secciones de segundo orden. Utilicé tf2sosen MATLAB para obtener los coeficientes para las secciones de segundo orden que me dieron un coeff 6x4 para secciones de 4 segundos, como se esperaba. Antes de la implementación como SOS, el filtro de octavo orden requería que se almacenaran 7 valores de muestra anteriores (y también los valores de salida). Ahora, al implementar secciones de segundo orden, ¿cómo funciona el flujo de entrada a salida? ¿Necesito almacenar solo 2 valores de muestra anteriores? ¿O la salida del primer filtro se alimenta como x_inen el segundo filtro y así sucesivamente?

anasimtiaz
fuente
necesita almacenar estados anteriores para cada etapa, dependiendo del orden del filtro en esa etapa para que no sea solo 2 como mencionó

Respuestas:

13

Es lo último que dijo ("¿O la salida del primer filtro se alimenta como x_in en el segundo filtro y así sucesivamente?"). La idea es simple: trata las biquads como filtros separados de segundo orden que están en cascada. La salida del primer filtro es la entrada al segundo, y así sucesivamente, por lo que las líneas de retardo se extienden entre los filtros. Si necesita optimizar la estructura en un entorno con memoria limitada, puede observar que los biquads adyacentes tienen memoria de retardo redundante (es decir, las últimas muestras de salida de la etapa 1 son las mismas que las últimas muestras de entrada de la etapa 2, por lo que no no tiene que almacenarlos por separado como lo haría si solo implementa los filtros de forma aislada).

Jason R
fuente
¡Gracias! Me las arreglé para hacerlo rápidamente en MATLAB. La causa de la confusión anterior era que me olvidé de multiplicar la ganancia (uf!) Y por lo tanto todo tipo de ideas comenzaron arrastrándose.
anasimtiaz
Si no se molesta en pedir la ganancia como un argumento de salida de tf2sos (como en mi código de ejemplo publicado), entonces no necesita molestarse en multiplicarlo nuevamente.
learnvst
9

En realidad, hay dos formas de implementar secciones de segundo orden: en paralelo y en serie. En la versión en serie, las salidas de la sección N son las entradas a la sección N + 1. En la versión paralela, todas las secciones tienen la misma entrada (y solo un cero real en lugar de un par complejo de ceros conjugados) y la salida de cada sección simplemente se resume. Los dos métodos están relacionados a través de la expansión de fracción parcial de la función de transferencia del dominio Z. ADVERTENCIA: este es un problema numéricamente complicado y la implementación estándar de Matlab "residualz" puede tener errores numéricos muy grandes para los filtros de audio típicos que tienen polos cerca del círculo unitario.

Hilmar
fuente
6

Aquí hay un poco de código de demostración para mostrar por qué es mejor que conecte en cascada las secciones de segundo orden.

clc

sr = 44100;
order = 13;

[b,a] = butter(order,1000/(sr/2),'low');
[sos] = tf2sos(b,a);

x = [1; zeros(299,1)]; %impulse


% all in one
Y = filter(b,a,x);

% cascaded biquads
Z = x;
for nn = 1:size(sos,1);
    Z = filter(sos(nn,1:3),sos(nn,4:6), Z );
end


cla; plot(Y, 'k'); hold on; plot(Z,':r'); hold off

Para el filtro de paso bajo dado en el ejemplo anterior, por órdenes de aproximadamente 12 a 13, los errores numéricos se acumulan para dar una respuesta de impulso visiblemente diferente para la implementación que no utiliza biquads en cascada. Dependiendo del filtro, su kilometraje variará.

ORDEN = 10

ingrese la descripción de la imagen aquí

ORDEN = 13

ingrese la descripción de la imagen aquí

aprender
fuente
@learvst Corrígeme si estoy equivocado, pero tu código pierde las ganancias. ¿No debería ser:[sos gain] = tf2sos(b,a); // Rest of code for nn = 1:size(sos,1); Z = filter(sos(nn,1:3),sos(nn,4:6), Z ); end Z = filter(gain,1,Z);
user915783