Meningkatkan resolusi spektrogram dengan Python?

21

Saya menggunakan specgram()fungsi dalam matplotlibuntuk menghasilkan spektogram file gelombang suara dalam Python, tetapi hasilnya selalu dengan kualitas yang jauh lebih rendah daripada yang dapat dihasilkan oleh perangkat lunak transkripsi normal saya, Praat. Misalnya, panggilan berikut:

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

Buat ini:

masukkan deskripsi gambar di sini

Saat Praat, mengerjakan sampel audio yang sama dengan pengaturan berikut:

  • Rentang tampilan: 0-8000Hz
  • Panjang jendela: 0,005s
  • Rentang dinamis: 70dB
  • Langkah waktu: 1000
  • Langkah frekuensi: 250
  • Bentuk jendela: Gaussian

Buat ini:

masukkan deskripsi gambar di sini

Apa yang saya lakukan salah? Saya sudah mencoba mengutak-atik semua specgram()parameter, tetapi sepertinya tidak ada yang memperbaiki resolusi. Saya hampir tidak memiliki pengalaman dengan FFT.

Badai Alek
sumber
Bisakah Anda memberikan contoh konfigurasi parameter matplotlib.specgram yang telah Anda coba? Anda memberikan contoh parameter untuk Praat yang sangat spesifik tetapi tidak menunjukkan konfigurasi yang sama untuk matplotlib.specgram?
Christopher Felton

Jawaban:

11

Berikut adalah parameter 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)

Parameter yang disediakan dalam deskripsi pertanyaan perlu dikonversi ke parameter mpl.specgram yang sebanding. Berikut ini adalah contoh pemetaan:

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

Jika Anda menggunakan 8ms Anda akan mendapatkan kekuatan 2 FFT (128). Berikut ini adalah deskripsi pengaturan Praat dari situs web mereka

Lihat rentang (Hz) : rentang frekuensi untuk ditampilkan. Standarnya adalah 0 Hz di bagian bawah dan 5000 Hz di atas. Jika frekuensi maksimum ini lebih tinggi dari frekuensi Nyquist of the Sound (yang merupakan setengah dari frekuensi pengambilan sampelnya), beberapa nilai dalam spektrogram akan menjadi nol, dan frekuensi yang lebih tinggi akan digambarkan dalam warna putih. Anda dapat melihat ini jika Anda merekam Suara pada 44100 Hz dan mengatur rentang tampilan dari 0 Hz hingga 25000 Hz.

Panjang jendela : durasi jendela analisis. Jika ini adalah 0,005 detik (standar), Praat menggunakan untuk setiap frame bagian dari suara yang terletak antara 0,0025 detik sebelum dan 0,0025 detik setelah pusat frame itu (untuk jendela Gaussian, Praat sebenarnya menggunakan sedikit lebih dari itu). Panjang jendela menentukan bandwidth analisis spektral, yaitu lebar garis horizontal dalam spektrogram gelombang sinus murni (lihat di bawah). Untuk jendela Gaussian, lebar pita -3 dB adalah 2 * sqrt (6 * ln (2)) / (π * Panjang jendela), atau 1.2982804 / Panjang jendela. Untuk mendapatkan broad-band' spectrogram (bandwidth 260 Hz), keep the standard window length of 5 ms; to get aspektrogram pita-sempit (bandwidth 43 Hz), atur ke 30 ms (0,03 detik). Bentuk jendela lainnya memberikan nilai yang sedikit berbeda.

Rentang dinamis (dB) : Semua nilai yang lebih dari rentang Dinamis dB di bawah maksimum (mungkin setelah kompresi dinamis, lihat Pengaturan spektrogram lanjutan ...) akan digambar putih. Nilai di antara keduanya memiliki nuansa abu-abu yang sesuai. Dengan demikian, jika puncak tertinggi dalam spektrogram memiliki ketinggian 30 dB / Hz, dan rentang dinamis adalah 50 dB (yang merupakan nilai standar), maka nilai di bawah -20 dB / Hz akan ditarik dalam warna putih, dan nilai-nilai antara -20 dB / Hz dan 30 dB / Hz akan ditarik dalam berbagai nuansa abu-abu.

Tautan ke pengaturan Praat

Pertanyaan OP mungkin mengenai perbedaan kontras antara specgram Praat dan mpl (matplotlib). Praat memiliki pengaturan Rentang Dinamis yang memengaruhi kontras. Fungsi mpl tidak memiliki pengaturan / parameter yang serupa. Mpl.specgram mengembalikan array tingkat daya 2D (spektrogram) yang rentang dinamis dapat diterapkan ke array kembali dan diplot ulang.

Berikut ini adalah cuplikan kode untuk membuat plot di bawah ini. Contohnya adalah ~ 1m15s pidato dengan kicauan dari 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
sumber
1
Memikirkan hal ini sedikit lagi, parameter "Dynamic Range" Praat mungkin menjadi faktor utama untuk perbedaan dalam bagaimana plot terlihat. Praat "Dynamic Range" mungkin membatasi rentang (kompresi) sehingga Anda mendapatkan kontras yang lebih besar dalam plot. BOMK MPL tidak memiliki fitur serupa tetapi satu dapat ditambahkan.
Christopher Felton
6

Tampaknya menjadi masalah resolusi waktu / frekuensi. Plot Praat Anda memiliki resolusi frekuensi yang lebih buruk (Anda bahkan tidak dapat melihat dengan jelas harmonik) dan resolusi waktu yang lebih baik. Coba kurangi ukuran jendela (NFFT) menjadi 16000 x 0,05 = 80 sampel. Saya sarankan menggunakan kekuatan 2 yang lebih besar di pad_to (128 atau 256).

pichenettes
sumber