Migliorare la risoluzione dello spettrogramma in Python?


21

Sto usando la specgram()funzione matplotlibper generare spettrogrammi di file di onde vocali in Python, ma l'output è sempre di qualità notevolmente inferiore a ciò che il mio normale software di trascrizione, Praat, può generare. Ad esempio, la seguente chiamata:

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

Genera questo:

inserisci qui la descrizione dell'immagine

Mentre Praat, lavorando sullo stesso campione audio con le seguenti impostazioni:

  • Visualizza intervallo: 0-8000Hz
  • Lunghezza della finestra: 0,005 s
  • Gamma dinamica: 70 dB
  • Fasi temporali: 1000
  • Passaggi di frequenza: 250
  • Forma della finestra: gaussiana

Genera questo:

inserisci qui la descrizione dell'immagine

Che cosa sto facendo di sbagliato? Ho provato a giocherellare con tutti i specgram()parametri, ma nulla sembra migliorare la risoluzione. Non ho praticamente alcuna esperienza con le FFT.


Potresti fornire l'esempio delle configurazioni dei parametri matplotlib.specgram che hai provato? Dai un esempio molto specifico dei parametri per Praat ma non mostri la stessa configurazione per matplotlib.specgram?
Christopher Felton,

Risposte:


11

Ecco i parametri 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)

I parametri forniti nella descrizione della domanda devono essere convertiti in parametri mpl.specgram comparabili. Di seguito è riportato un esempio del mapping:

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

Se usi 8ms otterrai una potenza di 2 FFT (128). La seguente è la descrizione delle impostazioni di Praat dal loro sito Web

Visualizza intervallo (Hz) : l'intervallo di frequenze da visualizzare. Lo standard è 0 Hz nella parte inferiore e 5000 Hz nella parte superiore. Se questa frequenza massima è superiore alla frequenza di Nyquist del suono (che è metà della sua frequenza di campionamento), alcuni valori nello spettrogramma saranno zero e le frequenze più alte saranno disegnate in bianco. Puoi vederlo se registri un suono a 44100 Hz e imposti l'intervallo di visualizzazione da 0 Hz a 25000 Hz.

Lunghezza finestra : la durata della finestra di analisi. Se questo è 0,005 secondi (lo standard), Praat usa per ogni fotogramma la parte del suono che si trova tra 0,0025 secondi prima e 0,0025 secondi dopo il centro di quel fotogramma (per le finestre gaussiane, Praat ne utilizza effettivamente un po 'di più). La lunghezza della finestra determina la larghezza di banda dell'analisi spettrale, ovvero la larghezza della linea orizzontale nello spettrogramma di un'onda sinusoidale pura (vedi sotto). Per una finestra gaussiana, la larghezza di banda di -3 dB è 2 * sqrt (6 * ln (2)) / (π * Lunghezza finestra) o 1.2982804 / Lunghezza finestra. Per ottenere uno broad-band' spectrogram (bandwidth 260 Hz), keep the standard window length of 5 ms; to get aspettrogramma a banda stretta (larghezza di banda 43 Hz), impostarlo su 30 ms (0,03 secondi). Le altre forme della finestra danno valori leggermente diversi.

Intervallo dinamico (dB) : tutti i valori che superano l'intervallo dinamico dB al di sotto del massimo (forse dopo la compressione dinamica, vedere Impostazioni avanzate dello spettrogramma ...) verranno disegnati in bianco. I valori intermedi hanno sfumature di grigio appropriate. Pertanto, se il picco più alto nello spettrogramma ha un'altezza di 30 dB / Hz e l'intervallo dinamico è 50 dB (che è il valore standard), i valori inferiori a -20 dB / Hz verranno disegnati in bianco e i valori tra -20 dB / Hz e 30 dB / Hz verranno disegnati in varie tonalità di grigio.

Collegamento alle impostazioni Praat

La domanda del PO potrebbe riguardare la differenza di contrasto tra lo schema Praat e lo schema mpl (matplotlib). Praat ha un'impostazione di gamma dinamica che influenza il contrasto. La funzione mpl non ha impostazioni / parametri simili. Il mpl.specgram restituisce l'array 2D di livelli di potenza (lo spettrogramma) che l'intervallo dinamico può essere applicato all'array di ritorno e riprogrammato.

Di seguito è riportato un frammento di codice per creare i grafici seguenti. L'esempio è un discorso di ~ 1m15 con un cinguettio da 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
Pensando a questo un po 'di più, il parametro Praat "Dynamic Range" potrebbe essere il fattore principale per la differenza nell'aspetto dei grafici. La "gamma dinamica" di Praat potrebbe limitare la portata (compressione) in modo da ottenere un maggiore contrasto nella trama. BOMK MPL non ha una funzione simile ma è possibile aggiungerne una.
Christopher Felton,

6

Sembra essere un problema di risoluzione tempo / frequenza. La trama di Praat ha una risoluzione di frequenza peggiore (non puoi nemmeno vedere chiaramente le armoniche) e una migliore risoluzione temporale. Prova a ridurre la dimensione della finestra (NFFT) a 16000 x 0,05 = 80 campioni. Suggerirei di usare una potenza maggiore di 2 in pad_to (128 o 256).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.