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)]
所以我的问题是:
我是否在上面的代码中做了一些我不应该做的事情? =)
大多数音乐播放器中的频谱分析仪通常代表什么单位,范围是多少?我应该将振幅转换为 dB 吗?
有没有简单的方法可以将波段数减少到12个?我猜带宽与间距成指数关系?我会说我需要手动实现这个指数和。
编辑:我现在使用我为任意数量的波段生成的参考对数标度对 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 结果箱。使比例大小的组足够大或足够小,以便最终获得所需的总条带数。
我正在编写一个脚本来处理 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)]
所以我的问题是:
我是否在上面的代码中做了一些我不应该做的事情? =)
大多数音乐播放器中的频谱分析仪通常代表什么单位,范围是多少?我应该将振幅转换为 dB 吗?
有没有简单的方法可以将波段数减少到12个?我猜带宽与间距成指数关系?我会说我需要手动实现这个指数和。
编辑:我现在使用我为任意数量的波段生成的参考对数标度对 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 结果箱。使比例大小的组足够大或足够小,以便最终获得所需的总条带数。