Обнаружение определенной частоты / тона из необработанных волновых данных

Я читаю поток сырой волны, идущий от микрофона.
(Эта часть работает так, как я могу отправить ее оратору и получить хорошее эхо.)

Для простоты, скажем, я хочу обнаружить DTMF-тон в волновых данных. На самом деле я хочу обнаружить любую частоту, а не только частоту в DTMF. Но я всегда знаю, какую частоту я ищу.

Я попытался запустить его через FFT, но он не кажется очень эффективным, если я хочу высокую точность в обнаружении (скажем, это там только в течение 20 мс). Я могу обнаружить его с точностью до 200 мс.

Какие у меня варианты в отношении алгоритмов? Есть ли.Net libs для этого?

6 ответов

Решение

Возможно, вы захотите взглянуть на алгоритм Гёртцела, если вы пытаетесь обнаружить определенные частоты, такие как вход DTMF. На 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 составляет 200 Гц - 1000 Гц. Тогда вам нужно будет обнаружить сигнал на основе от 4 до 20 циклов. Я полагаю, что FFT никуда вас не приведет, поскольку вы будете обнаруживать только кратные частоты 50 Гц: это встроенная функция FFT, увеличение количества выборок не решит вашу проблему. Вам придется сделать что-то более умное.

Ваш лучший снимок - это линейное наименьшее соответствие ваших данных

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

для данного омега (одна из частот DTMF). Смотрите это для деталей (в частности, как установить уровень статистической значимости) и ссылки на литературу.

Что касается любых библиотек.NET, которые делают это, попробуйте TAPIEx ToneDecoder.Net Component. Я использую его для обнаружения DTMF, но он также может выполнять пользовательские тоны.

Я знаю, что этот вопрос старый, но, возможно, он сэкономит кому-то еще несколько дней поиска и опробования примеров кода и библиотек, которые просто не работают.

Спектральный анализ.

Все приложения, где вы извлекаете частоты из сигналов, проходят полевой спектральный анализ.

Другие вопросы по тегам