Ir al contenido

Bancos de filtros

phonometry soporta varios tipos de filtro, cada uno con su propia función de transferencia característica. Todos los bancos sitúan sus puntos de −3 dB en los bordes de banda de ANSI S1.11, de modo que los niveles por banda son comparables entre arquitecturas.

Bandas de octava fraccionaria: las matemáticas

Sección titulada «Bandas de octava fraccionaria: las matemáticas»

IEC 61260-1:2014 construye cada banda a partir de la razón de octava en base 10 G=103/101.99526G = 10^{3/10} \approx 1.99526 (es decir, “una octava” no es exactamente 2). Para la fracción de banda 1/b1/b, las frecuencias centrales y los bordes de banda siguen (5.2-5.5):

fm=1000Gx/b(b impar),f1=fmG1/2b,f2=fmG+1/2bf_m = 1000 \cdot G^{x/b} \quad (b\ \text{impar}), \qquad f_1 = f_m G^{-1/2b}, \quad f_2 = f_m G^{+1/2b}

de modo que cada banda de tercio de octava abarca G1/31.2589101/10G^{1/3} \approx 1.2589 \approx 10^{1/10} — diez bandas por década, y por eso las frecuencias nominales (25, 31,5, 40 …) se repiten escaladas por 10. phonometry diseña cada banda como una cascada SOS cuyos puntos de −3 dB caen exactamente en f1f_1 y f2f_2 en todas las arquitecturas — para Chebyshev II, Elíptico y Bessel eso exige pre-deformar (pre-warping) el mapeo analítico de los bordes de banda en lugar de confiar en la parametrización por defecto de SciPy.

Una banda de tercio de octava de 25 Hz a 48 kHz abarca unos 5,8 Hz — el 0,024 % de Nyquist — con coeficientes tan rígidos que se vuelven numéricamente inestables. El banco lo evita filtrando las bandas bajas a una frecuencia decimada:

Decimación multitasa: las bandas altas se filtran a la frecuencia de entrada y las bajas tras un filtro paso bajo antialias y decimación, para que las secciones SOS se mantengan numéricamente sanasDecimación multitasa: las bandas altas se filtran a la frecuencia de entrada y las bajas tras un paso-bajo antialiasing y diezmado, para que las secciones SOS se mantengan numéricamente sanas

Parámetros de octavefilter() / OctaveFilterBank

Sección titulada «Parámetros de octavefilter() / OctaveFilterBank»
ParámetroTipoUnidadesRango / por defectoNotas
xarray 1D o 2Dunidades digitalesno vacío2D es [channels, samples]
fsintHz> 0
fractionintpor defecto 1; habitual 3; cualquier b ≥ 1Bandas por octava = b
orderintpor defecto 6Orden SOS por banda
limitslista [lo, hi]Hzpor defecto [12, 20000]Rango de análisis
filter_typestr'butter' (por defecto), 'cheby1', 'cheby2', 'ellip', 'bessel'Ver la comparación más abajo
ripple / attenuationfloatdBrequerido por los tipos cheby/ellipRizado de banda de paso / atenuación de banda eliminada
showboolpor defecto FalseDibuja la respuesta del banco (requiere matplotlib)
sigbandsboolpor defecto FalseDevuelve también las señales temporales por banda
zero_phaseboolpor defecto FalseFiltrado adelante-atrás (offline)
stateful / steady_ic (clase)boolpor defecto FalseEstado en streaming; consulta Procesado por bloques

verify_filter_class(bank) comprueba el banco diseñado contra los límites de aceptación de la Tabla 1 de IEC 61260-1 e informa de la clase (1, 2 o None si queda fuera de ambas) con los márgenes por banda.

Usamos secciones de segundo orden (SOS) en todos los filtros para garantizar la estabilidad numérica. La siguiente gráfica compara las arquitecturas centrándose en el punto de cruce a −3 dB.

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

TipoNombreEjemplo de usoIdeal para
butterButterworthoctavefilter(x, fs, filter_type='butter')Medición acústica general.
cheby1Chebyshev Ioctavefilter(x, fs, filter_type='cheby1', ripple=0.1)Caída más abrupta a costa de rizado.
cheby2Chebyshev IIoctavefilter(x, fs, filter_type='cheby2', attenuation=60)Banda de paso plana con ceros en la banda atenuada.
ellipElípticooctavefilter(x, fs, filter_type='ellip', ripple=0.1, attenuation=60)Máxima selectividad.
besselBesseloctavefilter(x, fs, filter_type='bessel')Preservar la forma de los transitorios.

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

ArquitecturaOctava 1/1 (fraction=1)Octava 1/3 (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

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.

from phonometry import octavefilter
# Medición estándar por defecto
spl, freq = octavefilter(x, fs, filter_type='butter')

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.

# Selectividad con 0.1 dB de rizado en la banda de paso
spl, freq = octavefilter(x, fs, filter_type='cheby1', ripple=0.1)

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 > 3.01 dB).

# Banda de paso plana con 60 dB de atenuación
spl, freq = octavefilter(x, fs, filter_type='cheby2', attenuation=60)

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.

# Máxima selectividad para aislamiento extremo entre bandas
spl, freq = octavefilter(x, fs, filter_type='ellip', ripple=0.1, attenuation=60)

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.

