4

我最近问了这个问题

我正在寻找一种算法来检测音高。其中一个答案建议我使用初始 FFT 来获得基本频率响应,找出哪些频率正在发声,然后在每个感兴趣的区域使用带通滤波器:

一个稍微高级的算法可以做这样的事情:

  1. 粗略检测音调频率(可以用 DFT 完成)。
  2. 带通信号过滤隔离音调频率。
  3. 计算滤波信号中两个峰值之间的样本数。

现在我可以做第一步了(我正在为 iOS 编码,Apple 有一个框架(加速框架)用于执行 FFT 等。

我已经从这里开始了:但我可以看到问题:一个 FFT 可以区分一个人可以唱的所有可能的音符需要大量的样本,而且我不想执行太多不必要的计算,因为我是针对移动设备。

所以我试图弄清楚上面的这个答案,但我不明白如何将带通滤波器的概念应用到代码中。

任何人都可以帮忙吗?

4

3 回答 3

3

过滤器设计相当复杂。有很多技巧。首先,您必须决定要创建哪种过滤器。有限脉冲响应 (FIR)?无限脉冲响应 (IIR)?然后,您选择一种算法来设计该类型的过滤器。Remez 算法常用于 FIR 滤波器设计。去这里看看我所指的复杂性:http ://en.wikipedia.org/wiki/Remez_algorithm

创建滤波器的最佳方法是使用现有的信号处理库。一个快速的谷歌搜索把我带到了这里: http ://spuc.sourceforge.net/

鉴于您的应用程序是什么,您可能想了解匹配过滤器。我不确定它们在这里是否相关,但它们可能是相关的。 http://en.wikipedia.org/wiki/Matched_filter

于 2011-02-04T03:08:24.393 回答
1

在维基百科中,检查低通滤波器和高通,然后加入它们以制作带通滤波器。维基百科有这两个过滤器的代码实现。

http://en.wikipedia.org/wiki/Low-pass_filter http://en.wikipedia.org/wiki/High-pass_filter

于 2014-09-16T01:07:59.777 回答
0

由于您只想检测单个频率,因此执行 DFT 然后只使用其中一个值将是一种过度杀伤力。

您可以实现Goertzel 算法。就像这个用于通过电话线检测 DTMF 音调的C 实现一样,来自 FreePBX 源代码:

float goertzel(short x[], int nmax, float coeff) {
    float s, power;
    float sprev, sprev2;
    int   n;

    sprev = 0;
    sprev2 = 0;
    for(n=0; n<nmax; n++) {
        s = x[n] + coeff * sprev - sprev2;
        sprev2 = sprev;
        sprev = s;
    }

    power = sprev2*sprev2 + sprev*sprev - coeff*sprev*sprev2;

    return power;
}

如您所见,该实现非常简单,并且对于单个频率非常有效。检查带有和不带有浮点的不同版本的链接,以及如何使用它。

于 2020-11-17T23:04:09.833 回答