写在前面
在Medium论坛,读到一篇关于梅尔谱图的帖子,作者讲得通俗易懂生动幽默,因此翻译过来分享一下。一则,为自己日后查阅方便,二则,帮助其他有困惑的小伙伴一起来学习学习。
当然,如果有条件(as you know),建议直接去原链接读英文原版。话不多说,一起来读吧!
原文链接:《Understanding the Mel Spectrogram》
作者:Leland Roberts
正文开始
如果你像我一样,试图理解mel频谱图
并不是一件容易的事。你读了一篇文章,却被引向了另一篇文章…和另一个…和另一个…继续前进。我希望这篇短文能够澄清一些混淆,并从头开始解释mel频谱图
。
信号
信号
是随时间推移一定数量的变化。对于音频,变化的量是气压。我们如何以数字方式捕获这些信息?我们可以随时间推移采集气压样本。我们对数据进行采样的速率可能会有所不同,但最常见的是44.1kHz
,即每秒44,100个样本
。我们捕获的是信号的波形,可以使用计算机软件对其进行解释,修改和分析。
import librosa
import librosa.display
import matplotlib.pyplot as plt
y, sr = librosa.load('./example_data/blues.00000.wav')
plt.plot(y);
plt.title('Signal');
plt.xlabel('Time (samples)');
plt.ylabel('Amplitude');
这太棒了!我们有一个音频信号的数字表示,我们可以使用它。欢迎来到信号处理领域!您可能想知道,我们如何从中提取有用的信息?它看起来像一团糟。这就是我们的朋友傅立叶的用武林立叶。
傅里叶变换
音频信号由几个单频声波组成。当随时间对信号进行采样时,我们只捕获产生的幅度。傅里叶变换是一个数学公式,它允许我们将信号分解为它的各个频率
和频率的幅度
。换句话说,它将信号从时域转换为频域
。其结果称为频谱
。
这是可能的,因为每个信号都可以分解成一组正弦波和余弦波,这些正弦波加起来就是原始信号。这是一个被称为傅里叶定理的非凡定理(Fourier’s theorem)。
点击https://youtu.be/UKHBWzoOKsY,如果你想要一个很好的直觉来解释为什么这个定理是正确的。
还有一个名为“3Blue1Brown”的博主关于傅里叶变换的惊人视频,链接为https://www.youtube.com/watch?v=spUNpyF58BY。
快速傅里叶变换 (FFT)
是一种可以有效计算傅里叶变换的算法。它广泛用于信号处理。我将在示例音频的窗口段上使用此算法。
import numpy as np
n_fft = 2048
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');
频谱图
快速傅里叶变换
是一个强大的工具,它允许我们分析信号的频率成分,但是如果我们信号的频率成分随时间变化怎么办?
大多数音频信号(如音乐和语音)都是这种情况。这些信号被称为非周期性信号
。我们需要一种方法来表示这些信号的频谱,因为它们随时间而变化。你可能会想,“嘿,我们不能通过在信号的几个窗口段上执行FFT
来计算几个频谱吗?是的!这正是所做的,它被称为 短时傅里叶变换。 FFT
是在信号的重叠窗口段上计算的,我们得到了所谓的频谱图。 哇!这需要吸收很多东西。这里发生了很多事情。良好的视觉效果是有序的。
您可以将频谱图视为一堆堆叠在一起的FFT
。它是一种直观地表示信号响度或幅度的方法,因为它在不同频率下随时间而变化。在计算频谱图时,背后还有一些额外的细节。y 轴
转换为对数刻度
,颜色尺寸
转换为分贝
(您可以将其视为振幅的对数刻度)。这是因为人类只能感知到非常小且集中的频率和振幅范围。
spec = np.abs(librosa.stft(y, hop_length=512))
spec = librosa.amplitude_to_db(spec, ref=np.max)
librosa.display.specshow(spec, sr=sr, x_axis='time', y_axis='log');
plt.colorbar(format='%+2.0f dB');
plt.title('Spectrogram');
Viola! 只需几行代码,我们就创建了一个频谱图。OK!我们快到了!我们对“频谱图”部分有很扎实的把握,但是“梅尔”呢?他是谁?
梅尔量表
研究表明,人类不会在线性尺度上感知频率。我们更擅长检测较低频率的差异``,而不是较高频率的差异。例如,我们可以很容易地分辨出500和1000 Hz之间的差异
,但是即使两对之间的距离相同,我们也很难区分10,000和10,500 Hz之间的差异。
1937年,史蒂文斯,沃尔克曼和纽曼提出了一个音高单位,使得音高的相等距离对听众来说听起来同样遥远。这称为梅尔尺度。 我们对频率执行数学运算,以将其转换为mel尺度
。
梅尔频谱图
mel频谱图是一种频谱图,其中频率转换为mel尺度。我知道,对吧?谁会想到呢?令人惊讶的是,在经历了所有那些心理准备以尝试理解mel频谱图之後,它只需要几行代码即可实现
。
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');
总结
这需要吸收很多信息,特别是如果你像我一样是信号处理的新手。但是,如果您继续回顾本文中列出的概念(并花足够的时间盯着墙角思考它们),它将开始有意义!让我们简要回顾一下我们所做的工作。
- 我们采集了随时间变化的气压样本,以数字方式表示音频信号。
- 我们使用快速傅里叶变换将音频信号
从时域映射到频域
,并在音频信号的重叠窗口段上执行此操作。 - 我们将
y轴(频率)
转换为对数刻度
,将颜色维度(振幅)
转换为分贝
以形成频谱图。
我们将y轴(频率)
映射到mel尺度
上以形成mel频谱图
。
就是这样!听起来很简单,对吧?嗯,不完全是,但我希望这篇文章能使mel频谱图
不那么令人生畏。我花了很长时间才理解它。然而,在一天结束时,我发现梅尔并没有那么冷漠。
(完)
再次感谢Leland Roberts写出的这篇文章,解答了笔者心中的一些困惑!