python語音信號處理詳細(xì)教程
1.語音信號的產(chǎn)生與特性
我們要對語音進(jìn)行分析,首先要提取能夠表示該語音的特征參數(shù),有了特征參數(shù)才可能利用這些參數(shù)進(jìn)行有效的處理,在對語音信號處理的過程中,語音信號的質(zhì)量不僅取決于處理方法,同時取決于時候選對了合適的特征參數(shù)。
語音信號是一個非平穩(wěn)的時變信號,但語音信號是由聲門的激勵脈沖通過聲道形成的,而聲道(人的口腔、鼻腔)的肌肉運動是緩慢的,所以“短時間”(10~30ms)內(nèi)可以認(rèn)為語音信號是平穩(wěn)時不變的。由此構(gòu)成了語音信號的“短時分析技術(shù)”。
提取的不同的語音特征參數(shù)對應(yīng)著不同的語音信號分析方法:時域分析、頻域分析、倒譜域分析…由于語音信號最重要的感知特性反映在功率譜上,而相位變化只起到很小的作用,所有語音頻域分析更加重要。
2.語音的讀取
本實驗使用wave庫,實現(xiàn)語音文件的讀取、波形圖繪制,相關(guān)的庫還有librosa、scipy等
import wave #調(diào)用wave模塊 import matplotlib.pyplot as plt #調(diào)用matplotlib.pyplot模塊作為Plt import numpy as np #調(diào)用numpy模塊記作np import scipy.signal as signal import pyaudio %matplotlib inline plt.rcParams['font.sans-serif'] = ['SimHei'] # 用來正常顯示中文標(biāo)簽 plt.rcParams['axes.unicode_minus'] = False # 用來正常顯示符號 f = wave.open(r"C:\Users\zyf\Desktop\Jupyter\1.wav", "rb")#讀取語音文件 params = f.getparams() #返回音頻參數(shù) nchannels, sampwidth, framerate, nframes = params[:4] #賦值聲道數(shù),量化位數(shù),采樣頻率,采樣點數(shù) print(nchannels,sampwidth,framerate,nframes)# 輸出聲道數(shù),量化位數(shù),采樣頻率,采樣點數(shù) str_data = f.readframes(nframes) # 讀取nframes個數(shù)據(jù),返回字符串格式 f.close() wave_data = np.frombuffer(str_data, dtype=np.short) # 將字符串轉(zhuǎn)換為數(shù)組,得到一維的short類型的數(shù)組 wave_data = wave_data * 1.0 / (max(abs(wave_data))) # 賦值的歸一化 time = np.arange(0, nframes) * (1.0 / framerate) # 最后通過采樣點數(shù)和取樣頻率計算出每個取樣的時間 # 整合左聲道和右聲道的數(shù)據(jù),如果語音為雙通道語音,具體代碼需做調(diào)整 #wave_data = np.reshape(wave_data, [nframes, nchannels]) # wave_data.shape = (-1, 2) # -1的意思就是沒有指定,根據(jù)另一個維度的數(shù)量進(jìn)行分割 plt.figure() # 單通道語音波形圖 plt.plot(time, wave_data[:]) plt.xlabel("時間/s",fontsize=14) plt.ylabel("幅度",fontsize=14) plt.title("波形圖",fontsize=14) plt.grid() # 標(biāo)尺 plt.tight_layout() # 緊密布局 plt.show()
3.語音的播放
# 音頻的播放,本實驗使用pyaudio(代碼相對matlab較麻煩,后期簡化) import pyaudio import wave chunk = 1024 wf = wave.open(r"C:\Users\zyf\Desktop\Jupyter\1.wav", 'rb') p = pyaudio.PyAudio() # 打開聲音輸出流 stream = p.open(format = p.get_format_from_width(wf.getsampwidth()), channels = wf.getnchannels(), rate = wf.getframerate(), output = True) # 寫聲音輸出流到聲卡進(jìn)行播放 while True: data = wf.readframes(chunk) if data == "": break stream.write(data) stream.stop_stream() stream.close() p.terminate() # 關(guān)閉PyAudio
4.音頻文件的寫入
# 音頻文件的寫入、存儲 # 使用wave庫,相關(guān)的庫還有l(wèi)ibrosa、scipy等,讀寫操作上的差異參閱博客: https://blog.csdn.net/weixin_38346042/article/details/119906391 import wave import numpy as np import scipy.signal as signal framerate = 44100 # 采樣頻率 time = 10 # 持續(xù)時間 t = np.arange(0, time, 1.0/framerate) # 調(diào)用scipy.signal庫中的chrip函數(shù), # 產(chǎn)生長度為10秒、取樣頻率為44.1kHz、100Hz到1kHz的頻率掃描波 wave_data = signal.chirp(t, 100, time, 1000, method='linear') * 10000 # 由于chrip函數(shù)返回的數(shù)組為float64型, # 需要調(diào)用數(shù)組的astype方法將其轉(zhuǎn)換為short型。 wave_data = wave_data.astype(np.short) # 打開WAV音頻用來寫操作 f = wave.open(r"sweep.wav", "wb") f.setnchannels(1) # 配置聲道數(shù) f.setsampwidth(2) # 配置量化位數(shù) f.setframerate(framerate) # 配置取樣頻率 comptype = "NONE" compname = "not compressed" # 也可以用setparams一次性配置所有參數(shù) # outwave.setparams((1, 2, framerate, nframes,comptype, compname)) # 將wav_data轉(zhuǎn)換為二進(jìn)制數(shù)據(jù)寫入文件 f.writeframes(wave_data.tobytes()) f.close()
5.語音的分幀加窗
5.1 分幀
語音數(shù)據(jù)和視頻數(shù)據(jù)不同,本沒有幀的概念,但是為了傳輸與存儲,我們采集的音頻數(shù)據(jù)都是一段一段的。為了程序能夠進(jìn)行批量處理,會根據(jù)指定的長度(時間段或者采樣數(shù))進(jìn)行分段,結(jié)構(gòu)化為我們編程的數(shù)據(jù)結(jié)構(gòu),這就是分幀。語音信號在宏觀上是不平穩(wěn)的,在微觀上是平穩(wěn)的,具有短時平穩(wěn)性(10—30ms內(nèi)可以認(rèn)為語音信號近似不變),這個就可以把語音信號分為一些短段來進(jìn)行處理,每一個短段稱為一幀(CHUNK)。
5.2 幀移
由于我們常用的信號處理方法都要求信號是連續(xù)的,也就說必須是信號開始到結(jié)束,中間不能有斷開。然而我們進(jìn)行采樣或者分幀后數(shù)據(jù)都斷開了,所以要在幀與幀之間保留重疊部分?jǐn)?shù)據(jù),以滿足連續(xù)的要求,這部分重疊數(shù)據(jù)就是幀移。
幀長=重疊+幀移
5.3 加窗
我們處理信號的方法都要求信號是連續(xù)條件,但是分幀處理的時候中間斷開了,為了滿足條件我們就將分好的幀數(shù)據(jù)乘一段同長度的數(shù)據(jù),這段數(shù)據(jù)就是窗函數(shù)整個周期內(nèi)的數(shù)據(jù),從最小變化到最大,然后最小。
常用的窗函數(shù):矩形窗、漢明窗、海寧窗
加窗即與一個窗函數(shù)相乘,加窗之后是為了進(jìn)行傅里葉展開.
1.使全局更加連續(xù),避免出現(xiàn)吉布斯效應(yīng)
2.加窗時候,原本沒有周期性的語音信號呈現(xiàn)出周期函數(shù)的部分特征。
加窗的代價是一幀信號的兩端部分被削弱了,所以在分幀的時候,幀與幀之間需要有重疊。
# 加窗分幀(接上) # 語音分幀、加窗 wlen=512 # 每幀信號長度 inc=128 # 幀移 signal_length=len(wave_data) #信號總長度 print(signal_length) if signal_length<=wlen: #若信號長度小于一個幀的長度,則幀數(shù)定義為1 nf=1 else: #否則,計算幀的總長度 nf=int(np.ceil((1.0*signal_length-wlen+inc)/inc)) # nf 為幀數(shù) # np.ceil向上取整,所以會導(dǎo)致實際分幀后的長度大于信號本身的長度,所以要對原來的信號進(jìn)行補(bǔ)零 pad_length=int((nf-1)*inc+wlen) #所有幀加起來總的鋪平后的長度 zeros=np.zeros((pad_length-signal_length,)) #不夠的長度使用0填補(bǔ),類似于FFT中的擴(kuò)充數(shù)組操作 pad_signal=np.concatenate((wave_data,zeros)) #填補(bǔ)后的信號記為pad_signal indices=np.tile(np.arange(0,wlen),(nf,1))+np.tile(np.arange(0,nf*inc,inc),(wlen,1)).T #相當(dāng)于對所有幀的時間點進(jìn)行抽取,得到nf*wlen長度的矩陣 indices=np.array(indices,dtype=np.int32) #將indices轉(zhuǎn)化為矩陣 frames=pad_signal[indices] #得到幀信號,587*512的矩陣信號 #a=frames[30:31] #print(frames.shape) winfunc = signal.hamming(wlen) # 調(diào)用窗函數(shù),本初以漢明窗為例 #print(winfunc.shape) win=np.tile(winfunc,(nf,1)) #窗函數(shù)為一維數(shù)組(512,),因此需要按照信號幀數(shù)進(jìn)行變換得到(587*512)矩陣信號 #print(win.shape) my = frames*win # 這里的*指的是計算矩陣的數(shù)量積(即對位相乘)。 # python中矩陣運算分為兩種形式,一是np.array,而是np.matrix # ---------------------------------- # 繪制分幀加窗后的圖像(接上) # 因為分幀加窗后的信號為587*512的矩陣信號,為了繪圖,將其轉(zhuǎn)換為一維信號 t=my.flatten() t=t.T print(t.shape) time = np.arange(0, len(t)) * (1.0 / framerate) # 調(diào)整時間軸 plt.figure() plt.plot(time,t,c="g") plt.grid() plt.show()
6.語音的頻譜分析
6.1 頻譜圖
通過FFT對時域語音信號進(jìn)行處理,得到頻譜圖
import numpy as np from scipy.io import wavfile import matplotlib.pyplot as plt %matplotlib inline sampling_freq, audio = wavfile.read(r"C:\Users\zyf\Desktop\Jupyter\1.wav") # 讀取文件 audio = audio / np.max(audio) # 歸一化,標(biāo)準(zhǔn)化 # 應(yīng)用傅里葉變換 fft_signal = np.fft.fft(audio) print(fft_signal) fft_signal = abs(fft_signal) print(fft_signal) # 建立時間軸 Freq = np.arange(0, len(fft_signal)) # 繪制語音信號的 plt.figure() plt.plot(Freq, fft_signal, color='blue') plt.xlabel('Freq (in kHz)') plt.ylabel('Amplitude') plt.show()
6.2 語譜圖
語譜圖綜合了時域和頻域的特點,明顯的顯示出來了語音頻率隨時間的變化情況**,語譜圖的橫軸為時間,縱軸為頻率任意給定頻率成分在給定時刻的強(qiáng)弱用顏色深淺表示。**顏色深表示頻譜值大,顏色淺表示頻譜值小,譜圖上不同的黑白程度形成不同的紋路,稱為聲紋,不用講話者的聲紋是不一樣的,可以用做聲紋識別。
import wave import matplotlib.pyplot as plt import numpy as np f = wave.open(r"C:\Users\zyf\Desktop\Jupyter\1.wav", "rb") params = f.getparams() nchannels, sampwidth, framerate, nframes = params[:4] strData = f.readframes(nframes)#讀取音頻,字符串格式 waveData = np.fromstring(strData,dtype=np.int16)#將字符串轉(zhuǎn)化為int waveData = waveData*1.0/(max(abs(waveData)))#wave幅值歸一化 waveData = np.reshape(waveData,[nframes,nchannels]).T f.close() plt.specgram(waveData[0],Fs = framerate, scale_by_freq = True, sides = 'default') plt.ylabel('Frequency(Hz)') plt.xlabel('Time(s)') plt.colorbar() plt.show()
參考博客:
- https://www.cnblogs.com/zhenmeili/p/14830176.html
- https://blog.csdn.net/sinat_18131557/article/details/105340416
- https://blog.csdn.net/weixin_38346042/article/details/119906391
- http://chabaoo.cn/article/126984.htm
總結(jié)
到此這篇關(guān)于python語音信號處理的文章就介紹到這了,更多相關(guān)python語音信號處理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python操作系統(tǒng)的6個自動化腳本小結(jié)
在Python中,實現(xiàn)操作系統(tǒng)自動化的腳本可以涵蓋從文件操作、系統(tǒng)監(jiān)控到網(wǎng)絡(luò)任務(wù)等多種功能,下面我將詳細(xì)介紹六個不同類別的Python自動化腳本示例,這些示例將幫助你理解如何用Python來自動化日常操作系統(tǒng)任務(wù),需要的朋友可以參考下2024-10-10Python使用numpy模塊實現(xiàn)矩陣和列表的連接操作方法
今天小編就為大家分享一篇Python使用numpy模塊實現(xiàn)矩陣和列表的連接操作方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-06-06tensorflow TFRecords文件的生成和讀取的方法
本篇文章主要介紹了tensorflow TFRecords文件的生成和讀取的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-02-02Pytorch數(shù)據(jù)類型Tensor張量操作的實現(xiàn)
本文主要介紹了Pytorch數(shù)據(jù)類型Tensor張量操作的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07Python數(shù)據(jù)結(jié)構(gòu)與算法中的棧詳解
這篇文章主要為大家詳細(xì)介紹了Python數(shù)據(jù)結(jié)構(gòu)與算法中的棧,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-03-03