數字語音處理 短時過零率 短時能量 短時幅度 Python代碼實現 可視化

選題自(數字語音處理理論及應用)

·窗函數選用 hamming 窗
原因:由於語音信號的非平穩特性,使用加窗可以對語音信號分幀當成平穩信號來分析和處理。
①由於直接對信號(加矩形窗)會產生頻譜泄露,爲了改善頻譜泄露的情況,選用 hamming 窗或者 hanning 窗,它們都是升餘弦窗,幅頻特性是旁瓣衰減較大,使得主瓣加寬並降低,旁瓣顯著減小,減小泄漏;但對比 hanning 窗,hamming窗的加權係數不同,它使得旁瓣寬度更小。
②在加 hamming 窗後,中間的數據體現出來了,兩邊的數據信息丟失了,在窗移的過程中,被前一幀或二幀丟失的數據又重新得到了體現。
·窗長選擇 480;窗移選擇 120
原因:首先在 Adobe Audition CC 上觀察 s5.wav 的部分濁音波形,如圖所示:
在這裏插入圖片描述

可以看出來濁音部分一個基音週期大概爲 10ms 左右,因爲窗函數的長度與主瓣寬度成反比,並且會影響對信號進行 STFT 的頻率分辨率。在本次中,將 hamming 窗長設置爲 6 個基音週期的長度,也即是 60ms,如此分析可以更好地分辨出諧波分量,採樣率爲 8000Hz,所以窗長大小爲 0.06x8000=480,而窗口每次移動的步長一般爲窗長大小的 0.25 左右,所以窗移大小爲 0.25x480=120,此時重疊(overlap)爲 360。

代碼段

import numpy as np
import wave as we
import matplotlib.pyplot as plt
import scipy.io.wavfile as wf

path = 's5.wav'
wlen=480
inc=120
sample_rate, sigs = wf.read(path)
times = np.arange(len(sigs)) / sample_rate
f = we.open(r's5.wav', "rb")
params = f.getparams()
nchannels, sampwidth, framerate, nframes = params[:4]
print(params)
str_data = f.readframes(nframes)
wave_data = np.fromstring(str_data, dtype=np.short)
wave_data = wave_data*1.0/(max(abs(wave_data)))
#print(wave_data[:10])
signal_length=len(wave_data)
if signal_length<=wlen:
        nf=1
else:
        nf=int(np.ceil((1.0*signal_length-wlen+inc)/inc))
#print(nf)
pad_length=int((nf-1)*inc+wlen)
zeros=np.zeros((pad_length-signal_length,))
pad_signal=np.concatenate((wave_data,zeros))
indices=np.tile(np.arange(0,wlen),(nf,1))+np.tile(np.arange(0,nf*inc,inc),(wlen,1)).T
#print(indices[:2])
indices=np.array(indices,dtype=np.int32)
frames=pad_signal[indices]
windown=np.hamming(wlen)
d=np.zeros(nf)
x=np.zeros(nf)
c=np.zeros(nf)
e=np.zeros(nf)
for i in range(nf):
    a=frames[i:i+1]
    b=windown*a[0]
    for j in range(wlen-1):
        if b[j]*b[j+1]<0:
            c[i]=c[i]+1
time = np.arange(0,nf) * (inc*1.0/framerate)
for i in range(0,nf):
        a=frames[i:i+1]
        b = a[0] * windown
        e[i] =np.sum(abs(b))
        c1=np.square(b)
        d[i]=np.sum(c1)
e = e*1.0/(max(abs(e)))
d = d*1.0/(max(abs(d)))
#print(d)

#信號波形
plt.figure(figsize=(15,8))
plt.subplot(4,1,1)
plt.title('Time Domain')
plt.xlabel('Time')
plt.ylabel('Signal')
plt.tick_params(labelsize=10)
plt.grid(linestyle=':')
plt.plot(times, sigs, c='blue', label='Signal')
plt.legend(['audio'])

#短時過零率
plt.subplot(4,1,2)
plt.xlabel('Time')
plt.ylabel('zero-crossing number')
plt.plot(time,c,c='blue')
plt.grid(linestyle=':')
plt.legend(['Zero Crossing Rate'])

#短時能量
plt.subplot(4,1,3)
plt.xlabel('Time')
plt.ylabel('short-time energy')
plt.tick_params(labelsize=10)
plt.grid(linestyle=':')
plt.plot(time, d, c='blue')
plt.legend(['Energy'])

#短時幅度
plt.subplot(4,1,4)
plt.xlabel('Time')
plt.ylabel('short-time magnitude')
plt.tick_params(labelsize=10)
plt.grid(linestyle=':')
plt.plot(time, e, c='blue')
plt.legend(['Magnitude'])

plt.rcParams['savefig.dpi'] = 300 #圖片像素
plt.rcParams['figure.dpi'] = 300 #分辨率
plt.savefig('image.png')
plt.show()

運行結果圖如下
在這裏插入圖片描述
分析:
①由繪製的語音信號波形中大致可以看出濁音(具有一定的週期性),和清音部分。
②在圖中可以看出濁音片段的短時過零次數要比清音片段的高出很多,在這個片段中,應該是存在噪聲的,而且清音的過零情況大致和噪聲的過零情況差不太多,無法直接區分。
③短時能量主要用於區分濁音段和清音段,濁音時能量比清音時大得多,這一點可以從圖 2 中觀察得出,短時能量還可以區分無話段與有話段。
④短時能量是信號絕對值的平方和,短時幅度是使用了信號絕對值的加權和,解決了較大級別的信號能量值敏感的問題(能量有平方項),在圖中,對比短時能量和短時幅度,在清音的部分差別很明顯,但濁音區域和清音區域間的級別差異不如短時能量時明顯。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章