Ir al contenido

Galería de arquitecturas de filtro

Normas aplicables: IEC 61260ANSI S1.11

Elegir una arquitectura de filtro es un compromiso: la selectividad, el rizado de banda de paso y el comportamiento de fase no pueden ser óptimos a la vez, y cada una de las cinco arquitecturas que ofrece phonometry resuelve el compromiso de forma distinta. Tres de ellas — Butterworth, Chebyshev II y Bessel — sitúan sus puntos de −3 dB en los bordes de banda de ANSI S1.11, así que para esas tres la elección cambia cómo rechaza una banda a sus vecinas y cómo trata los transitorios, no dónde se sitúa la banda. Los dos diseños de rizado constante son la excepción, y el apartado 3 da su tamaño: cheby1 y ellip toman los bordes de banda como su borde de rizado, así que sus bandas son efectivamente más anchas y todos sus niveles por banda salen unas décimas de decibelio por encima. Esta página pone las arquitecturas frente a frente: la comparación en el cruce a −3 dB, la galería completa de respuestas en octava y tercio de octava, ejemplos de uso por arquitectura y el crossover Linkwitz-Riley para cuando el objetivo es dividir una señal en lugar de medir bandas.

Las matemáticas de diseño de estos bancos (bordes de banda, polos y ceros, diezmado multitasa) y la referencia de parámetros viven en Bancos de filtros; demostrar que un banco diseñado cumple una clase de prestaciones de IEC 61260-1 es Verificación de clase de filtros.

1. Las cinco arquitecturas en los bordes de banda

Sección titulada «1. Las cinco arquitecturas en los bordes de banda»

Los cinco diseños se comparan sobre la misma banda de octava de 1 kHz a 48 kHz. Lee la figura dos veces: la vista amplia enseña con qué rapidez cae cada falda al alejarse de la banda, y el recuadro en torno a la línea de −3 dB enseña dónde se cruzan. Lo que cambia entre esas dos vistas es que Chebyshev I riza dentro de la banda, Chebyshev II riza fuera, el elíptico hace las dos cosas y es el que más rápido cae, y Bessel es el más suave y el más lento.

