你好,我是建元。
上一讲我们了解了音频信号的一些基础知识。因为语音和音乐是最常见的音频信号类型,所以接下来两节课我会分别从这两种类型入手,带你看看如何科学、量化地对音频信号进行分析,从而读懂音频信号所承载的内容和信息,以及了解音频现象产生的原因是什么。这些知识对音频工程师、开发者甚至是调音师、录音师、音乐制作者而言都是很重要的基础,所谓“听其然,更知其所以然”。
好的,那我们这节课就先从语音信号的分析开始说起吧。
语音按照发音原理可以分为清音和浊音,语音的音调、能量分布等信息可以用基频、谐波、共振峰等特征来分析。为了更好地分析语音,我们先来看看语音是如何产生的?
我们可以结合图1的人体发音器官结构示意图来看一下我们的语音是如何产生的。
我们知道,声道就是声音传播所通过的地方。发音的声道主要是指我们的三个腔体,即咽腔、口腔和鼻腔。而语音是由声源和声道共同作用产生的。按照声源的不同我们把语音分成以下两类:
那么清音和浊音的声源不同在频谱上有什么样的差异呢?我们先来看看语音的频谱图(如图2所示)。
图2中显示的是“实时音视频互动”这几个字的音频信号的时域图和频域图(频谱图)。时域就是信号幅度和时间的关系,而频域指的是能量与时间和频率的关系。
频域更方便我们观察不同频率的能量分布。我们可以看到浊音,比如最后两个字“互动”是明显的有规律的能量分布,即低频能量大于高频且有明显的能量比较集中的地方,如频谱图中的亮线。而“实时”和“视”这几个字,都有 “sh” 这个由牙齿间高速气流产生的清音。清音在频谱上显示为比较均匀的分布。在13kHz的高频,清音也有不少的能量。
根据这个简单的分布规律我们已经可以从频谱上分辨清浊音了。接下来我们再来看看,我们还能从有明显能量分布的浊音的频谱中得到哪些信息。
在发浊音的时候,声带会振动从而产生一个声波,我们把这个声波叫做基波,并且把基波的频率叫做基频(一般用F0来表示)。这个基频其实就可以对应到我们平时所说的音调。比如,你唱歌音调比较高,其实就是你的声音基频比较高。
一般来说,男生的正常说话基频在100~200Hz之间,而女生的则会高一些,在140~240Hz之间。这就是为什么女生的声音听起来比男生的尖锐一些。基频会随年龄变化而变化,比如小孩的基频比较高,可以达到300Hz,而年龄越大则基频会越来越低。基频的能量对应的是浊音频谱中频率最低的亮线。
声带振动产生的基波,在传输过程中会在声道表面反复碰撞反射,从而产生许多频率倍数于基频的声波,我们通常把这些声波叫做谐波。按照谐波频率从低到高,我们依次叫1次谐波,2次谐波等等。图3中我们可以看一下基频信号和谐波信号在时域上的样子。
谐波频率和基频是浊音能量集中的地方,这也就是为什么我们能看见浊音的频谱是一个栅格的形状。
一个200Hz基频的浊音,大部分的能量都分布在200Hz以及200Hz的整数倍的频率上。那么是什么决定了哪个谐波的能量高、哪个谐波的能量低呢?
由于高次谐波是由低次谐波在腔体表面碰撞反射得到的,并且碰撞反射会导致能量的衰减,但我们在看频谱图的时候发现谐波信号并不是从低到高依次衰减的。这是为什么呢?
这是因为在这个浊音的产生过程中,声源的振动信号通过声道时,声道本身也会发生共鸣,与声道共振频率相近的能量会被增强,远离声道共振频率的部分则会被衰减,从而谐波的能量就组成了一组高低起伏的形状包络,我们把这些包络中的巅峰位置叫做共振峰。
比如图4中英文单词father中的 “a” 这个音我们可以看到明显的三个共振峰,频率分别为750Hz、1100Hz、2600Hz。
频率从低到高我们分别用F1、F2、F3等来表示第一共振峰、第二共振峰、第三共振峰等。
从图4我们可以看到,发不同的音,比如 “a、i、u” 等,共振峰的位置和峰值都是不一样的。这是因为我们之前说的声道的三个腔体随发音的不同,开合、形状都会发生变化。从而形成了不同的腔体共振频率。所以,共振峰的位置和幅度就和发音可以一一对应起来了。这其实也是语音识别背后的原理之一,即通过共振峰的位置和能量分布来识别音频代表的语音。
好的,我们现在对语音是怎么产生的已经能够理解了,那接下来我们分别从时域、频域这两个方面来介绍几个常用的语音分析的方法。因为窗函数常作为时域或频域实时分析的前处理步骤,所以在介绍这些语音分析方法之前,我们先介绍一下窗函数。
我们分析音频时域或频域特征随时间的变化时,需要按照时间把音频截断成一个个小片段,每个小片段也就是我们说的音频帧。比如10ms的切片为1帧。
但如果直接截断信号则会导致频谱泄漏,即出现不该有的频谱分量。比如,你对一个50Hz的单频信号直接截断,可能会出现60Hz、200Hz的能量分量。因此,我们一般采用加窗,即在原有信号中乘一个两端为0的窗信号,来减少截断信号时的频谱泄漏。常用的窗函数有Haning(汉宁窗)、Hamming(汉明窗)、Blackman(布莱克曼窗)等。在时域上加窗(Haning)的过程如图5所示:
可以看到图5中加窗的过程其实就是输入信号乘以窗函数,得到了一个两边小、中间高的新信号。
好了,我们已经了解了窗函数,现在我们来聊聊时域分析。在时域上我们主要介绍两个指标,短时能量和短时平均过零率。
短时能量
由于语音的能量随时间的变化较快,比如能量小的时候可能就是没有在说话,而能量大的地方可能是语音中重读的地方。因此,短时能量常被用来判断语音的起止位置或者韵律。短时能量分析的定义如公式1所示:
$$E_{n}=\sum_{m=-\infty}^{\infty}{\left[ x(m)w(n-m)\right]^{2}}$$
其中,$x$代表采样点,$w$代表窗函数。第$n$个点的短时能量$E_n$就是由加窗后的采样信号的平方和来表示的。由于不涉及频谱分析,因此这里的窗可以使用简单的矩形窗。
短时能量主要有以下3个方面的应用:
短时平均过零率
短时平均过零率,顾名思义,就是每帧内信号通过零值的次数。连续的音频信号是围绕0值上下波动的,并且表现为音频信号正负号随时间不断切换。短时平均过零率可以通过公式2和3来计算。
$$Z_{n}=1/2\sum_{m=n}^{n+\text{N}-1}{\left| sgn[x(m)]-sgn[x(m-1)] \right|}$$
$$sgn[x(n)]=\begin{cases}1, & {x(n)>= 0} \\-1, & {x(n)<0}\end{cases}$$
其中,$\text{N}$为一帧中包含的信号点数,$sgn$为符号函数,$x$为音频采样点。
如果是正弦信号,例如图3中的基频和谐波信号,它们的短时平均过零率,就是信号的频率除以两倍的采样频率。
短时平均过零率在一定程度上可以表示语音信号的频率信息。由于清音的频率集中的范围要高于浊音,所以浊音的过零率要低于清音,从而我们可以初步用短时平均过零率来判断清浊音。
除了判断清浊音。还可以将短时能量和短时平均过零率结合起来判断语音起止点的位置。在背景噪声较小的情况下,短时能量比较准确;但当背景噪声比较大时,短时平均过零率有较好的效果。因此,一般的音频识别系统就是通过这两个参数相结合,来判断待检测语音是否真的开始。
上面我们讲了基于时域的两种语音分析方法,接下来我们来学习基于频域的两种语音分析方法:短时傅里叶变换和梅尔谱。
短时傅里叶变换
短时傅里叶变换(Short-time Fourier Transform)是音频频域分析最常用的方法之一,简称STFT。那它有什么作用呢?
我们在分析音频信号时经常会使用到频谱图(例如图2),那你知道这个频谱图是怎么得到的吗?
结合短时傅里叶变换的步骤(如图6所示),也许你就明白了:
图6中的Hop Length代表滑动窗移动一次的距离,并且Overlap Length就是两个相邻滑动窗重叠的范围。
清楚了这些,我们就可以回答刚才的问题了。其实呢,我们是把短时傅里叶变换的结果对复数频域信号求模,并取对数转换成分贝(dB),然后用热力图的形式展示出来,这样就能得到图2中的频谱图。频谱图的横坐标为时间,纵坐标为频率,并且热力图中的颜色代表每个频点在当前时刻的能量大小。这样我们就可以通过频谱图来观察每个时刻的语音能量分布了。
梅尔谱(Mel spectrum)
上面我们通过短时傅里叶变换得到的频谱图通常也叫做声谱、线性谱或者语谱。
由于心理和听力系统的构造,其实人耳对以Hz为单位的频率并不是很敏感。比如,人类很难区分500Hz和510Hz的声音。我们平时能区分的音调都是以指数排列的。比如,我们说的高八度其实就是把原有频率乘以2。因此,用对数的频率坐标来表示可以更好地反映人的实际听感。
除此之外,人耳对不同频率声音大小的感知也是不同的。如图7所示,红线代表人耳感知到的响度和实际声压的对应关系,人耳感知的响度我们一般用phon(方)来表示。
由图7可以看到,人类在4kHz的频率对声音的响度比较敏感,而在两端的高频和低频则需要更强的声压,人类才能感知。这其实和人类的进化有关,4kHz多为猛兽的叫声能量分布范围,所以人耳对这类危险的频率较为警觉。
因此,为了结合人耳对频率的感知。需要使用对数的频率坐标,且通过分配滤波器组对频谱图的能量按照听感重新分配,于是就有了梅尔谱等表示形式。
Mel谱的计算步骤分为下面几步:
三角滤波器组如图8所示。我们可以看到三角滤波器组把频率划分成了若干个频段。敏感的频段滤波器分布比较密集,而不敏感的频段比较稀疏,这样就能更好地表征人耳的实际听感。
梅尔谱以及对梅尔谱再进一步求倒谱系数得到的MFCC(梅尔倒谱系数),经常被用于语音识别、声音事件识别等领域。其实类似的基于人耳实际听感的表示还有Bark谱、Gamma Tone Filter 等,这里就不一一赘述了。如果你有兴趣可以自行了解一下,并且有问题也可以发表在留言区。
好了,这节课到这里就要结束了。我们先来回顾一下这节课的重点。
关于语音是如何产生的、在信号层面有何不同、语音是如何被人耳感知的这些都是这节课的重点。有了扎实的理论基础和分析方法,以后你再碰到语音算法设计、语音特征分析时就可以有针对性地进行选择了。
现在我给你简单总结一下,我们今天主要讲了哪些内容。
最后,给你介绍一个常用的Python音频处理工具librosa,利用它可以快速地画出频谱图和梅尔谱。下面是示例代码,你可以尝试用自己的音频绘制一下频谱图和梅尔图,分析一下清、浊音在两个频谱上有什么不同。
#绘制STFT
import numpy as np
import librosa
import matplotlib.pyplot as plt
audio,sr=librosa.load('Path',sr=48000)
n_fft=1024
ft = np.abs(librosa.stft(y[:n_fft], hop_length = n_fft+1))
plt.plot(ft)
plt.title('Spectrum')
plt.xlabel('Frequency Bin')
plt.ylabel('Amplitude')
#绘制梅尔频谱
mel_spect = librosa.feature.melspectrogram(y=y, sr=sr, n_fft=2048, hop_length=1024)
mel_spect = librosa.power_to_db(spect, ref=np.max)librosa.display.specshow(mel_spect, y_axis='mel', fmax=8000, x_axis='time');
plt.title('Mel Spectrogram');
plt.colorbar(format='%+2.0f dB');
好了,这节课就到这里。你可以把你的问题和答案写下来,分享到留言区,与我一起讨论。我们下节课再见。