hdo
beta
|
00001 // 00002 // C Interface: goertzel 00003 // 00004 // Description: 00005 // 00006 // 00007 // Author: Miroslav Mraz <Mrazik@volny.cz>, (C) 2009 00008 // 00009 // Copyright: See COPYING file that comes with this distribution 00010 // 00011 // 00012 #include <stdio.h> 00013 #include <math.h> 00014 #include <utility/trace.h> 00015 00016 #include "goertzel.h" 00017 /*---------------------------------------------------------------------------- 00018 * calc_coeffs 00019 *---------------------------------------------------------------------------- 00020 */ 00021 // NOCOMPUTE definovano v Makefile 00022 // #define NOCOMPUTE // ! pokud se toto definuje, zmenší se délka kódu podstatně, počítá vždy ve float 00023 aritfmt calc_coeff (float nfreq) { 00024 #ifdef NOCOMPUTE 00025 return 1706; // napevno pro 216,6 Hz 00026 #else // NOCOMPUTE - je to tu pro ukázku, jak se to počítá 00027 aritfmt reval; 00028 float coeff; 00029 coeff = 2.0 * 3.141592654 * nfreq; 00030 coeff = 2.0 * cos (coeff); 00031 #ifndef COMPUTE_FLOAT 00032 // aby se to dalo počítat v int, tak to tady zvětšíme 00033 coeff *= (float)(1 << ISHIFT); 00034 #endif // COMPUTE_FLOAT 00035 00036 reval = (aritfmt) coeff; 00037 // TRACE_INFO ("coeff = %d\r\n", reval); 00038 return reval; 00039 #endif // NOCOMPUTE 00040 } 00041 /*---------------------------------------------------------------------------- 00042 * goertzel 00043 *---------------------------------------------------------------------------- 00044 */ 00045 int goertzel (aritfmt coeff, short *samples, int n) { 00046 register aritfmt rv,q0,q1=0,q2=0; // prefix register je použit pro případnou optimalizaci 00047 register int i; 00048 //aritfmt min=0,max=0; // hledáme přetečení 00049 #ifdef COMPUTE_FLOAT 00050 aritfmt a,b,c; 00051 #endif // COMPUTE_FLOAT 00052 00053 // pro všechny vzorky 00054 for (i=0; i<n; i++) { 00055 q0 = coeff * q1; 00056 // pokud byl coeff zvětšen, je třeba to tu zase zmenšit. Bez FPU je to ale rychlejší než počítat ve float. 00057 #ifndef COMPUTE_FLOAT 00058 q0 >>= ISHIFT; // zmenšení pro int 00059 #endif // COMPUTE_FLOAT 00060 q0 += (aritfmt) samples[i] - q2; // vlastní výpočet 00061 00062 q2 = q1; // posuv o vzorek 00063 q1 = q0; // rekurze 00064 } 00065 // po n vzorcích vypočteme kvadrát výkonu signálu, počítá se to jen jednou za čas (120 ms) 00066 #ifdef COMPUTE_FLOAT 00067 a = (float) q1; 00068 b = (float) q2; 00069 c = (float) coeff; 00070 a /= (float)(1 << HSHIFT); // zmenšíme, jinak jsou tam moc velká čísla a přeteče to 00071 b /= (float)(1 << HSHIFT); 00072 // výpočet kvadrátu výkonu signálu pro danou frekvenci 00073 rv = (a * a) + (b * b) - (c * a * b); 00074 TRACE_INFO ("Presna hodnota = %f\n", r); 00075 return (int) r; 00076 #else 00077 // Předchozí jde udělat i v integer-32, ale není to tak přesné 00078 q1 >>= HSHIFT; 00079 q2 >>= HSHIFT; 00080 rv = q1 * q2; 00081 // TRACE_INFO ("q1*q2=%d\n", r); 00082 rv *= -coeff; 00083 rv >>= ISHIFT; // tady nutno zmenšit tak, jak bylo zvětšeno v calc_coeff() 00084 rv += q1 * q1 + q2 * q2; // výkon by byl sqrt (rv), není nutné počítat, napětí stačí 00085 return (int) rv; 00086 #endif // COMPUTE_FLOAT 00087 }