Ir al contenido

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 no correlacionado. 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.

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.

Ambas medidas están definidas para habla continua, y el procesado inicial es donde muerde esa suposición: la regla de los 40 dB se apoya en el rango dinámico de la señal limpia, así que existe para impedir que las pausas entre palabras dominen la correlación. Una señal sin pausas, ruido estacionario, un tono sostenido o música sin huecos, no pierde nada por ella y el índice pierde su sentido; una grabación que es casi toda silencio lo pierde casi todo y la llamada da error en lugar de devolver un número. Tienen que sobrevivir al menos unos 0,4 s de habla activa.

import numpy as np
from phonometry import stoi
fs = 10000
rng = np.random.default_rng(11)
n = 4 * fs
t = np.arange(n) / fs
# Material tipo habla: ruido de banda limitada bajo una envolvente silábica de
# 3,5 Hz, para que la regla de tramas silenciosas tenga pausas sobre las que
# actuar.
spectrum = np.fft.rfft(rng.standard_normal(n))
spectrum[(np.fft.rfftfreq(n, 1 / fs) < 200) | (np.fft.rfftfreq(n, 1 / fs) > 4000)] = 0
carrier = np.fft.irfft(spectrum, n)
clean = carrier * (0.15 + 0.85 * np.abs(np.sin(2 * np.pi * 3.5 * t)) ** 2)
noise = rng.standard_normal(n)
noise *= np.sqrt(np.mean(clean ** 2) / np.mean(noise ** 2)) # SNR de 0 dB
degraded = clean + noise
d = stoi(clean, degraded, fs) # STOI, remuestreado a 10 kHz por dentro
print(round(d.value, 3)) # 0.708
print(round(stoi(clean, clean, fs).value, 6)) # 1.0 (una señal contra sí misma)

Todo hasta los segmentos de 384 ms es común; las dos medidas solo se separan en la correlación. El diagrama despliega la cadena con los números del ejemplo del enmascarador plano.

Diagrama de bloques de la cadena de procesado de STOI y ESTOI: una referencia limpia y una versión degradada, en el ejemplo de la guía material tipo habla en un enmascarador plano a 0 dB de relación señal-ruido, se remuestrean a 10 kilohercios descartando las tramas silenciosas, pasan por una DFT de corto plazo de tramas Hann de 256 muestras con 50 por ciento de solape agrupada en 15 bandas de tercio de octava desde 150 hercios, y se comparan en segmentos de 384 milisegundos; la cadena se divide después en la correlación de envolventes con recorte de STOI y la correlación espectral normalizada por filas y columnas de ESTOI, y el ejemplo da STOI igual a 0,727, con la banda más baja conservando 0,27 de la correlación y las bandas por encima de 1,9 kilohercios llegando a 0,90Diagrama de bloques de la cadena de procesado de STOI y ESTOI: una referencia limpia y una versión degradada, en el ejemplo de la guía material tipo habla en un enmascarador plano a 0 dB de relación señal-ruido, se remuestrean a 10 kilohercios descartando las tramas silenciosas, pasan por una DFT de corto plazo de tramas Hann de 256 muestras con 50 por ciento de solape agrupada en 15 bandas de tercio de octava desde 150 hercios, y se comparan en segmentos de 384 milisegundos; la cadena se divide después en la correlación de envolventes con recorte de STOI y la correlación espectral normalizada por filas y columnas de ESTOI, y el ejemplo da STOI igual a 0,727, con la banda más baja conservando 0,27 de la correlación y las bandas por encima de 1,9 kilohercios llegando a 0,90

Los dos argumentos no son «dos señales» sin más. Tienen que ser la misma locución, con la misma longitud y alineadas con precisión de muestra, y esto último es el fallo que más puntuaciones cuesta en la práctica, porque nada en el resultado lo distingue de una degradación genuina. Ambas medidas correlacionan envolventes de corto plazo dentro de segmentos de 384 ms, así que un retardo constante las descorrelaciona directamente. Sobre el par de arriba, desplazar la señal degradada 20 ms lleva la puntuación de 0,708 a 0,329; sobre un par perfecto, esos mismos 20 ms llevan el 1,0 a 0,459 y 50 ms lo vuelven negativo. Media sílaba basta para convertir un buen realce en uno malo sobre el papel.

