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.
Mostrar el código de esta figura
import matplotlib.pyplot as pltimport numpy as npfrom scipy.signal import sosfreqzfrom phonometry import filters
fs = 48000fig, 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()| Tipo | Nombre | Ejemplo de uso | Ideal para |
|---|---|---|---|
butter | Butterworth | octave_filter(x, fs, design=FilterDesign(filter_type='butter')) | Medición acústica general. |
cheby1 | Chebyshev I | octave_filter(x, fs, design=FilterDesign(filter_type='cheby1', ripple=0.1)) | Caída más abrupta a costa de rizado. |
cheby2 | Chebyshev II | octave_filter(x, fs, design=FilterDesign(filter_type='cheby2')) | Banda de paso plana con ceros en la banda atenuada. |
ellip | Elíptico | octave_filter(x, fs, design=FilterDesign(filter_type='ellip', ripple=0.1)) | Máxima selectividad. |
bessel | Bessel | octave_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). |
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.
| Arquitectura | Rizado en el centro de banda | En | En | Retardo de grupo en | Clase IEC 61260-1 (orden 6, 48 kHz) |
|---|---|---|---|---|---|
butter | 0,00 dB | −39,6 dB | −88,2 dB | 1,74 ms | 1 |
cheby1 | 0,10 dB | −50,2 dB | −101,6 dB | 1,97 ms | ninguna |
cheby2 | 0,00 dB | −55,1 dB | −73,0 dB | 1,58 ms | 1 |
ellip | 0,10 dB | −72,1 dB | −80,8 dB | 1,75 ms | ninguna |
bessel | 0,21 dB | −16,4 dB | −60,2 dB | 1,22 ms | ninguna |
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 npfrom scipy.signal import sosfreqz
# `filters` es el import del fragmento anterior.fs = 48000for 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']}")2. Galería de respuestas del banco
Sección titulada «2. Galería de respuestas del banco»Vista espectral completa de los bancos para octava (1/1) y tercio de octava (1/3).
| Arquitectura | Octava (fraction=1) | Tercio de octava (fraction=3) |
|---|---|---|
| Butterworth | ||
| Chebyshev I | ||
| Chebyshev II | ||
| Elíptico | ||
| Bessel |
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 respuestasfs = 48000for 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))3. Uso y ejemplos por tipo de filtro
Sección titulada «3. Uso y ejemplos por tipo de filtro»1. Butterworth (butter)
Sección titulada «1. Butterworth (butter)»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 npfrom phonometry import filters
# Una señal calibrada en Pa para que la guía funcione por sí solafs = 48000x = 0.2 * np.sin(2 * np.pi * 1000 * np.arange(fs) / fs)
# Medición estándar en tercios de octavaspl, freq = filters.octave_filter(x, fs, fraction=3, design=filters.FilterDesign(filter_type='butter'))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))2. Chebyshev I (cheby1)
Sección titulada «2. Chebyshev I (cheby1)»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 npfrom phonometry import filters
# Una señal calibrada en Pa para que la guía funcione por sí solafs = 48000x = 0.2 * np.sin(2 * np.pi * 1000 * np.arange(fs) / fs)
# Selectividad con 0.1 dB de rizado en la banda de pasospl, freq = filters.octave_filter( x, fs, fraction=3, design=filters.FilterDesign(filter_type='cheby1', ripple=0.1))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))3. Chebyshev II (cheby2)
Sección titulada «3. Chebyshev II (cheby2)»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 npfrom phonometry import filters
# Una señal calibrada en Pa para que la guía funcione por sí solafs = 48000x = 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'))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))4. Elíptico (ellip)
Sección titulada «4. Elíptico (ellip)»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 npfrom phonometry import filters
# Una señal calibrada en Pa para que la guía funcione por sí solafs = 48000x = 0.2 * np.sin(2 * np.pi * 1000 * np.arange(fs) / fs)
# Máxima selectividad para aislamiento extremo entre bandasspl, freq = filters.octave_filter( x, fs, fraction=3, design=filters.FilterDesign(filter_type='ellip', ripple=0.1))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))5. Bessel (bessel)
Sección titulada «5. Bessel (bessel)»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 npfrom phonometry import filters
# Una señal calibrada en Pa para que la guía funcione por sí solafs = 48000x = 0.2 * np.sin(2 * np.pi * 1000 * np.arange(fs) / fs)
# Ideal para análisis de pulsos y preservación de transitoriosspl, freq = filters.octave_filter(x, fs, fraction=3, design=filters.FilterDesign(filter_type='bessel'))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:
order | order/2 | Diferencia de fase entre ramas en | Recombinación plana |
|---|---|---|---|
| 2 | 1 (impar) | 180° | low - high |
| 4 | 2 (par) | 0° | low + high |
| 6 | 3 (impar) | 180° | low - high |
| 8 | 4 (par) | 0° | 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 npfrom phonometry import filters
# recording: una captura calibrada en Pa para que la guía funcione por sí solafs = 48000recording = 0.2 * np.sin(2 * np.pi * 1000 * np.arange(fs) / fs)
# Dividir la grabación en bandas grave y aguda a 1000 Hzorder = 4low, high = filters.linkwitz_riley(recording, fs, freq=1000, order=order)# Recombinación plana: suma si order/2 es par, diferencia si order/2 es imparrecombined = low + high if (order // 2) % 2 == 0 else low - highMostrar el código de esta figura
import matplotlib.pyplot as pltimport numpy as npfrom scipy.signal import freqzfrom phonometry import filters
# Medimos ambas ramas: dividimos un impulso unitario y tomamos los espectros.fs = 48000impulse = np.zeros(fs)impulse[0] = 1.0low, 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.
Qué cubre esta guía
Sección titulada «Qué cubre esta guía»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()/OctaveFilterBankpermanecen 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.
Véase también
Sección titulada «Véase también»- Bancos de filtros: las matemáticas de banda, la maquinaria de diseño y la referencia de parámetros detrás de cada banco mostrado aquí.
- Verificación de clase de filtros (IEC 61260-1): la máscara de aceptación de la Tabla 1, la clase 0 y la ficha de conformidad de estas arquitecturas.
- Referencia de la API:
phonometryyfilters.core. - Teoría: Respuestas en magnitud: qué es una respuesta en magnitud como función de transferencia compleja, y en qué se diferencian las cinco arquitecturas antes de filtrar ninguna banda.
Respuestas rápidas
Sección titulada «Respuestas rápidas»¿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.
Referencias
Sección titulada «Referencias»- American National Standards Institute. (2004). Specification for octave-band and fractional-octave-band analog and digital filters (ANSI S1.11-2004). Acoustical Society of America. El convenio de bordes de banda sobre el que cada arquitectura de esta galería sitúa sus puntos de −3 dB, que es lo que hace comparables sus niveles de banda.
- International Electrotechnical Commission. (2014). Electroacoustics — Octave-band and fractional-octave-band filters — Part 1: Specifications (IEC 61260-1:2014). Las frecuencias centrales y los bordes de banda en base 10 a los que se diseña cada banco comparado en esta galería, sea cual sea la arquitectura que realice la banda.
- Smith, J. O. (s. f.). Introduction to digital filters with audio applications. Center for Computer Research in Music and Acoustics (CCRMA), Stanford University. Libro en línea gratuito y complementario sobre diseño y análisis de filtros digitales, que trata las arquitecturas clásicas comparadas en esta galería.