numpy.rfft 波形文件的频谱分析仪

spectrum analyzer of wave files with numpy.rfft

我正在编写一个脚本来处理 Python 中的波形文件并显示频谱分析仪,只是为了音频文件的良好可视化。在阅读了文档和论坛之后,我认为我需要使用 rfft。

我正在处理 2048 个值的样本,在 rfft 的输出中创建 1024 个波段。问题是,为了满足我的需要,我需要将频段数量大幅减少到 12 个频段(1 个八度音阶)。由于我正在处理音频文件并且频段数量有限,我想知道是否有一种聪明的方法来对频率进行分组,以便 90% 的歌曲看起来不错,低音节拍在最左边,高音节拍 voices/shouts/notes 在最右边。

有了下面这个初步代码,我有更多我需要的频段,但大多数峰值都集中在大多数歌曲的低频中,除了从 20 到 20k 的测试范围。有了这个范围,我也意识到音高越高,振幅越低。

def fft(self, sample_range):
    # sample_range is a sample of 2048 ints read from the self.file wave file
    fft_data = abs(numpy.fft.rfft(sample_range)) # real fft gives samplewidth/2 bands
    fft_freq = numpy.fft.rfftfreq(len(sample_range))
    freq_hz = [abs(fft_freq[i])*self.file.getframerate() for i, fft in enumerate(fft_data)]

    print len(zip(freq_hz, fft_data)), len(freq_hz), len(fft_data), zip(freq_hz, fft_data)

这是第一个斜坡样本 (~20Hz) 的打印输出:

1025 1025 1025 [(0.0, 1850501.0), (21.533203125, 2779524.1730200453), (43.06640625, 15469093.29481476), ... (22028.466796875, 3538.1225240980043), (22050.0, 3553.0)]

所以我的问题是:

编辑:我现在使用我为任意数量的波段生成的参考对数标度对 fft 频率求和:

In [22]: num_bands = 10
In [23]: [44100*2**(b-num_bands) for b in range(num_bands)]
Out[23]: [43.06640625,  86.1328125,  172.265625,  344.53125,  689.0625,  1378.125,  2756.25,  5512.5,  11025.0,  22050.0]

In [24]: num_bands = 12
In [25]: [44100*2**(b-num_bands) for b in range(num_bands)]
Out[25]: [10.7666015625,  21.533203125,  43.06640625,  86.1328125,  172.265625,  344.53125,  689.0625,  1378.125,  2756.25,  5512.5,  11025.0,  22050.0]

我将这些用作每个频段的最大频率。它一直有效到 num_bands = 10 最大值。从 11 开始,我开始听到超出可听范围的非常低的频率。有什么比这更好地缩小范围的想法吗?在任何情况下,第一个频段的最大频率应至少为 40 Hz。

是的,频谱显示经常转换为 dB(或其他对数刻度)。

减少频带数量的最简单方法是将相邻的 FFT 结果 bin 按每个八度音阶(或每半个或第 12 个八度音阶等)的组添加在一起,最高频率和最低频率之间的比率大致相等,表示为每个频段或一组 FFT 结果箱。使比例大小的组足够大或足够小,以便最终获得所需的总条带数。