Améliorer la résolution du spectrogramme en Python?


21

J'utilise la specgram()fonction in matplotlibpour générer des spectrogrammes de fichiers d'ondes vocales en Python, mais la sortie est toujours de bien meilleure qualité que ce que mon logiciel de transcription normal, Praat, peut générer. Par exemple, l'appel suivant:

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

Génère ceci:

entrez la description de l'image ici

Pendant que Praat, travaille sur le même échantillon audio avec les paramètres suivants:

  • Plage de vision: 0-8000Hz
  • Longueur de la fenêtre: 0,005 s
  • Plage dynamique: 70 dB
  • Pas de temps: 1000
  • Pas de fréquence: 250
  • Forme de la fenêtre: gaussienne

Génère ceci:

entrez la description de l'image ici

Qu'est-ce que je fais mal? J'ai essayé de jouer avec tous les specgram()paramètres, mais rien ne semble améliorer la résolution. Je n'ai pratiquement aucune expérience avec les FFT.


Pourriez-vous fournir l'exemple des configurations de paramètres matplotlib.specgram que vous avez essayées? Vous donnez un exemple très spécifique des paramètres de Praat mais ne montrez pas la même configuration pour matplotlib.specgram?
Christopher Felton

Réponses:


11

Voici les paramètres 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)

Les paramètres fournis dans la description de la question doivent être convertis en paramètres de mpl.specgram comparables. Voici un exemple de mappage:

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 vous utilisez 8 ms, vous obtiendrez une puissance de 2 FFT (128). Ce qui suit est la description des paramètres Praat de leur site Web

Plage d'affichage (Hz) d'affichage : la plage de fréquences à afficher. La norme est de 0 Hz en bas et de 5000 Hz en haut. Si cette fréquence maximale est supérieure à la fréquence de Nyquist du son (qui est la moitié de sa fréquence d'échantillonnage), certaines valeurs du spectrogramme seront nulles et les fréquences plus élevées seront dessinées en blanc. Vous pouvez le voir si vous enregistrez un son à 44100 Hz et réglez la plage d'affichage de 0 Hz à 25000 Hz.

Longueur de fenêtre : la durée de la fenêtre d'analyse. Si c'est 0,005 seconde (la norme), Praat utilise pour chaque image la partie du son qui se situe entre 0,0025 seconde avant et 0,0025 seconde après le centre de cette image (pour les fenêtres gaussiennes, Praat utilise en fait un peu plus que cela). La longueur de la fenêtre détermine la largeur de bande de l'analyse spectrale, c'est-à-dire la largeur de la ligne horizontale dans le spectrogramme d'une onde sinusoïdale pure (voir ci-dessous). Pour une fenêtre gaussienne, la bande passante de -3 dB est de 2 * sqrt (6 * ln (2)) / (π * longueur de fenêtre) ou 1,29880804 / longueur de fenêtre. Pour obtenir unbroad-band' spectrogram (bandwidth 260 Hz), keep the standard window length of 5 ms; to get a spectrogramme à bande étroite (bande passante 43 Hz), réglez-le sur 30 ms (0,03 seconde). Les autres formes de fenêtres donnent des valeurs légèrement différentes.

Plage dynamique (dB) : Toutes les valeurs supérieures à la plage dynamique dB en dessous du maximum (peut-être après compression dynamique, voir Paramètres avancés du spectrogramme ...) seront tracées en blanc. Les valeurs intermédiaires ont des nuances de gris appropriées. Ainsi, si le pic le plus élevé du spectrogramme a une hauteur de 30 dB / Hz et que la plage dynamique est de 50 dB (qui est la valeur standard), les valeurs inférieures à -20 dB / Hz seront tracées en blanc et les valeurs comprises entre -20 dB / Hz et 30 dB / Hz seront dessinés dans différentes nuances de gris.

Lien vers les paramètres Praat

La question du PO pourrait concerner la différence de contraste entre le specgramme Praat et le specgramme mpl (matplotlib). Praat a un réglage de plage dynamique qui affecte le contraste. La fonction mpl n'a pas de réglage / paramètre similaire. Le mpl.specgram renvoie le tableau 2D de niveaux de puissance (le spectrogramme), la plage dynamique pourrait être appliquée au tableau de retour et retracée.

Voici un extrait de code pour créer les tracés ci-dessous. L'exemple est ~ 1m15s de parole avec un chirp 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])


1
En y réfléchissant un peu plus, le paramètre Praat "Dynamic Range" pourrait être le principal facteur de la différence d'apparence des tracés. La "plage dynamique" de Praat peut limiter la plage (compression) afin d'obtenir un contraste plus important dans l'intrigue. BOMK MPL n'a pas de fonctionnalité similaire mais une pourrait être ajoutée.
Christopher Felton

6

Il semble que ce soit un problème de résolution temps / fréquence. Votre tracé Praat a une résolution de fréquence pire (vous ne pouvez même pas voir clairement les harmoniques) et une meilleure résolution de temps. Essayez de réduire la taille de la fenêtre (NFFT) à 16000 x 0,05 = 80 échantillons. Je suggère d'utiliser une plus grande puissance de 2 dans pad_to (128 ou 256).

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.