使用 EZAudio 从 FFT 获得更精确的频率?

Posted

技术标签:

【中文标题】使用 EZAudio 从 FFT 获得更精确的频率?【英文标题】:More precise frequency from FFT with EZAudio? 【发布时间】:2018-01-03 18:14:39 【问题描述】:

我已经用 Audacity 在不同的频率下生成了一些纯正弦音来进行测试。我看到的问题是代码为两个值相对接近的不同正弦音返回相同的频率。

例如:在 19255Hz 生成的正弦音将从 FFT 显示为 19293.750000Hz。以 19330Hz 生成的正弦音也是如此。

低频和高频存在同样的问题...例如 93hz 将从 FFT 中显示为 96.899414hz

计算中必须有一些东西。缓冲区大小为 4096。

对于如何修改上述代码以获得更精确的纯正弦音 FFT 频率读数的任何帮助,我们将不胜感激。谢谢!

//
// Initialize FFT
//
float maximumBufferSizeBytes = self.maximumBufferSize * sizeof(float);
self.info = (EZAudioFFTInfo *)calloc(1, sizeof(EZAudioFFTInfo));
vDSP_Length log2n = log2f(self.maximumBufferSize);
self.info->fftSetup = vDSP_create_fftsetup(log2n, FFT_RADIX2);
long nOver2 = maximumBufferSizeBytes / 2;
size_t maximumSizePerComponentBytes = nOver2 * sizeof(float);
self.info->complexA.realp = (float *)malloc(maximumSizePerComponentBytes);
self.info->complexA.imagp = (float *)malloc(maximumSizePerComponentBytes);
self.info->outFFTData = (float *)malloc(maximumSizePerComponentBytes);
memset(self.info->outFFTData, 0, maximumSizePerComponentBytes);
self.info->inversedFFTData = (float *)malloc(maximumSizePerComponentBytes);

//
// Calculate real + imaginary components and normalize
//
vDSP_Length log2n = log2f(bufferSize);
long nOver2 = bufferSize / 2;
float mFFTNormFactor = 10.0 / (2 * bufferSize);
vDSP_ctoz((COMPLEX*)buffer, 2, &(self.info->complexA), 1, nOver2);
vDSP_fft_zrip(self.info->fftSetup, &(self.info->complexA), 1, log2n, FFT_FORWARD);
vDSP_vsmul(self.info->complexA.realp, 1, &mFFTNormFactor, self.info->complexA.realp, 1, nOver2);
vDSP_vsmul(self.info->complexA.imagp, 1, &mFFTNormFactor, self.info->complexA.imagp, 1, nOver2);
vDSP_zvmags(&(self.info->complexA), 1, self.info->outFFTData, 1, nOver2);
vDSP_fft_zrip(self.info->fftSetup, &(self.info->complexA), 1, log2n, FFT_INVERSE);
vDSP_ztoc(&(self.info->complexA), 1, (COMPLEX *) self.info->inversedFFTData , 2, nOver2);
self.info->outFFTDataLength = nOver2;

//
// Calculate max freq
//
if (self.sampleRate > 0.0f)

    vDSP_maxvi(self.info->outFFTData, 1, &self.info->maxFrequencyMangitude, &self.info->maxFrequencyIndex, nOver2);
   self.info->maxFrequency = [self frequencyAtIndex:self.info->maxFrequencyIndex];

    float nyquistMaxFreq = self.sampleRate / 2.0;
    NSLog(@"FREQ: %f", (((float)self.info->maxFrequencyIndex / (float)self.info->outFFTDataLength) * nyquistMaxFreq));


此处为 EZAudio 代码:https://github.com/syedhali/EZAudio/blob/master/EZAudio/EZAudioFFT.m

【问题讨论】:

“全实时频率”是什么意思? 我已经用 Audacity 在不同的频率下生成了一些纯正弦音来进行测试。我看到的问题是代码为两个值相对接近的不同正弦音返回相同的频率。例如:在 19255Hz 生成的正弦音将从 FFT 显示为 19293.750000Hz。以 19330Hz 产生的正弦音也是如此。计算中一定有什么不对劲。非常感谢我如何修改上述代码以获得更精确的纯正弦音 FFT 频率读数的任何帮助。谢谢! 执行 FFT 的缓冲区有多大?它可能太小而无法区分这些频率。 缓冲区大小为 4096...我有另一个使用 AudioKit 的示例,它可以工作,但使用 EZAudio 则不行...同样的问题与低频和高频...例如 93hz 将从 FFT 中显示如 96.899414 【参考方案1】:

您正在查看一个幅度 FFT 结果箱的频率,它将频率量化为 dF = sample_rate/N。您可以使用更大的 N(更长的 FFT)来获得更小的量化。在低噪声和低干扰的情况下,对样本数据进行零填充以允许更长的 FFT 可能有助于提高绘图分辨率。

要获得更好的频率估计,您必须使用诸如加窗 Sinc 插值之类的方法在 FFT 结果 bin 之间进行估计,加上可能的逐次逼近,以找到最接近最大幅度 FFT 结果 bin 的频谱频率峰值。

p>

【讨论】:

以上是关于使用 EZAudio 从 FFT 获得更精确的频率?的主要内容,如果未能解决你的问题,请参考以下文章

EZAudio:如何将缓冲区大小与 FFT 窗口大小分开(希望更高的频率 bin 分辨率)。

如何使用 EZAudio 在 Swift 中获取 FFT 数据?

Android:通过fft获取更精确的频率

使用帧之间的相位变化从 FFT Bins 中提取精确频率

精确的音调开始/持续时间测量?

使用 vDSP 的 FFT 频率范围