00001 /**********************************************************/ 00002 /*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/ 00003 /* 00004 Copyright: 1994 - Grupo de Voz (DAET) ETSII/IT-Bilbao 00005 00006 Nombre fuente................ SPL2.C 00007 Nombre paquete............... SPL 00008 Lenguaje fuente.............. C (Borland C/C++ 3.1) 00009 Estado....................... Completado 00010 Dependencia Hard/OS.......... - 00011 Codigo condicional........... NDEBUG 00012 00013 Codificacion................. Borja Etxebarria 00014 00015 Version dd/mm/aa Autor Proposito de la edicion 00016 ------- -------- -------- ----------------------- 00017 1.1.1 30/07/95 Borja scope funciones explicito 00018 1.1.0 08/12/94 Borja revision general (tipos,idx,nel,tnel...) 00019 1.0.0 06/07/93 Borja Codificacion inicial. 00020 00021 ======================== Contenido ======================== 00022 Evaluacion de funciones de enventanado (hamming, hanning, 00023 etc). 00024 Cada grupo de funciones (win_???, win2_???, wini_???) va 00025 precedido por una descripcion general del contenido. 00026 00027 Definir NDEBUG para desconectar la validacion de parametros 00028 con assert(). No definir este simbolo mientras se depuren 00029 aplicaciones, ya que aunque las funciones son algo mas lentas, 00030 el chequeo de validacion de parametros resuelve muchos problemas. 00031 =========================================================== 00032 */ 00033 /*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/ 00034 /**********************************************************/ 00035 00036 #include "spli.h" 00037 00038 /**********************************************************/ 00039 /* Funciones para generacion de ventanas (win_???). 00040 00041 Parametros: 00042 00043 - SPL_pFLOAT {v} : es un vector de {N} elementos SPL_FLOAT donde se va a 00044 . meter la ventana. 00045 - SPL_INT {N} : es la longitud de la ventana, y longitud del vector {v}. 00046 . {N}>=1 00047 00048 Las funciones rellenan el vector {v} con la ventana adecuada. 00049 Ademas cada funcion {devuelve} el propio puntero SPL_pFLOAT {v}. 00050 La longitud del vector {v} es la misma que la de la ventana, es decir 00051 {N} elementos. Tambien se puede obtener este valor con la tonta-funcion 00052 nel_win(N), que tonta-simplemente devuelve {N}. 00053 00054 Ref: 00055 . Digital Processing of Speech Signals 00056 . L.R. Rabiner / R.W Schafer 00057 . Prentice Hall 00058 00059 . Mathcad 3.1 Electrical Engineering Handbook (WINDOWS.MCD) 00060 */ 00061 /**********************************************************/ 00062 /* Ventana rectangular */ 00063 00064 PUBLIC SPL_pFLOAT XAPI win_rect( SPL_pFLOAT v, SPL_INT N ) 00065 { 00066 SPL_INT i; 00067 assert(N>0); 00068 00069 for (i=0; i<N; i++) 00070 v[i]=1.0; 00071 00072 return v; 00073 } 00074 00075 /**********************************************************/ 00076 /* ventana de Bartlett (triangular) */ 00077 00078 PUBLIC SPL_pFLOAT XAPI win_bart( SPL_pFLOAT v, SPL_INT N ) 00079 { 00080 SPL_INT i, half; 00081 SPL_FLOAT k; 00082 assert(N>0); 00083 00084 half=N/2; 00085 N--; 00086 k=((SPL_FLOAT)N)/2.0; 00087 00088 v[half]=1.0; /* N puede ser impar */ 00089 for (i=0; i<half; i++) 00090 v[N-i]=v[i]=(SPL_FLOAT)i/k; 00091 00092 return v; 00093 } 00094 00095 /**********************************************************/ 00096 /* ventana de Hanning */ 00097 00098 PUBLIC SPL_pFLOAT XAPI win_hann( SPL_pFLOAT v, SPL_INT N ) 00099 { 00100 SPL_INT i, half; 00101 SPL_FLOAT k; 00102 assert(N>0); 00103 00104 half=N/2; 00105 N--; 00106 k=((SPL_FLOAT)N)/(2.0*M_PI); 00107 00108 v[half]=1.0; /* N puede ser impar */ 00109 for (i=0; i<half; i++) 00110 v[N-i]=v[i]=0.5-0.5*cos((SPL_FLOAT)i/k); 00111 00112 return v; 00113 } 00114 00115 /**********************************************************/ 00116 /* ventana de Hamming */ 00117 00118 PUBLIC SPL_pFLOAT XAPI win_hamm( SPL_pFLOAT v, SPL_INT N ) 00119 { 00120 SPL_INT i, half; 00121 SPL_FLOAT k; 00122 assert(N>0); 00123 00124 half=N/2; 00125 N--; 00126 k=((SPL_FLOAT)N)/(2.0*M_PI); 00127 00128 v[half]=1.0; /* N puede ser impar */ 00129 for (i=0; i<half; i++) 00130 v[N-i]=v[i]=0.54-0.46*cos((SPL_FLOAT)i/k); 00131 00132 return v; 00133 } 00134 00135 /**********************************************************/ 00136 /* ventana de Blackman */ 00137 00138 PUBLIC SPL_pFLOAT XAPI win_black( SPL_pFLOAT v, SPL_INT N ) 00139 { 00140 SPL_INT i, half; 00141 SPL_FLOAT k; 00142 assert(N>0); 00143 00144 half=N/2; 00145 N--; 00146 k=((SPL_FLOAT)N)/(2.0*M_PI); 00147 00148 v[half]=1.0; /* N puede ser impar */ 00149 for (i=0; i<half; i++) 00150 v[N-i]=v[i]=0.42 - 0.5*cos((SPL_FLOAT)i/k) + 00151 0.08*cos((2.0*(SPL_FLOAT)i)/k); 00152 00153 return v; 00154 } 00155 00156 /**********************************************************/ 00157 /* ventana de Kaiser con parametro beta (b). 00158 Esta funcion tiene un parametro extra: 00159 - SPL_FLOAT {b} : {b}=0-->ventana rectangular, y segun crece {b}, 00160 . la ventana de Kaiser se va estrechando. 00161 . {b}>=0 00162 */ 00163 00164 PUBLIC SPL_pFLOAT XAPI win_kais( SPL_pFLOAT v, SPL_INT N, SPL_FLOAT b ) 00165 { 00166 SPL_INT i, half; 00167 SPL_FLOAT k, I0b; 00168 assert(N>0); 00169 assert(b>=0.0); 00170 00171 half=N/2; 00172 N--; 00173 k=(SPL_FLOAT)N/(b*2.0); 00174 I0b=bessel_I0(b); 00175 00176 v[half]=1.0; /* N puede ser impar */ 00177 for (i=0; i<half; i++) 00178 v[N-i]=v[i]=v[i]=bessel_I0(sqrt((SPL_FLOAT)i* 00179 (SPL_FLOAT)(N-i))/k)/I0b; 00180 00181 return v; 00182 } 00183 00184 /**********************************************************/ 00185 /* {devuelve} el numero de ELEMENTOS (no bytes, sino SPL_FLOAT) que 00186 debe tener el vector {v} en las funciones de ventanas win_???(v,N). 00187 {N}>=0 */ 00188 00189 PUBLIC SPL_INT XAPI nel_win( SPL_INT N ) 00190 { 00191 assert(N>=0); 00192 00193 return N; 00194 } 00195 00196 /**********************************************************/ 00197 /* Funciones para generacion de 'medias' ventanas (win2_???). 00198 00199 Puesto que las ventanas son simetricas, basta generar media ventana. 00200 00201 Parametros: 00202 00203 - SPL_pFLOAT {v} : es un vector de XAPI elementos donde se va a meter la 00204 . ventana. El valor XAPI lo devuelve la funcion nel_win2(N). 00205 - SPL_INT {N} : es la longitud de la ventana (NO la del vector {v}). 00206 . {N}>=1 00207 00208 Las funciones rellenan el vector {v} con la mitad de la ventana adecuada. 00209 Cada funcion {devuelve} el propio puntero SPL_pFLOAT {v}. 00210 00211 La longitud XAPI del vector {v} varia dependiendo de si la longitud de 00212 la ventana {N} es par o impar. 00213 - si {N} es par, el vector {v} tendra XAPI={N}/2 elementos y contiene media 00214 . ventana, siendo la segunda mitad de la ventana la simetrica de {v}. 00215 - si {N} es impar, el vector {v} tendra XAPI=({N}-1)/2+1 elementos y contendra 00216 . una muestra central (la ultima de {v}), habiendo simetria respecto a 00217 . esta muestra (ella no tiene simetrica). 00218 La longitud XAPI para una ventana de longitud {N} se puede obtener llamando 00219 a la funcion nel_win2(N). 00220 Dada una posicion i (de 0 a {N}-1) dentro de una ventana de longitud {N}, 00221 el indice (comenzando en 0) dentro del vector {v} que corresponde a i 00222 se puede obtener con la funcion idx_win2(i,N). 00223 Esta funcion simplemente refleja los valores de i que estan en la 00224 segunda mitad de la ventana sobre la primera mitad, que es la contenida 00225 en el vector {v}. */ 00226 /**********************************************************/ 00227 /* media-ventana rectangular */ 00228 00229 PUBLIC SPL_pFLOAT XAPI win2_rect( SPL_pFLOAT v, SPL_INT N ) 00230 { 00231 SPL_INT i; 00232 assert(N>0); 00233 00234 N=(N+1)/2; 00235 for (i=0; i<N; i++) 00236 v[i]=1.0; 00237 00238 return v; 00239 } 00240 00241 /**********************************************************/ 00242 /* media-ventana de Bartlett (triangular) */ 00243 00244 PUBLIC SPL_pFLOAT XAPI win2_bart( SPL_pFLOAT v, SPL_INT N ) 00245 { 00246 SPL_INT i, half; 00247 SPL_FLOAT k; 00248 assert(N>0); 00249 00250 half=N/2; 00251 N--; 00252 k=((SPL_FLOAT)N)/2.0; 00253 00254 v[N/2]=1.0; /* N puede ser impar */ 00255 for (i=0; i<half; i++) 00256 v[i]=(SPL_FLOAT)i/k; 00257 00258 return v; 00259 } 00260 00261 /**********************************************************/ 00262 /* media-ventana de Hanning */ 00263 00264 PUBLIC SPL_pFLOAT XAPI win2_hann( SPL_pFLOAT v, SPL_INT N ) 00265 { 00266 SPL_INT i, half; 00267 SPL_FLOAT k; 00268 assert(N>0); 00269 00270 half=N/2; 00271 N--; 00272 k=((SPL_FLOAT)N)/(2.0*M_PI); 00273 00274 v[N/2]=1.0; /* N puede ser impar */ 00275 for (i=0; i<half; i++) 00276 v[i]=0.5-0.5*cos((SPL_FLOAT)i/k); 00277 00278 return v; 00279 } 00280 00281 /**********************************************************/ 00282 /* media-ventana de Hamming */ 00283 00284 PUBLIC SPL_pFLOAT XAPI win2_hamm( SPL_pFLOAT v, SPL_INT N ) 00285 { 00286 SPL_INT i, half; 00287 SPL_FLOAT k; 00288 assert(N>0); 00289 00290 half=N/2; 00291 N--; 00292 k=((SPL_FLOAT)N)/(2.0*M_PI); 00293 00294 v[N/2]=1.0; /* N puede ser impar */ 00295 for (i=0; i<half; i++) 00296 v[i]=0.54-0.46*cos((SPL_FLOAT)i/k); 00297 00298 return v; 00299 } 00300 00301 /**********************************************************/ 00302 /* media-ventana de Blackman */ 00303 00304 PUBLIC SPL_pFLOAT XAPI win2_black( SPL_pFLOAT v, SPL_INT N ) 00305 { 00306 SPL_INT i, half; 00307 SPL_FLOAT k; 00308 assert(N>0); 00309 00310 half=N/2; 00311 N--; 00312 k=((SPL_FLOAT)N)/(2.0*M_PI); 00313 00314 v[N/2]=1.0; /* N puede ser impar */ 00315 for (i=0; i<half; i++) 00316 v[i]=0.42 - 0.5*cos((SPL_FLOAT)i/k) + 00317 0.08*cos((2.0*(SPL_FLOAT)i)/k); 00318 00319 return v; 00320 } 00321 00322 /**********************************************************/ 00323 /* media-ventana de Kaiser con parametro beta (b). 00324 Esta funcion tiene un parametro extra: 00325 - SPL_FLOAT {b} : {b}=0-->ventana rectangular, y segun crece {b}, la ventana 00326 . de Kaiser se va estrechando. {b}>=0 00327 */ 00328 00329 PUBLIC SPL_pFLOAT XAPI win2_kais( SPL_pFLOAT v, SPL_INT N, SPL_FLOAT b ) 00330 { 00331 SPL_INT i, half; 00332 SPL_FLOAT k, I0b; 00333 assert(N>0); 00334 assert(b>=0.0); 00335 00336 half=N/2; 00337 N--; 00338 k=(SPL_FLOAT)N/(b*2.0); 00339 I0b=bessel_I0(b); 00340 00341 v[N/2]=1.0; /* N puede ser impar */ 00342 for (i=0; i<half; i++) 00343 v[i]=bessel_I0(sqrt((SPL_FLOAT)i*(SPL_FLOAT)(N-i))/k)/I0b; 00344 00345 return v; 00346 } 00347 00348 /**********************************************************/ 00349 /* {devuelve} el numero de ELEMENTOS que debe tener el vector {v} 00350 en las funciones de medias-ventanas win2_???(v,N). 00351 {N}>=0 */ 00352 00353 PUBLIC SPL_INT XAPI nel_win2( SPL_INT N ) 00354 { 00355 assert(N>=0); 00356 00357 return (N+1)/2; 00358 } 00359 00360 /**********************************************************/ 00361 /* Dado un vector {v} de media-ventana obtenido con las funciones 00362 win2_???(v,N), esta funcion {devuelve} que elemento de ese vector 00363 representa al elemento {i} de la ventana completa. 00364 00365 Parametros: 00366 - SPL_INT {N} : Longitud de la ventana (completa). {N}>=0 00367 - SPL_INT {i} : Posicion en la ventana. 0 <= {i} <= {N}-1 00368 00369 {i}=0 --> {devuelve} 0 00370 {i}={N}-1 --> {devuelve} 0 00371 {i}=1 --> {devuelve} 1 00372 {i}={N}-2 --> {devuelve} 1 00373 {i}=2 --> {devuelve} 2 00374 {i}={N}-3 --> {devuelve} 2 00375 etc. 00376 */ 00377 00378 PUBLIC SPL_INT XAPI idx_win2( SPL_INT i, SPL_INT N ) 00379 { 00380 assert(N>=0); 00381 assert(i>=0); 00382 assert(i<N); 00383 00384 return (i<((N+1)/2)) ? i : N-i-1; 00385 } 00386 00387 /**********************************************************/ 00388 /* Funciones para obtener valores de ventanas en puntos 00389 concretos (wini_???) 00390 00391 Parametros: 00392 00393 - SPL_INT {i} : punto del que se quire saber el valor de la ventana 00394 . Si {i}<0 o {i}>=N, las funciones estan indefinidas 00395 - SPL_INT {N} : es la longitud de la ventana. 00396 . {N}>=0 00397 00398 Cada funcion {devuelve} el valor de la ventana de longitud {N} en 00399 el punto {i} */ 00400 /**********************************************************/ 00401 /* Ventana rectangular */ 00402 00403 PUBLIC SPL_FLOAT XAPI wini_rect( SPL_INT i, SPL_INT N ) 00404 { 00405 assert(i>=0); 00406 assert(i<N); 00407 00408 #ifdef NDEBUG 00409 (void)i; 00410 (void)N; 00411 #endif 00412 00413 return 1.0; 00414 } 00415 00416 /**********************************************************/ 00417 /* ventana de Bartlett (triangular) */ 00418 00419 PUBLIC SPL_FLOAT XAPI wini_bart( SPL_INT i, SPL_INT N ) 00420 { 00421 SPL_FLOAT k; 00422 assert(i>=0); 00423 assert(i<N); 00424 00425 k=(2.0*(SPL_FLOAT)i)/(SPL_FLOAT)(N-1); 00426 if (k<=1.0) 00427 return k; 00428 else 00429 return 2.0-k; 00430 } 00431 00432 /**********************************************************/ 00433 /* ventana de Hanning */ 00434 00435 PUBLIC SPL_FLOAT XAPI wini_hann( SPL_INT i, SPL_INT N ) 00436 { 00437 assert(i>=0); 00438 assert(i<N); 00439 00440 return 0.5-0.5*cos(((2.0*M_PI)*(SPL_FLOAT)i)/(SPL_FLOAT)(N-1)); 00441 } 00442 00443 /**********************************************************/ 00444 /* ventana de Hamming */ 00445 00446 PUBLIC SPL_FLOAT XAPI wini_hamm( SPL_INT i, SPL_INT N ) 00447 { 00448 assert(i>=0); 00449 assert(i<N); 00450 00451 return 0.54-0.46*cos(((2.0*M_PI)*(SPL_FLOAT)i)/(SPL_FLOAT)(N-1)); 00452 } 00453 00454 /**********************************************************/ 00455 /* ventana de Blackman */ 00456 00457 PUBLIC SPL_FLOAT XAPI wini_black( SPL_INT i, SPL_INT N ) 00458 { 00459 assert(i>=0); 00460 assert(i<N); 00461 00462 return 0.42 - 0.5*cos(((2.0*M_PI)*(SPL_FLOAT)i)/(SPL_FLOAT)(N-1)) 00463 + 0.08*cos(((4.0*M_PI)* 00464 (SPL_FLOAT)i)/(SPL_FLOAT)(N-1)); 00465 } 00466 00467 /**********************************************************/ 00468 /* ventana de Kaiser con parametro b (beta). 00469 Esta funcion tiene un parametro extra: 00470 - SPL_FLOAT {b} : {b}=0-->ventana rectangular, y segun crece {b}, 00471 . la ventana de Kaiser se va estrechando. 00472 . {b}>=0 00473 */ 00474 00475 PUBLIC SPL_FLOAT XAPI wini_kais( SPL_INT i, SPL_INT N, SPL_FLOAT b ) 00476 { 00477 assert(i>=0); 00478 assert(i<N); 00479 assert(b>=0.0); 00480 00481 return bessel_I0((b*2.0*sqrt((SPL_FLOAT)i*(SPL_FLOAT)(N-1-i)))/ 00482 (SPL_FLOAT)(N-1))/bessel_I0(b); 00483 } 00484 00485 /**********************************************************/ 00486