result=librosa.feature.mfcc(signal, 16000, n_mfcc=13, n_fft=2048, hop_length=400)
result.shape()
该信号为1秒长,采样率为16000,我计算了13个具有400跳长的MFCC。输出维度为(13,41)
。为什么我得到41帧,不是应该是(time*sr/hop_length)=40
吗?
TL;DR回答
是的,它是正确的。
答案很长
您使用时间序列作为输入(signal
(,这意味着librosa首先使用melspectrogram函数计算melspectrogram。它需要一堆参数,其中您已经指定了一个(n_fft
(。需要注意的是,熔谱图还提供了两个参数center
和pad_mode
,默认值分别为True
和"reflect"
。
来自文档:
pad_mode:string:如果center=True,则在信号边缘使用填充模式。默认情况下,STFT使用反射填充。
center:boolean:如果为True,则填充信号y,使帧t以y[t*hop_length]为中心。如果为False,则帧t开始于y[t*hop_length]
换句话说,默认情况下,librosa会使信号更长(焊盘(,以支持居中。
如果您想避免这种行为,您应该将center=False
传递给您的mfcc
调用。
也就是说,当将center
设置为False
时,请记住,如果n_fft
长度为2048,跳变长度为400
,则不一定会得到(time*sr/hop_length)=40
帧,因为您还必须考虑窗口,而不仅仅是跳变长度(除非您以某种方式填充(。跳跃长度只是通过移动该窗口的样本数量来指定。
举一个极端的例子,考虑一个非常大的窗口和非常短的跳跃长度:假设10个样本(例如time=1s
、sr=10Hz
(,窗口长度为n_fft=9
,hop_length=1
具有center=False
。现在想象一下在10个样本上滑动窗口。
◼︎◼︎◼︎◼︎◼︎◼︎◼︎◼︎◼︎◻︎
◻︎◼︎◼︎◼︎◼︎◼︎◼︎◼︎◼︎◼︎
t 0123456789
◻︎ sample not covered by window
◼︎ sample covered by window
首先,窗口在t=0
处开始并且在t=8
处结束。我们可以通过hop_length
将其移位多少次,并且仍然期望它不会耗尽样本?正好一次,直到它从t=1
开始并在t=9
结束。加上第一个未移位的帧,得到2帧。这与不正确的CCD_ 26明显不同。
正确的是:(time*sr-n_fft)//hop_length+1=(1*10-9)//1+1=2
和//
表示Python风格的整数除法。
当使用默认值,即center=True
时,信号两端都填充了n_fft // 2
样本,因此n_fft
不在等式中。