我正在尝试使用FFT将音频数据的频谱显示为条形图。
如果我有440 Hz且采样率为44100 Hz的正弦波数据并分析其前 1024 个样本,我将得到一个具有 1024 个 FFT 值的数组。我知道这些值的前半部分(512)表示频率范围等于采样率的一半(22050 Hz)。
因此,要绘制条形图,我只需从 FFT 数组中获取前 15-20 个值,计算每个元素的频率范围并绘制它。
- 在 FFT 大小为1024 I 的情况下,每个频率约为 43 Hz宽。
- 但是,如果我将 FFT 大小更改为2048 ,则每个频率范围都是~21.5 Hz。所以正弦波频谱的峰值将在我的 15-20 条之外。
所以我想问一下是否可以针对频率范围和恒定图形条数对X 轴进行缩放/归一化?
限制数据的示例是:
- 频率范围 0-500 Hz
- 图表上有 16 个条形图
我想这是某种箱/幅度分组。但是我应该对它们求和还是得到最大值?当分组的 bin 编号不是整数时,可以用幅度做什么?(我希望我的解释不会太混乱,很难选择正确的术语)
谢谢。
这是我在Python中的测试代码:(
我使用了int
从另一个文件导入的静态数组,该数组表示正弦波)
import scipy.io.wavfile as wavfile
import scipy
import scipy.fftpack
import numpy as np
from scipy.signal.windows import *
from matplotlib import pyplot as plt
from imp.sine_440_hex import *
def run():
# fp = 'e:/sine_440_hz.wav'
# FS, data = wavfile.read(fp)
# data - array of int for a sine wave at 440Hz and amplitude 0.5
DS = len(data)
FS = 44100
FN = 1024
# FN = 2048
MAXS = 32768
MN = 15 # number of first frequencies in the FFT result
ndata = np.array(data)
ndata = ndata / MAXS
w = np.hamming(FN)
y = ndata[:FN] * w
freqs = scipy.fftpack.fftfreq(FN, 1/FS)
mags = abs(scipy.fft(y))
dbfs = 20 * np.log10(mags * 2 / np.sum(w))
dbs = dbfs + 120
# -------- plot --------
fr_res = freqs[:MN]
db_res = dbs[:MN]
ax1 = plt.subplot(211)
plt.plot(fr_res, db_res)
plt.grid(True)
plt.xlabel('Frequency [Hz]')
plt.ylabel('Amplitude [dB]')
ax2 = plt.subplot(212)
plt.bar(fr_res, db_res, fr_res[1]-10)
plt.grid(True)
ax2.set_ylim([80, 120])
ax2.set_xticks(fr_res)
ax2.set_xticklabels(fr_res.astype(int))
plt.show()
# -------
run()
示例图: