STFT和声谱图,梅尔频谱(Mel Bank Features)与梅尔倒谱(MFCCs)

提取声音特征
STFT和声谱图(Spectrogram)
声音信号本是一维的时域信号,直观上很难看出频率变化规律。如果通过傅里叶变换把它变到频域上,虽然可以看出信号的频率分布,但是丢失了时域信息,无法看出频率分布随时间的变化。为了解决这个问题,很多时频分析手段应运而生。短时傅里叶,小波,Wigner分布等都是常用的时频域分析方法。

短时傅里叶变换(STFT)是最经典的时频域分析方法。傅里叶变换(FT)想必大家都不陌生,这里不做专门介绍。所谓短时傅里叶变换,顾名思义,是对短时的信号做傅里叶变化。那么短时的信号怎么得到的? 是长时的信号分帧得来的。

STFT的原理非常简单,把一段长信号分帧、加窗,再对每一帧做傅里叶变换(FFT),最后把每一帧的结果沿另一个维度堆叠起来,得到类似于一幅图的二维信号形式。如果我们原始信号是声音信号,那么通过STFT展开得到的二维信号就是所谓的声谱图。

 

有很多工具方便地支持STFT展开,如果你是和小编一样是python爱好者,可以使用scipy库中的signal模块。如果你想做STFT分解的音频信号(wav文件)的路径存在path变量中,可通过下面的代码得到STFT数据。

import wavio
import numpy as np
from scipy import signal

wav_struct=wavio.read(path)
wav=wav_struct.data.astype(float)/np.power(2,wav_struct.sampwidth*8-1)
[f,t,X]=signal.spectral.spectrogram(wav,np.hamming(1024),nperseg=1024,noverlap=0,detrend=False,return_onesided=True,mode='magnitude')

关于signal模块中spectrogram的使用方法和各个参数的具体意义,参见https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.spectrogram.html#scipy.signal.spectrogram

梅尔频谱和梅尔倒谱
声谱图往往是很大的一张图,为了得到合适大小的声音特征,往往把它通过梅尔标度滤波器组(mel-scale filter banks),变换为梅尔频谱。什么是梅尔滤波器组呢?这里要从梅尔标度(mel scale)说起。

梅尔标度,the mel scale,由Stevens,Volkmann和Newman在1937年命名。我们知道,频率的单位是赫兹(Hz),人耳能听到的频率范围是20-20000Hz,但人耳对Hz这种标度单位并不是线性感知关系。例如如果我们适应了1000Hz的音调,如果把音调频率提高到2000Hz,我们的耳朵只能觉察到频率提高了一点点,根本察觉不到频率提高了一倍。如果将普通的频率标度转化为梅尔频率标度,映射关系如下式所示:
è¿éåå¾çæè¿°

但如果你只是想使用梅尔滤波器组得到梅尔频率谱,并不关心它怎么得到的,那么你只需要关注下面的代码段:

import numpy as np
import librosa

melW=librosa.filters.mel(fs=44100,n_fft=1024,n_mels=40,fmin=0.,fmax=22100)
melW /= np.max(melW,axis=-1)[:,None]
melX = np.dot(X,melW.T)

其中,变量X是上一小节代码段得到的声谱,melX就是我们说的梅尔频谱。librosa库是python中的语音和信号处理的专业库,具体说明参见:http://librosa.github.io/librosa/generated/librosa.filters.mel.html#librosa.filters.mel

知道梅尔频谱了,那么梅尔倒谱是怎么回事呢? 
这里涉及到倒谱分析的概念,在附录一(大神zouxy09的博客)介绍的很详细了。记住一句话,在梅尔频谱上做倒谱分析(取对数,做DCT变换)就得到了梅尔倒谱。这里通过一段代码展示梅尔倒谱怎么得到的:

import librosa

melM = librosa.feature.mfcc(wav,sr=44100,n_mfcc=20)

ibrosa.feature.mfcc这个函数内部是这样的:

# -- Mel spectrogram and MFCCs -- #
def mfcc(y=None, sr=22050, S=None, n_mfcc=20, **kwargs):
    if S is None:
        S = logamplitude(melspectrogram(y=y, sr=sr, **kwargs))

    return np.dot(filters.dct(n_mfcc, S.shape[0]), S)

可以看出,如果只给定原始的时域信号(即S参数为None),librosa会先通过melspectrogram()函数先提取时域信号y的梅尔频谱,存放到S中,再通过filters.dct()函数做dct变换得到y的梅尔倒谱系数。

  • 6
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在MATLAB中绘制梅尔频谱,可以按照以下步骤进行: 1. 首先,将音频信号加载到MATLAB中。你可以使用`audioread`函数来读取音频文件或直接使用已有的音频信号。 2. 将音频信号通过短时傅里叶变换(STFT)转换为时频表示。你可以使用`spectrogram`函数来实现这一步骤。 ```matlab [s, fs] = audioread('your_audio_file.wav'); % 读取音频文件,s为音频信号,fs为采样率 window = hamming(window_length); % 定义窗函数,例如汉明窗 noverlap = window_length - hop_size; % 计算重叠的样本数 [S, f, t] = spectrogram(s, window, noverlap, NFFT, fs); % 进行短时傅里叶变换 ``` 其中,`window_length`是窗口的长度,`hop_size`是帧移的样本数,`NFFT`是FFT的点数。 3. 计算梅尔滤波器组的中心频率。你可以使用以下代码计算梅尔滤波器组的中心频率: ```matlab num_filters = 26; % 梅尔滤波器的数量 f_min = 0; % 最低频率 f_max = fs/2; % 最高频率 mel_min = hz2mel(f_min); % 将最低频率转换为梅尔频率 mel_max = hz2mel(f_max); % 将最高频率转换为梅尔频率 mel_centers = linspace(mel_min, mel_max, num_filters+2); % 在梅尔频率上均匀分布滤波器中心 ``` 其中,`hz2mel`是将赫兹频率转换为梅尔频率的函数。 4. 将频谱转换为梅尔频谱。你可以使用以下代码将频谱转换为梅尔频谱: ```matlab mel_filters = melFilterBank(fs, NFFT, mel_centers); % 计算梅尔滤波器组 mel_spectrum = mel_filters * abs(S); % 将频谱乘以梅尔滤波器组 ``` 其中,`melFilterBank`是一个自定义函数,用于计算梅尔滤波器组。 5. 绘制梅尔频谱。你可以使用以下代码绘制梅尔频谱: ```matlab figure; imagesc(t, mel_centers, 10*log10(mel_spectrum)); % 绘制梅尔频谱 axis xy; % 设置y轴方向为正方向 xlabel('时间(秒)'); ylabel('梅尔频率(Hz)'); colorbar; % 添加颜色条 ``` 这样,你就可以在MATLAB中绘制出梅尔频谱了。注意,上述代码中的函数和变量名仅供参考,具体实现需要根据你的需求进行调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值