scipy.signal.spectrogram与matplotlib.pyplot.specgram的比较

15
以下代码使用scipy.signal.spectrogrammatplotlib.pyplot.specgram生成谱图。
但是specgram函数的颜色对比度相当低。有没有办法增加它?
import numpy as np
from scipy import signal
import matplotlib.pyplot as plt

# Generate data
fs = 10e3
N = 5e4
amp = 4 * np.sqrt(2)
noise_power = 0.01 * fs / 2
time = np.arange(N) / float(fs)
mod = 800*np.cos(2*np.pi*0.2*time)
carrier = amp * np.sin(2*np.pi*time + mod)
noise = np.random.normal(scale=np.sqrt(noise_power), size=time.shape)
noise *= np.exp(-time/5)
x = carrier + noise

使用matplotlib.pyplot.specgram会得到以下结果:
Pxx, freqs, bins, im = plt.specgram(x, NFFT=1028, Fs=fs)
x1, x2, y1, y2 = plt.axis()
plt.axis((x1, x2, 0, 200))
plt.show()

使用matplotlib.pyplot.specgram获得的图像

使用scipy.signal.spectrogram函数生成了如下图所示的绘图结果

f, t, Sxx = signal.spectrogram(x, fs, nfft=1028)
plt.pcolormesh(t, f[0:20], Sxx[0:20])
plt.ylabel('Frequency [Hz]')
plt.xlabel('Time [sec]')
plt.show()

使用scipy.signal.spectrogram获得的图像

这两个函数似乎都使用了“jet”色彩映射。

我也对这两个函数之间的区别感到普遍的兴趣。尽管它们执行类似的操作,但显然它们并不相同。


如果问题中有一张图片,并且对其进行描述和评论,那将极大地帮助,这样人们就能理解所需和不需要的内容。 - ImportanceOfBeingErnest
这个对你有帮助吗?链接 - Thomas Kühn
感谢您的评论,这些评论帮助我更好地说明和指定了问题。正如您在图像中所看到的,matplotlib.pyplot.specgram 的背景主要是温暖的颜色(黄色),而 scipy.signal.spectrogram 的背景则是相对冷色调的颜色(蓝色)。我想在 matplotlib 的 specgram 绘图中实现 scipy 所选择的颜色。 - NicolasBourbaki
1
我本来想回答这个问题,但是后来看到了这个问题的答案(顺便说一下,这是一个重复的问题),那个人应该直接放下麦克风:https://dev59.com/05Hea4cB1Zd3GeqPutZe - eric
2个回答

16
plt.specgram 不仅返回 Pxx, f, t,还会自动为您绘制图形。在绘制时,plt.specgram 会绘制 10*np.log10(Pxx) 而不是 Pxx
然而,signal.spectrogram 只返回 Pxx, f, t,不进行绘图。这就是为什么要使用 plt.pcolormesh(t, f[0:20], Sxx[0:20])。您可能想要绘制 10*np.log10(Sxx)

NB:matplotlib 和 scipy 之间的两个附加差异:(1)默认窗口;(2)默认去趋势。 很快会发布代码。 - eldad-a

2
关于问题生成的数据,发现Scipy(v 1.7.3)和Matplotlib(v 3.5.1)的输出有三个主要差异:
  1. 默认窗口:#scipy-signal-windows-tukey vs #matplotlib.mlab.window_hanning
  2. 去趋势:scp "默认为 'constant'";mpl "默认值为 'none' "
  3. @Sizhuang Liang之前的答案所述:mpl在dB中绘制Pxx

根据问题中提供的代码,将Scipy的输出与Matplotlib的输出进行匹配:

仅仅是为了展示一种匹配输出的方式,而不是声称matplotlib的默认设置比scipy更好。
import numpy as np
from scipy import signal
import matplotlib.pyplot as plt

# Generate data
fs = 10e3
N = 5e4
amp = 4 * np.sqrt(2)
noise_power = 0.01 * fs / 2
time = np.arange(N) / float(fs)
mod = 800*np.cos(2*np.pi*0.2*time)
carrier = amp * np.sin(2*np.pi*time + mod)
noise = np.random.normal(scale=np.sqrt(noise_power), size=time.shape)
noise *= np.exp(-time/5)
x = carrier + noise

# matplotlib

NFFT=1028
Pxx, freqs, bins, im = plt.specgram(x, NFFT=NFFT, Fs=fs)
plt.axis((None, None, 0, 200))
plt.show()

plt.specgram

## matching scipy.__version__ == '1.7.3' to  matplotlib.__version__ == '3.5.1'

mpl_specgram_window = plt.mlab.window_hanning(np.ones(NFFT))
f, t, Sxx = signal.spectrogram(x, fs, detrend=False,
                               nfft=NFFT, 
                               window=mpl_specgram_window, 
                              )

assert np.allclose(Sxx,Pxx), 'outputs aren't close')
plt.pcolormesh(t, f, 10*np.log10(Sxx))
plt.axis((None, None, 0, 200))
plt.ylabel('Frequency [Hz]')
plt.xlabel('Time [sec]')
plt.show()

scipy.signal.spectrogram

Sxx_to_Pxx_dB = 10*np.log10(Sxx/Pxx)
print(f'Largest difference (ratio in dB) : {np.abs(Sxx_to_Pxx_dB).max():4.3G}')

最大差异(以分贝为单位的比率):5.11E-12

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