# Ideal para análisis de pulsos y preservación de transitorios
spl, freq = octavefilter(x, fs, filter_type='bessel')

Diseñado específicamente para crossovers de audio. Los filtros Linkwitz-Riley (típicamente de 4.º orden, aunque se admite cualquier orden par) permiten dividir una señal en bandas que, al sumarse, producen una respuesta en magnitud perfectamente plana y sin diferencia de fase entre bandas en el cruce.

from phonometry import linkwitz_riley
# Dividir la señal en bandas grave y aguda a 1000 Hz
low, high = linkwitz_riley(signal, fs, freq=1000, order=4)
# Reconstrucción: low + high == signal (respuesta plana)

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

verify_filter_class comprueba cada banda de un banco contra los límites de aceptación de IEC 61260-1:2014 (Tabla 1, con el mapeo de breakpoints a fraccionales y la interpolación logarítmica de la norma) e informa de la clase por banda con su margen en dB:

from phonometry import OctaveFilterBank, verify_filter_class
bank = OctaveFilterBank(fs=48000, fraction=3, order=6)
result = verify_filter_class(bank)
print(result["overall_class"]) # 1, 2 o None
print(result["bands"][0]) # {'freq': ..., 'class': 1, 'margin_class1_db': ...}

Respuesta Butterworth serpenteando entre las regiones prohibidas de la máscara de clase 1 de IEC 61260-1Respuesta Butterworth serpenteando entre las regiones prohibidas de la máscara de clase 1 de IEC 61260-1

La respuesta del Butterworth de orden 6 (azul) serpentea entre las regiones prohibidas: debe atenuar al menos la máscara roja fuera de la banda y no más que la morada dentro de ella.

Con parámetros por defecto (orden 6), Butterworth cumple clase 1. Chebyshev II se queda en clase 2 — limitado exactamente por su attenuation=60 frente a los 70 dB exigidos en el stopband lejano (sube attenuation para alcanzar clase 1). Chebyshev I, Elíptico y Bessel no cumplen los límites de clase con orden 6: el rizado de banda de paso (cheby1/ellip) y la caída lenta (bessel) violan la máscara.

Con sigbands=True puedes recuperar las componentes en el dominio del tiempo de cada banda. Esto permite análisis avanzados o comparar cómo afectan distintas arquitecturas (p. ej. Butterworth vs Chebyshev) a la fase y al transitorio.

import numpy as np
from phonometry import octavefilter
# 1. Generar una señal (suma de 250 Hz y 1000 Hz)
fs = 48000
t = np.linspace(0, 0.5, int(fs * 0.5), endpoint=False)
y = np.sin(2 * np.pi * 250 * t) + np.sin(2 * np.pi * 1000 * t)
# 2. Comparar arquitecturas (Butterworth vs Chebyshev II)
spl_b, freq, xb_butter = octavefilter(y, fs=fs, fraction=1, sigbands=True, filter_type='butter')
spl_c2, _, xb_cheby2 = octavefilter(y, fs=fs, fraction=1, sigbands=True, filter_type='cheby2')
# 'xb_butter' y 'xb_cheby2' contienen las señales por banda en el dominio del tiempo

Descomposición por bandas en el tiempo comparando Butterworth y Chebyshev II, incluida la respuesta al impulsoDescomposición por bandas en el tiempo comparando Butterworth y Chebyshev II, incluida la respuesta al impulso

La gráfica compara las respuestas de Butterworth (azul, línea continua) y Chebyshev II (rojo, discontinua). El panel inferior muestra la respuesta al impulso, destacando las diferencias de estabilidad y decaimiento transitorio.

El retardo de grupo τg(ω)=dϕ(ω)dω\tau_g(\omega) = -\frac{d\phi(\omega)}{d\omega} de la banda de octava de 1 kHz muestra el compromiso directamente: Bessel se mantiene casi plano en la banda de paso (los transitorios sobreviven), mientras que Chebyshev I y el Elíptico pagan su caída abrupta con fuertes picos de retardo en los bordes de banda.

Retardo de grupo de la banda de 1 kHz para las cinco arquitecturas: Bessel casi plano, Chebyshev y elíptico con picos en los bordesRetardo de grupo de la banda de 1 kHz para las cinco arquitecturas: Bessel casi plano, Chebyshev y elíptico con picos en los bordes

Para análisis offline puedes eliminar por completo el retardo de grupo: zero_phase=True filtra cada banda hacia delante y hacia atrás (scipy.signal.sosfiltfilt), manteniendo las señales por banda alineadas con la entrada. La atenuación efectiva se duplica y la opción es incompatible con el procesado por bloques (stateful).

from phonometry import OctaveFilterBank
bank = OctaveFilterBank(fs=48000, fraction=3)
spl, freq, xb = bank.filter(y, sigbands=True, zero_phase=True)

Filtrado causal frente a fase cero de una ráfaga: la salida de fase cero queda alineada con la entradaFiltrado causal frente a fase cero de una ráfaga: la salida de fase cero queda alineada con la entrada

El filtrado causal retrasa la ráfaga según el retardo de grupo del filtro; el filtrado de fase cero la mantiene alineada con la entrada.

Creado y mantenido por· GitHub· PyPI