การปรับปรุงความละเอียด spectrogram ใน Python?


21

ฉันใช้specgram()ฟังก์ชั่นในmatplotlibการสร้างไฟล์คลื่นเสียงพูดใน Python แต่ผลลัพธ์นั้นมีคุณภาพด้อยกว่าอย่างมากสำหรับซอฟท์แวร์ถอดรหัสปกติของฉัน Praat สามารถสร้างได้ ตัวอย่างเช่นสายต่อไปนี้:

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

สร้างสิ่งนี้:

ป้อนคำอธิบายรูปภาพที่นี่

ขณะที่ Praat ทำงานกับตัวอย่างเสียงเดียวกันด้วยการตั้งค่าต่อไปนี้:

  • ระยะการมอง: 0-8000Hz
  • ความยาวหน้าต่าง: 0.005 วินาที
  • ช่วงแบบไดนามิก: 70dB
  • ขั้นตอนเวลา: 1,000
  • ขั้นตอนความถี่: 250
  • รูปร่างหน้าต่าง: Gaussian

สร้างสิ่งนี้:

ป้อนคำอธิบายรูปภาพที่นี่

ผมทำอะไรผิดหรือเปล่า? ฉันได้ลองเล่นซอกับspecgram()พารามิเตอร์ทั้งหมดแต่ดูเหมือนว่าไม่มีอะไรที่จะปรับปรุงความละเอียด ฉันแทบไม่มีประสบการณ์กับ FFT


คุณสามารถให้ตัวอย่างของการกำหนดค่าพารามิเตอร์ matplotlib.specgram ที่คุณได้ลองไปแล้วได้หรือไม่? คุณให้ตัวอย่างที่เจาะจงมากของพารามิเตอร์สำหรับ Praat แต่ไม่แสดงการกำหนดค่าเดียวกันสำหรับ matplotlib.specgram?
Christopher Felton

คำตอบ:


11

นี่คือพารามิเตอร์ 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)

พารามิเตอร์ที่ให้ไว้ในคำอธิบายคำถามจำเป็นต้องแปลงเป็นพารามิเตอร์ mpl.specgram ที่เปรียบเทียบกันได้ ต่อไปนี้เป็นตัวอย่างของการแมป:

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

หากคุณใช้ 8ms คุณจะได้รับ 2 FFT (128) ต่อไปนี้เป็นคำอธิบายของการตั้งค่า Praat จากเว็บไซต์ของพวกเขา

มุมมอง (Hz) : ช่วงความถี่ที่จะแสดง มาตรฐานคือ 0 Hz ที่ด้านล่างและ 5,000 Hz ที่ด้านบน หากความถี่สูงสุดนี้สูงกว่าความถี่ Nyquist ของเสียง (ซึ่งเป็นครึ่งหนึ่งของความถี่การสุ่มตัวอย่าง) ค่าบางอย่างใน spectrogram จะเป็นศูนย์และความถี่ที่สูงขึ้นจะถูกวาดด้วยสีขาว คุณสามารถดูสิ่งนี้หากคุณบันทึกเสียงที่ 44100 Hz และตั้งค่าระยะการมองจาก 0 Hz ถึง 25000 Hz

ความยาวหน้าต่าง : ระยะเวลาของหน้าต่างการวิเคราะห์ หากนี่คือ 0.005 วินาที (มาตรฐาน), Praat ใช้สำหรับแต่ละเฟรมส่วนของเสียงที่อยู่ระหว่าง 0.0025 วินาทีก่อนและ 0.0025 วินาทีหลังจากกึ่งกลางของเฟรมนั้น (สำหรับหน้าต่าง Gaussian, Praat ใช้บิตมากกว่านั้นจริง) ความยาวหน้าต่างกำหนดแบนด์วิดท์ของการวิเคราะห์สเปกตรัมนั่นคือความกว้างของเส้นแนวนอนในสเปคโทรแกรมของคลื่นไซน์บริสุทธิ์ (ดูด้านล่าง) สำหรับหน้าต่างเกาส์แบนด์วิดท์ -3 dB คือ 2 * sqrt (6 * ln (2)) / (π * ความยาวหน้าต่าง) หรือ 1.2982804 / ความยาวหน้าต่าง ในการรับbroad-band' spectrogram (bandwidth 260 Hz), keep the standard window length of 5 ms; to get aสเปคโทรแกรมแคบ (แบนด์วิดธ์ 43 Hz) ให้ตั้งค่าเป็น 30 มิลลิวินาที (0.03 วินาที) รูปร่างหน้าต่างอื่นให้ค่าแตกต่างกันเล็กน้อย

ช่วงไดนามิก (dB) : ค่าทั้งหมดที่มีมากกว่าช่วงไดนามิก dB ต่ำกว่าค่าสูงสุด (อาจเป็นหลังจากการบีบอัดแบบไดนามิกดูการตั้งค่าสเปกตรัมขั้นสูง ... ) จะถูกวาดด้วยสีขาว ค่าในระหว่างนั้นมีเฉดสีเทาที่เหมาะสม ดังนั้นถ้าสูงสุดสูงสุดใน spectrogram มีความสูง 30 dB / Hz และช่วงแบบไดนามิกคือ 50 dB (ซึ่งเป็นค่ามาตรฐาน) แล้วค่าต่ำกว่า -20 dB / Hz จะถูกวาดในสีขาวและค่าระหว่าง -20 dB / Hz และ 30 dB / Hz จะวาดในเฉดสีเทาต่างๆ

เชื่อมโยงไปยังการตั้งค่า Praat

คำถามของ OP อาจเกี่ยวข้องกับความแตกต่างของความแตกต่างระหว่างโปรแกรม specatat และ mpl (matplotlib) Praat มีการตั้งค่าช่วงไดนามิกซึ่งมีผลต่อความคมชัด ฟังก์ชั่น mpl ไม่มีการตั้งค่า / พารามิเตอร์ที่คล้ายกัน mpl.specgram จะส่งกลับอาร์เรย์ 2 มิติของระดับพลังงาน (spectrogram) ช่วงไดนามิกสามารถนำไปใช้กับอาร์เรย์ส่งคืนและพล็อตใหม่ได้

ต่อไปนี้เป็นข้อมูลโค้ดเพื่อสร้างแปลงด้านล่าง ตัวอย่างคือการพูด ~ 1m15s ด้วยเสียงร้องเจี๊ยก ๆ จาก 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
เมื่อคิดเกี่ยวกับสิ่งนี้อีกเล็กน้อยพารามิเตอร์ Praat "Dynamic Range" อาจเป็นปัจจัยหลักสำหรับความแตกต่างในวิธีการแปลงดู Praat "Dynamic Range" อาจ จำกัด ช่วง (บีบอัด) เพื่อให้คุณได้คอนทราสต์ที่มากขึ้นในพล็อต BOMK MPL ไม่มีคุณสมบัติที่คล้ายกัน แต่สามารถเพิ่มได้
Christopher Felton

6

ดูเหมือนว่าจะเป็นปัญหาการแก้ไขปัญหาเวลา / ความถี่ พล็อต Praat ของคุณมีความละเอียดความถี่ที่แย่ลง (คุณไม่สามารถมองเห็นฮาร์โมนิกได้อย่างชัดเจน) และการแก้ไขเวลาที่ดีกว่า ลองลดขนาดหน้าต่าง (NFFT) เป็น 16000 x 0.05 = 80 ตัวอย่าง ฉันขอแนะนำให้ใช้กำลังที่ใหญ่กว่าเป็น 2 ใน pad_to (128 หรือ 256)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.