如何有效地生成和连接频谱图

Posted

技术标签:

【中文标题】如何有效地生成和连接频谱图【英文标题】:How to generate and concatenate spectrograms efficiently 【发布时间】:2021-04-03 05:41:02 【问题描述】:

我正在研究与信号处理相关的问题。我有一个超过 2000 个 EEG 信号的数据集。每个 EEG 信号由一个 2D Numpy 数组 (19 x 30000) 表示。阵列的每一行都是信号的通道之一。我要做的是在这些单独的通道(行)上找到频谱图并将它们垂直连接起来。这是我目前写的代码。

raw = np.load('class_1_ar/'+filename)

images = []

for i in range(19):    
    print(i,end=" ")
    spec,freq,t,im = plt.specgram(raw[i],Fs=100,NFFT=100,noverlap=50)
    plt.axis('off')
    figure = plt.gcf()
    figure.set_size_inches(12, 1)

    figure.canvas.draw()
    img = np.array(figure.canvas.buffer_rgba())
    img = cv2.cvtColor(img, cv2.COLOR_RGBA2BGRA)

    b = figure.axes[0].get_window_extent()
    img = np.array(figure.canvas.buffer_rgba())
    img = img[int(b.y0):int(b.y1),int(b.x0):int(b.x1),:]
    img = cv2.cvtColor(img, cv2.COLOR_RGBA2BGRA)
    
    images.append(img)

base = cv2.vconcat(images)
cv2.imwrite('class_1_sp/'+filename[:-4]+'.png',base)


c -= 1
print(c)

这是我的输出:

但是,该过程需要花费太多时间来处理。前 200 个样本的处理耗时近 8 小时。

我的问题是,我该怎么做才能让它更快?

【问题讨论】:

您是否分析了您的代码以查看哪个部分花费的时间最多?看起来你绘制了一个频谱图,然后从屏幕上抓取图像?这似乎是一种相当迂回的做事方式...... 假设每个 EEG 的生成相互独立,您可以使用 Python 多处理并行化您的代码。此外,正如 Cris Luengo 所指出的,可能有一种更快的方法将数字存储到 Numpy 数组中。此外,请注意 matplotlib 通常很慢。可能有更快的软件包可以做到这一点(请看一下 scipy)。 谢谢。并行化它起作用了。现在速度更快了 【参考方案1】:

正如其他人所说,通过 matplotlib 的开销可能会减慢速度。最好用scipy.signal.spectrogram 计算(而不是绘制)频谱图。此函数直接将频谱图作为 2D numpy 数组返回,因此您无需将其从画布中取出。请注意,这确实意味着您必须自己将频谱图输出映射到像素强度。在此过程中,请注意 scipy.signal.spectrogram 将频谱图返回为功率,而不是分贝,因此您可能希望对结果执行 10*np.log10(Sxx)(另请参阅 scipy.signal.spectrogram compared to matplotlib.pyplot.specgram)。

撇开绘图不谈,计算频谱图的瓶颈操作是 FFT。不是使用 100 个样本的变换大小,而是 128 或 2 的某个其他幂更有效。对于scipy.signal.spectrogram,这是通过设置nfft=128 来完成的。请注意,您可以设置 nperseg=100nfft=128 以便每个段仍使用 100 个样本,但在执行 FFT 之前将零填充到 128。另一种想法:如果 raw 是 64 位浮点数,则将其转换为 32 位可能会有所帮助:raw = np.load(...).astype(np.float32)

【讨论】:

以上是关于如何有效地生成和连接频谱图的主要内容,如果未能解决你的问题,请参考以下文章

如何在频谱图Python中找到峰值[重复]

FFmpeg:流式音频播放列表,标准化响度并生成频谱图和波形

关于用MATLAB设计确定信号的频谱分析和滤波

如何从傅里叶输出中生成详细的频谱图?

了解音频文件频谱图值

matlab如何作出信号频谱图?