Comparación de la respuesta en magnitud de las cinco arquitecturas para la banda de octava de 1 kHz, con zoom en el cruce a -3 dBComparación de la respuesta en magnitud de las cinco arquitecturas para la banda de octava de 1 kHz, con zoom en el cruce a -3 dB
Mostrar el código de esta figura
import matplotlib.pyplot as plt
import numpy as np
from scipy.signal import sosfreqz
from phonometry import filters
fs = 48000
fig, ax = plt.subplots(figsize=(9, 5))
for ftype in ("butter", "cheby1", "cheby2", "ellip", "bessel"):
# limits selecciona únicamente la banda de octava de 1 kHz
bank = filters.OctaveFilterBank(fs, fraction=1, order=6, limits=[800, 1200],
design=filters.FilterDesign(filter_type=ftype))
idx = int(np.argmin(np.abs(np.array(bank.freq) - 1000)))
fsd = fs / bank.factor[idx] # frecuencia real de la banda
w, h = sosfreqz(bank.sos[idx], worN=16384, fs=fsd)
ax.semilogx(w, 20 * np.log10(np.abs(h) + 1e-9), label=ftype)
ax.axhline(-3, color="gray", linestyle=":", label="-3 dB")
# El recuadro que da nombre al apartado: las mismas curvas junto al cruce.
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
axins = inset_axes(ax, width="35%", height="45%", loc="upper left", borderpad=3)
for line in ax.get_lines()[:-1]:
axins.semilogx(line.get_xdata(), line.get_ydata(), label=line.get_label())
axins.axhline(-3, color="gray", linestyle=":")
axins.set(xscale="log", xlim=(650, 1500), ylim=(-4, 0.5),
title="Zoom en -3 dB (escala log)")
ax.set(xlim=(100, 8000), ylim=(-80, 5),
xlabel="Frecuencia [Hz]", ylabel="Magnitud [dB]")
ax.grid(True, which="both", alpha=0.3)
ax.legend()
plt.show()
TipoNombreEjemplo de usoIdeal para
butterButterworthoctave_filter(x, fs, design=FilterDesign(filter_type='butter'))Medición acústica general.
cheby1Chebyshev Ioctave_filter(x, fs, design=FilterDesign(filter_type='cheby1', ripple=0.1))Caída más abrupta a costa de rizado.
cheby2Chebyshev IIoctave_filter(x, fs, design=FilterDesign(filter_type='cheby2'))Banda de paso plana con ceros en la banda atenuada.
ellipElípticooctave_filter(x, fs, design=FilterDesign(filter_type='ellip', ripple=0.1))Máxima selectividad.
besselBesseloctave_filter(x, fs, design=FilterDesign(filter_type='bessel'))Preservar la forma de los transitorios (ver la figura de retardo de grupo de Bancos de filtros).
Dos paneles para la banda de octava de 1 kHz a 48 kHz, orden 6. A la izquierda, barras agrupadas con la atenuación relativa una y dos octavas por encima de la frecuencia central de banda para cada una de las cinco arquitecturas: Bessel es la más suave, con menos 16 y menos 60 decibelios; Butterworth, menos 40 y menos 88; Chebyshev I, menos 50 y menos 102; Chebyshev II, menos 55 y menos 73; y el elíptico es el más abrupto, con menos 72 y menos 81. A la derecha, el retardo de grupo en la frecuencia central de banda en milisegundos: Bessel 1,22; Chebyshev II 1,58; Butterworth 1,74; elíptico 1,75 y Chebyshev I 1,97Dos paneles para la banda de octava de 1 kHz a 48 kHz, orden 6. A la izquierda, barras agrupadas con la atenuación relativa una y dos octavas por encima de la frecuencia central de banda para cada una de las cinco arquitecturas: Bessel es la más suave, con menos 16 y menos 60 decibelios; Butterworth, menos 40 y menos 88; Chebyshev I, menos 50 y menos 102; Chebyshev II, menos 55 y menos 73; y el elíptico es el más abrupto, con menos 72 y menos 81. A la derecha, el retardo de grupo en la frecuencia central de banda en milisegundos: Bessel 1,22; Chebyshev II 1,58; Butterworth 1,74; elíptico 1,75 y Chebyshev I 1,97

La elección, cuantificada. La selectividad y el retardo de grupo se mueven en sentidos contrarios, y la columna de clase de la tabla de abajo dice cuáles de las cinco puedes usar de verdad para una medida de banda conforme a norma.

ArquitecturaRizado en el centro de bandaEn En Retardo de grupo en Clase IEC 61260-1 (orden 6, 48 kHz)
butter0,00 dB−39,6 dB−88,2 dB1,74 ms1
cheby10,10 dB−50,2 dB−101,6 dB1,97 msninguna
cheby20,00 dB−55,1 dB−73,0 dB1,58 ms1
ellip0,10 dB−72,1 dB−80,8 dB1,75 msninguna
bessel0,21 dB−16,4 dB−60,2 dB1,22 msninguna

Lee primero la última columna: tres de las cinco no sirven en absoluto para una medida de banda conforme a norma con los parámetros por defecto; las dos de rizado constante porque sus bordes de banda no son sus puntos de −3 dB (ver Bancos de filtros), y Bessel porque cae demasiado despacio para la máscara. Eso es una restricción dura, no una preferencia, y va antes que cualquiera de las demás columnas. Entre las dos que sí pasan, la elección es un compromiso real: cheby2 compra 15 dB más de rechazo a una octava de distancia y lo paga con una banda atenuada lejana 15 dB más somera, porque su suelo de rizado constante queda clavado en attenuation.

Una cosa más que la tabla no puede enseñar: el rechazo solo importa cuando una vecina fuerte no debe contaminar una banda débil, y ahí el techo lo pone el parámetro attenuation (72 dB por defecto), no la arquitectura.

