首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用kissFFT计算峰值?

如何使用kissFFT计算峰值?
EN

Stack Overflow用户
提问于 2013-06-05 07:37:01
回答 2查看 2.2K关注 0票数 1

我想把FFT应用到真正的音频设备上,并计算出它的峰值。

这是我的密码。

代码语言:javascript
复制
    N=8192
    kiss_fft_cpx out[N/2 +1];

    int len = fft->N / 2 + 1;

    kiss_fft_scalar* samples = &samples2[0]; //inputs from the mic

    kiss_fftr(fft->config, samples, out);

    for (int i = 0; i < len; i++) {

        float re = scale(out[i].r) * N;
        float im = scale(out[i].i) * N;

        if (i > 0)
            spectrum[i] = sqrtf(re * re + im * im) / (N / 2);
        else
            spectrum[i] = sqrtf(re * re + im * im) / N;

    }

现在,我使用代码计算挑选。但是每次它返回0

代码语言:javascript
复制
float peak = 0;
float maxEnergy = 0;
for (int i = 0; i < BUFFER_SIZE / 2 + 1; i++) {

    float binEnergy = spectrum.at(i);

    if (binEnergy > maxEnergy) {

        maxEnergy = binEnergy;
        peak = i;

    }

}

在这里,我总是得到peak=0。请帮帮忙

以下是我对前25个FFT样本的频谱输出:

代码语言:javascript
复制
 06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[0]: 0.036530
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[1]: 0.011568
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[2]: 0.012086
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[3]: 0.011568
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[4]: 0.040397
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[5]: 0.011568
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[6]: 0.012086
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[7]: 0.011568
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[8]: 0.044121
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[9]: 0.011568
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[10]: 0.012086
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[11]: 0.011568
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[12]: 0.040396
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[13]: 0.011568
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[14]: 0.012086
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[15]: 0.011568
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[16]: 0.116464
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[17]: 0.011568
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[18]: 0.012086
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[19]: 0.011568
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[20]: 0.040397
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[21]: 0.011568
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[22]: 0.012086
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[23]: 0.011568
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[24]: 0.044121
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(267) > peak   2223.000000
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(270) > FREQUENCY   4342.773438
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(281) > octave 8
EN

回答 2

Stack Overflow用户

发布于 2013-06-05 07:39:01

我怀疑你(a)没有在快速傅立叶变换之前应用合适的窗口函数和/或(b)你有一个大的直流分量。这将导致一个很大,可能是涂抹(由于光谱泄漏)峰值在0赫兹。您可以通过打印/绘制光谱阵列来验证这一点。

为补救这一问题:

  • 在快速傅立叶变换之前应用合适的窗口函数(例如汉恩)
  • 更改峰值查找循环,使其开始于bin 0以上的某个位置。 const int PEAK_MIN = BUFFER_SIZE / 1024; for (int i = PEAK_MIN; i < BUFFER_SIZE / 2 + 1; i++) { ...
票数 2
EN

Stack Overflow用户

发布于 2013-06-06 10:12:36

有一个相当简单,但计算密集的方法来做基音检测使用自相关方法。我不明白为什么它也不适用于吉他!然而,当有一个以上的基本频率时,这将是一场斗争。不过,我不知道有一种算法能处理这个问题。

你需要采取足够的样本,以涵盖至少3个音高周期。然后,将信号进行自相关(自相关可以有效地实现用FFT执行)。

如果你有你的自相关信号,你会在滞后0时找到最大的峰值。第二高峰应该是你的投球。

在自相关之前,使用类似hamming窗口的方法对输入信号进行加窗,可以得到更好的结果。

更有甚者,普拉特名声的保罗·波尔斯玛( Paul )提出了一个“远更精确的基音检测方法”( far 更精确的基音检测方法)。

基本上是用他的计划。您可以使用窗口函数的自相关,然后存储以供以后使用。接下来,你要打开输入信号。自动关联那个信号。现在除以窗口函数的自相关。最后,选择最高的峰值和偏移从滞后0是样本的数目,以您的基音检测。

值得注意的是,您确实需要插值自相关峰值才能得到最佳结果。就我个人而言,我使用了抛物线插值,我获得的精度提高是巨大的。抛物线插值非常容易:

代码语言:javascript
复制
void ParabolicInterpolation( const float kA, const float kB, const float kC, float& p, float& m )
{
    p   = 0.5f * ((kA - kC) / (kA - (2.0f * kB) + kC));
    m   = (0.25f * (kA - kC) * p);
}

其中,kB是您识别的自相关峰值,kA是它之前的自相关样本,kC是之后的样本。

编辑:,如果不需要这种精度,上面的方法提供了另一种非常简单的计算基频的方法,叫做谐波乘积谱(检查此演示文稿的开头。)。基本上你从FFT开始。你把它转换成星等光谱。最后,将其降为2x、3x和4x。然后你把样本相乘。最大的峰值将由你的基本频率。然而,这是严重限制您的FFT分辨率。

希望这能帮上忙!

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16934097

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档