Python中基于多FFT生成频谱图:现有代码结果不符预期
问题分析与解决方案
我明白你的问题所在了——你用错工具啦!scipy.signal.spectrogram是用来处理原始时域信号的,它会把时域信号切成多个小段,每个小段做FFT,最终生成时频图(X轴时间、Y轴频率、颜色对应功率)。但你输入的已经是单份FFT频域数据,用这个函数相当于把FFT结果当成时域信号再做一次分帧FFT,结果自然和你想要的完全不符。
你想要的是:一条水平的色块条(对应单个时间点的FFT结果),Y轴表示频率,每个位置的颜色对应该频率点的FFT数值。那直接可视化你的FFT数据就行,完全不需要用spectrogram。
正确实现代码
下面是适配你需求的完整示例,假设你的data是2048点的FFT结果(幅度谱或功率谱均可):
import numpy as np import matplotlib.pyplot as plt # 替换成你的实际FFT数据 data = np.random.rand(2048) # 模拟2048个浮点数的FFT结果 Fs = 2048 # 采样率,和你原代码保持一致 # 生成频率轴:默认用单边频谱(0到Fs/2),适合大多数场景 n = len(data) f = np.linspace(0, Fs/2, n//2 + 1) # 如果你的FFT是包含负频率的双边谱,替换成这行: # f = np.fft.fftfreq(n, 1/Fs) # 把一维FFT数据转成2D数组(pcolormesh要求输入为二维) # 时间轴只保留一个点,对应单份FFT的时刻 Sxx = data[:len(f)].reshape(1, -1) # 取单边频谱部分,转成(1, 频率点数)格式 t = [0] # 单个时间点标记 # 绘制水平颜色条 plt.pcolormesh(t, f, Sxx.T, shading='auto') # 转置Sxx让频率对应Y轴 plt.ylabel('Frequency (Hz)') plt.xlabel('Time') plt.title('Single FFT Spectrum as Horizontal Color Bar') plt.colorbar(label='FFT Value') plt.xticks(t) # 只显示单个时间点刻度 plt.show()
关键细节说明
- 频率轴适配:如果你的FFT是双边谱(包含负频率),直接用
np.fft.fftfreq生成完整频率轴,同时去掉data[:len(f)]的截取操作;如果是单边谱(仅保留正频率),用np.linspace生成0到Fs/2的频率点即可。 - 二维数组转换:
pcolormesh要求输入二维数据,我们把一维FFT转成(1, N)的二维格式,这样绘制出来就是对应单个时间点的水平色块条。 - 转置操作:
Sxx.T是为了让频率对应Y轴、时间对应X轴,符合你的可视化需求。
如果你的FFT数据是4096点,只需要修改len(data)的对应值、调整采样率Fs即可,代码逻辑完全通用。
内容的提问来源于stack exchange,提问作者massem