Mostrar el código de esta figura
import numpy as np
from scipy.signal import sosfreqz
# `filters` es el import del fragmento anterior.
fs = 48000
for ftype in ("butter", "cheby1", "cheby2", "ellip", "bessel"):
# resample=False para que la respuesta exista por encima del Nyquist diezmado
bank = filters.OctaveFilterBank(
fs, fraction=1, order=6, limits=[800, 1200],
design=filters.FilterDesign(filter_type=ftype, resample=False))
idx = int(np.argmin(np.abs(np.array(bank.freq) - 1000)))
f_m = float(bank.freq[idx])
w, h = sosfreqz(bank.sos[idx], worN=1 << 17, fs=fs)
mag = 20 * np.log10(np.abs(h) + 1e-15)
mag -= mag.max()
grid = np.linspace(f_m * 0.95, f_m * 1.05, 4001)
_, h_c = sosfreqz(bank.sos[idx], worN=2 * np.pi * grid / fs)
delay = -np.gradient(np.unwrap(np.angle(h_c)), 2 * np.pi * grid)
banked = filters.OctaveFilterBank(
fs, fraction=1, order=6, limits=[800, 1200],
design=filters.FilterDesign(filter_type=ftype))
print(f"{ftype:8s} {mag[np.argmin(abs(w - 2 * f_m))]:7.1f} dB "
f"{mag[np.argmin(abs(w - 4 * f_m))]:7.1f} dB "
f"{delay[len(delay) // 2] * 1e3:5.2f} ms "
f"clase {filters.verify_filter_class(banked)['overall_class']}")

Vista espectral completa de los bancos para octava (1/1) y tercio de octava (1/3).

ArquitecturaOctava (fraction=1)Tercio de octava (fraction=3)
ButterworthRespuesta en frecuencia del banco de filtros Butterworth de banda de octavaRespuesta en frecuencia del banco de filtros Butterworth de banda de octavaRespuesta en frecuencia del banco Butterworth de tercio de octavaRespuesta en frecuencia del banco Butterworth de tercio de octava
Chebyshev IRespuesta en frecuencia del banco Chebyshev I de banda de octavaRespuesta en frecuencia del banco Chebyshev I de banda de octavaRespuesta en frecuencia del banco Chebyshev I de tercio de octavaRespuesta en frecuencia del banco Chebyshev I de tercio de octava
Chebyshev IIRespuesta en frecuencia del banco Chebyshev II de banda de octavaRespuesta en frecuencia del banco Chebyshev II de banda de octavaRespuesta en frecuencia del banco Chebyshev II de tercio de octavaRespuesta en frecuencia del banco Chebyshev II de tercio de octava
ElípticoRespuesta en frecuencia del banco elíptico de banda de octavaRespuesta en frecuencia del banco elíptico de banda de octavaRespuesta en frecuencia del banco elíptico de tercio de octavaRespuesta en frecuencia del banco elíptico de tercio de octava
BesselRespuesta en frecuencia del banco Bessel de banda de octavaRespuesta en frecuencia del banco Bessel de banda de octavaRespuesta en frecuencia del banco Bessel de tercio de octavaRespuesta en frecuencia del banco Bessel de tercio de octava

Compara las filas fijándote solo en dos cosas y las diferencias dejan de ser sutiles. Las mesetas: Chebyshev I pone su rizado dentro de cada banda, sobre la meseta; Chebyshev II lo pone fuera, como el tren de muescas entre bandas; el elíptico hace las dos cosas. La profundidad de los valles: cuánto cae la respuesta entre dos bandas contiguas es la fuga que un nivel de banda puede permitirse, y las faldas de Bessel se solapan mucho más que las de cualquiera de los demás; ese solapamiento es su caída lenta, dibujada.

Mostrar el código de esta figura
from phonometry import filters
# Una figura por arquitectura y fracción: la galería completa de respuestas
fs = 48000
for ftype in ("butter", "cheby1", "cheby2", "ellip", "bessel"):
for fraction in (1, 3):
# ResponsePlot(show=True) dibuja la respuesta en frecuencia del banco
filters.OctaveFilterBank(fs=fs, fraction=fraction, order=6,
limits=[12, 20000],
design=filters.FilterDesign(filter_type=ftype),
response_plot=filters.ResponsePlot(show=True))

El filtro Butterworth es conocido por su banda de paso máximamente plana. Es la elección estándar para mediciones acústicas donde no se admite rizado dentro de las bandas de frecuencia.