La biblioteca impone la igualdad de longitud y nada más: no alinea, así que es quien llama el que compensa antes cualquier latencia algorítmica. Correlaciona las envolventes de banda ancha (o antepón un chirp corto de marca), desplaza y recorta luego ambas al tramo común. Si las dos señales pasaron por relojes de reproducción y de captura distintos, vigila además la deriva: un desplazamiento fijo no puede corregir una diferencia de frecuencia de muestreo, así que remuestrea al reloj de referencia o graba a través de un solo equipo. La comprobación que merece la pena hacer una vez en cualquier cadena nueva es el par de líneas de arriba: stoi(x, x, fs).value vale 1.0, y stoi(x, np.roll(x, k), fs) se desploma deprisa con k.

Lo que no hace falta igualar es el nivel: la normalización por segmento hace a ambas medidas invariantes a la ganancia de la señal degradada. Lo que hay que acertar es la alineación; la ganancia, no.

Tres condiciones dan error en lugar de devolver un valor, y conviene reconocerlas: longitudes distintas, muestras no finitas y que sobrevivan menos de 30 tramas de corto plazo a la eliminación de tramas silenciosas, que son los ~0,4 s de habla activa mencionados arriba.

Capturar la señal degradada a través de un equipo real

Sección titulada «Capturar la señal degradada a través de un equipo real»

Todo lo anterior supone que la señal degradada se produjo numéricamente. En cuanto se captura acústicamente, un audífono sobre un oído artificial en una caja de ensayo, unos auriculares o un bucle de altavoz y micrófono, cuatro cosas pasan a ser responsabilidad de quien mide:

  • La referencia limpia sigue siendo el archivo original. Volver a grabarla por la misma cadena elimina justo la distorsión que se está evaluando, y además rompe la selección de tramas silenciosas, que se deriva solo de la señal limpia.
  • La cadena de captura se puntúa como degradación. La respuesta del altavoz, el ruido de fondo de la caja de ensayo y el ruido propio del micrófono entran todos en el índice medido, así que mide el bucle una vez con el equipo puenteado y declara ese número como el suelo de la comparación.
  • Reproduce al nivel de trabajo del equipo. El índice es invariante al nivel; el equipo no lo es: un compresor o un reductor de ruido se comportan de otra manera a otro nivel de entrada.
  • Repite. Una sola captura arrastra la variabilidad entre repeticiones del camino acústico; declara la dispersión sobre varias capturas, no un solo número.
El banco para un par capturado acústicamente. Un archivo de habla limpia se bifurca en dos caminos: el superior va directo a la comparación, etiquetado como el archivo original y nunca una regrabación; el inferior pasa por un amplificador y un altavoz de reproducción calibrados hasta una caja de ensayo que aloja el equipo bajo ensayo, un audífono sobre un oído artificial o unos auriculares sobre un simulador de torso, y sale por un micrófono de captura y su preamplificador. Ambos caminos se encuentran en un bloque de alinear y recortar cuyas llamadas dicen correlacionar las envolventes, igual longitud y un solo reloj, y solo entonces entran en la cadena de STOI y ESTOI. Una llamada a trazos bajo el camino inferior dice que hay que recorrerlo una vez con el equipo puenteado, porque el altavoz, el ruido de la caja y el micrófono se puntúan también como degradación, y un pie dice que hay que reproducir al nivel de trabajo del equipo y repetir la capturaEl banco para un par capturado acústicamente. Un archivo de habla limpia se bifurca en dos caminos: el superior va directo a la comparación, etiquetado como el archivo original y nunca una regrabación; el inferior pasa por un amplificador y un altavoz de reproducción calibrados hasta una caja de ensayo que aloja el equipo bajo ensayo, un audífono sobre un oído artificial o unos auriculares sobre un simulador de torso, y sale por un micrófono de captura y su preamplificador. Ambos caminos se encuentran en un bloque de alinear y recortar cuyas llamadas dicen correlacionar las envolventes, igual longitud y un solo reloj, y solo entonces entran en la cadena de STOI y ESTOI. Una llamada a trazos bajo el camino inferior dice que hay que recorrerlo una vez con el equipo puenteado, porque el altavoz, el ruido de la caja y el micrófono se puntúan también como degradación, y un pie dice que hay que reproducir al nivel de trabajo del equipo y repetir la captura

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):

