如何使用傅里叶变换从WAV文件中提取半精确频率

时间:2010-05-21 11:25:30

标签: c audio wav signal-processing fftw

我们说我有一个WAV文件。在此文件中,是精确1秒间隔的一系列正弦音。我想使用FFTW库按顺序提取这些音调。这特别难吗?我该怎么做呢?

另外,将这种音调写入WAV文件的最佳方法是什么?我假设我只需要一个简单的音频库来输出。

我选择的语言是C

3 个答案:

答案 0 :(得分:22)

获取文件某部分的power spectrum

  • 收集N个样本,其中N是2的幂 - 如果你的采样率是44.1 kHz,你想要大约每秒采样一次,那就去说N = 32768个样本。

  • 对样本应用合适的window function,例如Hanning

  • 将窗口样本传递给FFT例程 - 理想情况下,您需要一个真实到复数的FFT,但如果你只有一个是复数到复数的FFT,则为所有虚拟输入传递0份

  • 计算FFT输出区的平方幅度(re * re + im * im)

  • (可选)计算每个幅度平方输出箱的10 * log10,以获得dB

    中的幅度值

现在您拥有了功率谱,您只需要确定峰值,如果您有合理的信噪比,这应该非常简单。请注意,频率分辨率随着N的增大而提高。对于上述44.1 kHz采样率和N = 32768的示例,每个箱的频率分辨率为44100/32768 = 1.35 Hz。

答案 1 :(得分:3)

你基本上对estimating a Spectrum感兴趣 - 假设你已经经历了阅读WAV并将其转换为离散时间信号的阶段。

在各种方法中,最基本的是周期图,相当于采用窗口离散傅立叶变换(带FFT)并保持其平方幅度。这符合保罗的答案。您需要一个窗口,该窗口跨越您想要检测的最低频率的几个周期。例如:如果你的正弦曲线可以低至10赫兹(周期= 100毫秒),你应该在200毫秒到300毫秒左右(或更长)的窗口。但是,周期图有一些disadvantages,虽然它很容易计算,如果不需要高精度,它就足够了:

  

原始周期图并不好   由于光谱的光谱估计   偏见和方差的事实   在给定频率下不会减少   作为使用的样本数量   计算量增加。

通过平均几个窗口,可以更好地选择周期图,并明智地选择宽度(Bartlet method)。还有许多其他估算频谱的方法(AR建模)。

实际上,您并不完全对估计全频谱感兴趣,而只对单一频率的位置感兴趣。这可以通过寻找估计频谱的峰值(如所解释的那样)来完成,但也可以通过更具体和更强大(和复杂)methods(Pisarenko,MUSIC算法)来完成。在你的情况下,他们可能会有点矫枉过正。

答案 2 :(得分:2)

WAV文件包含linear pulse code modulated (LPCM)个数据。这只意味着它是固定采样率的一系列振幅值。文件开头包含RIFF header,以传达sampling rate等信息和每个样本的比特(例如8 kHz带符号的16位)。

格式非常简单,您可以轻松自己动手。但是,有几个库可用于加速此过程,例如libsndfileSimple Direct-media Layer (SDL) / SDL_mixerPortAudio是两个很好的播放库。

至于将数据馈送到FFTW,您需要缓冲1秒的块(通过采样率和每个样本的位确定大小)。然后将所有样本转换为IEEE浮点(即floatdouble,具体取决于FFTW配置 - libsndfile可以为您执行此操作)。接下来创建另一个数组来保存频域输出。最后,通过将两个缓冲区传递到fftw_plan_dft_r2c_1d并调用fftw_execute with the returned fftw_plan handle来创建并执行FFTW计划。