Análisis espectral calibrado
Referencias: Bendat y Piersol 2010Welch 1967Harris 1978Thomson 1982Percival y Walden 1993
Un espectro sin su incertidumbre es media medición. Esta página cubre los
estimadores espectrales de Welch de phonometry.signals que informan,
junto al propio espectro, de la calidad estadística de la estimación
siguiendo a Bendat y Piersol, Random Data: Analysis and Measurement
Procedures (4.ª ed., 2010): la densidad espectral de potencia y la
densidad espectral cruzada con el número efectivo de promedios, el error
aleatorio normalizado y los intervalos de confianza chi-cuadrado; el
espectro de salida coherente que separa una salida medida en la parte
explicada linealmente por la entrada y el resto de ruido, con la relación
señal-ruido espectral; un suavizador en fracciones de octava con núcleo
de potencia constante; y generadores de ruido de colores con pendiente
exacta en ley de potencias para ejercitar todo lo anterior. Un estimador
multitaper de Thomson (Percival y Walden, 1993) completa la familia para
registros demasiado cortos para segmentar. Cada fórmula de error es una
forma cerrada de las fuentes, verificada por Monte Carlo con semilla en la
batería de tests.
1. Densidad espectral de potencia con su error estadístico
Sección titulada «1. Densidad espectral de potencia con su error estadístico»power_spectral_density estima la densidad autoespectral unilateral
por el método de Welch: el registro se divide en segmentos con
ventana (Hann por defecto) y solape del 50 % cuyos periodogramas se
promedian. No se aplica eliminación de tendencia, así que la calibración
absoluta se conserva: una señal en pascales da Pa²/Hz. Hay dos escalados:
'density' (unidades²/Hz, integra a la potencia de la señal) y 'spectrum'
(unidades², lee directamente la potencia de tonos discretos).
El precio de conservar la calibración es que cualquier desplazamiento de continua o deriva lenta se queda en el registro y se filtra. El desplazamiento cae en el bin de continua, y los lóbulos laterales de la ventana de Hann reparten una fracción de él por los primeros bins, así que un desplazamiento sin corregir aparece como una subida espuria en baja frecuencia que no elimina ninguna cantidad de promediado. Cuando importen los bins más bajos, resta la media o filtra el registro en paso alto explícitamente antes de la llamada (eso es un cambio en la señal, no un ajuste del estimador), y ten en cuenta que ese mismo desplazamiento es invisible en una representación en fracciones de octava, porque ninguna banda llega a continua. La misma condición reaparece en Cualificación de datos, cuyos estadísticos de cruce de nivel y de picos están escritos para un proceso de media nula.
El estimador es una cadena fija: la ventana fija el ancho de banda de resolución, y los promedios efectivos se derivan de la longitud del registro (el número de segmentos brutos) junto con la ventana y el solape. Con ellos fijados, cada cifra de calidad se deriva de la decisión principal de diseño, la longitud del segmento. El diagrama la recorre con los números del ejemplo de esta página.
Promediar segmentos independientes da al estimador grados de libertad chi-cuadrado (ec. 8.162), de donde sale todo lo demás:
Con segmentos solapados y con ventana los promedios están correlacionados, así
que el resultado informa tanto del número bruto de segmentos (n_segments)
como del número efectivo de promedios independientes (n_averages),
calculado con la fórmula de correlación de ventana de Welch (1967) que
Bendat y Piersol citan en la sección 11.5.2.2: para Hann con solape del 50 %,
aproximadamente 0,95 del número bruto. El error aleatorio y el intervalo de
confianza usan el valor efectivo. En DC, y en Nyquist con longitud de
segmento par, el espectro unilateral tiene una sola componente de Fourier
real, así que esos bins llevan la mitad de grados de libertad y un intervalo
proporcionalmente más ancho.
from phonometry import power_spectral_density
# record: un canal de una captura calibrada, en pascales (ver la guía de# Calibración más abajo); trabajando en dBFS es el vector bruto en [-1, 1] y# el resultado sale en FS^2/Hz. fs: su frecuencia de muestreo en Hz.res = power_spectral_density(record, fs) # Hann, solape 50 %, IC 95 %print(res.n_averages, res.random_error) # nd y 1/sqrt(nd)print(res.ci_lower[10], res.psd[10], res.ci_upper[10])res.plot() # PSD en dB con la banda de ICEl sesgo de resolución es la otra mitad del presupuesto de error: un
ancho de banda de análisis finito (expuesto como
resolution_bandwidth, el ancho de banda de ruido efectivo de la ventana)
suaviza los rasgos espectrales abruptos, siempre en la dirección de reducir
el rango dinámico (ec. 8.139). Para un pico resonante de ancho de banda de
media potencia , el sesgo normalizado de primer orden es la forma
cerrada de la ec. 8.141, expuesta como resolution_bias_error:
from phonometry import resolution_bias_error
eps_b = resolution_bias_error(res.resolution_bandwidth, 25.0) # pico de Br = 25 HzUn estrecho (segmentos largos) suprime el sesgo pero deja menos promedios y un error aleatorio mayor; los dos requisitos sobre la longitud de segmento tiran en direcciones opuestas, y ese es exactamente el compromiso que los números expuestos hacen visible.
Elegir la longitud del segmento, y después la del registro
Sección titulada «Elegir la longitud del segmento, y después la del registro»La fórmula del sesgo es más útil leída al revés. Mantener el sesgo del pico de una resonancia por debajo de 1 dB significa , y por tanto ; mantenerlo por debajo de una décima de decibelio significa . La regla empírica de siempre, tres o cuatro anchos de banda de análisis a lo ancho de la anchura a media potencia del rasgo más estrecho que importe, es exactamente esta fórmula, y ahora lleva un número al lado.
Trabaja hacia delante desde la medición y no desde un nperseg de costumbre. Un
modo a 100 Hz con tiene Hz. Mantener su sesgo por debajo
del 2 % (0,09 dB) pide Hz y, para la
ventana de Hann, , así que a 48 kHz eso es
nperseg , es decir, segmentos de al menos 3,1 s. Pedir
después un error aleatorio del 10 % necesita promedios efectivos, lo
que con un solape del 50 % significa un registro de unos 150 s:
target_bias = 0.02 # 2 % sobre el pico, unos 0,09 dBb_r, q = 100.0 / 50.0, 100 # un modo de 100 Hz con Q = 50b_e = b_r * (3 * target_bias) ** 0.5 # el ancho de banda de análisis que permitenperseg = 1.5 * 48000 / b_e # Hann: Be = 1,5 fs / npersegrecord_s = q * 0.5 * nperseg / 48000 # nd = 100 promedios con solape del 50 %print(round(b_e, 2), int(nperseg), round(record_s)) # 0.49 146969 153La misma resonancia de 25 Hz de ancho vista con cuatro longitudes de segmento.
Con nperseg = 512 el ancho de banda de análisis es de 140,6 Hz, cinco veces la
anchura de la resonancia, y el pico se lee unos 8 dB de menos y mucho más ancho de
la cuenta; con 4096 el ancho de banda es de 17,6 Hz y el pico está esencialmente
resuelto. El panel derecho pone los dos errores en un mismo eje: el sesgo cae
como y el error aleatorio sube como , y se igualan cerca de
nperseg = 7400 para esta resonancia, que es la longitud de segmento a elegir si
no hay razón para preferir un error sobre el otro.
Las dos decisiones son independientes: la longitud del segmento la fija el rasgo más agudo que importe, y la del registro la precisión que quieras. Alargar los segmentos sin alargar el registro cambia un error por el otro y no compra nada. Y 150 s de registro son 150 s durante los cuales el proceso tiene que mantenerse estacionario, lo cual es una afirmación y no una suposición, y es la que decide Cualificación de datos. Cuando el registro sencillamente no puede ser tan largo, la salida es el estimador multitaper del §7.
De unidades digitales a dB SPL
Sección titulada «De unidades digitales a dB SPL»power_spectral_density escala lo que se le dé y no aplica ninguna calibración
propia, así que el factor de sensibilidad va sobre el registro, antes de la
estimación:
calibration_factor = 1.002 # Pa por unidad digital, del calibradorpressure = calibration_factor * recordpsd = power_spectral_density(pressure, fs) # ahora en Pa^2/HzLa ordenada es entonces dB re (20 µPa)²/Hz, y con
scaling="spectrum" esa misma llamada lee directamente el nivel de un tono
discreto como dB. Para pasar de ahí al nivel de banda que
contiene un informe acústico, integra la densidad en la banda (suma los bins y
multiplica por la separación entre bins) y divide por ;
fractional_octave_smoothing del §4 es un suavizador de representación y no un
sustituto de esa integración, como detalla ese mismo apartado. El factor sale de
Calibración y dBFS.
Lo que compran 20 s de registro, leído sobre la figura. 467 segmentos de 4096 muestras dan 442 promedios efectivos, un error aleatorio normalizado de 0,047 y una banda de confianza chi-cuadrado del 95 % de 0,81 dB de ancho, así que la estimación dentada no se aparta de la curva suavizada más de unos 0,8 dB en toda la década, y la afirmación honesta de lo que se sabe es la banda sombreada, no el rizado. Las dos curvas ajustan −3,007 dB/octava frente a los −3,01 dB/octava exactos del ruido rosa. Suavizar no estrecha nada: redibuja la misma estimación, y el intervalo que hay debajo sigue valiendo.
Mostrar el código de esta figura
import matplotlib.pyplot as pltimport numpy as npfrom phonometry import ( fractional_octave_smoothing, noise_signal, power_spectral_density,)
fs = 48000.0x = noise_signal(fs, 20.0, color="pink", seed=11)res = power_spectral_density(x, fs, nperseg=4096)band = (res.frequencies >= 20.0) & (res.frequencies <= 20000.0)freqs = res.frequencies[band]smooth = fractional_octave_smoothing(res.frequencies, res.psd, 3.0)[band]
fig, ax = plt.subplots(figsize=(10, 6))ax.fill_between(freqs, 10 * np.log10(res.ci_lower[band]), 10 * np.log10(res.ci_upper[band]), alpha=0.3, label="Intervalo de confianza chi-cuadrado del 95 %")ax.semilogx(freqs, 10 * np.log10(res.psd[band]), lw=1.0, label="Estimación de la PSD de Welch")ax.semilogx(freqs, 10 * np.log10(smooth), lw=2.2, label="Suavizado en 1/3 de octava")ax.set_xlabel("Frecuencia [Hz]")ax.set_ylabel("PSD [dB re 1/Hz]")ax.legend()plt.show()2. Densidad espectral cruzada
Sección titulada «2. Densidad espectral cruzada»cross_spectral_density estima la compleja entre dos canales con
el mismo núcleo de Welch, e informa de la coherencia ordinaria
junto a los errores aleatorios de Bendat y Piersol
de la magnitud y la fase (ecs. 9.33 y 9.52, con la coherencia medida en
lugar del valor verdadero desconocido, como recomienda el libro para datos
medidos):
Ambos se reducen cuando la coherencia se acerca a uno: un par fuertemente coherente necesita muchos menos promedios para la misma confianza. La fase se devuelve desenrollada, así que su pendiente frente a la frecuencia es el retardo de grupo ; para un camino de retardo puro la fase es lineal y esa pendiente lee directamente el retardo de propagación.
from phonometry import cross_spectral_density
res = cross_spectral_density(x, y, fs)print(res.magnitude_random_error[100], res.phase_std[100]) # errores del bin 100res.plot() # magnitud, fase con banda ±sigma, coherenciaLa densidad espectral cruzada de un camino con retardo de 2 ms: la fase desenrollada es exactamente la recta , así que su pendiente lee el retardo de propagación directamente, y la banda ±1 d.e. de la Ec. 9.52 cuantifica cuánto fiarse de ella por frecuencia.
Mostrar el código de esta figura
import matplotlib.pyplot as pltimport numpy as npfrom phonometry import cross_spectral_density, noise_signal
fs = 8000.0tau = 0.002 # 2 ms = 16 muestrasdelay = int(tau * fs)x = noise_signal(fs, 8.0, seed=8)noise = noise_signal(fs, 8.0, rms=0.3, seed=9)y = 0.9 * np.concatenate([np.zeros(delay), x[:-delay]]) + noise
res = cross_spectral_density(x, y, fs)
# Una línea: magnitud, fase con su banda ±sigma y coherencia:res.plot(language="es")plt.show()
# A mano, desde los campos que lleva el resultado:band = (res.frequencies >= 20) & (res.frequencies <= 3500)freqs = res.frequencies[band]fig, (ax_m, ax_p) = plt.subplots(2, 1, sharex=True)ax_m.semilogx(freqs, 10 * np.log10(res.magnitude[band]), label="|Gxy| (estimación de Welch)")ax_m.set_ylabel("Magnitud [dB]")ax_p.semilogx(freqs, res.phase[band], label="Fase desenrollada")ax_p.fill_between(freqs, res.phase[band] - res.phase_std[band], res.phase[band] + res.phase_std[band], alpha=0.25, label="±1 d.e. (Ec. 9.52)")ax_p.semilogx(freqs, -2 * np.pi * freqs * tau, "r--", label="pendiente -2·pi·f·tau")ax_p.set(xlabel="Frecuencia [Hz]", ylabel="Fase [rad]")for ax in (ax_m, ax_p): ax.legend()plt.show()3. Espectro de salida coherente y SNR espectral
Sección titulada «3. Espectro de salida coherente y SNR espectral»En el modelo de una entrada y una salida, el autoespectro medido de la salida se separa exactamente en la parte explicada linealmente por la entrada y el resto no correlacionado (ecs. 9.55–9.57):
coherent_output_spectrum devuelve los tres espectros, la relación
señal-ruido espectral (lineal y en dB) y el error aleatorio del estimador de
la salida coherente (ec. 9.73), más la propagación de primer orden del error
de la coherencia a través de la SNR:
Para ruido aditivo no correlacionado en la salida con nivel conocido, la coherencia tiene la forma cerrada , lo que hace toda la cadena verificable con una señal sintética:
import numpy as npfrom phonometry import coherent_output_spectrum, noise_signal
fs = 48000.0x = noise_signal(fs, 8.0, color="white", seed=1)noise = noise_signal(fs, 8.0, color="white", rms=0.5, seed=2)y = 0.8 * x + noise # SNR = 0.64/0.25 en toda frecuencia
res = coherent_output_spectrum(x, y, fs)print(np.median(res.coherence)) # -> SNR/(1+SNR) = 0.719print(np.median(res.snr_db)) # -> 10·lg(2.56) = 4.1 dBres.plot() # Gyy, Gvv, Gnn y el panel de SNREl reparto exacto del modelo del fragmento: explica la salida salvo el resto de ruido plano , y la SNR espectral se dispersa alrededor de su forma cerrada dB en toda frecuencia.
Mostrar el código de esta figura
import matplotlib.pyplot as pltimport numpy as npfrom phonometry import coherent_output_spectrum, noise_signal
fs = 48000.0x = noise_signal(fs, 8.0, color="white", seed=1)noise = noise_signal(fs, 8.0, color="white", rms=0.5, seed=2)y = 0.8 * x + noise # SNR = 0.64/0.25 por banda
res = coherent_output_spectrum(x, y, fs, nperseg=2048)
# Una línea: los tres espectros y el panel de SNR:res.plot(language="es")plt.show()
# A mano, desde los campos que lleva el resultado:band = (res.frequencies >= 20) & (res.frequencies <= 20000)freqs = res.frequencies[band]fig, (ax_g, ax_s) = plt.subplots(2, 1, sharex=True)for values, style, label in ((res.output_psd, "-", "Gyy (medida)"), (res.coherent_psd, "--", "Gvv (coherente)"), (res.noise_psd, ":", "Gnn (ruido)")): ax_g.semilogx(freqs, 10 * np.log10(values[band]), style, label=label)ax_g.set_ylabel("Densidad espectral [dB re 1/Hz]")ax_s.semilogx(freqs, res.snr_db[band], label="SNR espectral [dB]")ax_s.axhline(10 * np.log10(0.64 / 0.25), color="r", linestyle="--", label="forma cerrada 4,1 dB")ax_s.set(xlabel="Frecuencia [Hz]", ylabel="SNR [dB]")for ax in (ax_g, ax_s): ax.legend()plt.show()El campo coherence_bias informa del pequeño sesgo positivo del estimador
de coherencia, (ec. 9.75):
despreciable en cuanto
llega a unos cientos, y otra razón para promediar con generosidad antes de
fiarse de una coherencia baja.
Dos canales en la práctica
Sección titulada «Dos canales en la práctica»Los §2 y §3 parten los dos de una pareja de registros, y todo lo que informan vale lo que valga esa pareja. Dos mitades: cómo adquirirla y cómo leer una coherencia que vuelve por debajo de uno.
Adquisición. Usa una sola interfaz con entradas de muestreo simultáneo, o mide el desfase entre canales y elimínalo. Un convertidor que secuencia sus canales mete un desfase fijo directamente en la fase del espectro cruzado y, por tanto, en todos los retardos de grupo que se lean de ella: una muestra de desfase a 48 kHz son 20,8 µs, que son 15° de fase a 2 kHz y un error plano de 20,8 µs en cualquier estimación de retardo. Fija las dos ganancias antes de la tirada y no las toques, porque el reparto de salida coherente del §3 supone que los dos canales comparten una escala fija. Valida la pareja una vez con una tirada de base cero: mete la misma señal en los dos canales (el generador partido hacia ambas entradas, o los dos micrófonos uno al lado del otro) y confirma que el retardo medido es una fracción pequeña de muestra y que la coherencia vale uno en toda la banda. Esa única tirada separa un problema de cadena de un problema de física para todas las mediciones que vengan después.
Leer una coherencia por debajo de uno. No es automáticamente un problema de relación señal-ruido, y Bendat y Piersol nombran cinco causas con arreglos distintos:
| Lo que ves | La causa | El arreglo |
|---|---|---|
| Coherencia plana en toda la banda, coherente con | ruido no correlacionado en alguno de los sensores, el caso modelado del §3 | promedia más, sube el nivel, acércate |
| Coherencia que cae progresivamente con la frecuencia, peor cuanto más corto se segmenta el registro | un retardo global de propagación comparable con la longitud del segmento | alinea antes los registros, o sube nperseg muy por encima del retardo; ver Correlación y retardo |
| Hundimientos abruptos justo en las resonancias | sesgo de resolución: el ancho de banda de análisis emborrona el pico de forma distinta en cada canal | alarga el segmento; la fórmula de del §1 dice cuánto |
| Baja en los armónicos de un tono fuerte mientras la coherencia de banda ancha sigue alta | no linealidad, un traqueteo o un canal recortado | arregla el camino, o trabaja por debajo del nivel al que aparece |
| Baja en toda una banda sin estructura evidente | una segunda fuente no correlacionada está excitando también la salida | la página de MISO: una entrada no puede explicar dos fuentes |
Dos advertencias de cierre. La estimación de coherencia está sesgada al alza en , así que una coherencia baja leída con un puñado de promedios es todavía más baja de lo que parece. Y, leído al revés, una coherencia cercana a uno es el criterio de aceptación que permite declarar toda la estimación: decláralo banda a banda junto a la función de transferencia, porque las bandas donde cae son exactamente las bandas donde los números de encima no significan nada.
4. Suavizado en fracciones de octava
Sección titulada «4. Suavizado en fracciones de octava»fractional_octave_smoothing promedia un espectro sobre una ventana
rectangular de anchura relativa constante: 1/n de octava,
alrededor de cada frecuencia. Es el
ancho de banda de resolución de porcentaje constante que Bendat y Piersol
recomiendan
para espectros de sistemas resonantes (sección 8.5.3), y el estándar de
facto para presentar respuestas de altavoces y salas. El promedio se calcula
siempre sobre potencia (las amplitudes se elevan al cuadrado primero,
los niveles en dB se convierten ida y vuelta), así que se conserva la
potencia de banda y no la amplitud, y un espectro plano pasa exactamente
sin cambios.
Los tres valores de domain= nombran qué es la ordenada que se le entrega,
porque el promedio se hace siempre sobre potencia y la conversión de vuelta tiene
que saber de dónde partió: una densidad o un espectro de potencia ("power", el
valor por defecto), una magnitud lineal como el de una respuesta en
frecuencia ("amplitude", que se eleva antes al cuadrado), o una curva ya en
decibelios ("db", que se convierte y se vuelve a convertir).
from phonometry import fractional_octave_smoothing
freqs = res.frequencies # de la estimación del §1smooth_psd = fractional_octave_smoothing(freqs, res.psd, 3.0)magnitude = np.sqrt(res.psd) # aquí valdría cualquier |H| linealsmooth_mag = fractional_octave_smoothing(freqs, magnitude, 6.0, domain="amplitude") # una FRF |H|levels = 10.0 * np.log10(res.psd) # aquí valdría cualquier curva en dBsmooth_db = fractional_octave_smoothing(freqs, levels, 3.0, domain="db")Una sola línea espectral con ordenada de PSD (unidades²/Hz) en un bin de anchura se suaviza al nivel en forma cerrada sobre una anchura de núcleo: el oráculo fijado en los tests.
Una densidad suavizada sigue siendo una densidad
Sección titulada «Una densidad suavizada sigue siendo una densidad»El suavizado cambia la resolución de la estimación, nunca sus unidades. La
salida de fractional_octave_smoothing es una densidad en unidades²/Hz,
exactamente como lo era la entrada (el ruido blanco plano se suaviza a la misma
densidad plana), mientras que los niveles de banda de tercio de octava de ese
mismo ruido blanco suben 3 dB por banda. Superpón una PSD suavizada sobre un
espectro de banco de filtros sin convertir y las dos discreparán en 20 o 30 dB, y
ninguna estará equivocada.
La conversión es un solo término. Una banda de fracción de octava de frecuencia central tiene un ancho de banda , es decir, en un tercio de octava y en una octava completa, así que
que a 1 kHz en tercio de octava añade dB al nivel de densidad, y 3 dB más por cada octava hacia arriba. Sumar los bins de la PSD a lo ancho de la banda y multiplicar por la separación entre bins es la forma exacta; la expresión de arriba es su aproximación de banda plana.
Qué representación va dónde: la densidad suavizada para comparar respuestas
en magnitud de altavoces y salas, donde el ojo quiere una curva a resolución
relativa constante; el nivel de banda para todo lo que se enfrente a un
criterio, o que tenga que cuadrar con octave_filter y OctaveFilterBank; ver
Niveles.
5. Generadores de ruido de colores
Sección titulada «5. Generadores de ruido de colores»noise_signal produce ruido gaussiano cuya PSD sigue
de
forma exacta en esperanza: ruido blanco con semilla se moldea en el dominio
de la frecuencia con la respuesta en magnitud exacta
bin a
bin (un filtro de fase cero aplicado de forma circular), así que una
pendiente medida solo se desvía de la ley de potencias por el error
aleatorio de la estimación espectral, no como las aproximaciones rosas por
tramos o de pocos polos cuya pendiente ondula fracciones de dB. El registro
tiene media cero y se reescala exactamente al RMS pedido, y la misma semilla
reproduce el mismo registro bit a bit.
| color | pendiente de la PSD | |
|---|---|---|
white | 0 | 0 dB/octava |
pink | -1 | -3,01 dB/octava |
red (browniano) | -2 | -6,02 dB/octava |
blue | +1 | +3,01 dB/octava |
violet | +2 | +6,02 dB/octava |
from phonometry import noise_signal
pink = noise_signal(48000, 10.0, color="pink", seed=7) # deterministawhite = noise_signal(48000, 10.0, color="white", rms=0.5, seed=7)Medida sobre tres décadas (20 Hz – 20 kHz) con el estimador de la sección 1, la pendiente de regresión de cada color cae a unas milésimas de dB/octava del valor exacto: la batería de conformidad fija la pendiente rosa en -3,0116 frente al exacto -3,0103.
Esas pendientes son pendientes de densidad, y no son lo que muestra una representación en fracciones de octava de la misma señal. La anchura de una banda crece en proporción a su frecuencia central, así que un nivel de banda es la densidad más con : todos los colores se leen 3 dB por octava más altos en una representación por bandas de lo que sugiere su pendiente de densidad. El ruido blanco, cuya densidad es plana, sube por tanto 3 dB por octava a través de un banco de filtros de octava, y el ruido rosa, a −3 dB/octava, sale plano, que es por lo que el rosa es el estímulo de referencia en trabajo de salas y altavoces, y por lo que un espectro en bandas de octava de ruido blanco que sube no es ningún defecto. El ruido rojo cae 3 dB por octava en una representación por bandas y el azul sube 6. Los mismos +3 dB por octava valen para cualquier comparación de densidad frente a banda en esta biblioteca; el §4 de arriba da la conversión exacta, y en Niveles vive el lado de las bandas.
Los cinco generadores a lo largo de tres décadas, cada uno normalizado a su propio nivel en 1 kHz para que las pendientes se abran en abanico desde un solo punto, con la ley de potencias exacta discontinua debajo. Las pendientes de regresión medidas caen a menos de cuatro milésimas de decibelio por octava de los valores exactos, y el residuo es el error aleatorio del estimador, no del generador: la misma semilla reproduce el registro bit a bit.
6. Elegir la ventana
Sección titulada «6. Elegir la ventana»Todos los estimadores de esta página aceptan cualquier ventana que conozca
scipy.signal.get_window, pero la elección es un compromiso cuantificado,
no una preferencia. window_metrics calcula las figuras de mérito que
Harris (1978) tabuló, para cualquier ventana y longitud, muestreadas en modo
periódico (DFT-even) exactamente como las aplican los estimadores de Welch:
- ENBW (ancho de banda equivalente de ruido, en bins): cuánto más ancho
que un bin es el ancho de banda de análisis efectivo. Es el mismo número
que el resultado de la PSD informa como
resolution_bandwidth(ENBW·fs/npersegen Hz), y entra directamente en el balance tono/ruido: un suelo de ruido de banda ancha leído de un espectro con ventana queda dB por encima de la densidad verdadera. - Ganancia coherente: la ganancia en continua que escala un tono centrado en un bin.
- Pérdida de festoneado: la atenuación en el peor caso de un tono que cae a medio camino entre dos bins (3,92 dB para la rectangular, 1,42 dB para Hann).
- Pérdida de proceso en el peor caso: el festoneado más , la reducción de SNR de salida en el peor caso al detectar un tono en ruido blanco.
- Lóbulo lateral máximo y anchura a -3 dB del lóbulo principal: suelo de fuga frente a resolución.
from phonometry import window_metrics
m = window_metrics("hann", 2048)print(m.enbw_bins) # 1.5, exactoprint(m.scalloping_loss_db) # 1.42 dBprint(m.highest_sidelobe_db) # -31.5 dBm.plot() # ventana + espectro con las métricasLas formas cerradas anclan los tests: el ENBW es exactamente 1 para la rectangular, 3/2 para Hann, 1987/1458 para Hamming y 1523/882 para Blackman (muestreo DFT-even), y la pérdida de festoneado de la rectangular es , el núcleo de Dirichlet evaluado medio bin fuera del centro.
El compromiso en una imagen, y 0,73 de bin cuestan 44,8 dB de suelo de fuga. Pasar de la rectangular a la Blackman baja el lóbulo lateral máximo de −13,3 dB a −58,1 dB mientras el ENBW se ensancha de 1,000 a 1,727 bins y el lóbulo principal a −3 dB de 0,886 a 1,644 bins. La Hann se queda donde está el valor por defecto del módulo: −31,5 dB por 1,500 bins. Lee los dos ejes juntos: un lóbulo principal estrecho separa dos tonos de nivel parecido, un suelo de lóbulos laterales bajo encuentra un tono débil al lado de uno fuerte, y ninguna ventana hace las dos cosas.
Mostrar el código de esta figura
import matplotlib.pyplot as pltimport numpy as npfrom phonometry import window_metrics
n, oversample = 1024, 256fig, ax = plt.subplots(figsize=(10, 6.2))for name in ("boxcar", "hann", "hamming", "blackman"): res = window_metrics(name, n) spectrum = np.abs(np.fft.rfft(res.taps, n=n * oversample)) level = 20.0 * np.log10(spectrum / spectrum[0]) bins = np.arange(level.size) / oversample shown = bins <= 16.0 ax.plot(bins[shown], level[shown], label=(f"{name}: ENBW {res.enbw_bins:.2f} bins, " f"lóbulo lateral {res.highest_sidelobe_db:.1f} dB"))ax.set_xlim(0.0, 16.0)ax.set_ylim(-100.0, 5.0)ax.set_xlabel("Desplazamiento en frecuencia [bins de la DFT]")ax.set_ylabel("Nivel re lóbulo principal [dB]")ax.legend(loc="upper right")plt.tight_layout()plt.show()La ventana Hann por defecto de este módulo es la elección equilibrada: la caída rápida de los lóbulos laterales (-18 dB/octava) protege los espectros de ruido frente a la fuga, su ENBW de 1,5 solo cuesta 1,76 dB frente a la rectangular, y su correlación de solape al 50 % conserva casi toda la información de los segmentos en el número efectivo de promedios. Recurre a una ventana de lóbulos más bajos (Blackman, Kaiser con beta alta) cuando haya que encontrar un tono débil junto a uno fuerte, aceptando el lóbulo principal más ancho; y a la rectangular solo para registros que se autoenventanan (transitorios que decaen dentro del segmento) o síntesis centrada en bins.
7. Estimación multitaper para registros cortos
Sección titulada «7. Estimación multitaper para registros cortos»El método de Welch compra estabilidad con longitud de registro: cada
segmento independiente añade dos grados de libertad, así que un registro en
el que solo caben un par de segmentos deja una estimación apenas mejor que
un periodograma. multitaper_psd implementa la alternativa de Thomson
(1982), tal y como la desarrollan Percival y Walden (1993, capítulo 7): el
registro entero se multiplica por ventanas ortogonales esferoidales
prolatas discretas (de Slepian) - las secuencias que concentran la mayor
energía de su ventana espectral dentro de una banda de diseño
elegida - y se promedian los autoespectros propios resultantes:
Como las ventanas son ortogonales, los autoespectros están casi
no correlacionados, así que el promedio acarrea unos grados de libertad
chi-cuadrado de un único registro - la misma maquinaria estadística que el
resultado de Welch (error aleatorio, intervalo de confianza chi-cuadrado),
sin segmentar. El parámetro de diseño es el producto adimensional de duración
por semiancho de banda (4 por defecto), y para un registro de
muestras a fija el semiancho en hercios. es la
resolución de la estimación (informada como resolution_bandwidth), y solo las
ventanas por debajo del número de Shannon mantienen la energía de su ventana
espectral dentro de la banda de diseño - sus concentraciones se
informan como eigenvalues, y el número de ventanas por defecto es
, todas las de concentración casi unidad. Un mayor
admite más ventanas (menos varianza) a costa de resolución.
from phonometry import multitaper_psd
res = multitaper_psd(record, fs) # p = NW = 4, K = 7, adaptativoprint(res.degrees_of_freedom.mean()) # ~2K de un solo registroprint(res.eigenvalues) # concentracionesres.plot(language="es") # densidad con la banda de ICPor defecto los autoespectros se combinan con los pesos adaptativos de Thomson (P&W Ecs. 368a/370a, iterados hasta converger). El peso de cada ventana en cada frecuencia equilibra el espectro local frente a la fuga de banda ancha que esa ventana podría acarrear:
de modo que las ventanas de orden alto, con más fuga, pierden peso
exactamente donde el espectro es localmente débil, y no se pierde nada donde
es localmente blanco (para ruido blanco los pesos son uniformes). El precio
queda contabilizado con honestidad: los grados de libertad equivalentes
pasan a depender de la frecuencia,
con
(P&W Ec. 370b), y el intervalo de confianza se ensancha
allí
donde la protección contra la fuga los gastó. adaptive=False selecciona en
su lugar el promedio ponderado por autovalores.
La calibración coincide exactamente con los estimadores de Welch: sin
eliminación de tendencia, 'density' integra a la potencia de la señal y
'spectrum' lee en el pico de una sinusoide de amplitud (la
potencia de un tono en escalado 'density' se reparte sobre la banda ).
Las propias ventanas de Slepian proceden de scipy.signal.windows.dpss;
sus concentraciones reproducen la tabla en cuádruple precisión de Percival y
Walden (tabla 382) hasta la precisión de máquina, que es el oráculo ancla de
la batería de tests.
A la izquierda, el caso en el que el texto sostiene que gana la multitaper: un registro de 171 ms. Welch con un segmento de 2048 muestras solo mete promedios efectivos dentro de él, así que su banda de confianza es visiblemente la más ancha de las dos y su curva la más rugosa, mientras que la estimación adaptativa de 7 ventanas acarrea 13,7 grados de libertad equivalentes del mismo registro. A la derecha, la otra razón para echar mano de ella: un tono de 60 dB sobre un suelo rosa. La ventana de Hann deja una falda más ancha alrededor del tono que los pesos adaptativos, y el precio está impreso en el eje derecho: los grados de libertad equivalentes caen allí donde los pesos compraron esa protección, que es exactamente lo que ensancha ahí el intervalo de confianza.
Mostrar el código de esta figura
import matplotlib.pyplot as pltimport numpy as npfrom phonometry import multitaper_psd, noise_signal
fs = 48000.0x = noise_signal(fs, 8192 / fs, color="pink", seed=11) # registro de 171 mssingle = multitaper_psd(x, fs, n_tapers=1, adaptive=False)res = multitaper_psd(x, fs) # NW = 4, K = 7band = (res.frequencies >= 20.0) & (res.frequencies <= 20000.0)freqs = res.frequencies[band]
fig, ax = plt.subplots(figsize=(10, 6))ax.semilogx(freqs, 10 * np.log10(single.psd[band]), color="gray", alpha=0.45, lw=0.7, label="Una sola ventana de Slepian (K = 1)")ax.fill_between(freqs, 10 * np.log10(res.ci_lower[band]), 10 * np.log10(res.ci_upper[band]), alpha=0.3, label="Intervalo de confianza chi-cuadrado del 95 %")ax.semilogx(freqs, 10 * np.log10(res.psd[band]), lw=1.2, label="Estimación multitaper (K = 7, adaptativa)")ax.set_xlabel("Frecuencia [Hz]")ax.set_ylabel("PSD [dB re 1/Hz]")ax.legend()plt.show()Recurre a multitaper_psd cuando el registro sea demasiado corto para
segmentar (colas de respuestas al impulso de salas, capturas de transitorios,
ciclos sueltos de máquina) o cuando un espectro de gran rango dinámico
necesite una protección contra la fuga que un promedio de Welch con ventana
Hann no puede dar; quédate con power_spectral_density para registros
largos, donde promediar segmentos es más barato que FFT de longitud
completa y ambos estimadores coinciden.
Congruencia con los estimadores de respuesta en frecuencia y de intensidad
Sección titulada «Congruencia con los estimadores de respuesta en frecuencia y de intensidad»Los estimadores de respuesta en
frecuencia forman los
mismos espectros cruzados en una función de transferencia (,
insesgado cuando el ruido está en la salida, y , insesgado
cuando está en la entrada), y la sonda de
intensidad acústica de dos micrófonos
forma la parte imaginaria de . Esos estimadores,
transfer_function y coherence, la sonda de intensidad y
estos estimadores comparten un único núcleo de Welch (misma ventana, misma
política de solape y calibración sin eliminación de tendencia), así que una
PSD, una coherencia y una calculadas con la misma longitud de segmento
son mutuamente congruentes bin a bin. La misma matriz de espectros cruzados
sustenta la coherencia múltiple y
parcial,
que extiende la coherencia ordinaria a varias entradas correlacionadas y una
salida.
Qué cubre esta guía
Sección titulada «Qué cubre esta guía»Cubierto
Los estimadores de Welch de Bendat y Piersol (Random Data, 4.ª ed., 2010, secciones 5.2, 8.5, 9.1-9.2 y 11.5):
power_spectral_densityycross_spectral_densitycon el número efectivo de promedios, los intervalos de confianza chi-cuadrado y el error de sesgo por resolución; el espectro de salida coherente y la relación señal-ruido espectral; las figuras de mérito de las ventanas de Harris (1978) dewindow_metrics; y el estimador multitaper de Thomson (1982) demultitaper_psd, siguiendo los capítulos 7 y 8 de Percival y Walden.fractional_octave_smoothingynoise_signalcompletan la caja de herramientas.No cubierto
Los estimadores de respuesta en frecuencia
transfer_functionycoherence, y la sonda de intensidad acústica, comparten el núcleo de Welch de esta página pero se documentan en las páginas de electroacústica y intensidad acústica, no aquí. Lo mismo ocurre con la coherencia múltiple y parcial, en la página de coherencia MISO. Esta página implementa los estimadores del libro de Bendat y Piersol, no una norma de certificación, así que no lleva números de apartado ni límites de cumplimiento que comprobar.
Véase también
Sección titulada «Véase también»- Cualificación de datos: la estacionariedad que da por supuesta todo intervalo chi-cuadrado de esta página.
- Calibración y dBFS: de dónde sale el factor que convierte las densidades de esta página en Pa²/Hz.
- Coherencia MISO: la misma matriz de espectros cruzados con varias entradas correlacionadas.
- Análisis tiempo-frecuencia: la misma segmentación de Welch representada en lugar de promediada.
- Niveles: el lado de los niveles de banda de la conversión densidad/banda del §4.
- Referencia de la API:
signals.spectra,signals.windowsysignals.multitaper. - Teoría: Resolución frecuencial vs separación de bins FFT: por qué la separación de bins de una FFT no es la resolución de la estimación, y qué le hace la ventana a ambas.
Referencias
Sección titulada «Referencias»- Bendat, J. S. y Piersol, A. G. (2010). Random data: Analysis and measurement procedures (4.ª ed.). Wiley. https://doi.org/10.1002/9781118032428Secciones 5.2 y 8.5 (autoespectros y sus errores aleatorios y de sesgo, intervalos chi-cuadrado), 9.1-9.2 (espectros cruzados, espectro de salida coherente y sus errores) y 11.5 (procesado de Welch, ventanas y solape). ISBN 978-0-470-24877-5.
- Harris, F. J. (1978). On the use of windows for harmonic analysis with the discrete Fourier transform. Proceedings of the IEEE, 66(1), 51-83. https://doi.org/10.1109/PROC.1978.10837Las figuras de mérito de las ventanas (tabla 1): ancho de banda equivalente de ruido, ganancia coherente, pérdida de festoneado, pérdida de proceso en el peor caso, nivel del lóbulo lateral máximo y anchura del lóbulo principal, calculadas por window_metrics para cualquier ventana de scipy.
- Percival, D. B. y Walden, A. T. (1993). Spectral analysis for physical applications: Multitaper and conventional univariate techniques. Cambridge University Press. https://doi.org/10.1017/CBO9780511622762Capítulo 7 (estimación multitaper: autoespectros propios, ponderación adaptativa, grados de libertad equivalentes) y capítulo 8 (cálculo de las secuencias de Slepian); los autovalores de la tabla 382 anclan el oráculo de las ventanas en la batería de tests. ISBN 978-0-521-43541-3.
- Thomson, D. J. (1982). Spectrum estimation and harmonic analysis. Proceedings of the IEEE, 70(9), 1055-1096. https://doi.org/10.1109/PROC.1982.12433El método multitaper: ventanas de Slepian, autoespectros propios y los pesos adaptativos que implementa multitaper_psd.
- Welch, P. D. (1967). The use of fast Fourier transform for the estimation of power spectra: A method based on time averaging over short, modified periodograms. IEEE Transactions on Audio and Electroacoustics, 15(2), 70-73. https://doi.org/10.1109/TAU.1967.1161901La fórmula de varianza con segmentos solapados tras el número efectivo de promedios (Bendat y Piersol, sección 11.5.2.2, ref. 11).