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

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

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

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

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


person Tedd Hansen    schedule 26.01.2011    source источник
comment
Какие хочу, щас 44,1k (16-битное стерео). Я получаю образец 2k каждые ~ 20 мс.   -  person Tedd Hansen    schedule 27.01.2011
comment
Эй, у меня такая же проблема... у вас есть какой-нибудь код или решение? потому что вопрос немного старый.   -  person Danilo Breda    schedule 29.07.2014


Ответы (6)


Вы можете посмотреть на алгоритм Goertzel, если вы пытаетесь определить определенные частоты, такие как DTMF Вход. На Sourceforge есть библиотека генератора/детектора C# DTMF, основанная на этом алгоритме.

person Jeffrey Hantin    schedule 26.01.2011
comment
Спасибо за совет. Похоже, Герцель - это то, что нужно. Я просматривал код, на который вы ссылались, но он не так хорошо документирован, так сложно разобраться в нем. - person Tedd Hansen; 27.01.2011
comment
Будет ли Герцель работать даже с другим шумом (например, с музыкой) или он требует более или менее чистого тона? - person Tedd Hansen; 27.01.2011
comment
Я не понимаю, почему это не сработает в присутствии других шумов; он должен быть как минимум не хуже любого другого алгоритма дискретного преобразования Фурье. - person Jeffrey Hantin; 27.01.2011

здесь очень хорошая реализация Goertzel. Модификация С#:

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

Отлично работает для меня.

person maag    schedule 16.04.2014

Предположим, что типичная частота DTMF составляет 200–1000 Гц. Затем вам нужно будет обнаружить сигнал на основе от 4 до 20 циклов. Я думаю, БПФ никуда вас не приведет, так как вы обнаружите только частоты, кратные 50 Гц: это встроенная функция БПФ, увеличение количества выборок не решить вашу проблему. Вам придется сделать что-то более хитрое.

Лучше всего использовать линейный метод наименьших квадратов для ваших данных.

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

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

person Alexandre C.    schedule 26.01.2011
comment
Спасибо. Тогда я понимаю, почему БПФ не очень помог. Изучаю линейную подгонку по методу наименьших квадратов, чтобы узнать, могу ли я найти какие-нибудь .Net или пригодные для использования библиотеки .dll для тестирования. - person Tedd Hansen; 26.01.2011
comment
Раньше я не знал об алгоритме Герцеля, он должен быть намного быстрее, чем метод наименьших квадратов, соответствующий синусоиде. - person Alexandre C.; 26.01.2011
comment
Я не понимаю, что вы говорите о БПФ. Частоты DTMF находятся в диапазоне от 697 Гц до 1477 Гц с интервалом не менее 73 Гц. На частоте 8 кГц 256-точечное БПФ будет работать нормально. Конечно, использование БПФ для обнаружения определенных частот является излишним, но оно все равно должно работать. - person Gabe; 27.01.2011
comment
@Gabe: если ваши данные составляют 20 мс, БПФ предоставит вам данные на частотах 50 Гц, 100 Гц, 150 Гц и т. Д., Независимо от вашей частоты дискретизации. В сочетании с утечкой вы, скорее всего, ничего не обнаружите (что и наблюдает ОП) - person Alexandre C.; 27.01.2011
comment
Для выполнения 256-точечного БПФ на частоте 8 кГц требуется выборка 32 мс, что все же в несколько раз короче минимума в 200 мс, которого удалось достичь OP. - person Gabe; 27.01.2011

Я нашел это как простую реализацию Герцеля. Пока еще не заработал (ищете неправильную частоту?), но все равно решил поделиться. Он скопирован с сайта этот сайт.

        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)));
        }
person Tedd Hansen    schedule 27.01.2011

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

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

person Eric Stassen    schedule 09.12.2011

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

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

person Amir Rezaei    schedule 26.01.2011
comment
Это не очень хороший ответ на вопрос. Вообще говоря, ссылка на Википедию не является ответом на вопрос. - person Gabe; 27.01.2011
comment
@ Гейб, я указываю ему правильное направление. Там все алгоритмы годные. - person Amir Rezaei; 27.01.2011
comment
Намек в правильном направлении должен быть комментарием, а не ответом. - person Gabe; 27.01.2011