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

How to generate and concatenate spectrograms efficiently

我正在处理与信号处理相关的问题。我有一个包含 >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 个小时。

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

正如其他人所说,通过 matplotlib 的开销可能会减慢速度。最好只计算(而不是绘制)频谱图 scipy.signal.spectrogram. This function directly returns the spectrogram as a 2D numpy array, so that you don't have the roundabout step of getting it out of the canvas. Note, that does mean you'll have to map the spectrogram output yourself to pixel intensities. In doing that, beware scipy.signal.spectrogram returns the spectrogram as powers, not decibels, so you probably want to do 10*np.log10(Sxx) to the result (see also 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).