我正在读取来自麦克风的原始波流。
(这部分很有效,因为我可以将它发送到扬声器并获得很好的回声。)
为简单起见,假设我想检测波形数据中的 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;
}
对我很有用。
假设典型的 DTMF 频率是 200Hz - 1000Hz。然后你必须检测基于 4 到 20 个周期的信号。我猜 FFT 不会让你得到任何地方,因为你只会检测到 50Hz 频率的倍数:这是 FFT 的内置功能,增加样本数量不会解决你的问题。你必须做一些更聪明的事情。
您最好的方法是线性最小二乘拟合您的数据
h(t) = A cos (omega t) + B sin (omega t)
对于给定的欧米茄(DTMF 频率之一)。有关详细信息(特别是如何设置统计显着性水平)和文献链接,请参阅此内容。
我发现这是 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)));
}
至于执行此操作的任何 .NET 库,请尝试TAPIEx ToneDecoder.Net Component。我用它来检测 DTMF,但它也可以做自定义音调。
我知道这个问题很老,但也许它会节省其他人几天的搜索和尝试代码示例和库的时间。
光谱分析。
从信号中提取频率的所有应用都需要进行场频谱分析。