音频信号特征提取的一般流程为:
![](https://i-blog.csdnimg.cn/blog_migrate/b5d0374a97178aa12155af1ad5e00713.png)
假设我们的语音信号采样频率为 8000Hz,语音数据在这里获取。
import numpy
import scipy.io.wavfile
from scipy.fftpack import dct
sample_rate, signal = scipy.io.wavfile.read('OSR_us_000_0010_8k.wav')
# sample_rate = 8000
signal = signal[0:int(3.5 * sample_rate)] # 我们只取前3.5s
得到频率图如下:
![时域中的音频信号](https://i-blog.csdnimg.cn/blog_migrate/774f0dfc72381888fecb5d24cc9344d9.png)
Q: 为什么信号值有正有负?
A: 信号值是相对于周围气压的压力差,正值表示气压高于周围气压,负值表示低于周围气压。
预加重
在音频录制过程中,高频信号更容易衰减,而像元音等一些因素的发音包含了较多的高频信号的成分,高频信号的丢失,可能会导致音素的共振峰并不明,使得声学模型对这些音素的建模能力不强。预加重是个一阶高通滤波器,可以提高信号高频部分的能量,给定时域输入信号 , 预加重之后信号为
其中滤波器系数的值通常为 0.95 或 0.97,这里取
pre_emphasis = 0.97
:
emphasized_signal = numpy.append(signal[0], signal[1:] - 0.97 * signal[:-1])
题外话:预加重在现代系统中的影响不大,主要是因为除避免在现代 FFT 实现中不应成为问题的 FFT 数值问题,大多数预加重滤波器的动机都可以通过均值归一化来实现。
分帧加窗
分帧
语音信号是一个非稳态的、时变的信号。但在短时间范围内可以认为语音信号是稳态的、时不变的。这个短时间一般取 10-30ms,因此在进行语音信号处理时,为减少语音信号整体的非稳态、时变的影响,从而对语音信号进行分段处理,其中每一段称为一帧,帧长一般取 25ms。为了使帧与帧之间平滑过渡,保持其连续性,分帧一般采用交叠分段的方法,保证相邻两帧相互重叠一部分。相邻两帧的起始位置的时间差称为帧移,我们一般在使用中帧移取值为 10ms。
对于一个 16000Hz 采样的音频来说,帧长有 16000 * 0.025 = 400 个点,帧移有 16000 * 0.01 = 160 个点。使用 num_samples、frame_len、frame_shift 分别代表音频的数据点数、帧长和帧移,那么 i 帧的数据需要的点数为
加窗
因为后面会对信号做 FFT,而 FFT 变换的要求为:信号要么从 -∞ 到 +∞ ,要么为周期信号。现实世界中,不可能采集时间从 -∞ 到 +∞ 的信号,只能是有限时间长度的信号。由于分帧后的信号是非周期的,进行 FFT 变换之后会有频谱泄露的问题发生,为了将这个泄漏误差减少到最小程度,我们需要使用加权函数,也叫窗函数。加窗主要是为了使时域信号似乎更好地满足 FFT 处理的周期性要求,减少泄漏。
关于频率泄露,可参考 https://blog.csdn.net/zhaomengszu/article/details/72627750 。总结来说,对信号的非周期性截断做 FFT。
在语音识别中,一般选择汉明窗作为窗函数,它能使信号在窗边界的值近似为 0,从而使得信号趋近于是一个周期信号,该窗函数如下:
傅里叶变换
傅里叶变换的几个概念:
- FT(Fourier Transformation):傅里叶变换。就是我们理论上的概念,但是对于连续的信号无法在计算机上使用。其时域信号和频域信号都是连续的。
- DTFT(Discrete-time Fourier Transform):离散时间傅里叶变换。这里的“离散时间”指的是时域上式离散的,也就是计算机进行了采样。不过傅里叶变换