绘制整个语音的短时能量和一帧的短时能量对比

it2024-08-06  40

绘制整个语音的短时能量和一帧的短时能量对比

import numpy as np import wave import matplotlib.pyplot as plt wlen = 512 inc = 128 f = wave.open('./data/orange/orange06.wav', 'rb') params = f.getparams() nchannels, sampwidth, framerate, nframes = params[:4] str_data = f.readframes(nframes) wave_data = np.fromstring(str_data, dtype=np.short) wave_data = wave_data * 1.0 / (max(abs(wave_data))) time = np.arange(0,wlen) * (1.0 / framerate) signal_length = len(wave_data) if signal_length<=wlen: nf = 1 else: nf = int(np.ceil((1.0 * signal_length - wlen + inc) / inc)) # 所有帧加起来总的铺平后的长度 pad_length = int((nf - 1) * inc + wlen) # 不够的长度使用0填补,类似于FFT中的扩充数组操作 zeros = np.zeros((pad_length - signal_length,)) # 填补后的信号记为pad_signal pad_signal = np.concatenate((wave_data, zeros)) # 相当于对所有帧的时间点进行抽取,得到nf*nw长度的矩阵 indices = np.tile(np.arange(0, wlen), (nf, 1)) + np.tile(np.arange(0, nf * inc, inc), (wlen, 1)).T # 将indices转化为矩阵 indices = np.array(indices, dtype=np.int32) # 得到帧信号 frames = pad_signal[indices] # 读取第30-31这一帧 a=frames[30:31] # 一帧短时能量的x轴配置 time_0 = np.arange(0, wlen) * (1.0 / framerate) # 整个语音段的短时能量x轴配置 time_all = np.arange(0, nf) * (inc * 1.0 /framerate) # 添加汉明窗 windown = np.hanning(512) d = np.zeros(nf) x = np.zeros(nf) # 绘制整个语音段的短时能量 for i in range(0, nf): a = frames[i:i+1] b = a[0] * windown c = np.square(b) d[i] = np.sum(c) d = d*1.0/max(abs(d)) # 一帧的短时能量 k = a[0]*windown m = np.square(k) # All short-time energy plt.figure(figsize=(10, 4)) plt.subplot(3, 1, 1) plt.plot(time_all, d, c="g") plt.xlabel('All short-time energy') plt.grid() # Frame short-time energy plt.subplot(3, 1, 3) plt.plot(time_0, m, c='b') plt.xlabel('Frame short-time energy') plt.grid() # show plt.show()

​ 发音为apple的短时能量图

短时平均过零率

短时平均过零率-表示一帧语音中语音信号波形穿过横轴(零电平)的次数。对于连续语音信号,过零意味着时域波形通过时间轴,对于离散信号,如果相邻的取样值改变符号,则称为过零。短时平均过零率就是样本数值改变符号的次数。

浊音具有较低的过零率,而清音具有较高的过零率。在背景噪声较小时,用平均能量识别较为有效;在背景噪声较大时,用短时平均过零率较为有效。

主要应用短时平均过零率来判断清音和浊音,有话段和无话段。

# 绘制过零率 c_zero = np.zeros(nf) for i in range(nf): a_zero = frames[i:i+1] b_zero = windown * a_zero[0] for j in range(wlen-1): if b_zero[j] * b_zero[j+1] < 0: c_zero[i] = c_zero[i] + 1 time = np.arange(0,nf) * (inc*1.0/framerate) plt.figure(figsize=(10,4)) plt.plot(time,c,c="g") plt.grid() plt.show()

时域和频域的转换

短时傅里叶分析适用于分析缓慢时变信号的频谱分析。先将语音信号分帧,再将各帧进行傅里叶变换,每一帧语音信号可以被认为是从各个不同的平稳信号波形中截取出来的,各帧语音的短时频谱就是各个平稳信号波形频谱的近似。

而语音信号是短时平稳的,因此可以对语音信号进行分帧处理。

"""频域处理,时域转换为频域""" import numpy as np import wave import matplotlib.pyplot as plt wlen = 512 inc = 128 f = wave.open('./data/apple/apple02.wav', 'rb') params = f.getparams() nchannels, samwidth, framerate, nframes = params[:4] str_data = f.readframes(nframes) wave_data = np.fromstring(str_data, dtype=np.short) wave_data = wave_data * 1.0 / (max(abs(wave_data))) # 信号总长度 signal_length = len(wave_data) if signal_length<=wlen: nf = 1 else: nf = int(np.ceil((1.0*signal_length-wlen+inc)/inc)) # 所有帧加起来的总长度 pad_length = int((nf-1)*inc+wlen) # 0 填充 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 indices = np.array(indices, dtype=np.int32) frames = pad_signal[indices] windown = np.hanning(wlen) a = frames[20:21] b = a[0] * windown # 短时傅里叶变换 fft_signal_short = np.fft.fft(b) # 取变换的模 fft_signal_short = abs(fft_signal_short) # 傅里叶变换 fft_signal = np.fft.fft(wave_data) # 取变换的模 fft_signal = abs(fft_signal) plt.figure(figsize=(10, 4)) time = np.arange(0, nframes) * framerate / nframes time_short = np.arange(0, wlen) * framerate / nframes plt.subplot(3, 1, 1) plt.plot(time, fft_signal, c='b') plt.xlabel('FFT') plt.grid() plt.subplot(3, 1, 3) plt.plot(time_short, fft_signal_short, c='g') plt.xlabel('STFT') plt.grid() plt.show()

语谱图

plt.specgram(wave_data,Fs = framerate, scale_by_freq = True, sides = 'default')

语谱图的横坐标是时间,纵坐标是频率,坐标点值为语音数据能量。由于是采用二维平面表达三维信息,所以能量值的大小是通过颜色来表示,颜色深表示该点的语音能量强。

最新回复(0)