import numpy as np
from phonometry import filters
# Una señal calibrada en Pa para que la guía funcione por sí sola
fs = 48000
x = 0.2 * np.sin(2 * np.pi * 1000 * np.arange(fs) / fs)
# Medición estándar en tercios de octava
spl, freq = filters.octave_filter(x, fs, fraction=3,
design=filters.FilterDesign(filter_type='butter'))
Respuesta en frecuencia del banco Butterworth de tercio de octavaRespuesta en frecuencia del banco Butterworth de tercio de octava
Mostrar el código de esta figura
from phonometry import filters
# Dibuja la respuesta de este banco (1/3 de octava, orden 6, Butterworth)
filters.OctaveFilterBank(fs=48000, fraction=3, order=6, limits=[12, 20000],
design=filters.FilterDesign(filter_type='butter'),
response_plot=filters.ResponsePlot(show=True))

Los filtros Chebyshev tipo I ofrecen una caída más abrupta que Butterworth a cambio de rizado en la banda de paso. Útiles cuando se necesita alta selectividad cerca de las frecuencias de corte.

import numpy as np
from phonometry import filters
# Una señal calibrada en Pa para que la guía funcione por sí sola
fs = 48000
x = 0.2 * np.sin(2 * np.pi * 1000 * np.arange(fs) / fs)
# Selectividad con 0.1 dB de rizado en la banda de paso
spl, freq = filters.octave_filter(
x, fs, fraction=3,
design=filters.FilterDesign(filter_type='cheby1', ripple=0.1))
Respuesta en frecuencia del banco Chebyshev I de tercio de octavaRespuesta en frecuencia del banco Chebyshev I de tercio de octava
Mostrar el código de esta figura
from phonometry import filters
# Dibuja la respuesta de este banco (1/3 de octava, orden 6, Chebyshev I)
filters.OctaveFilterBank(fs=48000, fraction=3, order=6, limits=[12, 20000],
design=filters.FilterDesign(filter_type='cheby1', ripple=0.1),
response_plot=filters.ResponsePlot(show=True))

También llamado Chebyshev inverso, tiene banda de paso plana y rizado en la banda atenuada. Ofrece una caída más rápida que Butterworth sin afectar a la señal en la banda de paso. Los bordes de la banda atenuada se colocan automáticamente para que los puntos de −3 dB caigan en los bordes de banda (attenuation debe ser para que exista siquiera un punto de −3 dB; por debajo de eso el diseño lanza ValueError). Conviene notar que el valor por defecto de 72 dB lo fija la conformidad y no la realizabilidad: SciPy clava el suelo de rizado constante en exactamente attenuation, y la clase 1 de IEC 61260-1 exige 70 dB lejos de la banda, así que una attenuation de, pongamos, 6 dB es aritméticamente legal y pierde la clase en silencio; ver Verificación de clase de filtros.

import numpy as np
from phonometry import filters
# Una señal calibrada en Pa para que la guía funcione por sí sola
fs = 48000
x = 0.2 * np.sin(2 * np.pi * 1000 * np.arange(fs) / fs)
# Banda de paso plana, 72 dB de atenuación por defecto (clase 1)
spl, freq = filters.octave_filter(x, fs, fraction=3,
design=filters.FilterDesign(filter_type='cheby2'))
Respuesta en frecuencia del banco Chebyshev II de tercio de octavaRespuesta en frecuencia del banco Chebyshev II de tercio de octava
Mostrar el código de esta figura
from phonometry import filters
# Dibuja la respuesta de este banco (1/3 de octava, orden 6, Chebyshev II)
filters.OctaveFilterBank(fs=48000, fraction=3, order=6, limits=[12, 20000],
design=filters.FilterDesign(filter_type='cheby2'),
response_plot=filters.ResponsePlot(show=True))

Los filtros elípticos (Cauer) tienen la transición más corta (caída más abrupta) para un orden dado. Presentan rizado tanto en la banda de paso como en la atenuada.

