什么是语谱图
语谱图(Spectrogam)是表示语音频谱随时间变化的图形,其实是一个二维的图像,但却能表示三个维度的信息,横坐标表示时间,纵坐标表示频率,颜色的深浅来映射能量的大小。任一给定频率成分在给定时刻的强弱用相应点的灰度或色调的浓淡来表示。颜色深,表示该点的语音能量越强,反之表示该点语音能量较弱。
绘制语谱图首先需要对载入的音频进行分帧和加窗处理,然后进行傅里叶变化,然后求出每一帧所对应的时间刻度,然后再将傅里叶变换后的数据取对数求出能量密度谱,将能量与颜色做一个映射,然后画出图像
分帧
语音信号是一个准稳态的信号,若把它分成较短的帧,每帧中可将其看做稳态信号,可用处理稳态信号的方法来处理。为了使一帧与另一帧之间的参数能够平稳过渡,应在相邻两帧之间互相有部分重叠。一般情况下,帧长取10 ~ 30ms,所以每秒的帧数约为33 ~ 100帧。帧移与帧长的比值一般取0~1/2。其中设每帧长度为win,后一帧对前一帧的位移量为inc。
因此设计分帧函数就是在函数名中给三个参数,enframe(x, win, inc),其中x为加载的音频数据,win为帧长,inc为帧移,返回值为分帧后的数据。
代码如下:
#分帧函数
def enframe(x, win, inc=None):
'''
:param x: 音频数据
:param win: 帧长
:param inc: 帧移
:return: 分帧后的列表
'''
nx = len(x)# 获取音频的长度
if isinstance(win, list) or isinstance(win, np.ndarray):# 判断win是否为窗函数
nwin = len(win)
nlen = nwin # 帧长=窗长
elif isinstance(win, int):# 说明没有窗函数,将帧长设置为1
nwin = 1
nlen = win # 设置为帧长
if inc is None:# 帧移不为空则传给nlen
inc = nlen
nf = (nx - nlen + inc) // inc# 算出有多少帧
frameout = np.zeros((nf, nlen))# 填充一个零矩阵出来,行为帧,列为帧数据
indf = np.multiply(inc, np.array([i for i in range(nf)])) # 设置每帧在x中的位移量位置
for i in range(nf):# 将数据分帧存在frameout中
frameout[i, :] = x[indf[i]:indf[i] + nlen]
return frameout
加窗
在语音处理中,经常可以听到对语音进行分帧和加窗的操作,那加窗到底是什么,为什么要加窗呢?语音信号是一种非平稳的时变信号,要进行FFT或其他针对平稳信号而进行的信号处理时就十分困难。加窗和分帧就类似与高等数学中求积分一样,将曲线分成无限个小格,每个格就可以等似为矩形。在语音处理中也是这样,通过分帧和加窗可以把语音信号在一帧内看作是短时平稳的,加窗其实就是对分帧后的每一帧数据 s ( n ) s(n) s(n)分别乘上窗数据 w ( n ) w(n) w(n),从而形成加窗语音信号 s w ( n ) = s ( n ) ∗ w ( n ) s_w(n)=s(n) \ast w(n) sw(n)