从原始波数据中检测特定频率/音调

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

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

我试过通过FFT运行它,但如果我想要高精度的检测(例如它只有20毫秒),它似乎不是很有效。 我可以检测到它的精度大约为200毫秒。

关于算法,我有哪些选择? 它有任何.Net库吗?

如果您尝试检测特定频率(如DTMF输入),您可能需要查看Goertzel算法 。 基于该算法,Sourceforge上有一个C#DTMF生成器/检测器库。

有很好的Goertzel实现。 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; } 

对我很有用。

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

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

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

您最好的镜头是线性最小二乘拟合您的数据

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

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

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

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

光谱分析

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