¿Mejorando la resolución del espectrograma en Python?

21

Estoy usando la specgram()función matplotlibpara generar espectrogramas de archivos de ondas de voz en Python, pero la salida siempre es de una calidad muy inferior a la que puede generar mi software de transcripción normal, Praat. Por ejemplo, la siguiente llamada:

specgram(
    fromstring(spf.readframes(-1), 'Int16'),
    Fs=framerate,
    cmap=cm.gray_r,
)

Genera esto:

ingrese la descripción de la imagen aquí

Mientras Praat, trabaja en la misma muestra de audio con la siguiente configuración:

  • Rango de visión: 0-8000Hz
  • Longitud de ventana: 0.005s
  • Rango dinámico: 70dB
  • Pasos de tiempo: 1000
  • Pasos de frecuencia: 250
  • Forma de ventana: gaussiana

Genera esto:

ingrese la descripción de la imagen aquí

¿Qué estoy haciendo mal? He intentado jugar con todos los specgram()parámetros, pero nada parece mejorar la resolución. Prácticamente no tengo experiencia con FFT.

Tormenta Alek
fuente
¿Podría proporcionar el ejemplo de las configuraciones de parámetros matplotlib.specgram que ha probado? ¿Da un ejemplo muy específico de los parámetros para Praat pero no muestra la misma configuración para matplotlib.specgram?
Christopher Felton

Respuestas:

11

Aquí están los parámetros matplotlib.specgram

matplotlib.mlab.specgram(x, 
                         NFFT=256, 
                         Fs=2, 
                         detrend=<function detrend_none at 0x1dd6410>, 
                         window=<function window_hanning at 0x1e0b1b8>, 
                         noverlap=128, 
                         pad_to=None, 
                         sides='default', 
                         scale_by_freq=None)

Los parámetros proporcionados en la descripción de la pregunta deben convertirse a parámetros comparables de mpl.specgram. El siguiente es un ejemplo de la asignación:

View range: 0-8000Hz            Fs=16000
Window length: 0.005s           NFFT = int(Fs*0.005) = 80
                                noverlap = int(Fs*0.0025) = 40
Dynamic range: 70dB             n/a
Time steps: 1000                n/a
Frequency steps: 250            
Window shape: Gaussian          default window is hanning change to gaussian

Si usa 8 ms, obtendrá una potencia de 2 FFT (128). La siguiente es la descripción de la configuración de Praat desde su sitio web

Ver rango (Hz) : el rango de frecuencias para mostrar. El estándar es 0 Hz en la parte inferior y 5000 Hz en la parte superior. Si esta frecuencia máxima es más alta que la frecuencia Nyquist del sonido (que es la mitad de su frecuencia de muestreo), algunos valores en el espectrograma serán cero, y las frecuencias más altas se dibujarán en blanco. Puede ver esto si graba un sonido a 44100 Hz y establece el rango de visualización de 0 Hz a 25000 Hz.

Longitud de la ventana : la duración de la ventana de análisis. Si esto es 0.005 segundos (el estándar), Praat usa para cada cuadro la parte del sonido que se encuentra entre 0.0025 segundos antes y 0.0025 segundos después del centro de ese cuadro (para las ventanas gaussianas, Praat en realidad usa un poco más que eso). La longitud de la ventana determina el ancho de banda del análisis espectral, es decir, el ancho de la línea horizontal en el espectrograma de una onda sinusoidal pura (ver más abajo). Para una ventana gaussiana, el ancho de banda de -3 dB es 2 * sqrt (6 * ln (2)) / (π * longitud de la ventana), o 1.2982804 / longitud de la ventana. Para obtener un broad-band' spectrogram (bandwidth 260 Hz), keep the standard window length of 5 ms; to get aespectrograma de banda estrecha (ancho de banda 43 Hz), configúrelo en 30 ms (0,03 segundos). Las otras formas de ventana dan valores ligeramente diferentes.

Rango dinámico (dB) : todos los valores que están por encima del rango dinámico dB por debajo del máximo (quizás después de la compresión dinámica, consulte Configuración avanzada de espectrograma ...) se dibujarán en blanco. Los valores intermedios tienen tonos de gris apropiados. Por lo tanto, si el pico más alto en el espectrograma tiene una altura de 30 dB / Hz, y el rango dinámico es 50 dB (que es el valor estándar), los valores por debajo de -20 dB / Hz se dibujarán en blanco, y los valores entre -20 dB / Hz y 30 dB / Hz se dibujarán en varios tonos de gris.

Enlace a la configuración de Praat

La pregunta del OP podría ser sobre la diferencia de contraste entre el espectrograma Praat y el espectrograma mpl (matplotlib). Praat tiene una configuración de rango dinámico que afecta el contraste. La función mpl no tiene una configuración / parámetro similar. El mpl.specgram devuelve la matriz 2D de niveles de potencia (el espectrograma), el rango dinámico podría aplicarse a la matriz de retorno y volver a trazarse.

El siguiente es un fragmento de código para crear los gráficos a continuación. El ejemplo es ~ 1m15s de voz con un chirrido de 20Hz-8000Hz.

import numpy
import pylab
import wave
import array
pylab.close('all')
w1 = wave.open('example_no_noise.wav')
w2 = wave.open('example_noise.wav')
# hmmm, probably a better way to do this, scipy.io function?
x1 = numpy.array(array.array('h', w1.readframes(w1.getnframes())))
x2 = numpy.array(array.array('h', w2.readframes(w2.getnframes())))
x1 = x1 / (2.**(16-1))  # normalize
x2 = x2 / (2.**(16-1))  # normalize
Fs = 16000.
NFFT = int(Fs*0.005)  # 5ms window
noverlap = int(Fs*0.0025)
pylab.figure(1)
pylab.specgram(x1, NFFT=NFFT, Fs=Fs, noverlap=noverlap, 
               cmap=pylab.get_cmap('Greys'))
pylab.title('Full 1m15s example min noise')
pylab.figure(2)
pylab.specgram(x2, NFFT=NFFT, Fs=Fs, noverlap=noverlap, 
               cmap=pylab.get_cmap('Greys'))
pylab.title('Full 1m15s example more noise')
pylab.figure(3); n=2100*176;
pylab.specgram(x2[n:n+256*256], NFFT=NFFT, Fs=Fs, noverlap=noverlap, 
               cmap=pylab.get_cmap('Greys'))
pylab.title('Full ~4s example min noise')
pylab.figure(4); pylab.plot(x1[n:n+256*256])

Christopher Felton
fuente
1
Pensando un poco más en esto, el parámetro Praat "Rango dinámico" podría ser el factor principal para la diferencia en la apariencia de las gráficas. El "Rango dinámico" de Praat podría estar limitando el rango (compresión) para obtener un mayor contraste en la trama. BOMK MPL no tiene una característica similar, pero podría agregarse una.
Christopher Felton
6

Parece ser un problema de resolución de tiempo / frecuencia. Su diagrama de Praat tiene una resolución de frecuencia peor (ni siquiera puede ver claramente los armónicos) y una mejor resolución de tiempo. Intente reducir el tamaño de la ventana (NFFT) a 16000 x 0.05 = 80 muestras. Sugeriría usar una potencia mayor de 2 en pad_to (128 o 256).

pichenettes
fuente