2  第二章

在上一章中,我们从信号采样、切换与滤波一直探索到了频域分析与STFT。通过STFT,我们能够将一维的时间序列音频转化为二维的频谱图,直观观察频率随时间的变化。然而STFT记录的线性物理频率,与人类大脑实际感受声音的方式并不一致。

本章将从声音的“特征工程”出发,探讨如何将物理声波抽象成更符合人类听觉机制的表征,从而进而进一步踏入音频处理的世界。

2.1 梅尔频谱

人耳听觉系统对声音的感知存在两个显著特征: 首先是对低频变化非常敏锐,例如我们能很容易地分辨出200Hz与300Hz的声音,但是对同样相差100Hz的10000Hz与10100Hz,在主观听感上我们几乎无法分辨差别。

其次我们感知到的声音响度与声压能量,也就是振幅并非成正比关系,而是呈对数关系,这也是STFT纵坐标为dB的原因。

为了以接近人们听觉的方式表示音频,在STFT的基础上,梅尔频谱应运而生。研究发现人耳频率感知大概符合以下公式:

\[ m = 2595 \log_{10}\left(1 + \frac{f}{700}\right) \tag{2.1}\]

其中\(f\)是声音频率,\(m\)是梅尔刻度:

图 2.1: 声音频率与梅尔刻度映射关系

可以看到随着\(f\)线性增大,\(m\)的增加幅度变的越来越小,表明人类的感知对于高频声音变化会越来越不敏感。

这点也和音乐里八度的概念相吻合,升高一个八度代表频率变为原来的两倍,人耳听力范围覆盖十个八度,每个八度之内又可以细分成十二个音符。音乐就在这十二个不同八度的音符间流动从而产生旋律。那为什么八度是两倍关系呢?其实从 图 2.1 可以看出:人耳的感知刻度是梅尔刻度的,在\(m\)上的0~1000Mel和2000~3000Mel有相同的感知尺度,然而它们对应的频率刻度\(f\)却大约从0~1000Hz到3500~8000Hz,后者频率覆盖的范围大约是前者的4倍,因此直接用线性关系划分音域是不行的。

在有了梅尔刻度之后,梅尔频谱还需要把STFT的能量映射过来,基本思想是统计相同间隔\(m\)下对应的\(f\)区间内STFT平均能量。

该过程可以用一系列不同的乘法三角滤波器计算,如图所示:

图 2.2: 频率 \(f\) 刻度下的梅尔三角滤波器组

三角滤波器其实就是一组加权函数,用于提取不同频率区间的平均能量。

经过变换后 图 1.22 的梅尔谱如下:

图 2.3: 音频信号梅尔频谱图

2.2 优化问题

现代化的音频处理技术已经超越了调整滤波器或均衡器的范畴,来到了由数字驱动的时代。前者在即使没有数字系统的地方,也可以用模拟电路实现相关功能,随着数字系统的发展和越来越快的计算能力,音频处理逐渐导向了以优化为目标的任务中。

它通常表现为以下形式:对于一组变量\(x\),优化问题通常致力于寻找到具有最大值或最小值的\(f(x)\),并满足过程中的不等式约束和等式约束:

\[ \begin{aligned} \arg\min_{x} \quad &f(x), \\ s.t. \quad &g(x) \leq 0 \\ \quad &h(x) = 0 \end{aligned} \tag{2.2}\]

\(f(x)\)被称为优化目标、目标函数或损失函数,\(g(x)\)\(h(x)\)分别为不等式约束和等式约束,\(\arg\min\)是求解运算符,目的是为了寻找到最优的\(x\)以满足 式 2.2

例如对于简单线性回归,方程\(y=ax+b\)如何从一组数据中找到合适斜率\(a\)和截距\(b\),使得达到某种意义上“最好的”拟合?

图 2.4: 简单线性回归中不同斜率 \(a\) 与截距 \(b\) 的拟合

优化问题根据\(f(x)\)的性质,可以分为凸优化和非凸优化,通常来说凸优化有很多很强的算法可以保证找到全局最优。

对于简单线性回归,我们认为一个“足够好的”拟合直线应该保证它与每个数据点足够接近,也就是说我们希望找到一组\((a,b)\),使得对所有的数据点\((x_i,y_i)\),其 \(\sum_{i=1}^{N} |y_i - (ax_i + b)|\) 最小。\(|y_i - (ax_i + b)|\)也可以用其二范数替代:\(\sqrt{\sum_{i=1}^{N} \|y_i - (ax_i + b)\|^2}\)

由此可得简单线性回归的目标函数 \(f(a, b) = \sqrt{\sum_{i=1}^{N} |y_i - (ax_i + b)|^2}\)。并且该目标函数是一个凸函数。

数学上凸函数被定义为:一个函数 \(f\) 是凸的当且仅当函数图像上任意两点的连线位于函数图像上方。为什么凸性如此重要?因为凸性表明函数的图形是一个“碗形”,使得人们总有办法找到“碗底”在哪儿:

图 2.5: 凸优化中的“碗形”损失曲面与两种参数优化轨迹

这个寻找“碗底”的过程也叫参数优化。对于更大规模的复杂任务,其目标函数可能不是严格意义上凸的(但这种非凸性通常来自凸函数的折叠,其产生的结构化非凸性通常比任意构造的非凸函数更容易优化),但只要目标函数曲面保留“碗形”的特点,就能保证至少可以找到局部最优解,如图所示:

图 2.6: 非严格的凸损失曲面

2.3 梯度下降

梯度下降是基于梯度的参数优化方法,所谓参数优化方法通常是指迭代算法,对于目标函数 \(f(x)\),当前参数组合为\(x_k\),迭代函数\(F(x)\)输入当前\(x_k\),并输出\(x_{k+1}\)

