【问题标题】:Detect a specific frequency/tone from raw wave-data从原始波形数据中检测特定频率/音调
【发布时间】:2011-06-16 02:02:42
【问题描述】:

我正在读取来自麦克风的原始波流。
(这部分很有效,因为我可以将它发送到扬声器并获得很好的回声。)

为简单起见,假设我想检测波形数据中的 DTMF 音调。实际上,我想检测任何频率,而不仅仅是 DTMF 中的频率。但我总是知道我在寻找哪个频率。

我尝试过通过 FFT 运行它,但如果我想在检测中获得高精度(比如它只存在 20 毫秒),它似乎效率不高。我可以将其检测到 200 毫秒左右的准确度。

在算法方面我有哪些选择? 有没有它的 .Net 库?

【问题讨论】:

  • 任何我想要的,现在 44,1k(16 位立体声)。我每 20 毫秒收到一个 2k 样本。
  • 嘿,我有同样的问题...你有一些代码或解决方案吗?因为这个问题有点老了。

标签: c# algorithm audio wave


【解决方案1】:

如果您尝试检测特定频率(例如 DTMF 输入),您可能需要查看 Goertzel algorithm。 Sourceforge 上有一个基于此算法的C# DTMF generator/detector 库。

【讨论】:

  • 感谢您的提示。看起来Goertzel是要走的路。我一直在查看您链接到的代码,但它的文档不太好,很难弄清楚它的正面和反面。
  • Goertzel 是否可以在其他噪音(例如音乐)的情况下工作,还是需要或多或少干净的音调?
  • 我不明白为什么它在存在其他噪音的情况下不起作用;它至少应该不会比任何其他离散傅里叶变换算法差。
【解决方案2】:

Spectral Analysis

从信号中提取频率的所有应用都需要进行场频谱分析。

【讨论】:

  • 这不是一个很好的问题答案。一般来说,维基百科的链接不能回答问题。
  • @Gabe 我为他指明了正确的方向。那里的所有算法都适用。
  • 正确方向的提示应该是评论,而不是答案。
【解决方案3】:

假设典型的 DTMF 频率为 200Hz - 1000Hz。然后你必须检测基于 4 到 20 个周期的信号。我猜 FFT 不会让你得到任何结果,因为你只会检测到 50Hz 频率的倍数:这是 FFT 的内置功能,增加样本数量将不会解决你的问题。你必须做一些更聪明的事情。

您最好的方法是线性最小二乘拟合您的数据

h(t) = A cos (omega t) + B sin (omega t)

对于给定的欧米茄(DTMF 频率之一)。有关详细信息(特别是如何设置统计显着性水平)和文献链接,请参阅this

【讨论】:

  • 谢谢。然后我明白了为什么 FFT 不是很有帮助。查看线性最小二乘拟合,看看我是否可以找到一些 .Net 或可用的 .dll 进行测试。
  • 我以前不知道 Görtzel 算法,它应该比拟合正弦波的最小二乘法快得多。
  • 我不明白你在说什么 FFT。 DTMF 频率从 697Hz 到 1477Hz,每个频率至少相隔 73Hz。在 8kHz 时,256 点 FFT 可以正常工作。当然,使用 FFT 来检测特定频率是多余的,但它仍然可以工作。
  • @Gabe:如果您的数据是 20 毫秒,FFT 会以 50Hz、100Hz、150Hz 等频率为您获取数据,无论您的采样率是多少。结合泄漏,您可能无法检测到任何东西(这是 OP 观察到的)
  • 在 8kHz 下进行 256 点 FFT 需要 32ms 的采样,这仍然比 OP 能够实现的 200ms 最小值短几倍。
【解决方案4】:

我发现这是一个简单的 Goertzel 实现。还没有让它工作(寻找错误的频率?),但我想我还是会分享它。复制自this site

        public static double CalculateGoertzel(byte[] sample, double frequency, int samplerate)
        {
            double Skn, Skn1, Skn2;
            Skn = Skn1 = Skn2 = 0;
            for (int i = 0; i < sample.Length; i++)
            {
                Skn2 = Skn1;
                Skn1 = Skn;
                Skn = 2 * Math.Cos(2 * Math.PI * frequency / samplerate) * Skn1 - Skn2 + sample[i];
            }
            double WNk = Math.Exp(-2 * Math.PI * frequency / samplerate);
            return 20 * Math.Log10(Math.Abs((Skn - WNk * Skn1)));
        }

【讨论】:

    【解决方案5】:

    就任何执行此操作的 .NET 库而言,请尝试 TAPIEx ToneDecoder.Net Component。我用它来检测 DTMF,但它也可以做自定义音调。

    我知道这个问题已经过时了,但也许它会为其他人节省几天的搜索和尝试代码示例和库的时间。

    【讨论】:

      【解决方案6】:

      Goertzel 的非常好的实现是 there。 C#修改:

      private double GoertzelFilter(float[] samples, double freq, int start, int end)
          {
              double sPrev = 0.0;
              double sPrev2 = 0.0;
              int i;
              double normalizedfreq = freq / SIGNAL_SAMPLE_RATE;
              double coeff = 2 * Math.Cos(2 * Math.PI * normalizedfreq);
              for (i = start; i < end; i++)
              {
                  double s = samples[i] + coeff * sPrev - sPrev2;
                  sPrev2 = sPrev;
                  sPrev = s;
              }
              double power = sPrev2 * sPrev2 + sPrev * sPrev - coeff * sPrev * sPrev2;
              return power;
          }
      

      非常适合我。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-03-31
        • 1970-01-01
        • 2023-03-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多