13

I am reading a raw wave stream coming from the microphone.
(This part works as I can send it to the speaker and get a nice echo.)

For simplicity lets say I want to detect a DTMF-tone in the wave data. In reality I want to detect any frequency, not just those in DTMF. But I always know which frequency I am looking for.

I have tried running it through FFT, but it doesn't seem very efficient if I want high accuracy in the detection (say it is there for only 20 ms). I can detect it down to an accuracy of around 200 ms.

What are my options with regards to algorithms? Are there any .Net libs for it?

Tedd Hansen
  • 11,020
  • 14
  • 57
  • 93

6 Answers6

13

You may want to look at the Goertzel algorithm if you're trying to detect specific frequencies such as DTMF input. There is a C# DTMF generator/detector library on Sourceforge based on this algorithm.

Jeffrey Hantin
  • 33,679
  • 7
  • 71
  • 92
  • Thanks for the tip. Looks like Goertzel is the way to go. I've been lookin at the code you linked to, but it is not so well documentet so difficult to make heads and tails of it. – Tedd Hansen Jan 27 '11 at 06:53
  • Would Goertzel work even with other noise (for instance music), or does it require a more or less clean tone? – Tedd Hansen Jan 27 '11 at 12:58
  • I don't see why it wouldn't work in the presence of other noise; it should at the very least be no worse than any other discrete Fourier transform algorithm. – Jeffrey Hantin Jan 27 '11 at 17:32
5

Very nice implementation of Goertzel is there. C# modification:

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

Works great for me.

maag
  • 51
  • 1
  • 4
1

I found this as a simple implementation of Goertzel. Haven't gotten it to work yet (looking for wrong frequency?), but I thought I'd share it anywas. It is copied from 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)));
        }
Tedd Hansen
  • 11,020
  • 14
  • 57
  • 93
0

Let's say that typical DTMF frequency is 200Hz - 1000Hz. Then you'd have to detect a signal based on between 4 and 20 cycles. FFT will not get you anywhere I guess, since you'll detect only multiples of 50Hz frequencies: this is a built in feature of FFT, increasing the number of samples will not solve your problem. You'll have to do something more clever.

Your best shot is to linear least-square fit your data to

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

for a given omega (one of the DTMF frequencies). See this for details (in particular how to set a statistical significance level) and links to the litterature.

Alexandre C.
  • 52,206
  • 8
  • 116
  • 189
  • Thanks. Then I see why FFT wasn't very helpful. Looking into Linear least-square fit to see if I can find some .Net or usable .dll's to test. – Tedd Hansen Jan 26 '11 at 20:03
  • I did not know about Görtzel algorithm before, it should be way faster than least square fitting a sine wave. – Alexandre C. Jan 26 '11 at 20:11
  • I don't understand what you're saying about FFTs. DTMF frequencies are from 697Hz to 1477Hz, each at least 73Hz apart. At 8kHz a 256-point FFT would work fine. Of course using FFTs to detect specific frequencies is overkill, but it should still work. – Gabe Jan 27 '11 at 07:09
  • @Gabe: if your data is 20ms, FFT will get you data at frequencies 50Hz, 100Hz, 150Hz, etc., whatever is your sampling rate. Combined with leakage, you are likely not to detect anything (which is what OP observes) – Alexandre C. Jan 27 '11 at 10:05
  • Doing a 256-point FFT at 8kHz requires a 32ms sample, which is still several times shorter than the 200ms minimum that the OP was able to achieve. – Gabe Jan 27 '11 at 10:30
0

As far as any .NET libraries that do this try TAPIEx ToneDecoder.Net Component. I use it for detecting DTMF, but it can do custom tones as well.

I know this question is old, but maybe it will save someone else several days of searching and trying out code samples and libraries that just don't work.

Eric Stassen
  • 274
  • 1
  • 5
-3

Spectral Analysis.

All application where you extract frequencies from signals goes under field spectral analysis.

Amir Rezaei
  • 4,640
  • 5
  • 29
  • 49