图 2.7: 参数优化示意图

那什么是梯度呢,梯度就是多元函数里的偏导数向量,多元函数的梯度定义为:

\[ \nabla f(\mathbf{x}) = \begin{bmatrix} \frac{\partial f}{\partial x_1} \\[8pt] \frac{\partial f}{\partial x_2} \\[8pt] \vdots \\[8pt] \frac{\partial f}{\partial x_n} \end{bmatrix} \tag{2.3}\]

\(\nabla\)是求偏导算符,梯度是一个向量,代表当前目标函数变化最快的方向。不过为什么是最快的方向呢?以连续的二元函数\(f(x_1,x_2)\)为例,它在\(\mathbf{x_0}\)处的泰勒一阶展开为:

\[ f(\mathbf{x_0}+\Delta \mathbf{x}) \approx f(\mathbf{x_0})+\nabla f(\mathbf{x_0})^{\top} \Delta \mathbf{x}\\ =f(\mathbf{x_0}) + \frac{\partial f}{\partial x_1} \Delta x_1 + \frac{\partial f}{\partial x_2} \Delta x_2 \tag{2.4}\]

式 2.4\(\nabla f(\mathbf{x_0})^{\top} \Delta \mathbf{x}\)是向量内积,考虑\(\Delta \mathbf{x}\)是一个单位长度向量(为了只比较方向不比较步长),要使内积最大,\(\Delta \mathbf{x}\)的方向则必须和梯度方向一致。

为了直观理解,可以拖动下图的红色向量:

f (x0)T Δx = 2.50 × 1.00 × cos(0°) = 2.50 (最大变化率:与梯度同向)
图 2.8: 梯度向量与不同方向单位步长的内积

\(\Delta \mathbf{x}\)的方向与梯度方向相反时,内积最小,目标函数下降地最快,因此梯度下降算法是:

\[ \mathbf{x}_{k+1} = \mathbf{x}_k - \eta \nabla f(\mathbf{x}_k) \tag{2.5}\]

其中\(\eta\)是步长,也被称为学习率。至于为什么是梯度的反方向呢,因为我们是为了最小化目标函数,从 式 2.4 可以看出,如果是正方向,目标函数会越来越大。

2.4 LMS滤波器

LMS是最小均方(Least Mean Square)的缩写,它是一种自适应滤波器,诞生自1960年,其基本思想是通过不断调整滤波器的系数,使输出数据与观测数据之间的差异最小。

考虑一个视频会议的场景,对方正在播放一首新制作的音乐,然后你需要及时在播放时指出这一段伴奏稍微有点问题。此时麦克风收录了你的声音,但是经过扬声器播放出来的音乐片段,也就是回声信号也被收录了。如果想要消除回声该怎么办呢?

对于这个问题,传统滤波器无能为力,在20世纪40年代之前,工程师设计滤波器的思维是确定性的,滤波器的作用只是一个筛子,如目标信号和回声信号频段混合,那滤波器只能一刀切地把频段内的信号全部滤除。

二战期间,数学家维纳在研究高射炮如何预测敌机飞行轨迹时,遇到了这种“信号与噪声混杂”的难题,为了解决这个问题,维纳天才般地提出了维纳滤波器,并奠定了最优线性滤波理论。

假设收集的信号是目标信号和回声信号混合在一起,即\(y[n]=s[n]+echo[n]\),其中\(s[n]\)是目标信号,\(echo[n]\)是回声信号,回声信号来自原始信号\(x[n]\)的延迟反射:\(echo[n] = \alpha_1 x[n] + \alpha_2 x[n-1]+ \dots\)。当然我们无从得知系数\(\alpha\)的具体值,因为环境不一样它们当然就不一样,因此就算知道了并把它们固定下来也没有意义。

维纳认为我们不需要知道它是多少,只需要估计就行:

图 2.9: 用于估计的FIR滤波器

怎么估计呢?用\(echo[n]-\hat{echo}[n]\)作为误差,如果其平方的均值越小即\(E[(echo[n]-\hat{echo}[n])^2]\)越小,那就越消除了误差。

LMS算法的改进在于,直接用当下的\((echo[n]-\hat{echo}[n])^2\)代替需要记录过期所有历史的\(E[(echo[n]-\hat{echo}[n])^2]\)

定义\(e[n]=s[n] + echo[n] - \hat{echo}[n]\),目标函数\(J = \frac{1}{2}e[n]^2\)(最小化\(J\)不会消除\(s[n]\),因为它们在统计上是不相关的),根据链式法则,其偏导数为:

\[ \frac{\partial J}{\partial a_i} = e[n]\frac{\partial e[n]}{\partial a_i} = e[n]\frac{\partial (-\sum a_k x[n-k])}{\partial a_i} = -e[n]x[n-i] \tag{2.6}\]

因此梯度为\(\nabla J = [-e[n]x[n], -e[n]x[n-1], \dots, -e[n]x[n-M+1]]^\top\),计算出梯度后,就可以用梯度实时更新滤波器系数\(\mathbf{a}\)了:

\[ \mathbf{a}_{k+1} = \mathbf{a}_{k} - \mu·\nabla J \tag{2.7}\]

LMS算法的一个特别之处在于\(\mathbf{a}\)会一直保持更新,不会在某个时刻停止了(不同于其他机器学习算法),因为\((echo[n]-\hat{echo}[n])^2\)是基于实时数据的(而不是给定了所有的训练样本),这意味着目标函数\(J\)永远在最小化误差的路上。

同时效果也和滤波器的阶数有关,简单来说就是\(a_M\)越多,能记住的过去数据就越多,效果也会更好,但速度更慢。

图 2.10: LMS回声消除