使用对数频率轴的Scipy谱图?

5
使用scipy.signal.spectrogram进行玩耍。对于它的用途来说效果很好。
from scipy.io import wavfile
from scipy import signal
import numpy as np
import matplotlib.pyplot as plt

sf, audio = wavfile.read('serious.wav')
sig = np.mean(audio, axis=1)
f, t, Sxx = signal.spectrogram(sig, sf, scaling='spectrum')

plt.pcolormesh(t, f, np.log10(Sxx))
plt.ylabel('f [Hz]')
plt.xlabel('t [sec]')
plt.show()

这是结果:

spectrogram

但频率轴是线性的。对于音频来说,这通常不是理想的 - 至少不是我想要的。
有没有办法让scipy.signal.spectrogram输出对数频率刻度?
如果scipy无法实现这一点,您能否推荐一个同样简单的方法来获得这个结果?
编辑:问题不在于图像的显示方式。问题在于signal.spectrogram()生成数据的方式。
我已经将代码更改为:
plt.pcolormesh(t, f, np.log10(Sxx))
plt.ylabel('f [Hz]')
plt.xlabel('t [sec]')
plt.yscale('log')
plt.savefig('spec.png')
plt.show()

现在图像看起来是这样的:

spectrogram

f向量(由signal.spectrogram()生成)长成这个样子:
array([    0.      ,   172.265625,   344.53125 ,   516.796875,
         689.0625  ,   861.328125,  1033.59375 ,  1205.859375,
        1378.125   ,  1550.390625,  1722.65625 ,  1894.921875,
        2067.1875  ,  2239.453125,  2411.71875 ,  2583.984375,
...
       19982.8125  , 20155.078125, 20327.34375 , 20499.609375,
       20671.875   , 20844.140625, 21016.40625 , 21188.671875,
       21360.9375  , 21533.203125, 21705.46875 , 21877.734375,
       22050.      ])

这是线性分布。我需要更多的点在底部,而在顶部则需要更少的点。

3
这与scipy无关,而是与你如何使用matplotlib进行绘图有关。我认为在pcolormesh之后设置plt.xscale('log')应该可以解决你的问题。 - alkasm
@alkasm,问题不在于图像的显示方式。问题在于signal.spectrogram()所生成的数据的方式。我做了一个编辑以说明这个问题。 - Florin Andrei
明白了,你想要非线性采样。如果在底部有更多的采样点,这真的很重要吗?也就是说,如果你对高端进行足够的采样,那么你不可以随着频率降低而丢弃一些采样点(或者干脆不丢弃,用更密集的采样来绘制)。或者由于某些原因,这样做还不够? - alkasm
2
你可能想要通过 plt.ylim(100, 22050) 来调整图形的频率限制。 - SleuthEye
@alkasm,我已经找到了问题并发布了答案。谢谢! - Florin Andrei
@SleuthEye 这是其中的一部分,没错。但实际问题是 - 我一开始没有足够的频率样本。增加这个数量解决了问题。请看我下面发布的答案。 - Florin Andrei
1个回答

3
我已经找到了问题所在。FFT是线性的,而我的图像是对数的。在频率谱的较低部分,默认的频率间隔太大了。
因此,我只需通过 nperseg 参数增加频率样本数量即可。在这个例子中,连续频率之间的距离为1 Hz,这是相当好的分辨率。此外,对数比例尺最好。
npts = int(sf)
f, t, Sxx = signal.spectrogram(sig, sf, nperseg=npts)
plt.yscale('symlog')

当然,在频率范围的顶部有太多的频率,因此必须在f和Sxx数组中进行修剪(尺寸必须匹配,因此以相同方式修剪它们)。此外,显示频率范围必须限制在10-20000或一些合理的值内。所有这些优化都超出了本答案的范围。
但我将脚本带到可以使用的地步,并将其放在GitHub上:

https://github.com/FlorinAndrei/soundspec

这是一个工作中的频谱图示例:

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接