donde es la envolvente temporal de corto plazo limpia de la banda en la trama dentro del segmento de 30 tramas; es la envolvente degradada después de la normalización de ganancia por segmento y del recorte a dB, de modo que ese acento marca el procesado y no una media; una barra sobre una magnitud completa (, ) es su media sobre el segmento; y es la norma euclídea sobre esas mismas 30 tramas. Así que es una correlación de Pearson corriente en .

El índice es el promedio de esas correlaciones intermedias sobre todas las bandas y segmentos (Ec. 6), y las dos marginales de ese promedio son lo que exponen band_scores y segment_scores. 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.

from phonometry import stoi
# La señal `clean` tipo habla de la sección 1, degradada con cuatro relaciones
# señal-ruido. Conviene que la referencia siga siendo tipo habla: una referencia
# gaussiana plana no tiene pausas, así que la regla de los 40 dB no elimina nada
# y el índice pierde su sentido.
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))
# -10 0.083 | 0 0.484 | 10 0.858 | 20 0.956

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.

Correlación intermedia media por banda de tercio de octava de 150 Hz a 3810 Hz para material tipo habla en un enmascarador plano con relación señal-ruido de 0 dB: la banda más grave conserva solo unos 0,27 de la correlación de envolvente y el valor sube de forma sostenida hasta unos 0,9 en las bandas consonánticas por encima de 1,9 kHz, promediando un STOI de 0,727Correlación intermedia media por banda de tercio de octava de 150 Hz a 3810 Hz para material tipo habla en un enmascarador plano con relación señal-ruido de 0 dB: la banda más grave conserva solo unos 0,27 de la correlación de envolvente y el valor sube de forma sostenida hasta unos 0,9 en las bandas consonánticas por encima de 1,9 kHz, promediando un STOI de 0,727
Mostrar el código de esta figura
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import butter, lfilter
from phonometry import stoi
# Material tipo habla: ruido de banda limitada con envolvente silábica de
# 3,5 Hz, en un enmascarador plano con SNR de 0 dB.
fs = 10000
rng = np.random.default_rng(11)
t = np.arange(4 * fs) / fs
b, 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 perfil por bandas es una de las marginales del promedio; la otra es el tiempo, y responde a una pregunta que la vista por bandas no puede responder:

Dos paneles apilados sobre cuatro segundos. Arriba: la forma de onda de la referencia limpia con pausas silábicas, tres de sus 311 tramas de corto plazo sombreadas porque caen más de 40 dB por debajo de la trama más intensa y se descartan, y una región de corte de señal de 0,35 segundos marcada. Abajo: las puntuaciones de STOI por segmento para dos degradaciones de la misma referencia. El ruido estacionario a 0 dB da una serie plana en torno a 0,77 para un STOI de 0,772; un corte de señal de 0,35 segundos deja la serie en 1,0 en todas partes salvo un hundimiento profundo por debajo de cero a lo largo del corte, y aun así promedia un STOI mayor, de 0,874Dos paneles apilados sobre cuatro segundos. Arriba: la forma de onda de la referencia limpia con pausas silábicas, tres de sus 311 tramas de corto plazo sombreadas porque caen más de 40 dB por debajo de la trama más intensa y se descartan, y una región de corte de señal de 0,35 segundos marcada. Abajo: las puntuaciones de STOI por segmento para dos degradaciones de la misma referencia. El ruido estacionario a 0 dB da una serie plana en torno a 0,77 para un STOI de 0,772; un corte de señal de 0,35 segundos deja la serie en 1,0 en todas partes salvo un hundimiento profundo por debajo de cero a lo largo del corte, y aun así promedia un STOI mayor, de 0,874

Dos degradaciones de la misma referencia, y el escalar las ordena al revés: el corte de señal puntúa 0,874 frente al 0,772 del enmascarador estacionario, porque una catástrofe corta se diluye en el promedio y una degradación leve en todas partes no. La marginal temporal las separa de inmediato: una serie es plana y la otra es perfecta salvo en un puñado de segmentos. Ese es el diagnóstico al que hay que recurrir cuando un STOI bajo no tiene causa evidente: un transitorio, un corte o un artefacto de procesado aparecen aquí y en ningún otro sitio. Las tramas sombreadas de arriba son las que descarta la regla de los 40 dB, que es lo que significa en concreto que «la entrada tiene que tener dinámica de habla».

