![3ab86b67d69adf7ddb430ef9f8b6dea8.png](https://i-blog.csdnimg.cn/blog_migrate/6d79ab6de56ad0ca9e86c832f74131af.jpeg)
这篇文章主要讲述以下内容:
前:
- 声音的时域表示
- 正弦余弦信号
- 声音的频域表示
- 相关性、DFT、补零
后:
- 窗函数、STFT
- 滤波器
- 声音的时域表示
如同物理学中各种波一样,声音也是一种波。而声波在各个时刻的振幅按时间顺序记录下来,便是声音的时域表示。通常来说,我们说声音的波形便是指的声音的时域表示。
我们可以使用大多数音频处理软件查看声音的波形,比如Audacity或者Adobe Audition。在这里我们使用Audacity,因为它功能够用,而且是免费的。
安装好Audacity后,我们打开一个音频文件,便直接可以看到声音的波形,横着为时间轴,竖着为振幅轴,振幅越偏离0点表示振幅越大。
![a614d09990bdffea1ed19c88425b8c93.png](https://i-blog.csdnimg.cn/blog_migrate/940f74da703e66ed8f4ba005cef0c82b.jpeg)
同样的,我们可以在Python中自己加载wav文件并绘制出波形图。
import
使用Python 3运行之:
![af2ccc0986ee5d1aa799eb136844436f.png](https://i-blog.csdnimg.cn/blog_migrate/f5cba727a2fa13954301c718415dee1d.jpeg)
2. 正弦余弦信号
在Audacity,我们可以将鼠标放置在波形窗口后通过 Ctrl+滚轮上滚 来在时间维度放大波形,或将鼠标放置在波形窗口的时间轴后通过 Ctrl+滚轮上滚 在振幅轴上放大波形。如此一来我们便可以仔细观察声波的形状了。在很多音乐中(尤其是乐器单一的音乐,比如纯人声),放大到足够大小时你会发现,波形中出现了一些周期变化的形状(如图)。
![fa40181fb1be543e245575a6ffa7d6be.png](https://i-blog.csdnimg.cn/blog_migrate/782315658e9e5e7ed00636f98fb59355.jpeg)
看到这上下波动的形状,是不是想到了物理课上讲波时经常出现的 正弦/余弦函数 了呢?没错,离散的声音信号 都是可以由有限个 正弦/余弦信号 叠加得到的,这个叠加和物理中波的叠加没什么区别。公式可以表示为
我们可以在Audacity里生成正弦。
![450672f9a044ea9f6efd39a6a3f6e011.png](https://i-blog.csdnimg.cn/blog_migrate/ec3dd3abd0ffe693953d7b42e025e04b.jpeg)
![c5d19ff192b43b821239aaadadc94aa3.png](https://i-blog.csdnimg.cn/blog_migrate/b6525449ed1e1b4c104aa8248c7d5c75.jpeg)
我们还可以增加多个轨道,生成出不同频率的正弦,然后混缩到一条轨道(相当于叠加)。
![c1f3e10cc44433e0dbe2a43b69bb7ac4.png](https://i-blog.csdnimg.cn/blog_migrate/bfece993ecf34eb36092ab4694f4f643.jpeg)
是不是和之前音乐中的波形有几分相似之处呢?
我们也可以通过Python生成:
import
![e01e5e70762e7e452b7db7cf89b60275.png](https://i-blog.csdnimg.cn/blog_migrate/d56d077cfe9ab139a8cb29afad4c5ace.jpeg)
注意:播放时振幅最大处不应超出[-1.0, 1.0]的范围,不然会被削成[-1.0, 1.0],导致破音。
注意:我们生成的 正弦/余弦信号 的频率是有限制的,它不应该超过1/2采样率大小。因为根据采样定理,只有采样率1/2倍以下频率的信号才能被完美恢复,这个最大的频率即为Nyquist频率。超出最大范围的部分不但无法表示,还会造成混叠,即高于采样频率一半的频率成分将被重建成低于采样频率一半的信号。
3. 声音的频域表示
自然界的声音都可以分解成简单的 正弦/余弦。但是在上面的例子中,即使只有三个正弦叠加起来,我们用肉眼也难以分辨出那三个成分。这时我们可以使用 DFT(离散傅里叶变换)这种方法将信号从时域变换到频域,这样我们就可以轻松看出来其中不同的频率成分了。
在Audacity中,我们可以划选一段信号,然后点击 分析->频率分析 来查看这段信号的傅里叶变换。对之前我们生成的440Hz+880Hz+1320Hz信号,它的频谱可能是这样的:
![d984a2c8eaf8e3c0b4f0fc6a656364cf.png](https://i-blog.csdnimg.cn/blog_migrate/23eb15f6e3858f2e8fb26d24d6e1b781.jpeg)
同样,我们可以在Python中使用numpy提供的FFT(快速傅里叶变换,你可以理解成DFT的快速版)函数实现类似的效果:
import
![2c819472afdf42e03d043e2b43f17624.png](https://i-blog.csdnimg.cn/blog_migrate/ab10664f7882ac49d0f2ff31bfae8851.jpeg)
可以看到有三个振幅0.25的峰,正是我们生成的信号。和Audacity中不同是因为Audacity中振幅的单位是分贝,换算公式为
你可能对DFT输出的形式有点好奇:为什么它是一个复数?因为根据欧拉公式,三角函数可以转换成复指数函数的形式,即
我们将一个n点的实数信号输入进DFT,其会返回一个n // 2 + 1点的输出。其中每个点代表一个余弦信号分量,从0Hz直到Nyquist频率,我们称每一个数据点叫一个bin(桶)。比如我们将一个采样率为1000Hz,长度为100采样的信号输入进去,DFT输出的每个bin对应的频率即为0Hz, 10Hz, 20Hz, ..., 500Hz。对于离散实数信号来说,n // 2 + 1个bin足以表示原来的信号。而对于长度为n的复数输入信号,则需要n个bin才能表示,这里我们不过多讨论复数输入,因为在语音处理中它并不常用。
4. 相关性、DFT、补零
我们在前面介绍了如何使用DFT(实际用的是FFT,DFT的快速版本),但是DFT是如何实现的呢?让我们先讲讲信号的 相关性。
相关性 顾名思义,就是两个信号的相似程度(实际定义更复杂些)。计算相关性的方法为
import
更前面我们提到,DFT输出结果中每个桶都是余弦信号分量,任意相位的余弦信号又可以拆成一个正弦和一个余弦的叠加。现在我们又提到,用相关性的方法可以求两个信号的相似程度。于是自然可以想到,可以将原始信号与每个桶对应频率的正弦信号和余弦信号求相关性,便可以直接得到DFT输出复数的实部和虚部。
import
![57b8295068de6fc1cd673038dea22a6e.png](https://i-blog.csdnimg.cn/blog_migrate/a28eca47bc0b2171b224a7894fe4ab0c.jpeg)
与此同时,不知你是否注意到一个问题:DFT输出结每个桶之间隔着的距离是和信号输入长度相关的,如果信号很短,桶之间距离就很远,频率分辨率就会变得很低。在这种情况下,你可以试试将输入信号末尾加一定长度的0,这样做相当于将频域结果进行Sinc插值,并没有真的提高频率分辨率。但是很多时候它还是能为我们提供很大帮助。
import
![18b789345e38bcd1825111cc527e1037.png](https://i-blog.csdnimg.cn/blog_migrate/53504ac0d518c1cd37ba51320db86cde.jpeg)
观察补零后(橘色)和补零前(蓝色)的DFT结果,很明显在补零后的信号上我们能更准确更轻松地找到峰。
Tux ZZ:零、信号处理基础知识快速介绍(后)zhuanlan.zhihu.com