import numpy as np
from phonometry import filters
# Una señal calibrada en Pa para que la guía funcione por sí sola
fs = 48000
x = 0.2 * np.sin(2 * np.pi * 1000 * np.arange(fs) / fs)
# Máxima selectividad para aislamiento extremo entre bandas
spl, freq = filters.octave_filter(
x, fs, fraction=3,
design=filters.FilterDesign(filter_type='ellip', ripple=0.1))
Respuesta en frecuencia del banco elíptico de tercio de octavaRespuesta en frecuencia del banco elíptico de tercio de octava
Mostrar el código de esta figura
from phonometry import filters
# Dibuja la respuesta de este banco (1/3 de octava, orden 6, elíptico)
filters.OctaveFilterBank(fs=48000, fraction=3, order=6, limits=[12, 20000],
design=filters.FilterDesign(filter_type='ellip', ripple=0.1),
response_plot=filters.ResponsePlot(show=True))

Los filtros Bessel están optimizados para una respuesta de fase lineal y un retardo de grupo mínimo. Preservan la forma de las ondas filtradas (transitorios) mejor que ningún otro tipo, pero tienen la caída más lenta. Esa afirmación es temporal, así que la prueba también lo es, y vive en la página hermana: la figura de retardo de grupo de Bancos de filtros enseña a Bessel manteniéndose casi plano en toda la banda de paso mientras Chebyshev I y el elíptico hacen pico en los bordes de banda, y la figura de descomposición por bandas de esa misma página enseña qué le hace a un transitorio una resonancia más larga.

import numpy as np
from phonometry import filters
# Una señal calibrada en Pa para que la guía funcione por sí sola
fs = 48000
x = 0.2 * np.sin(2 * np.pi * 1000 * np.arange(fs) / fs)
# Ideal para análisis de pulsos y preservación de transitorios
spl, freq = filters.octave_filter(x, fs, fraction=3,
design=filters.FilterDesign(filter_type='bessel'))
Respuesta en frecuencia del banco Bessel de tercio de octavaRespuesta en frecuencia del banco Bessel de tercio de octava
Mostrar el código de esta figura
from phonometry import filters
# Dibuja la respuesta de este banco (1/3 de octava, orden 6, Bessel)
filters.OctaveFilterBank(fs=48000, fraction=3, order=6, limits=[12, 20000],
design=filters.FilterDesign(filter_type='bessel'),
response_plot=filters.ResponsePlot(show=True))

4. Crossover Linkwitz-Riley (linkwitz_riley)

Sección titulada «4. Crossover Linkwitz-Riley (linkwitz_riley)»

Linkwitz-Riley no es una sexta arquitectura: no construye una banda IEC ni es un valor de FilterDesign(filter_type=…). Se llama directamente, y hace el trabajo contrario: divide una señal en dos ramas que se recombinan en una respuesta plana en magnitud, que es lo que necesita un crossover de altavoz y lo que una banda de medida no debe hacer jamás. Cada rama es un Butterworth de orden order/2 aplicado dos veces, así que cada una queda exactamente a −6 dB en la frecuencia de cruce (no a −3 dB como las bandas de arriba): las ramas suman a la unidad en amplitud, no en potencia.

Qué recombinación es plana depende de la paridad de order/2, y la suma ingenua es incorrecta para la mitad de los órdenes pares:

orderorder/2Diferencia de fase entre ramas en Recombinación plana
21 (impar)180°low - high
42 (par)low + high
63 (impar)180°low - high
84 (par)low + high

Con los órdenes 2 y 6 las ramas quedan en antifase en y low + high se hunde ahí en una muesca profunda en vez de sumar plano. Incluso en los casos planos la suma es paso todo, no libre de fase: su magnitud es plana dentro de 0,001 dB de 20 Hz a 20 kHz mientras su fase gira 360° completos a través del cruce.

