Verbessern Sie die Auflösung von Spektrogrammen in Python?


21

Ich benutze die specgram()Funktion in matplotlib, um Spektrogramme von Sprachwellendateien in Python zu generieren, aber die Ausgabe ist immer von erheblich schlechterer Qualität als die, die meine normale Transkriptionssoftware Praat generieren kann. Zum Beispiel der folgende Aufruf:

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

Erzeugt dies:

Bildbeschreibung hier eingeben

Während Praat an demselben Audiobeispiel mit den folgenden Einstellungen arbeitet:

  • Sichtbereich: 0-8000Hz
  • Fensterlänge: 0,005s
  • Dynamikbereich: 70dB
  • Zeitschritte: 1000
  • Frequenzschritte: 250
  • Fensterform: Gauß

Erzeugt dies:

Bildbeschreibung hier eingeben

Was mache ich falsch? Ich habe versucht, mit allen specgram()Parametern zu experimentieren, aber nichts scheint die Auflösung zu verbessern. Ich habe praktisch keine Erfahrung mit FFTs.


Können Sie das Beispiel für die Parameterkonfigurationen von matplotlib.specgram angeben, die Sie ausprobiert haben? Sie geben ein sehr spezifisches Beispiel für die Parameter von Praat, zeigen aber nicht die gleiche Konfiguration für matplotlib.specgram an?
Christopher Felton

Antworten:


11

Hier sind die matplotlib.specgram-Parameter

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)

Die in der Fragenbeschreibung angegebenen Parameter müssen in vergleichbare mpl.specgram-Parameter konvertiert werden. Das Folgende ist ein Beispiel für die Zuordnung:

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

Wenn Sie 8 ms verwenden, erhalten Sie eine Potenz von 2 FFT (128). Das Folgende ist die Beschreibung der Praat-Einstellungen von ihrer Website

Anzeigebereich (Hz) : Der Bereich der anzuzeigenden Frequenzen. Der Standard ist 0 Hz unten und 5000 Hz oben. Wenn diese maximale Frequenz höher ist als die Nyquist-Frequenz des Klangs (die Hälfte seiner Abtastfrequenz), sind einige Werte im Spektrogramm Null, und die höheren Frequenzen werden in Weiß gezeichnet. Sie können dies sehen, wenn Sie einen Ton mit 44100 Hz aufnehmen und den Anzeigebereich von 0 Hz bis 25000 Hz einstellen.

Fensterlänge : Die Dauer des Analysefensters. Wenn dies 0,005 Sekunden (der Standard) ist, verwendet Praat für jedes Bild den Teil des Klangs, der zwischen 0,0025 Sekunden vor und 0,0025 Sekunden nach der Mitte dieses Bilds liegt (für Gaußsche Fenster verwendet Praat tatsächlich etwas mehr als das). Die Fensterlänge bestimmt die Bandbreite der Spektralanalyse, dh die Breite der horizontalen Linie im Spektrogramm einer reinen Sinuswelle (siehe unten). Für ein Gauß-Fenster beträgt die -3 dB-Bandbreite 2 * sqrt (6 * ln (2)) / (π * Fensterlänge) oder 1,2982804 / Fensterlänge. Um ein broad-band' spectrogram (bandwidth 260 Hz), keep the standard window length of 5 ms; to get aschmalbandiges Spektrogramm (Bandbreite 43 Hz) zu erhalten, stellen Sie es auf 30 ms (0,03 Sekunden) ein. Die anderen Fensterformen ergeben geringfügig andere Werte.

Dynamikbereich (dB) : Alle Werte, die über dem Dynamikbereich (dB) liegen, der unter dem Maximum liegt (möglicherweise nach dynamischer Komprimierung, siehe Erweiterte Spektrogrammeinstellungen ...), werden weiß dargestellt. Werte dazwischen haben geeignete Graustufen. Wenn der höchste Peak im Spektrogramm eine Höhe von 30 dB / Hz hat und der Dynamikbereich 50 dB (dies ist der Standardwert) beträgt, werden Werte unter -20 dB / Hz in Weiß und Werte zwischen diesen Werten gezeichnet -20 dB / Hz und 30 dB / Hz werden in verschiedenen Graustufen gezeichnet.

Link zu den Praat-Einstellungen

Die Frage des OP könnte sich auf den Kontrastunterschied zwischen dem Praat-Specgramm und dem MPL-Specgramm (Matplotlib) beziehen. Praat hat eine Dynamic Range- Einstellung, die den Kontrast beeinflusst. Die MPL-Funktion hat keine ähnliche Einstellung / Parameter. Das mpl.specgram gibt das 2D-Array von Leistungspegeln (das Spektrogramm) zurück, mit dem der Dynamikbereich auf das Return-Array angewendet und neu gezeichnet werden kann.

Das Folgende ist ein Codeausschnitt, um die folgenden Darstellungen zu erstellen. Das Beispiel ist ~ 1m15s Sprache mit einem Chirp von 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
Wenn Sie etwas genauer darüber nachdenken, ist der Praat-Parameter "Dynamic Range" möglicherweise der Hauptfaktor für die unterschiedliche Darstellung der Diagramme. Der Praat "Dynamic Range" kann den Bereich einschränken (Komprimieren), so dass Sie einen größeren Kontrast im Plot erhalten. BOMK MPL hat keine ähnliche Funktion, aber eine könnte hinzugefügt werden.
Christopher Felton

6

Es scheint ein Problem mit der Zeit- / Frequenzauflösung zu sein. Ihr Praat-Plot hat eine schlechtere Frequenzauflösung (Sie können die Harmonischen nicht einmal klar erkennen) und eine bessere Zeitauflösung. Versuchen Sie, die Fenstergröße (NFFT) auf 16000 x 0,05 = 80 Samples zu reduzieren. Ich würde vorschlagen, eine größere Potenz von 2 in pad_to (128 oder 256) zu verwenden.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.