Bancos de filtros
Normas aplicables: IEC 61260ANSI S1.11ISO 266Referencias: Oppenheim y Schafer 2010
phonometry ofrece varios tipos de filtro, cada uno con su propia función de transferencia característica. Butterworth, Chebyshev II y Bessel sitúan sus puntos de −3 dB en los bordes de banda de ANSI S1.11, de modo que sus niveles por banda son directamente comparables. Los dos diseños de rizado constante (Chebyshev I, Elíptico) no: toman esos bordes como borde de rizado, lo que ensancha la banda y sesga todos los niveles por banda en unas décimas de decibelio fijas — ver el apartado 1, porque el sesgo es sistemático y no se promedia a cero.
Al terminar esta página sabrás diseñar un banco para cualquier fracción , leer todos los argumentos en una sola tabla, encadenar secciones de EQ RBJ, extraer las señales temporales por banda y filtrar con fase cero. El apartado 1 son las matemáticas sobre las que se apoya el diseño; si solo quieres llamar a la función, empieza por el apartado 2. En qué se diferencian las cinco arquitecturas es la Galería de arquitecturas de filtro, y qué significa «clase 1» para el resultado es Verificación de clase de filtros.
1. Bandas de fracción de octava: las matemáticas
Sección titulada «1. Bandas de fracción de octava: las matemáticas»IEC 61260-1:2014 construye cada banda a partir de la razón de octava en base 10 (es decir, «una octava» no es exactamente 2). Para la fracción de banda , las frecuencias centrales y los bordes de banda siguen (5.2-5.5):
de modo que cada banda de tercio de octava abarca : 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 sobre esos bordes, pero dónde acaba cayendo el punto de −3 dB depende de qué entiende cada arquitectura por su frecuencia de diseño, y solo tres de las cinco lo ponen en y .
Las dos formas existen para que la frecuencia de referencia de 1000 Hz sea una
frecuencia central de banda cuando es impar y un borde de banda
cuando es par. Eso es lo que mantiene anidadas las fracciones impares (cada
banda de octava son exactamente tres bandas de tercio de octava) mientras que
las pares parten justo en las fronteras de octava; las fórmulas de los bordes
son las mismas en ambos casos. La consecuencia práctica es fácil de pisar: un
espectro con fraction=2, 12 o 24 no tiene banda de 1 kHz en absoluto, sus
etiquetas nominales salen del redondeo a cifras significativas del Anexo E.3 y
no de la serie preferente de ISO 266, y compararlo banda a banda con una tabla
de tercios de octava no significa nada.
Dónde cae de verdad el punto de −3 dB de cada arquitectura
Sección titulada «Dónde cae de verdad el punto de −3 dB de cada arquitectura»La frecuencia de diseño de SciPy para Butterworth es su punto de −3 dB, así
que no necesita corrección. Chebyshev II se diseña por sus bordes de banda
eliminada, obtenidos analíticamente desde los bordes de banda, y Bessel se
normaliza con norm="mag" en lugar de con la normalización de fase por defecto
de SciPy: las dos correcciones existen para que sus puntos de −3 dB caigan
también en los bordes. A Chebyshev I y al Elíptico se les entregan los bordes de
banda directamente, y para esas dos familias SciPy los lee como borde de la
banda de paso de rizado constante: la respuesta ahí es la profundidad del
rizado, no −3 dB. Medido sobre la banda de octava de 1 kHz a 48 kHz con orden 6
y el ripple=0.1 por defecto:
| Arquitectura | Respuesta en y | Ancho de banda de ruido / | Desviación del nivel de banda |
|---|---|---|---|
butter | −3,01 dB | 1,003 | referencia |
cheby2 | −3,01 dB | 1,003 | −0,02 dB |
bessel | −3,01 dB | 0,971 | +0,05 dB |
cheby1 | −0,10 dB | 1,066 | +0,33 dB |
ellip | −0,10 dB | 1,052 | +0,25 dB |
Las tres primeras columnas son la banda de octava de 1 kHz; la última es la
diferencia mediana de nivel de banda respecto a Butterworth sobre un banco
entero de tercios de octava analizando 20 s de ruido blanco. Esa última columna
importa porque es un sesgo, no dispersión: no se reduce con el tiempo de
promediación, es mayor que todo el corredor de banda de paso de clase 1
(±0,4 dB) y mueve todas las bandas a la vez, así que un espectro medido con
cheby1 queda en bloque por encima de uno medido con butter. Conviene elegir
una arquitectura por campaña y no mezclar nunca arquitecturas dentro de un mismo
espectro. Subir el order reduce la desviación, porque una banda de transición
más estrecha devuelve el punto de −3 dB hacia el borde de rizado: para cheby1
la mediana pasa de +0,76 dB con orden 4 a +0,33 dB con orden 6, +0,16 dB con
orden 8 y +0,04 dB con orden 12. Bajar design.ripple hace lo contrario de lo
que sugiere la intuición y hace la desviación mayor (+0,62 dB con
ripple=0.02), porque a orden fijo una banda de paso más plana se paga con una
caída más lenta.
Polos, ceros y estabilidad
Sección titulada «Polos, ceros y estabilidad»Un paso banda digital es una constelación de polos y ceros en el plano z: los ceros en DC y Nyquist, o cerca de ellos, sujetan la respuesta lejos de la banda (hasta el suelo de la banda atenuada, en los diseños de rizado constante), y los polos se agrupan justo dentro del círculo unidad en los ángulos que abarca la banda de paso. De ahí salen dos intuiciones. Primera, la selectividad es proximidad: cuanto más cerca del círculo unidad están los polos, más abrupta es la banda y más tiempo resuena el filtro (los picos de retardo de grupo de la sección 4 son esa resonancia, medida). Segunda, la estabilidad es un margen, no una propiedad de la arquitectura: un filtro IIR es estable solo mientras todos sus polos permanecen estrictamente dentro del círculo unidad, y una banda estrecha a una frecuencia de muestreo alta los empuja hacia fuera (radio del polo para un ancho de banda ) y los aprieta entre sí, hasta que los coeficientes en doble precisión ya no pueden representar sus posiciones con exactitud. Las secciones de segundo orden (SOS) desactivan la mitad del problema: cada par de polos conserva sus propios coeficientes, de modo que los errores de redondeo quedan localizados en lugar de acumularse en un único polinomio de orden alto. La otra mitad, la minúscula razón en sí, es lo que arregla el diezmado.
La selectividad es proximidad, y el precio es el condicionamiento. A la frecuencia completa, los polos de la banda de 25 Hz quedan a menos de del círculo unidad y unos encima de otros; esa misma banda realizada a su frecuencia diezmada los tiene repartidos y 500 veces más lejos. El panel derecho es la decisión de diseño resumida en una curva: el banco multitasa mantiene todas las bandas en la misma región bien condicionada, sea cual sea su frecuencia central.
Cómo se midió esta figura
Los dos bancos salen de la tabla de parámetros del apartado 2, uno con el
design por defecto y otro con design=FilterDesign(resample=False). Las
posiciones de los polos se leen directamente del banco: bank.sos[idx] es la
cascada SOS de la banda idx y scipy.signal.sos2zpk la convierte en ceros,
polos y ganancia, de modo que la distancia al círculo unidad es
1 - abs(poles).max(). Para la banda de 25,1 Hz de un banco de tercios de
octava a 48 kHz esa distancia es 8.73e-05 a la frecuencia completa y
4.62e-02 a la frecuencia diezmada que el banco usa realmente
(bank.factor[idx] vale 500, así que la banda corre a 96 Hz). SciPy lanza
BadCoefficients al leer el diseño a la frecuencia completa: ese aviso es el
argumento de este apartado, escrito por la biblioteca que se lo encontró.
Diezmado multitasa
Sección titulada «Diezmado multitasa»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 diezmada:
Diezmar por reescala el problema: el mismo ancho de banda de 5,8 Hz se vuelve veces mayor respecto al nuevo Nyquist, el radio de los polos se separa del círculo unidad y los coeficientes SOS regresan a un rango bien condicionado. El precio es una contabilidad que el banco paga internamente: antes de cada etapa de diezmado debe ejecutarse un paso bajo antialiasing, porque una componente por encima del nuevo Nyquist que se pliegue hacia abajo cae dentro de las bandas bajas que se están midiendo, y ningún filtro posterior puede eliminarla.
Trampas de aliasing
Sección titulada «Trampas de aliasing»El banco protege sus propias etapas de diezmado, pero solo puede analizar lo que la cadena de captura le entrega:
- Plegado en el ADC. La energía por encima de que llega al conversor sin un filtro antialiasing analógico se pliega dentro del rango de análisis y es indistinguible del sonido real dentro de banda. Las tarjetas de sonido lo filtran internamente; las cadenas de instrumentación a medida pueden no hacerlo.
- Remuestreo barato. Convertir una grabación de 44,1 kHz a 48 kHz con un
remuestreador de baja calidad deja imágenes que sesgan las bandas más
altas. Usa un remuestreador polifásico (
scipy.signal.resample_poly) o, más sencillo, analiza a la frecuencia nativa: todas las funciones de phonometry aceptanfsdirectamente. - Bandas cerca de Nyquist. Una banda cuyo borde superior se acerca a
no puede realizar su respuesta de diseño: la transformada bilineal
comprime allí el eje de frecuencias (el mismo efecto que los filtros de
ponderación contrarrestan con
high_accuracy). Mantén el borde de la banda superior holgadamente por debajo de Nyquist o subefs, y deja queverify_filter_classinforme del margen restante.
¿Cuánto tiene que durar el registro?
Sección titulada «¿Cuánto tiene que durar el registro?»Un nivel de banda no se lee de una señal, se estima a partir de ella, y cuanto más estrecha es la banda más tarda esa estimación. El ancho de banda de una banda de de octava es , que para tercios de octava vale , y de ahí se siguen dos consecuencias.
El filtro tiene que asentarse: una banda resuena durante unas pocas veces , así que ese trozo del principio del registro es transitorio y no nivel, y hay que descartarlo (alrededor de un segundo en la banda de 12,5 Hz, doce milisegundos a 1 kHz). Y la estimación arrastra un error aleatorio de unos dB con sonido de tipo ruido, así que una desviación típica de 0,4 dB exige :
| Banda más baja informada | [Hz] | para una desviación típica de 0,4 dB |
|---|---|---|
| 12,5 Hz | 2,9 | 35 s |
| 125 Hz | 29 | 3,5 s |
| 1 kHz | 231 | 0,4 s |
La regla que se sigue cabe en una línea: la banda más baja que pienses
informar fija la duración del registro de todo el banco. Analizar un
fragmento de 1 s hasta 12,5 Hz e informar el resultado con un decimal no es una
medida de esa banda, y ni octave_filter ni OctaveFilterBank te avisan. La
ley general se deduce en
Correlación, retardo y envolvente;
esa misma aritmética aplicada por trama en vez de por registro es la nota sobre
window_time de
Niveles integrados y estadísticos.
Las matemáticas de banda anteriores son comunes a todas las arquitecturas. Cómo difieren realmente las arquitecturas, la comparación en el cruce a −3 dB, la galería completa de respuestas en octava y tercio de octava y los ejemplos de uso por arquitectura, hasta el crossover Linkwitz-Riley, es la Galería de arquitecturas de filtro.
2. Parámetros de octave_filter() / OctaveFilterBank
Sección titulada «2. Parámetros de octave_filter() / OctaveFilterBank»Los argumentos de cada día van primero y por posición — x, fs, fraction,
order, limits — y todo lo demás se agrupa en cuatro dataclases congeladas
que se pasan por palabra clave: design (FilterDesign), calibration
(LevelCalibration), block_processing (BlockProcessing) y response_plot
(ResponsePlot). Al ser congeladas son hashables, que es lo que permite que dos
grupos de opciones iguales acierten en la misma caché de diseño. La tabla de
abajo nombra cada opción por el grupo en el que viaja.
Tres puntos de llamada comparten esta tabla, y no aceptan las mismas opciones,
así que la columna Dónde nombra aquel al que pertenece cada una:
octave_filter() es la función de un solo uso, OctaveFilterBank(...) es el
constructor y bank.filter() es el método por llamada.
| Parámetro | Dónde | Tipo | Unidades | Rango / por defecto | Notas |
|---|---|---|---|---|---|
x | función, .filter() | array 1D o 2D | unidades digitales | no vacío | 2D es [channels, samples] |
fs | función, constructor | int | Hz | > 0 | |
fraction | función, constructor | int | — | por defecto 1; habitual 3; cualquier | Bandas por octava = |
order | función, constructor | int | — | por defecto 6 | Orden SOS por banda |
limits | función, constructor | lista [lo, hi] | Hz | por defecto [12, 20000] | Rango de análisis |
design.filter_type | función, constructor | str | — | 'butter' (por defecto), 'cheby1', 'cheby2', 'ellip', 'bessel' | Consulta la Galería de arquitecturas de filtro |
design.ripple / design.attenuation | función, constructor | float | dB | ripple defecto 0.1; attenuation defecto 72.0 | Rizado de banda de paso / atenuación en banda atenuada (cheby/ellip); cheby2 necesita attenuation para clase 1, ya que scipy fija su suelo de rizado constante en exactamente este valor |
design.resample | función, constructor | bool | — | por defecto True | Filtra cada banda a una frecuencia diezmada (multitasa) |
response_plot.show | función, constructor | bool | — | por defecto False | Dibuja la respuesta del banco (requiere matplotlib) |
response_plot.file | función, constructor | str o None | — | por defecto None | Guarda la gráfica de respuesta del banco en esta ruta |
calibration.factor | función, constructor | float | — | por defecto 1.0 | Escala la entrada a pascales (consulta la guía de Calibración) |
calibration.dbfs | función, constructor | bool | — | por defecto False | Referencia los niveles a fondo de escala digital en vez de 20 µPa |
block_processing.stateful / .steady_ic | solo constructor | bool | — | por defecto False | Estado en streaming; consulta Procesado por bloques |
sigbands | función, .filter() | bool | — | por defecto False | Devuelve también las señales temporales por banda |
mode | función, .filter() | str | — | 'rms' (por defecto) o 'peak' | Estadístico por banda devuelto |
nominal | función, .filter() | bool | — | por defecto False | Devuelve etiquetas nominales (p. ej. 1000) en vez de las frecuencias centrales exactas |
detrend | función, .filter() | bool | — | por defecto True | Elimina el offset DC de cada banda antes del nivel (mejora la precisión en graves) |
zero_phase | solo .filter() | bool | — | por defecto False | Filtrado adelante-atrás (offline); ver el apartado 5 |
calculate_level | solo .filter() | bool | — | por defecto True | Con False devuelve las señales de banda sin calcular niveles (usar con sigbands=True) |
El reparto no es arbitrario: la octave_filter() de un solo uso diseña un banco
y lo usa una vez, así que solo lleva las opciones de tiempo de diseño.
zero_phase y calculate_level se deciden en cada llamada y por eso viven en
OctaveFilterBank.filter() — octave_filter(x, fs, zero_phase=True) lanza
TypeError —, mientras que el estado de streaming queda fijado al construir el
banco.
mode tiene exactamente dos valores. 'rms' da el nivel medio energético de la
banda sobre todo el registro, que es lo que toda norma entiende por «nivel de
banda». 'peak' da de la mayor muestra en valor absoluto dentro
de la banda, contra la misma referencia de 20 µPa; es un pico instantáneo de
banda, no una lectura de retención de pico, está limitado en banda y sin
ponderar, así que no es el pico ponderado C de la guía de
Niveles, y en señales impulsivas lo
domina la propia resonancia del filtro: pertenece al diagnóstico de transitorios,
no a la comunicación de niveles. No hay modo 'sum': un total entre bandas es
una suma energética que hace quien llama,
10*np.log10(np.sum(10**(spl/10))), nunca una media aritmética de decibelios.
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.
Qué compra order, y dónde deja de comprar
Sección titulada «Qué compra order, y dónde deja de comprar»order es el orden de cada par de secciones paso banda, así que fija con qué
rapidez caen las faldas y, por tanto, cuánto se cuela una banda vecina en el
nivel de una banda. El orden 6 es el valor por defecto porque supera la máscara
de IEC 61260-1 con holgura para Butterworth, y la aritmética merece verse: a
48 kHz sobre un banco Butterworth de tercios de octava, el orden 2 se queda a
27,03 dB de la clase 1 en la banda atenuada lejana, mientras que los órdenes 4,
6, 8 y 10 pasan todos con un margen de clase 1 de exactamente +0,40 dB.
Que el margen sea idéntico no es casualidad, y es la mitad útil de la regla. A partir del orden 4 la restricción que manda se ha desplazado de la banda atenuada a la banda de paso, donde un diseño máximamente plano se queda en 0 dB de desviación y el corredor de clase 1 es de ±0,4 dB: subir más el orden compra profundidad en la banda atenuada, pero ni un decibelio de margen de clase. Y cuesta: cada par de polos de más alarga la resonancia (los picos de retardo de grupo del apartado 4 crecen con el orden), que es la razón por la que el trabajo con transitorios y los espectrogramas de ventana corta prefieren órdenes bajos. La aritmética del margen en sí es Verificación de clase de filtros.
3. EQ paramétrico (ParametricEQ)
Sección titulada «3. EQ paramétrico (ParametricEQ)»Secciones biquad de ecualización según el RBJ Audio EQ Cookbook
(Bristow-Johnson): campana (peaking), shelving grave/agudo, paso bajo/alto,
paso banda (pico a 0 dB constante o faldas constantes), rechazo de banda
(notch) y paso todo, cada una parametrizada por fs, f0, gain_db y uno
de q, bw (ancho de banda en octavas) o slope, exactamente como los
define el cookbook. Las secciones se encadenan en una cascada SOS
numéricamente robusta, y el diseño es exacto en forma cerrada: una campana
pasa exactamente gain_db en f0 y exactamente 0 dB en DC y Nyquist, los
shelving caen exactamente en gain_db en su extremo, y el paso todo tiene
magnitud unidad en todas las frecuencias (solo gira la fase).
import numpy as npfrom phonometry import EQSection, ParametricEQ
fs = 48000rng = np.random.default_rng(1)x = rng.standard_normal(fs) # un segundo de ruido
eq = ParametricEQ(fs, [ EQSection("lowshelf", 100.0, gain_db=4.0), EQSection("peaking", 1000.0, gain_db=-6.0, bw=1.0), # recorte de 1 octava EQSection("highshelf", 8000.0, gain_db=3.0),])y = eq.filter(x) # aplicar la cascadares = eq.response() # resultado congelado con la cascada SOSaxes = res.plot(language="es") # magnitud + fase de la cascadaPara procesado por bloques pasa stateful=True (la misma convención que
WeightingFilter); el atajo de un solo uso es
parametric_eq(x, fs, sections).
Las tres secciones del fragmento (en gris) y la cascada que suman; el panel
inferior es la fase que cuesta esa magnitud. Cualquier resultado de la
biblioteca se redibuja así: el res.plot() de arriba produjo exactamente esta
figura.
Mostrar el código de esta figura
import matplotlib.pyplot as pltfrom phonometry import EQSection, ParametricEQ
fs = 48000familia = [ EQSection("peaking", 1000.0, gain_db=6.0, q=1.4), EQSection("lowshelf", 125.0, gain_db=6.0), EQSection("highshelf", 4000.0, gain_db=-6.0), EQSection("lowpass", 10000.0), EQSection("highpass", 50.0), EQSection("bandpass", 500.0, q=2.0), EQSection("notch", 2000.0, q=6.0),]fig, ax = plt.subplots(figsize=(10, 6))for section in familia: res = ParametricEQ(fs, [section]).response(f_min=20.0, f_max=20000.0) ax.semilogx(res.frequencies, res.magnitude_db, label=f"{section.filter_type} @ {section.f0:g} Hz")ax.set(xlim=(20, 20000), ylim=(-27, 9), xlabel="Frecuencia [Hz]", ylabel="Magnitud [dB]")ax.grid(True, which="both", alpha=0.3)ax.legend(loc="lower center", ncols=2, fontsize=9)plt.show()Todo lo anterior es diseño. Demostrar que un banco diseñado cumple una clase de prestaciones de IEC 61260-1, banda a banda y con su margen en decibelios, es Verificación de clase de filtros: la máscara de aceptación de la Tabla 1, la clase 0 más estricta de la edición retirada de 1995, qué aporta una clase en una medición y la ficha de conformidad acreditada.
4. Señales de banda y retardo de grupo
Sección titulada «4. Señales de banda y retardo de grupo»sigbands=True devuelve las señales temporales por banda junto a los niveles, y
es lo que hace visible el comportamiento en fase y en transitorio, y lo que deja
al descubierto el retardo de grupo que cada arquitectura paga por su
selectividad. La estabilidad en sí es asunto del apartado 1, en
Polos, ceros y estabilidad; lo que este apartado
añade es la prueba, porque un filtro cuya respuesta al impulso decae a cero es
un filtro estable.
import numpy as npfrom phonometry import filters
# 1. Generar una señal (suma de 250 Hz y 1000 Hz)fs = 48000t = 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 = filters.octave_filter( y, fs=fs, fraction=1, sigbands=True, design=filters.FilterDesign(filter_type='butter'))spl_c2, _, xb_cheby2 = filters.octave_filter( y, fs=fs, fraction=1, sigbands=True, design=filters.FilterDesign(filter_type='cheby2'))
# 'xb_butter' y 'xb_cheby2' contienen las señales por banda en el dominio del tiempoEl panel superior es la entrada, los intermedios son sus señales de banda con Butterworth (línea continua) y Chebyshev II (discontinua), y el inferior es la respuesta al impulso de la banda de 1 kHz de cada uno. Las dos respuestas al impulso decaen a cero — esa es la comprobación de estabilidad —, pero la resonancia de Chebyshev II dura visiblemente más, que es el precio en transitorio de su falda más abrupta.
Mostrar el código de esta figura
import matplotlib.pyplot as pltimport numpy as npfrom phonometry import filters
fs = 48000t = 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)
bank_b = filters.OctaveFilterBank(fs=fs, fraction=1, order=6, limits=[100.0, 2000.0])bank_c = filters.OctaveFilterBank(fs=fs, fraction=1, order=6, limits=[100.0, 2000.0], design=filters.FilterDesign(filter_type="cheby2"))_, freq, xb_butter = bank_b.filter(y, sigbands=True)_, _, xb_cheby2 = bank_c.filter(y, sigbands=True)
# La figura publicada lleva dos paneles más: la entrada arriba y, abajo, la# banda de 1 kHz de un impulso unitario a través de cada banco.impulse = np.zeros_like(t)impulse[0] = 1.0_, _, imp_butter = bank_b.filter(impulse, sigbands=True)_, _, imp_cheby2 = bank_c.filter(impulse, sigbands=True)one_k = int(np.argmin(np.abs(np.asarray(freq) - 1000.0)))
fig, axes = plt.subplots(len(freq) + 2, 1, figsize=(9, 2 * (len(freq) + 2)), sharex=True)axes[0].plot(t, y)axes[0].set_title("Señal original (250 Hz + 1000 Hz)")for ax, fc, xb, xc in zip(axes[1:-1], freq, xb_butter, xb_cheby2): ax.plot(t, xb, label="Butterworth") ax.plot(t, xc, "--", label="Chebyshev II") ax.set_title(f"Banda de {fc:.0f} Hz")axes[-1].plot(t, imp_butter[one_k], label="Butterworth")axes[-1].plot(t, imp_cheby2[one_k], "--", label="Chebyshev II")axes[-1].set_title("Respuesta al impulso, banda de 1 kHz")axes[1].legend()axes[0].set_xlim(0, 0.04)axes[-1].set_xlabel("Tiempo [s]")plt.tight_layout()plt.show()El retardo de grupo, cuantificado
Sección titulada «El retardo de grupo, cuantificado»El retardo de grupo 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.
Mostrar el código de esta figura
import matplotlib.pyplot as pltimport numpy as npfrom scipy.signal import group_delayfrom phonometry import filters
fs = 48000w = np.logspace(np.log10(500), np.log10(2000), 1024)fig, ax = plt.subplots(figsize=(9, 5))for ftype in ("butter", "cheby1", "cheby2", "ellip", "bessel"): 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] # Retardo de grupo de una cascada SOS = suma del de sus secciones gd = sum(group_delay((sec[:3], sec[3:]), w=w, fs=fsd)[1] for sec in bank.sos[idx]) ax.semilogx(w, gd / fsd * 1000, label=ftype)ax.set(xlim=(500, 2000), xlabel="Frecuencia [Hz]", ylabel="Retardo de grupo [ms]")ax.grid(True, which="both", alpha=0.3)ax.legend()plt.show()5. Filtrado de fase cero
Sección titulada «5. Filtrado de fase cero»Para análisis offline puedes eliminar por completo el retardo de grupo:
OctaveFilterBank.filter(…, 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. Es una opción por llamada del banco, no un argumento
de la octave_filter() de un solo uso. La atenuación efectiva se duplica y la banda de paso efectiva se
estrecha, reduciendo el nivel de banda ancha medido en ~0,2 a 0,3 dB por banda
(un tono puro dentro de banda no se ve afectado); prefiere el filtrado hacia
delante cuando el SPL absoluto de banda debe coincidir con el convenio de un
solo paso, y reserva la fase cero para cuando importa la envolvente temporal
(p. ej. decaimiento de reverberación). La opción es incompatible con el
procesado por bloques (stateful).
import numpy as npfrom phonometry import filters
fs = 48000t = 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)
bank = filters.OctaveFilterBank(fs=48000, fraction=3)spl, freq, xb = bank.filter(y, sigbands=True, zero_phase=True)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.
Mostrar el código de esta figura
import matplotlib.pyplot as pltimport numpy as npfrom phonometry import filters
fs = 48000t = np.linspace(0, 0.15, int(fs * 0.15), endpoint=False)x = np.zeros_like(t) # ráfaga de 250 Hz a mitad de tramastart, end = int(0.05 * fs), int(0.10 * fs)x[start:end] = np.sin(2 * np.pi * 250 * t[start:end]) * np.hanning(end - start)
bank = filters.OctaveFilterBank(fs=fs, fraction=1, order=6, limits=[200.0, 300.0])_, _, fwd = bank.filter(x, sigbands=True, calculate_level=False)_, _, zp = bank.filter(x, sigbands=True, calculate_level=False, zero_phase=True)
fig, ax = plt.subplots(figsize=(9, 4.5))ax.plot(t, x, color="gray", alpha=0.5, label="Ráfaga de entrada (250 Hz)")ax.plot(t, fwd[0], label="Causal (retardo de grupo)")ax.plot(t, zp[0], "--", label="zero_phase=True (alineado)")ax.set(xlabel="Tiempo [s]", ylabel="Amplitud")ax.legend()plt.show()Qué cubre esta guía
Sección titulada «Qué cubre esta guía»Cubierto
La matemática de bordes de banda de la IEC 61260-1:2014 (apartados 5.2-5.5) y la serie de frecuencias preferentes de la ISO 266:1997 tras
nominal_frequencies. La biblioteca diseña cada banda como una cascada SOS en cinco arquitecturas (Butterworth, Chebyshev I/II, elíptico, Bessel), más elParametricEQdel RBJ Audio EQ Cookbook, con la descomposición por bandas y el filtrado de fase cero.No cubierto
Las respuestas comparadas de las cinco arquitecturas, la galería completa de octava y tercio de octava y los ejemplos de uso por arquitectura, incluido el crossover Linkwitz-Riley, son la Galería de arquitecturas de filtro. Las máscaras de aceptación de clase de la Tabla 1 y su verificación se han trasladado a Verificación de clase de filtros. Cerca de Nyquist, la transformada bilineal deforma el eje de frecuencia y el banco no tiene corrección para ello (a diferencia de la opción
high_accuracydeWeightingFilter): mantén el borde superior de banda con margen cómodo respecto a Nyquist, o subefs, y confirma el margen converify_filter_class.
Véase también
Sección titulada «Véase también»- Galería de arquitecturas de filtro: las cinco arquitecturas comparadas en los bordes de banda, la galería completa de respuestas y el uso por arquitectura, con el crossover Linkwitz-Riley.
- 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 los bancos que se diseñan aquí.
- Referencia de la API:
phonometry,filters.coreyfilters.weighting. - Teoría: Frecuencias de banda de octava: de dónde salen la rejilla de frecuencias centrales en base 10 y los bordes de banda, y por qué el banco se diseña sobre ellos y no sobre las etiquetas nominales.
Respuestas rápidas
Sección titulada «Respuestas rápidas»¿Cómo se definen las frecuencias centrales y los bordes de banda de fracción de octava?
Sección titulada «¿Cómo se definen las frecuencias centrales y los bordes de banda de fracción de octava?»IEC 61260-1:2014 (apartados 5.2-5.5) construye cada banda a partir de la razón de octava en base 10 , de modo que una octava no es exactamente 2. Las frecuencias centrales siguen para impar y para par — de modo que 1 kHz es una frecuencia central de banda en las fracciones impares y un borde de banda en las pares — y los bordes son y en ambos casos; cada banda de tercio de octava abarca , diez bandas por década.
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 banco de esta guía sitúa sus puntos de −3 dB.
- Bristow-Johnson, R. (2021). Audio EQ Cookbook. Nota de grupo de trabajo del W3C (ed. R. Toy), 8 de junio de 2021. Las recetas de coeficientes biquad y la parametrización por Q / ancho de banda / pendiente de shelving detrás de ParametricEQ (sección 3).
- International Electrotechnical Commission. (2014). Electroacoustics — Octave-band and fractional-octave-band filters — Part 1: Specifications (IEC 61260-1:2014). Las matemáticas de bordes de banda de la sección 1 (frecuencias centrales y bordes de banda en base 10, apartados 5.2-5.5) y las etiquetas nominales de banda de todos los bancos que se diseñan aquí.
- International Organization for Standardization. (1997). Acoustics — Preferred frequencies (ISO 266:1997). La serie de frecuencias preferentes en la que se basan las etiquetas nominales de banda que devuelve nominal_frequencies.
- Oppenheim, A. V. y Schafer, R. W. (2010). Discrete-time signal processing (3.ª ed.). Pearson. La teoría de polos y ceros, estabilidad y multitasa condensada en la sección 1: cascadas SOS, transformada bilineal y diezmado (ISBN 978-0-13-198842-2).
- 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, de la geometría de polos y ceros a la estabilidad.