import numpy as np
from phonometry import filters
# recording: una captura calibrada en Pa para que la guía funcione por sí sola
fs = 48000
recording = 0.2 * np.sin(2 * np.pi * 1000 * np.arange(fs) / fs)
# Dividir la grabación en bandas grave y aguda a 1000 Hz
order = 4
low, high = filters.linkwitz_riley(recording, fs, freq=1000, order=order)
# Recombinación plana: suma si order/2 es par, diferencia si order/2 es impar
recombined = low + high if (order // 2) % 2 == 0 else low - high
Crossover Linkwitz-Riley de 4.º orden: paso bajo, paso alto y su suma planaCrossover Linkwitz-Riley de 4.º orden: paso bajo, paso alto y su suma plana
Mostrar el código de esta figura
import matplotlib.pyplot as plt
import numpy as np
from scipy.signal import freqz
from phonometry import filters
# Medimos ambas ramas: dividimos un impulso unitario y tomamos los espectros.
fs = 48000
impulse = np.zeros(fs)
impulse[0] = 1.0
low, high = filters.linkwitz_riley(impulse, fs, freq=1000, order=4)
w, h_lp = freqz(low, worN=8192, fs=fs)
_, h_hp = freqz(high, worN=8192, fs=fs)
fig, ax = plt.subplots(figsize=(9, 5))
ax.semilogx(w, 20 * np.log10(np.abs(h_lp) + 1e-9), label="Paso bajo (LR4)")
ax.semilogx(w, 20 * np.log10(np.abs(h_hp) + 1e-9), label="Paso alto (LR4)")
ax.semilogx(w, 20 * np.log10(np.abs(h_lp + h_hp) + 1e-9), "--",
label="Suma (plana)")
ax.set(xlim=(20, 20000), ylim=(-60, 5),
xlabel="Frecuencia [Hz]", ylabel="Magnitud [dB]")
ax.grid(True, which="both", alpha=0.3)
ax.legend()
plt.show()

En un crossover real las dos ramas suman acústicamente, no eléctricamente, y la planitud de arriba solo sobrevive si los dos caminos acústicos están alineados en el tiempo. Bastan unos pocos centímetros de desalineamiento entre los centros acústicos del woofer y el tweeter para que la rotación de fase a 1 kHz hunda la suma en una muesca, y el remedio es un retardo en el altavoz adelantado, no otro orden de filtro. Se comprueba midiendo la respuesta sumada en eje con el método de barrido sinusoidal de Medición de sistemas.

  • Cubierto

    Las cinco arquitecturas sobre las que puede construirse cualquier banco de bandas IEC (Butterworth, Chebyshev I/II, elíptico, Bessel): sus respuestas en magnitud comparadas en el cruce a −3 dB y en la galería completa de octava y tercio de octava, el convenio de bordes de banda (exacto para Butterworth, Chebyshev II y Bessel; el borde de rizado para las dos familias de rizado constante), y un ejemplo de uso por arquitectura, más el crossover Linkwitz-Riley, cuyas dos ramas se recombinan planas por suma o por diferencia según la paridad de order/2.

  • No cubierto

    Las matemáticas de banda, el diseño de polos y ceros, estabilidad y multitasa y la referencia de parámetros de octave_filter() / OctaveFilterBank permanecen en Bancos de filtros. Las máscaras de aceptación de clase de la Tabla 1 de IEC 61260-1, que deciden la clase que alcanza realmente cada una de estas arquitecturas, son Verificación de clase de filtros.

¿Qué arquitectura de filtro debería elegir?

Sección titulada «¿Qué arquitectura de filtro debería elegir?»

Butterworth es la elección estándar para medición acústica general: banda de paso máximamente plana y sin rizado. Chebyshev I da una caída más abrupta a costa de rizado en la banda de paso; Chebyshev II mantiene la banda de paso plana y traslada el rizado a la banda atenuada; el elíptico ofrece la máxima selectividad, con rizado en ambas bandas; y Bessel preserva la forma de los transitorios gracias a su respuesta de fase lineal, pero tiene la caída más lenta. Conviene tener presente que Chebyshev I y el elíptico toman los bordes de banda como su borde de rizado y no como su punto de −3 dB, así que sus niveles por banda quedan unas décimas de decibelio por encima de los de las otras tres y no deben mezclarse con ellos en un mismo espectro. Linkwitz-Riley no es una de las cinco: es un crossover, y sus dos ramas se recombinan planas con low + high cuando order/2 es par y con low - high cuando es impar.