如何使用kissFFT计算峰值?
How can i calculate the peak using kissFFT?
我想在真实音频设备上应用FFT并从中计算峰值
这是我的代码。
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
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样本的频谱输出:
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
我怀疑您是(a)未能在FFT之前应用合适的窗口函数和/或(b)您有一个大的DC组件。这将导致一个大的,可能是模糊的(由于频谱泄漏)峰值在0赫兹。你可以通过打印/绘制你的频谱阵列来验证这一点。
修改:
-
在FFT之前应用合适的窗函数(例如Hann)
-
改变你的峰值查找循环,使它开始于bin 0以上的某个地方,例如
const int PEAK_MIN = BUFFER_SIZE / 1024;
for (int i = PEAK_MIN; i < BUFFER_SIZE / 2 + 1; i++) { ...
有一种相当简单但计算量很大的方法可以使用自相关方法对声音进行音高检测。我不明白为什么它不能适用于吉他!然而,当存在不止一个基频时,它就会陷入困境。然而,我不知道有什么算法可以处理这个问题。
你需要收集足够的样本来覆盖至少3个音高周期。然后,您可以自相关信号(自相关可以有效地执行FFT)。
如果你有自相关信号,你会在滞后0处发现最大的峰值。第二高峰应该是你的演讲。
通过在自相关之前使用汉明窗之类的东西对输入信号加窗,可以得到更好的结果。
Praat的Paul Boersma进一步提出了一种更准确的音高检测方法。
基本上使用他的方案。您取窗口函数的自相关,然后存储以供以后使用。接下来打开输入信号的窗口。自相关信号。现在除以窗函数的自相关。最后,选择最高的峰值,滞后0的偏移量是音调检测的样本数量。
值得注意的是,您确实需要插值自相关峰值以获得最佳结果。我个人使用抛物线插值,我获得的精度提高是巨大的。抛物线插值很容易:
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分辨率的严重限制。
希望有帮助!
- 在计算中使用二的幂有多有利可图
- 如何使用 std::累积在 C++ 中计算总和立方体
- 使用Qt C++计算类似Git的SHA1哈希
- 多个If语句与使用逻辑运算符计算条件的单个语句的比较
- 如何使用发送数据包所花费的时间计算两个节点之间的距离?
- 计算用户使用循环输入的整数数量
- 如何转换一个普通的makefile以创建可以在另一台计算机上使用的静态可执行文件
- 如何在MACOS上的C 计算中使用双AMD FirePro D300的GPU
- 在当前计算机上使用主机名
- 通过给定输出,程序计算中使用了多少个项
- 我如何使用函数来计算并使用void函数显示
- 尝试在旧计算机上使用新的LibstDC 会导致错误
- 如何计算和使用CVMAT平均值
- 在计算中使用布尔值以避免分支
- 如何编译C++项目(使用g++)以便在其他计算机上使用
- 如何在计算中使用英尺和英寸C++计算 BMI
- 在编译时间计算中使用GMP
- 在超级计算机上使用OpenMP
- 在计算中使用空指针
- 如何对接口的引用执行延迟计算(尝试使用bind)