Цитата(AVL @ Jun 15 2007, 13:18)

В смысле считаете общее число переходов через ноль например на интервале 1 с, или считаете только в том случае, если переходы лежат строго на 9-м отсчете, затем на 19-м отсчете, затем на 28 и т.д.?
Смысл в том, что если в сигнале присутсвует тон, то расстояние между пересечениями нулевого уровня
будет равно (частота дискретизации / (2*частота тона)). Надо это расстояние посчитать на необходимой длине (например 75% длительности искомого тона).
Вот примерный алгоритм:
требуемое расстояние = 9;
1. Обнуляю счетчик отсчетов.
2. Затем в цикле на каждый отсчет:
а) увеличиваю счетчик отчетов;
б) если есть пересечение нуля и (счетчик отсчетов=требуемому расстоянию или требуемому расстоянию+1), то увеличиваю счетчик верных срабатываний, а если не равен то уменьшаю его
(также после каждого пересечния нуля надо обнулить счетчик отсчетов)
в) если счетчик отсчетов убежал далеко от требуемого расстояния, тоже уменьшаю счетчик верных срабатываний и обнуляю счетчик отсчетов.
г) если счетчик верных срабатываний = 50 , например (в зависимости от длительности искомого тона)
то тон найден.
Вот классик на C для этого дела:
template <class T> class CToneCrossFind {
public:
CToneCrossFind() {}
// частота дискретизации, частота тона
CToneCrossFind(float fSamplingFreq,float fToneFreq) {
Init(fSamplingFreq,fToneFreq);
}
virtual ~CToneCrossFind() {}
// частота дискретизации, частота тона
void Init(float fSamplingFreq, float fToneFreq) {
fQuant = fSamplingFreq;
fTone = fToneFreq;
nCurrentCrossPeriod = 0; // счетчик отсчетов
nNeededCrossPeriod = (unsigned int)(fSamplingFreq * 0.5f / fTone); // требуемый период
FLAG = 0; // возвращаемый функцией обработки флаг (1 - есть срабатывание по пересчению, 0 - нет)
pred_value = 0;// предыдущее значение отсчета
detect_counter = 0; // счетчик верных срабатываний
}
// обработка отсчета
unsigned int Detect(T value) {
nCurrentCrossPeriod++; // увеличили счетчик отсчетов
// если было пересечение или счетчик отсчетов убежал
if (((value>=0) && (pred_value<0)) ||
((value<0) && (pred_value>=0)) ||
(nCurrentCrossPeriod>(nNeededCrossPeriod+3))
)
{
// в случае если счетчик отсчетов в нужном диапазоне
if ((nCurrentCrossPeriod==nNeededCrossPeriod) || (nCurrentCrossPeriod==(nNeededCrossPeriod+1))) {
// возвр. 1 и увеличиваем счетчик верных срабатываний
FLAG = 1;
detect_counter++;
} else {
// иначе вовр.0 и уменьшаем счетчик верных срабатываний
FLAG = 0;
if (detect_counter>=5) detect_counter-=5; else detect_counter = 0;
}
// обнуляем счетчик отсчетов
nCurrentCrossPeriod = 0;
}
pred_value = value; // запоминаем тек. отсчет
return FLAG;
}
float fQuant;
float fTone;
unsigned int nCurrentCrossPeriod;
unsigned int nNeededCrossPeriod;
unsigned int FLAG;
T pred_value;
unsigned int detect_counter;
};
Таким образом, если среднее расстояние между пересечениями нуля на определенной длине (75% от длительности тона) совпадает с заданным диапазоном, то тон найден.