Mostrar el código de esta figura
# El mismo material de la sección 1 pero con silencio entre las palabras, para
# que algunas tramas caigan de verdad 40 dB por debajo de la más intensa.
fig_rng = np.random.default_rng(11)
freq = np.fft.rfftfreq(n, 1 / fs)
spec = np.fft.rfft(fig_rng.standard_normal(n))
spec[(freq < 200) | (freq > 4000)] = 0
env = np.abs(np.sin(2 * np.pi * 3.5 * t)) ** 2
ref = np.fft.irfft(spec, n) * np.where(env < 0.08, 0.0, env)
masker = fig_rng.standard_normal(n)
masker *= np.sqrt(np.mean(ref ** 2) / np.mean(masker ** 2))
steady = stoi(ref, ref + masker, fs)
hole = np.ones(n)
hole[int(1.6 * fs):int(1.95 * fs)] = 0.0 # un corte de 0,35 s
dropout = stoi(ref, ref * hole, fs)
print(round(steady.value, 3), round(dropout.value, 3)) # 0.772 0.874
print(round(float(dropout.segment_scores.min()), 3)) # -0.078

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.

Dos paneles del índice de inteligibilidad frente al SNR de -15 a 20 dB. Izquierda (STOI): las curvas del enmascarador estacionario y del modulado casi se superponen, de modo que STOI apenas separa los dos enmascaradores. Derecha (ESTOI): la curva del enmascarador modulado queda claramente por encima de la del estacionario en todo el rango de SNR, de modo que ESTOI acredita el habla vislumbrada en los silencios del enmascaradorDos paneles del índice de inteligibilidad frente al SNR de -15 a 20 dB. Izquierda (STOI): las curvas del enmascarador estacionario y del modulado casi se superponen, de modo que STOI apenas separa los dos enmascaradores. Derecha (ESTOI): la curva del enmascarador modulado queda claramente por encima de la del estacionario en todo el rango de SNR, de modo que ESTOI acredita el habla vislumbrada en los silencios del enmascarador
Mostrar el código de esta figura
import numpy as np
import matplotlib.pyplot as plt
from phonometry import stoi
fs = 10000
rng = 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 Hz
modulated = 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()
ParámetroTipoUnidadesRango / def.Notas
cleanarray 1Dcualquierano vacíoLa referencia limpia; la medida es invariante al nivel, así que la calibración da igual
degradedarray 1Dcualquieramisma longitud que cleanMisma locución, misma frecuencia de muestreo, alineada muestra a muestra
fsintHz> 0Frecuencia de muestreo de ambas señales; se remuestrea a 10 kHz por dentro
extendedbooldef. FalseTrue selecciona ESTOI

Devuelve un STOIResult: value, band_scores (15), segment_scores, band_frequencies y extended. Da error con longitudes distintas, con entradas no finitas y cuando sobreviven menos de 30 tramas de corto plazo a la eliminación de tramas silenciosas.

El índice bruto no tiene interpretación absoluta, y tampoco pretende tenerla. El paso de a un porcentaje de palabras entendidas es una logística ajustada a un corpus y a un grupo de oyentes concretos, que la biblioteca deliberadamente no implementa, así que un mismo predice puntuaciones distintas para materiales distintos, y citar «STOI = 0,73» como una inteligibilidad es un error de categoría.

De ahí sale la práctica de trabajo. Mantén fijos el material, los hablantes, la alineación y la duración de análisis, y declara la diferencia entre condiciones (el ΔSTOI entre un procesador y su entrada sin procesar) junto con el número de locuciones sobre el que se promedió, porque los valores de una sola locución dispersan. Atiende también a la forma: el índice satura cerca de 1 para las degradaciones leves y se aplana por el extremo bajo, así que una mejora de 0,85 a 0,90 vale mucho más en inteligibilidad que una de 0,35 a 0,40; monótono no significa lineal. Y cuando dos condiciones puntúan parecido, las vistas por banda y por segmento son los diagnósticos que dicen si llegaron ahí por el mismo camino.

STOIESTOI
Magnitud intermediaCorrelación de envolventes por banda, con recorteCorrelación espectral normalizada por filas y por columnas
Invariancia al nivelSí (normalización por segmento)Sí (normalización por fila y por columna)
Enmascaradores estacionariosBien validadaBien validada
Enmascaradores modulados, hablantes competidoresInfravalora el beneficio del habla vislumbradaLo sigue
CosteMenorAlgo 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.

  • 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.

  • 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).