Inteligibilidad objetiva (STOI y ESTOI)
Referencias: Taal et al. 2011Taal et al. 2010Jensen y Taal 2016
STOI y ESTOI son medidas de inteligibilidad objetiva basadas en
correlación. Cada una compara una referencia limpia con una versión degradada o
procesada de la misma habla y devuelve un escalar con relación monótona con la
fracción de palabras que un oyente entendería: 1 cuando la señal degradada
coincide con la limpia y cerca de 0 para ruido incorrelado. Trabajan
directamente sobre las dos formas de onda, lo que las convierte en la vara de
medir habitual para el habla con ponderación tiempo-frecuencia: reducción de
ruido, separación de fuentes y procesado por máscara binaria, donde separar el
habla limpia de su distorsión no es inmediato.
1. El procesado inicial común
Sección titulada «1. El procesado inicial común»Ambas medidas ejecutan el mismo procesado antes de divergir (Taal et al. 2011, sección II): remuestreo a 10 kHz; una transformada de corto plazo de 256 muestras (25,6 ms) con ventana de Hann y solape del 50 %, rellenada con ceros hasta 512 puntos; eliminación de las tramas cuya energía limpia está más de 40 dB por debajo de la trama limpia más intensa; una agrupación por 15 bandas de tercio de octava de las magnitudes DFT desde un centro mínimo de 150 Hz; y segmentos de análisis de 384 ms (30 tramas) como unidad de comparación. La frecuencia de muestreo de las entradas es libre, la biblioteca remuestrea internamente.
from phonometry import stoi
d = stoi(clean, degraded, fs) # STOI, remuestreado a 10 kHz por dentroprint(round(d.value, 3)) # un escalar en torno a [0, 1]print(stoi(clean, clean, fs).value) # 1.0 (una señal contra sí misma)2. STOI: correlación de envolventes con recorte
Sección titulada «2. STOI: correlación de envolventes con recorte»Para cada banda y segmento STOI normaliza la envolvente degradada respecto a la limpia, la recorta en un límite inferior de relación señal-distorsión ( dB) para que una unidad completamente degradada no pueda arrastrar la puntuación por debajo de su suelo, y toma la correlación muestral de ambas envolventes (Taal et al. 2011, Ecs. 3-6):
El índice es el promedio de esas correlaciones intermedias sobre todas las bandas y segmentos (Ec. 6). Como la normalización divide una ganancia por segmento, STOI es invariante al nivel de reproducción de la señal degradada, y a mayor SNR corresponde una puntuación monótonamente mayor.
import numpy as npfrom phonometry import stoi
fs = 10000rng = np.random.default_rng(1)clean = rng.standard_normal(3 * fs)for snr_db in (-10, 0, 10, 20): g = 10.0 ** (-snr_db / 20.0) noisy = clean + g * rng.standard_normal(clean.size) print(snr_db, round(stoi(clean, noisy, fs).value, 3))El STOIResult incluye la correlación media por banda (band_scores) y las
puntuaciones por segmento (segment_scores) que promedian a value, y su
.plot() dibuja la correlación intermedia por banda. Merece la pena mirar esa
vista por bandas antes de citar el índice: muestra dónde muerde la
degradación, algo que el número único no puede indicar.
Mostrar el código de esta figura
import numpy as npimport matplotlib.pyplot as pltfrom scipy.signal import butter, lfilterfrom phonometry import stoi
# Material tipo habla: ruido limitado en banda con envolvente silábica de# 3,5 Hz, en un enmascarador plano con SNR de 0 dB.fs = 10000rng = np.random.default_rng(11)t = np.arange(4 * fs) / fsb, a = butter(2, [200 / (fs / 2), 4000 / (fs / 2)], btype="band")carrier = lfilter(b, a, rng.standard_normal(t.size))clean = carrier * (0.15 + 0.85 * np.abs(np.sin(2 * np.pi * 3.5 * t)) ** 2)masker = rng.standard_normal(clean.size)gain = np.sqrt(np.mean(clean ** 2)) / np.sqrt(np.mean(masker ** 2))res = stoi(clean, clean + gain * masker, fs)print(round(res.value, 3)) # 0.727
# En una línea: la correlación intermedia por banda que hay tras el índice.res.plot(language="es")plt.show()
# A mano, reproduciendo lo que dibuja STOIResult.plot():pos = np.arange(res.band_scores.size)fig, ax = plt.subplots()ax.bar(pos, res.band_scores)ax.set_xticks(pos)ax.set_xticklabels([f"{f:.0f}" for f in res.band_frequencies], rotation=45, ha="right")ax.set_xlabel("Banda de tercio de octava [Hz]")ax.set_ylabel("Correlación intermedia media")ax.set_title(f"STOI = {res.value:.3f}")plt.show()El enmascarador plano castiga sobre todo a las bandas graves, porque ahí el espectro del habla cae y el del enmascarador no, y la correlación se recupera en las bandas consonánticas por encima de 1 kHz. Un perfil por bandas plano, o que se hunde solo en una banda, apunta a algo distinto del ruido de banda ancha: un filtro de rechazo, una resonancia o un artefacto de procesado del realce que se está evaluando.
3. ESTOI: correlación espectral para enmascaradores modulados
Sección titulada «3. ESTOI: correlación espectral para enmascaradores modulados»ESTOI (extended=True) sustituye la correlación por banda independiente por una
conjunta espectro-temporal. Dentro de cada segmento de 384 ms normaliza en media
y varianza las filas del espectrograma (las envolventes de banda) y luego
sus columnas (los espectros por trama), y promedia la correlación de las
columnas normalizadas (Jensen y Taal 2016, Ecs. 4-8). Hacer competir las
columnas significa que un enmascarador que deja silencios, donde el habla limpia
es audible por instantes, recibe crédito por el habla vislumbrada ahí, algo que
el promedio por banda de STOI apenas capta.
Mostrar el código de esta figura
import numpy as npimport matplotlib.pyplot as pltfrom phonometry import stoi
fs = 10000rng = np.random.default_rng(20)t = np.arange(3 * fs) / fs# Una señal limpia tipo habla: tonos con modulación de amplitud.clean = np.zeros_like(t)for f0 in (200.0, 400.0, 700.0, 1100.0, 1800.0, 2600.0): depth = 0.5 * (1.0 + np.sin(2 * np.pi * rng.uniform(2.0, 6.0) * t + rng.uniform(0.0, 2 * np.pi))) clean += depth * np.sin(2 * np.pi * f0 * t + rng.uniform(0.0, 2 * np.pi))p_clean = np.sqrt(np.mean(clean ** 2))
base = rng.standard_normal(clean.size)gate = 0.5 * (1.0 + np.sign(np.sin(2 * np.pi * 5.0 * t))) # puerta on/off a 5 Hzmodulated = base * (0.05 + 0.95 * gate)snrs = np.arange(-15.0, 20.1, 5.0)
def curve(masker, extended): p_m = np.sqrt(np.mean(masker ** 2)) return [stoi(clean, clean + (p_clean / (p_m * 10.0 ** (s / 20.0))) * masker, fs, extended=extended).value for s in snrs]
fig, (a, b) = plt.subplots(1, 2, figsize=(12, 5), sharey=True)for ax, extended, title in ((a, False, "STOI"), (b, True, "ESTOI")): ax.plot(snrs, curve(base, extended), "o-", label="Enmascarador estacionario") ax.plot(snrs, curve(modulated, extended), "s--", label="Enmascarador modulado") ax.set_title(title); ax.set_xlabel("SNR [dB]"); ax.set_ylim(0, 1); ax.legend()a.set_ylabel("Índice de inteligibilidad")plt.show()4. Qué medida usar y cuándo
Sección titulada «4. Qué medida usar y cuándo»| STOI | ESTOI | |
|---|---|---|
| Magnitud intermedia | Correlación de envolventes por banda, con recorte | Correlación espectral normalizada por filas y por columnas |
| Invariancia al nivel | Sí (normalización por segmento) | Sí (normalización por fila y por columna) |
| Enmascaradores estacionarios | Bien validada | Bien validada |
| Enmascaradores modulados, hablantes competidores | Infravalora el beneficio de los vistazos | Lo sigue |
| Coste | Menor | Algo mayor |
Para ruido aditivo estacionario las dos medidas son intercambiables y STOI es la opción ligera por defecto; cuando la interferencia fluctúa en el tiempo, o al comparar procesadores que remodelan el habla en tiempo y frecuencia, prefiere ESTOI.
Ambas responden a una pregunta más estrecha que las dos métricas normalizadas de habla de la biblioteca, y la elección entre las tres familias es en realidad una elección de qué se puede medir. STOI y ESTOI necesitan una referencia limpia y la señal degradada, así que pertenecen al trabajo de procesado: reducción de ruido, separación de fuentes, códecs, algoritmos de audífonos. El STI (IEC 60268-16) no necesita referencia limpia, solo el canal, y es lo que valora una sala o un sistema de megafonía. El SII (ANSI S3.5-1997) no necesita ninguna señal, solo espectros, y es lo que predice la audibilidad para un oyente con un umbral de audición dado. Cuando hay más de una disponible, responden a preguntas distintas en lugar de confirmarse entre sí: un procesador puede subir el STOI mientras la sala mantiene un STI pobre.
Qué cubre esta guía
Sección titulada «Qué cubre esta guía»Cubierto. Taal et al. 2011 (STOI) y Jensen y Taal 2016 (ESTOI), las dos
medidas basadas en correlación que implementa stoi(): el procesado inicial
común de remuestreo a 10 kHz, tramas Hann de 256 muestras, 15 bandas de tercio
de octava, segmentos de 384 ms y la eliminación de tramas silenciosas a 40 dB
(Taal et al. 2011, Ecs. 1-4); la correlación de envolventes por banda y el
índice promediado (Ecs. 5-6); y, con extended=True, la normalización por
filas y columnas del espectrograma y el índice de correlación espectral
(Jensen y Taal 2016, Ecs. 4-8).
No cubierto. Taal et al. 2011 también ajusta una función logística que
convierte el índice en un porcentaje de palabras entendidas previsto,
calibrada sobre corpus concretos de pruebas de escucha. stoi() devuelve
solo , como STOIResult.value, no ese porcentaje: la API no tiene salida
de porcentaje ni coeficientes ajustados. El artículo de ICASSP de 2010 se
cita solo como la versión corta de congreso del mismo algoritmo, sin añadir
nada implementado más allá de las ecuaciones de 2011/2016 anteriores.
Véase también
Sección titulada «Véase también»- Índice de transmisión del habla: valora un canal de transmisión a partir de su respuesta al impulso o de una grabación STIPA.
- Índice de inteligibilidad del habla: predice la inteligibilidad a partir de espectros de habla, ruido y umbral.
- Bancos de filtros: las bandas de tercio de octava en las que el procesado inicial agrupa la DFT.
- Referencia de la API:
hearing.objective_intelligibility.
Referencias
Sección titulada «Referencias»- Jensen, J. y Taal, C. H. (2016). An algorithm for predicting the intelligibility of speech masked by modulated noise maskers. IEEE/ACM Transactions on Audio, Speech, and Language Processing, 24(11), 2009-2022. https://doi.org/10.1109/TASLP.2016.2585878ESTOI: la normalización en media y varianza de las filas y las columnas del espectrograma de corto plazo (Ecs. 4-7) y el índice intermedio de correlación espectral (Ec. 8).
- Taal, C. H., Hendriks, R. C., Heusdens, R. y Jensen, J. (2010). A short-time objective intelligibility measure for time-frequency weighted noisy speech. 2010 IEEE International Conference on Acoustics, Speech and Signal Processing (ICASSP), 4214-4217. https://doi.org/10.1109/ICASSP.2010.5495701La versión corta de congreso de STOI.
- Taal, C. H., Hendriks, R. C., Heusdens, R. y Jensen, J. (2011). An algorithm for intelligibility prediction of time-frequency weighted noisy speech. IEEE Transactions on Audio, Speech, and Language Processing, 19(7), 2125-2136. https://doi.org/10.1109/TASL.2011.2114881STOI: el procesado inicial común (10 kHz, tramas Hann de 256 muestras, 15 bandas de tercio de octava, segmentos de 384 ms), la normalización y el recorte por relación señal-distorsión (Ecs. 1-4), la correlación de envolventes por banda (Ec. 5) y el índice promediado (Ec. 6).