Python语音基础操作--3.1语音分帧与加窗

《语音信号处理试验教程》(梁瑞宇等)的代码主要是Matlab实现的,现在Python比较热门,所以把这个项目大部分内容写成了Python实现,大部分是手动写的。使用CSDN博客查看帮助文件:

Python语音基础操作–2.1语音录制,播放,读取
Python语音基础操作–2.2语音编辑
Python语音基础操作–2.3声强与响度
Python语音基础操作–2.4语音信号生成
Python语音基础操作–3.1语音分帧与加窗
Python语音基础操作–3.2短时时域分析
Python语音基础操作–3.3短时频域分析
Python语音基础操作–3.4倒谱分析与MFCC系数
Python语音基础操作–4.1语音端点检测
Python语音基础操作–4.2基音周期检测
Python语音基础操作–4.3共振峰估计
Python语音基础操作–5.1自适应滤波
Python语音基础操作–5.2谱减法
Python语音基础操作–5.4小波分解
Python语音基础操作–6.1PCM编码
Python语音基础操作–6.2LPC编码
Python语音基础操作–6.3ADPCM编码
Python语音基础操作–7.1帧合并
Python语音基础操作–7.2LPC的语音合成
Python语音基础操作–10.1基于动态时间规整(DTW)的孤立字语音识别试验
Python语音基础操作–10.2隐马尔科夫模型的孤立字识别
Python语音基础操作–11.1矢量量化(VQ)的说话人情感识别
Python语音基础操作–11.2基于GMM的说话人识别模型
Python语音基础操作–12.1基于KNN的情感识别
Python语音基础操作–12.2基于神经网络的情感识别
Python语音基础操作–12.3基于支持向量机SVM的语音情感识别
Python语音基础操作–12.4基于LDA,PCA的语音情感识别

代码可在Github上下载:busyyang/python_sound_open

一般来讲,语音信号的采样率是挺高的,而且认为语音信号在一定时间段的基本特性不会发生较大的变化,具有一定的短时平稳性。进行“短时分析”就行将信号分解成一段一段地来处理,每一段就叫一帧,大约10-30ms,也就是一秒钟大约33-100帧,对于通常10K的采样率来说,这样也能有一定的信息存在。分帧通常有一定的交叠部分,就是帧移。帧移与帧长的比通常为0~1/2。

