Escolar Documentos
Profissional Documentos
Cultura Documentos
Hay unos pocos algoritmos robustos disponibles para medir objetivamente la inteligibilidad del habla. Comparan lo que
se escucha por un oyente a la informacin que se transmite por la persona que habla, sin embargo, slo uno de estos
algoritmos disponibles obras en las salas reverberantes y en ese momento yo estaba buscando una aplicacin para
MATLAB, no pude encontrar ninguna, nada de nada. Por lo tanto, decid codificar desde cero a m mismo y le mostrar
cmo hacerlo paso a paso.
El ndice de articulacin (AI) es una medicin ms antigua que ha evolucionado hasta el ndice de inteligibilidad del habla
(SII). El SII utiliza una funcin de banda importancia y la banda audible para dar cuenta de la falta de informacin mutua
de enmascaramiento y de diferentes niveles de presentacin de la voz limpia. Tambin existe la corta duracin
inteligibilidad objetivo medida (STOI) que est diseado para la prediccin de tiempo-frecuencia ponderada de voz con
ruido y el ndice de transmisin de voz (STI), que hace uso de la funcin de transferencia de modulacin.
Ahora, esto puede sonar todo un poco confuso, pero en pocas palabras slo el ITS es adecuado para medir la
inteligibilidad en las salas reverberantes. El STI, en esencia, mide la respuesta del canal acstico entre el oyente y la
persona que habla y desde esta medicin del canal se estima la cantidad de informacin mutua podra mantenerse a
travs de ese canal. La razn es razonablemente robusto para diferentes niveles de reverberacin es porque analiza
poderes bandas espectrales usando la funcin de transferencia de modulacin (MTF).
En primer lugar, para medir la ITS necesitaremos la respuesta al impulso (IR) del canal. Esto se puede encontrar
algunas maneras para que las simulaciones y para las grabaciones del mundo real. Algunos de estos pueden ser para
transmitir una seal vlida, grabar el resultado y luego deconvoluir la grabacin con la seal original. Algunas seales
que podran ser utilizados son la secuencia de longitud mxima (MLS), el ruido blanco, barrido sinusoidal, barrido
sinusoidal logartmica, haciendo estallar de un globo o cualquier otra cosa que va explosin. Voy a repasar algunos
mtodos agradables en un futuro post.
Una vez que tenemos una IR vamos a utilizar esto como la entrada a nuestra funcin de MATLAB que se calcule
la ITS. Ir mostrando cmo hacer esto utilizando la versin anterior de la norma (todava bastante exacto para niveles
bajos de presentacin). He utilizado esto como mi definicin de funcin:
function [STI_val, ALcons, STI_val_approx, ALcons_approx] = STI( ImpulseResponse, fs, OctaveFilters )
el cual est listo para algunas caractersticas adicionales que explicar ms adelante.
Ahora, antes de empezar a calcular el ITS queremos establecer una segunda funcin para encontrar la MTF,
porque para encontrar el ITS tenemos que hacer esto muchas veces. Por lo que aade otra definicin de la funcin
despus de la end de palabra clave para la primera funcin y se utiliza esta definicin:
function MTF = getMTF(ir)
Por lo tanto, para encontrar el SMN para una IR dada hay cinco sencillos pasos que tenemos que aadir a la getMTF
funcin. El primer paso es la cuadratura del IR:
ir_2 = ir .^ 2;
Tenemos que conseguir que la energa total del cuadrado IR en algn momento por lo que puede que tambin lo haga
ahora. Esto se puede hacer mediante la integracin de la cual es una suma de los valores discretos de la matriz de IR:
ir_2_int = sum(ir_2);
Despus de esto, necesitamos transformar el cuadrado de infrarrojos en el dominio de la frecuencia. Esto se puede
hacer usando una transformada de Fourier rpida que MATLAB convenientemente tiene una funcin para:
IR_2_fft = fft(ir_2);
Una vez que tenemos nuestra seal en el dominio de frecuencia (espectro sobre) debemos normalizarlo basa en la
energa total se calcul anteriormente:
IR_MTF = IR_2_fft / ir_2_int;
Por ltimo, la MTF queremos volver para su uso en nuestra STI funcin slo debe ser el valor absoluto de la envolvente
del espectro complejo. Esto se puede hacer de esta manera:
MTF = abs(IR_MTF);
Ese es el end de la getMTF funcin.
Ahora podemos empezar a trabajar en encontrar el valor real de las ITS, la parte divertida. Para ello necesitamos
para funcionar todo el IR (IR ancho de banda completo) a travs de filtros de banda de octava y luego encontrar la MTF
de cada una de las seales filtradas. Para realizar un filtrado del IR con filtros de banda de octava debemos crear un filtro
para cada banda de octava, luego filtrar el IR y luego guardar el resultado cada vez. Esto se puede hacer con el cdigo
siguiente:
BandsPerOctave = 1;
N = 6; % Filter Order
F0 = 1000; % Center Frequency (Hz)
f = fdesign.octave(BandsPerOctave,'Class 1','N,F0',N,F0,fs);
F0 = validfrequencies(f);
F0(F0<125)=[]; F0(F0>min([8000,fs/2]))=[]; % Only keep bands in the range required for the STI calculation
Nfc = length(F0);
for i=1:Nfc
if nargin < 3
f.F0 = F0(i);
H = design(f,'butter');
ir_filtered = filter(H, ImpulseResponse);
else
ir_filtered = filter(OctaveFilters(i), ImpulseResponse);
end
MTF_octband(:,i) = getMTF(ir_filtered);
end
Si se lee el cdigo anterior se habrn dado cuenta de la sentencia condicional que dice que si tenemos tres o ms
argumentos de entrada entonces deberamos usar el tercer argumento de entrada, OctaveFilters . He aadido esto
porque la creacin de los filtros de banda de octava es computacionalmente caro, as que si terminamos llamando a
nuestra funcin muchas veces que sera mejor para el clculo de los filtros una vez y reutilizarlos para cada llamada a la
funcin, voy a mostrar cmo se puede hacer esto en un futuro post. Tambin tenga en cuenta la llamada de funcin a
nuestra funcin, getMTF() .
Ahora que tenemos nuestras seales filtradas de banda de octava deberamos obtener la amplitud en diferentes
frecuencias de modulacin. Para el STI hay 14 diferentes frecuencias de modulacin que tienen 1/3 de octava
separacin. Es decir, deberamos obtener la magnitud a las 14 frecuencias especficas de cada MTF. El siguiente cdigo
de lograr esto:
After this we need to transform the squared IR into the frequency domain. This can be done using a fast Fourier transform
which MATLAB conveniently has a function for:
IR_2_fft = fft(ir_2);
Once we have our frequency domain signal (the envelope spectrum) we should normalise it based on the total energy we
calculated earlier:
IR_MTF = IR_2_fft / ir_2_int;
Lastly, the MTF we want to return for use in our STI function should only be the absolute value of the complex envelope
spectrum. This can be done like so:
MTF = abs(IR_MTF);
That is the end of the getMTF function.
Now we can get started on finding the actual STI value, the fun part. For this we need to run the entire IR (the full
bandwidth IR) through octave band filters and then find the MTF of each of the filtered signals. To filter the IR with octave
band filters we must create a filter for each octave band, then filter the IR and then save the result each time. This can be
done with the following code:
BandsPerOctave = 1;
N = 6; % Filter Order
F0 = 1000; % Center Frequency (Hz)
f = fdesign.octave(BandsPerOctave,'Class 1','N,F0',N,F0,fs);
F0 = validfrequencies(f);
F0(F0<125)=[]; F0(F0>min([8000,fs/2]))=[]; % Only keep bands in the range required for the STI calculation
Nfc = length(F0);
for i=1:Nfc
if nargin < 3
f.F0 = F0(i);
H = design(f,'butter');
ir_filtered = filter(H, ImpulseResponse);
else
ir_filtered = filter(OctaveFilters(i), ImpulseResponse);
end
MTF_octband(:,i) = getMTF(ir_filtered);
end
If you read the code above you may have noticed the conditional statement that says that if we have three or more input
arguments then we should use the third input argument, OctaveFilters. I have added this because creating the octave
band filters is computationally expensive, so if we end up calling our function many times it would be better to calculate
the filters once and reuse them for each function call, I will show how this can be done in a future post. Also note the
function call to our function, getMTF().
Now that we have our octave band filtered signals we should get the amplitude at different modulation
frequencies. For the STI there are 14 different modulation frequencies which have 1/3 octave spacing. That is to say, we
should get the magnitude at 14 specific frequencies from each MTF. The following code will accomplish this:
modulation_freqs = (0.63) * ((2.0) .^ ([0:13]./3));
freqs = linspace(0, fs/2, size(MTF_octband,1)/2+1); freqs=freqs(1:end-1);%No nyquist frequency
for i=1:Nfc
for j=1:14
m(i,j) = interp1(freqs,MTF_octband(1:end/2,i),modulation_freqs(j));
end
end
good_freqs = ~any(isnan(m),2);
m(~good_freqs,:)=[];
The last couple of lines here are a little bit special, I have added them so that if we have any frequencies which return bad
results they will be ignored.
The amplitude values we now have are known as the m values and the next step is to convert them into an
apparent signal-to-noise ratio (SNR). This is how it is done in MATLAB:
SNR_apparent = 10*log10( m ./ (1-m) );
The STI says we should limit the apparent SNR to 15dB. I did this like so:
SNR_apparent( SNR_apparent > 15 ) = 15;
SNR_apparent( SNR_apparent < -15 ) = -15;
Once we have our apparent SNRs all we need to do is find the average for each of the octave bands. With our
matrix of apparent SNR values we can do this quite simply in MATLAB:
SNR_avg = mean(SNR_apparent,2);
At this point we still have more than a single STI value, though.
To get these octave band SNR values into a single STI value we need to find a weighted average of them and
then turn that weighted average into a value between 0 and 1. The weighted average means we need to know the
different weights for each band, these are described in the STI standard but if youre clever you can work them out from
the following code:
W = [0.13, 0.14, 0.11, 0.12, 0.19, 0.17, 0.14];
SNR_Wavg = sum(SNR_avg' .* W(good_freqs));
SNR_Wavg_approx = sum(SNR_avg' .* W(good_freqs)/sum(W(good_freqs)));
I have also added a weighted average which is performed on only the good frequencies which we defined before and
called it an approximation. This means that if, for instance, the sampling frequency is too low and we dont have enough
octave bands to fulfill the proper STI standard, then we can still approximate what the result might be by ignoring the
bands that are too high.
Of course, the rescaling needs to be done too:
STI_val = (SNR_Wavg + 15) / 30;
STI_val_approx = (SNR_Wavg_approx + 15) / 30;
Thats it! but of course, I think it is nice to add just a couple more convenient return values before we end our function:
ALcons = 170.5405 * exp(-5.419*STI_val);
ALcons_approx = 170.5405 * exp(-5.419*STI_val_approx);
Those calculations are for the articulation loss of consonants (ALcons) which is another useful value.
Ok, now we are done and the function can be ended with the end keyword. If you have done it all properly you should
have code that works like the one you can download from here.
How do you use your newly created STI function?
Easy, just pass your IR array and the sampling frequency (fs) to the function:
y=sinc(-7999:8000);
fs=44100;
STIval=STI(y,fs)
Want the articulation loss of consonants instead? No problem:
[~,ALcons]=STI(y,fs)
What if the signal doesnt meet the sampling requirements for the STI standard? Well, lets approximate the STI and
ALcons and compare them with the true standard-abiding values:
fs=8000;
[STIval,ALcons,STIval_apprx,ALcons_apprx]=STI(y,fs)
If youd like to pass the octave filters to the function you can read over this code and try write a separate function to create
them. I will go over this in a future post.
Thats it, you can now pass the impulse response of any audio channel through this function to find the STI value.