数字语音处理 短时过零率 短时能量 短时幅度 Python代码实现 可视化

选题自(数字语音处理理论及应用)

·窗函数选用 hamming 窗
原因:由于语音信号的非平稳特性,使用加窗可以对语音信号分帧当成平稳信号来分析和处理。
①由于直接对信号(加矩形窗)会产生频谱泄露,为了改善频谱泄露的情况,选用 hamming 窗或者 hanning 窗,它们都是升余弦窗,幅频特性是旁瓣衰减较大,使得主瓣加宽并降低,旁瓣显著减小,减小泄漏;但对比 hanning 窗,hamming窗的加权系数不同,它使得旁瓣宽度更小。
②在加 hamming 窗后,中间的数据体现出来了,两边的数据信息丢失了,在窗移的过程中,被前一帧或二帧丢失的数据又重新得到了体现。
·窗长选择 480;窗移选择 120
原因:首先在 Adobe Audition CC 上观察 s5.wav 的部分浊音波形,如图所示:
数字语音处理 短时过零率 短时能量 短时幅度 Python代码实现 可视化

可以看出来浊音部分一个基音周期大概为 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()

运行结果图如下
数字语音处理 短时过零率 短时能量 短时幅度 Python代码实现 可视化
分析:
①由绘制的语音信号波形中大致可以看出浊音(具有一定的周期性),和清音部分。
②在图中可以看出浊音片段的短时过零次数要比清音片段的高出很多,在这个片段中,应该是存在噪声的,而且清音的过零情况大致和噪声的过零情况差不太多,无法直接区分。
③短时能量主要用于区分浊音段和清音段,浊音时能量比清音时大得多,这一点可以从图 2 中观察得出,短时能量还可以区分无话段与有话段。
④短时能量是信号绝对值的平方和,短时幅度是使用了信号绝对值的加权和,解决了较大级别的信号能量值敏感的问题(能量有平方项),在图中,对比短时能量和短时幅度,在清音的部分差别很明显,但浊音区域和清音区域间的级别差异不如短时能量时明显。

上一篇:WIFI、蓝牙、射频、Zigbee 浅谈智能家居的几种控制协议


下一篇:AF(操作者框架)系列(4)-基于重写Actor Core实现的用户界面