如何在 C 中实现带通滤波器(目的:基音检测)?

发布于 2024-10-01 10:45:47 字数 704 浏览 0 评论 0原文

我最近问了这个问题

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

稍微先进的算法可以做这样的事情:

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

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

我已经开始了 此处:但我可以看到问题:要区分人们可以唱的所有可能音符的 FFT 需要一个很多样本,而且我不想执行太多不必要的计算,因为我的目标是移动设备,

所以我试图理解上面的这个答案,但我不明白如何应用它。带通滤波器的概念编码。

有人可以帮忙吗?

I recently asked this question:

I am looking for an algorithm to detect pitch. one of the answers suggested that I use an initial FFT to get the basic frequency response, figure out which frequencies are getting voiced, and follow it up with a band pass filter in each area of interest:

A slightly advanced algorithm could do something like this:

  1. Roughly detect pitch frequency (could be done with DFT).
  2. Bandpass signal to filter isolate pitch frequency.
  3. Count the number of samples between two peaks in the filtered signals.

Now I can do the first step okay ( I am coding for iOS, and Apple has a framework (the accelerate framework) for doing FFTs etc.

I have made a start here: but I can see the problem: an FFT that would differentiate all of the possible notes one could sing would require a lot of samples, and I don't want to perform too much unnecessary computation as I'm targeting a mobile device.

So I'm trying to get my head round this answer above, but I don't understand how I could apply the concept of a band pass filter to code.

Can anyone help?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

花想c 2024-10-08 10:45:48

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

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

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

Filter design is pretty complex. There are many techniques. First you have to decide what kind of filter you want to create. Finite impulse response (FIR)? Infinite impulse response (IIR)? Then you select an algorithm for designing a filter of that type. The Remez algorithm is often used for FIR filter design. Go here to see the complexity that I was referring to: http://en.wikipedia.org/wiki/Remez_algorithm

Your best best for creating a filter is to use an existing signal processing library. A quick Google search led me here: http://spuc.sourceforge.net/

Given what your application is, you may want to read about matched filters. I am not sure if they are relevant here, but they might be. http://en.wikipedia.org/wiki/Matched_filter

孤城病女 2024-10-08 10:45:48

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

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

well in Wikipedia, checkup on low-pass filter, and hi-pass, then join them to make a band-pass filter. Wikipedia has code implementations for those two filters.

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

请帮我爱他 2024-10-08 10:45:48

由于您只想检测单个频率,因此执行 DFT 后仅使用其中一个值就显得有些过分了。

您可以实现 Goertzel 算法。就像这个C实现用于检测DTMF电话线上的音调,来自 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;
}

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

Since you only want to detect a single frequency, it would be an overkill to perform a DFT to then only use one of the values.

You could implement the Goertzel algorithm. Like this C implementation used to detect DTMF tones over a phone line, from the FreePBX source code:

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;
}

As you can see, the implementation is fairly trivial and quite effective for single frequencies. Check the link for different versions with and without floating point, and how to use it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文