Re[15]: Частотная характеристика звука.
От: vdimas Россия  
Дата: 27.12.05 02:55
Оценка: 33 (1)
Здравствуйте, adontz, Вы писали:

A>Есть бесконечный массив семплов (ну грубо говоря, сильно старые меня конечно не волнуют).

A>Есть частота дискретизацц D, частота которую надо распознать F, минимальная распознаваемая длительность сигнала T.
A>Для каждого sample[i], частоты D я вычисляю

A>sum1[F, i] += sample[i] * sin(2*pi*i/D);

A>sum2[F, i] += sample[i] * sin(2*pi*i/D + pi/2);
A>energy[F, i] = sqrt(sum1[F, i]*sum1[F, i]) + sqrt(sum2[F, i]*sum2[F, i])

Мне больше импонирует потоковый вариант, т.е. алгоритм надо писать просто в расчете подачи на вход очередного sample, без ориентации на массивы.

A>Если есть такой промежуток [k — D*T, k], что на нём energy[F, i] всегда больше некоторого порогового значения, то считать, что сигнал распознан.


Нет, из-за шума и из-за второй частоты не все твои отсчеты будут больше некоторого порогового значения. Это все надо сглаживать. Если подобрать частоту среза ФНЧ 1/20мс, то достаточно обнаружить сам факт достижения порогового значения.

Затем надо не забыть обнаружить паузу

Сигнал распознан, если две и только две частоты из сетки обнаружены.


A>Насколько я понимаю, мне понадобиться считать и общую энергию сигнала.


Обязательно, порог — величина относительная. Громкость в канале не постоянная. Я тут давал уже как считать общую енергию. Ее тоже надо сглаживать точно таким же фильтром.

Короче, навскидку так:
    // фильтр НЧ
    public struct FNC {
        public double k;        // коэф
        public double outp;     // выход фильтра

        public void Step(double inp) {
            outp -= (outp - inp) * k;
        }

        public FNC(double k) {
            this.k = k;
            this.outp = 0;
        }
    }

    // подсчитываем квадрат текущей мощности сигнала
    public struct EnergySum {
        FNC fnc;

        public void Step(double inp) {
            fnc.Step(inp * inp);
        }

        public EnergySum(double k) {
            fnc = new FNC(k);
        }
    }

    // генерируем отсчеты
    public struct Generator {
        public double outp, outp90;
        double df, q;

        /// <param name="f_discr">частота дискретизации</param>
        /// <param name="f_generate">частота генератора</param>
        public Generator(double f_discr, double f_generate) {
            df = 2 * Math.PI * f_generate / f_discr;

            q = 0;
            outp = outp90 = 0;
        }

        public void Step() {
            q += df;
            if (q > 2 * Math.PI)
                q -= 2 * Math.PI;

            outp = Math.Sin(q);
            outp90 = Math.Cos(q);
        }
    }

    // целевой детектор частоты
    public class Detector {
        FNC fnc, fnc90;
        Generator generator;
        public double outp;            // выход детектора
        public bool signal;            // обнаружен сигнал выше порога

        const double reaction = 0.025; // 25 mc
        const double threshold = 0.2;

        public Detector(double f_discr, double f_detect) {
            double k = 1 - Math.Pow(Math.Sqrt(2) / 2, 1 / (2 * f_discr * reaction));
            fnc = new FNC(k);
            fnc90 = new FNC(k);
            generator = new Generator(f_discr, f_detect);
            outp = 0;
            signal = false;
        }

        public void Step(double inp, double energy) {
            generator.Step();
            fnc.Step(inp * generator.outp);
            fnc90.Step(inp * generator.outp90);
            outp = fnc.outp * fnc.outp + fnc90.outp * fnc90.outp;
            signal = energy * threshold < outp;
        }
    }

    // пересечение 2-х частот на клавиатуре
    public class Analizer {
        Detector horizontal;
        Detector vertical;
        public char symbol;
        public bool signal = false;

        public Analizer(Detector h, Detector v, char symb) {
            horizontal = h;
            vertical = v;
            symbol = symb;
        }

        public void Step() {
            signal = horizontal.signal && vertical.signal;
        }
    }


Могут быть всякие мелкие неточности.
С инкапсуляцией тоже не заморачивался.

Замечание.
Генератор вполне может генерить {0, 1}, а не просчитывать синусы/косинусы каждый раз. Если точности будет не хватать, то буквально в 3-х битах закодированая таблица синусоиды дает уже весьма точные результаты. Т.е. почти все здесь можно переводить на int.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.