分帧就是通过加窗函数实现的,假设原始信号为 s ( n ) s(n) s(n),窗函数为 w ( n ) w(n) w(n),那么分帧就是 s w ( n ) = s ( n ) ∗ w ( n ) s_w(n)=s(n)*w(n) sw(n)=s(n)w(n),窗函数需要满足1. 窗口两端不引起急剧变化,应该平滑过渡到0,2.在频域有较宽的3dB贷款以及较大的边带最大值。窗口的长度一般为10~20ms。有三种常见的窗函数为:

  • 矩形窗
    w ( n ) = { 1 , 0 ⩽ n ⩽ N − 1 0 , o t h e r s (矩形窗) w(n)=\left\{\begin{array}{ll} 1&,0\leqslant n \leqslant N-1\\ 0&,others \end{array}\right. \tag{矩形窗} w(n)={10,0nN1,others()

  • 汉明窗

w ( n ) = { 0.54 − 0.46 cos ⁡ [ 2 π n / ( N − 1 ) ] , 0 ⩽ n ⩽ N − 1 0 , o t h e r s (汉明窗) w(n)=\left\{\begin{array}{ll} 0.54-0.46\cos[2\pi n/(N-1)]&,0\leqslant n \leqslant N-1\\ 0&,others \end{array}\right.\tag{汉明窗} w(n)={0.540.46cos[2πn/(N1)]0,0nN1,others()

  • 海宁窗

w ( n ) = { 0.5 ( 1 − cos ⁡ ( 2 π n / ( N − 1 ) ) ) , 0 ⩽ n ⩽ N − 1 0 , o t h e r s (汉明窗) w(n)=\left\{\begin{array}{ll} 0.5(1-\cos(2\pi n/(N-1)))&,0\leqslant n \leqslant N-1\\ 0&,others \end{array}\right.\tag{汉明窗} w(n)={0.5(1cos(2πn/(N1)))0,0nN1,others()

其图形如下:
Python语音基础操作--3.1语音分帧与加窗_第1张图片

import matplotlib.pyplot as plt
import numpy as np

plt.rcParams['font.family'] = ['sans-serif']
plt.rcParams['font.sans-serif'] = ['SimHei']

N = 32
nn = [i for i in range(N)]
plt.subplot(3, 1, 1)
plt.stem(np.ones(N))
plt.title('(a)矩形窗')

w = 0.54 - 0.46 * np.cos(np.multiply(nn, 2 * np.pi) / (N - 1))
plt.subplot(3, 1, 2)
plt.stem(w)
plt.title('(b)汉明窗')

w = 0.5 * (1 - np.cos(np.multiply(nn, 2 * np.pi) / (N - 1)))
plt.subplot(3, 1, 3)
plt.stem(w)
plt.title('(c)海宁窗')
# plt.show()
plt.savefig('images/window.png')
plt.close()

分帧操作,相当于将信号分解为若干个信号片段,并将片段与窗函数进行对应元素的乘法。

from scipy.io import wavfile
import numpy as np
import matplotlib.pyplot as plt

plt.rcParams['font.family'] = ['sans-serif']
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False


def enframe(x, win, inc=None):
    nx = len(x)
    if isinstance(win, list):
        nwin = len(win)
        nlen = nwin  # 帧长=窗长
    elif isinstance(win, int):
        nwin = 1
        nlen = win  # 设置为帧长
    if inc is None:
        inc = nlen
    nf = (nx - nlen + inc) // inc
    frameout = np.zeros((nf, nlen))
    indf = np.multiply(inc, np.array([i for i in range(nf)]))
    for i in range(nf):
        frameout[i, :] = x[indf[i]:indf[i] + nlen]
    if isinstance(win, list):
        frameout = np.multiply(frameout, np.array(win))
    return frameout


fs, data = wavfile.read('C3_1_y.wav')
inc = 100
wlen = 200
en = enframe(data, wlen, inc)
i = input('起始帧(i):')
i = int(i)
tlabel = i
plt.subplot(4, 1, 1)
x = [i for i in range((tlabel - 1) * inc, (tlabel - 1) * inc + wlen)]
plt.plot(x, en[tlabel, :])
plt.xlim([(i - 1) * inc + 1, (i + 2) * inc + wlen])
plt.title('(a)当前波形帧号{}'.format(tlabel))

plt.subplot(4, 1, 2)
x = [i for i in range((tlabel + 1 - 1) * inc, (tlabel + 1 - 1) * inc + wlen)]
plt.plot(x, en[i + 1, :])
plt.xlim([(i - 1) * inc + 1, (i + 2) * inc + wlen])
plt.title('(b)当前波形帧号{}'.format(tlabel + 1))

plt.subplot(4, 1, 3)
x = [i for i in range((tlabel + 2 - 1) * inc, (tlabel + 2 - 1) * inc + wlen)]
plt.plot(x, en[i + 2, :])
plt.xlim([(i - 1) * inc + 1, (i + 2) * inc + wlen])
plt.title('(c)当前波形帧号{}'.format(tlabel + 2))

plt.subplot(4, 1, 4)
x = [i for i in range((tlabel + 3 - 1) * inc, (tlabel + 3 - 1) * inc + wlen)]
plt.plot(x, en[i + 3, :])
plt.xlim([(i - 1) * inc + 1, (i + 2) * inc + wlen])
plt.title('(d)当前波形帧号{}'.format(tlabel + 3))

# plt.show()
plt.savefig('images/en.png')
plt.close()

Python语音基础操作--3.1语音分帧与加窗_第2张图片

另外,也可以直接使用numpy.hanning(N)来获得窗函数。其中N就是点数。

你可能感兴趣的:(语音信号,Python)