annotate tools/sigproc.c @ 0:5242703e91d3 tip

Initial checkin for AIM92 aimR8.2 (last updated May 1997).
author tomwalters
date Fri, 20 May 2011 15:19:45 +0100
parents
children
rev   line source
tomwalters@0 1 #include <stdio.h>
tomwalters@0 2 #include <math.h>
tomwalters@0 3 #include "sigproc.h"
tomwalters@0 4
tomwalters@0 5
tomwalters@0 6 /*
tomwalters@0 7 C is n complex numbers: (real,imag), (ie 2n floats).
tomwalters@0 8 Overwrite the first n floats with the modulus of the n complex numbers.
tomwalters@0 9 */
tomwalters@0 10
tomwalters@0 11 Mod( C, n )
tomwalters@0 12 complex *C ;
tomwalters@0 13 int n ;
tomwalters@0 14 {
tomwalters@0 15 register complex *eptr = C+n ;
tomwalters@0 16 register float *V = (float *)C ;
tomwalters@0 17
tomwalters@0 18 for ( ; C < eptr ; C++ )
tomwalters@0 19 *V++ = mod(C) ;
tomwalters@0 20 }
tomwalters@0 21
tomwalters@0 22 /*
tomwalters@0 23 Return the modulus of the given complex number
tomwalters@0 24 */
tomwalters@0 25
tomwalters@0 26 float mod( C )
tomwalters@0 27 complex *C ;
tomwalters@0 28 {
tomwalters@0 29 return ( sqrt( sq(Re(C)) + sq(Im(C)) ) ) ;
tomwalters@0 30 }
tomwalters@0 31
tomwalters@0 32
tomwalters@0 33
tomwalters@0 34 /*
tomwalters@0 35 C is n complex numbers: (real,imag), (ie 2n floats).
tomwalters@0 36 Overwrite the first n floats with the argument of the n complex numbers.
tomwalters@0 37 */
tomwalters@0 38
tomwalters@0 39 Arg( C, n )
tomwalters@0 40 complex *C ;
tomwalters@0 41 int n ;
tomwalters@0 42 {
tomwalters@0 43 register complex *eptr = C+n ;
tomwalters@0 44 register float *V = (float *)C ;
tomwalters@0 45
tomwalters@0 46 for ( ; C < eptr ; C++ )
tomwalters@0 47 *V++ = arg(C) ;
tomwalters@0 48 }
tomwalters@0 49
tomwalters@0 50 /*
tomwalters@0 51 Return the argument of the given complex number
tomwalters@0 52 */
tomwalters@0 53
tomwalters@0 54 float arg( C )
tomwalters@0 55 complex *C;
tomwalters@0 56 {
tomwalters@0 57 if (Im(C) >= 0) {
tomwalters@0 58 if (Re(C) >= 0) return ( atan(Im(C)/Re(C)) ); /* 1st quad */
tomwalters@0 59 else return ( PI + atan(Im(C)/Re(C)) ); /* 2nd quad */
tomwalters@0 60 }
tomwalters@0 61 else {
tomwalters@0 62 if (Re(C) < 0) return ( PI + atan(Im(C)/Re(C)) ); /* 1st quad */
tomwalters@0 63 else return ( TWOPI + atan(Im(C)/Re(C)) ); /* 2nd quad */
tomwalters@0 64 }
tomwalters@0 65 }
tomwalters@0 66
tomwalters@0 67
tomwalters@0 68 /*
tomwalters@0 69 C1 and C2 are both n complex numbers: (real,imag), (ie each 2n floats).
tomwalters@0 70 Overwrite the C1 with product of C1 and the complex conjugate of C2.
tomwalters@0 71 (When C1==C2, result is squared mod in the real parts, and 0 imag parts).
tomwalters@0 72 */
tomwalters@0 73
tomwalters@0 74 conj( C1, C2, n )
tomwalters@0 75 complex *C1, *C2 ;
tomwalters@0 76 int n ;
tomwalters@0 77 {
tomwalters@0 78 register complex *eptr = C1+n ;
tomwalters@0 79 float ReC1, ReC2 ;
tomwalters@0 80
tomwalters@0 81 for ( ; C1 < eptr ; C1++, C2++ ) {
tomwalters@0 82 Re(C1) = ( ReC1=Re(C1) ) * ( ReC2=Re(C2) ) + Im(C1) * Im(C2) ;
tomwalters@0 83 Im(C1) = ReC2 * Im(C1) - ReC1 * Im(C2) ;
tomwalters@0 84 }
tomwalters@0 85 }
tomwalters@0 86
tomwalters@0 87
tomwalters@0 88 /*
tomwalters@0 89 Autocorrelation function via fft.
tomwalters@0 90 A complex fft (of real data) is multiplied by its conjugate, and also scaled
tomwalters@0 91 prior to the inverse fft.
tomwalters@0 92 */
tomwalters@0 93
tomwalters@0 94
tomwalters@0 95
tomwalters@0 96 acf( V, m )
tomwalters@0 97 float *V ;
tomwalters@0 98 int m ;
tomwalters@0 99 {
tomwalters@0 100 register complex *C, *eptr ;
tomwalters@0 101 register int n = m>>1 ;
tomwalters@0 102 float tmp ;
tomwalters@0 103
tomwalters@0 104 fft( V, m, 1 ) ;
tomwalters@0 105 tmp = V[1] ; V[1] = 0 ;
tomwalters@0 106
tomwalters@0 107 for ( C=(complex *)V, eptr=C+n ; C<eptr ; C++ ) {
tomwalters@0 108 Re(C) = ( sq(Re(C)) + sq(Im(C)) ) / n ;
tomwalters@0 109 Im(C) = 0 ;
tomwalters@0 110 }
tomwalters@0 111 V[1] = sq( tmp ) / n ;
tomwalters@0 112
tomwalters@0 113 fft( V, m, -1 ) ;
tomwalters@0 114 }
tomwalters@0 115
tomwalters@0 116
tomwalters@0 117 /*
tomwalters@0 118 Test x: return 1 if x is a power of 2, otherwise return 0.
tomwalters@0 119 */
tomwalters@0 120
tomwalters@0 121 int ispower( x )
tomwalters@0 122 int x ;
tomwalters@0 123 {
tomwalters@0 124 return ( x > 1 && log2(x) == (int)log2(x) ) ;
tomwalters@0 125 }
tomwalters@0 126
tomwalters@0 127
tomwalters@0 128 /*
tomwalters@0 129 Return a power of 2, either equal to x (if x is already a power of 2), or
tomwalters@0 130 the next power of 2 larger than x.
tomwalters@0 131 */
tomwalters@0 132
tomwalters@0 133 int getpower( x )
tomwalters@0 134 int x ;
tomwalters@0 135 {
tomwalters@0 136 if ( log2(x) > (int)log2(x) )
tomwalters@0 137 x = 1 << ( 1 + (int)log2(x) ) ;
tomwalters@0 138 return ( x ) ;
tomwalters@0 139 }
tomwalters@0 140
tomwalters@0 141
tomwalters@0 142 /*
tomwalters@0 143 Copy float array x into short array y, both length n points.
tomwalters@0 144 Scale each point using the given scale factor.
tomwalters@0 145 Return 1 if no 16-bit over or underflow.
tomwalters@0 146 Otherwise return a scale factor to replace the given scale factor.
tomwalters@0 147
tomwalters@0 148 */
tomwalters@0 149
tomwalters@0 150 float ftos( x, y, n, scale )
tomwalters@0 151 float *x ;
tomwalters@0 152 short *y ;
tomwalters@0 153 int n ;
tomwalters@0 154 float scale ;
tomwalters@0 155 {
tomwalters@0 156 float p ;
tomwalters@0 157 float min = MAXSHORT, fmin ;
tomwalters@0 158 float max = MINSHORT, fmax ;
tomwalters@0 159 int i ;
tomwalters@0 160
tomwalters@0 161 fmax = fmin = 1. ;
tomwalters@0 162
tomwalters@0 163 for ( i = 0 ; i < n ; i++ ) {
tomwalters@0 164 p = x[i] * scale ;
tomwalters@0 165
tomwalters@0 166 if ( p > max ) max = p ;
tomwalters@0 167 if ( p < min ) min = p ;
tomwalters@0 168
tomwalters@0 169 y[i] = (short)p ;
tomwalters@0 170 }
tomwalters@0 171
tomwalters@0 172 if ( max > MAXSHORT || min < MINSHORT ) {
tomwalters@0 173
tomwalters@0 174 if ( max > MAXSHORT ) fmax = MAXSHORT / max ;
tomwalters@0 175 if ( min < MINSHORT ) fmin = MINSHORT / min ;
tomwalters@0 176
tomwalters@0 177 if ( fmax < fmin ) return ( scale * fmax ) ;
tomwalters@0 178 else return ( scale * fmin ) ;
tomwalters@0 179 }
tomwalters@0 180
tomwalters@0 181 return ( 1. ) ;
tomwalters@0 182 }
tomwalters@0 183
tomwalters@0 184
tomwalters@0 185
tomwalters@0 186
tomwalters@0 187 /*************************** convolution **********************************/
tomwalters@0 188
tomwalters@0 189 /*
tomwalters@0 190 Time-domain convolution. An input signal y of length n points is convolved
tomwalters@0 191 with a window x of length m points (where m is assumed odd for symmetry).
tomwalters@0 192 Return convolution signal z which must have allocated space of length n.
tomwalters@0 193
tomwalters@0 194 Discrete convolution is defined:
tomwalters@0 195 z[i] = sum{j=-inf to inf} x[i-j].y[j] for i=-inf to inf
tomwalters@0 196 But the signal y and window x are assumed to be zero for all time outside
tomwalters@0 197 the given points so that:
tomwalters@0 198 z[i] = sum{j=-m/2 to m/2} x[i-j].y[j] for i=0,1,...,n-1
tomwalters@0 199
tomwalters@0 200 Since the response of a linear filter to an arbitiary input signal is the
tomwalters@0 201 convolution of the signal with the filter's impulse response, the window may
tomwalters@0 202 be seen as the impulse response characterising the filter, and the return
tomwalters@0 203 z is then the filter output in response to input y.
tomwalters@0 204
tomwalters@0 205 Alternatively the convolution may be seen as a local averaging operation
tomwalters@0 206 on y with weights obtained by time-reversing and shifting x.
tomwalters@0 207 */
tomwalters@0 208
tomwalters@0 209 convolve_time( y, n, x, m, z )
tomwalters@0 210 short *y ; /* input signal */
tomwalters@0 211 int n ; /* length of array y */
tomwalters@0 212 float *x ; /* convolution window or filter impulse response */
tomwalters@0 213 int m ; /* length of array x */
tomwalters@0 214 float *z ; /* output signal of length n (same as input) */
tomwalters@0 215 {
tomwalters@0 216 register int i, j, k, lim1, lim2 ;
tomwalters@0 217 register float sum ;
tomwalters@0 218
tomwalters@0 219 for ( i = 0 ; i < n ; i++ ) {
tomwalters@0 220
tomwalters@0 221 k = m - 1 ;
tomwalters@0 222 if ( ( lim1 = i - (m-1)/2 ) < 0 ) {
tomwalters@0 223 k += lim1 ;
tomwalters@0 224 lim1 = 0 ;
tomwalters@0 225 }
tomwalters@0 226 if ( ( lim2 = i + (m-1)/2 ) > n )
tomwalters@0 227 lim2 = n - 1 ;
tomwalters@0 228
tomwalters@0 229 sum = 0 ;
tomwalters@0 230 for ( j = lim1 ; j <= lim2 ; j++, --k )
tomwalters@0 231 sum += x[k] * y[j] ;
tomwalters@0 232
tomwalters@0 233 z[i] = sum ;
tomwalters@0 234 }
tomwalters@0 235 }
tomwalters@0 236
tomwalters@0 237
tomwalters@0 238 /*
tomwalters@0 239 Frequency-domain convolution.
tomwalters@0 240 */
tomwalters@0 241
tomwalters@0 242 convolve_freq( y, n, x, m, z )
tomwalters@0 243 short *y ; /* input signal */
tomwalters@0 244 int n ; /* length of array y */
tomwalters@0 245 float *x ; /* convolution window or filter impulse response */
tomwalters@0 246 int m ; /* length of array x */
tomwalters@0 247 float *z ; /* output signal of length n (same as input) */
tomwalters@0 248 {
tomwalters@0 249 int i, j, n1 ;
tomwalters@0 250 float *data, *respns, *ans ;
tomwalters@0 251
tomwalters@0 252 n1 = getpower( n + m ) ; /* padded length of input signal */
tomwalters@0 253
tomwalters@0 254 data = (float *)malloc( ( n1 + 1 ) * sizeof(float) ) ;
tomwalters@0 255 respns = (float *)malloc( ( n1 + 1 ) * sizeof(float) ) ;
tomwalters@0 256 ans = (float *)malloc( ( n1 * 2 + 1 ) * sizeof(float) ) ;
tomwalters@0 257
tomwalters@0 258 /* copy and pad signal */
tomwalters@0 259
tomwalters@0 260 for ( i = 0 ; i < n ; i++ )
tomwalters@0 261 data[i] = y[i] ;
tomwalters@0 262 for ( ; i < n1 ; i++ )
tomwalters@0 263 data[i] = (float)0 ;
tomwalters@0 264
tomwalters@0 265 /* copy window into wrap-around order */
tomwalters@0 266
tomwalters@0 267 for ( i = m/2, j = 0 ; i < m ; i++, j++ )
tomwalters@0 268 respns[i] = x[j] ;
tomwalters@0 269 for ( i = 0 ; i < m/2 ; i++, j++ )
tomwalters@0 270 respns[i] = x[j] ;
tomwalters@0 271
tomwalters@0 272 /* Convolve and copy output */
tomwalters@0 273
tomwalters@0 274 convlv( data-1, n1, respns-1, m, 1, ans-1 ) ;
tomwalters@0 275
tomwalters@0 276 for ( i = 0 ; i < n ; i++ )
tomwalters@0 277 z[i] = ans[i] ;
tomwalters@0 278
tomwalters@0 279 free( data ) ;
tomwalters@0 280 free( respns ) ;
tomwalters@0 281 free( ans ) ;
tomwalters@0 282 }
tomwalters@0 283
tomwalters@0 284
tomwalters@0 285 /*
tomwalters@0 286 Convolution of two functions. [See NR: pp407-413].
tomwalters@0 287 Function 1 (the input signal) is in `data', length n, (n power of 2).
tomwalters@0 288 Function 2 (the response function) is in `respns', length m, (m<=n and odd).
tomwalters@0 289 (However respns must have n space available).
tomwalters@0 290 The response file should be stored in respns in "wrap-around order", ie with
tomwalters@0 291 its last half first and first half last in the array.
tomwalters@0 292 Return is the first n numbers in `ans', (though ans must have 2*n space).
tomwalters@0 293 Return convolution if isign==1, or deconvolution if isign==(-1).
tomwalters@0 294
tomwalters@0 295 The data array should be padded with zeroes to a power of 2.
tomwalters@0 296 The recommended amount of padding [NR: p411] is at least m/2, but need not be
tomwalters@0 297 more than m.
tomwalters@0 298 */
tomwalters@0 299
tomwalters@0 300 static float sqrarg;
tomwalters@0 301 #define SQR(a) (sqrarg=(a),sqrarg*sqrarg)
tomwalters@0 302
tomwalters@0 303
tomwalters@0 304 convlv( data, n, respns, m, isign, ans )
tomwalters@0 305 float data[], respns[], ans[] ;
tomwalters@0 306 int n, m, isign ;
tomwalters@0 307 {
tomwalters@0 308 int i, no2 ;
tomwalters@0 309 float dum, mag2, *fftbuf ;
tomwalters@0 310
tomwalters@0 311 fftbuf = (float *)malloc( 2 * n * sizeof(float) ) ;
tomwalters@0 312
tomwalters@0 313 for (i=1;i<=(m-1)/2;i++)
tomwalters@0 314 respns[n+1-i]=respns[m+1-i];
tomwalters@0 315 for (i=(m+3)/2;i<=n-(m-1)/2;i++)
tomwalters@0 316 respns[i]=0.0;
tomwalters@0 317
tomwalters@0 318 twofft(data,respns,fftbuf,ans,n);
tomwalters@0 319 no2=n/2;
tomwalters@0 320 for (i=2;i<=n+2;i+=2) {
tomwalters@0 321 if (isign == 1) {
tomwalters@0 322 ans[i-1]=(fftbuf[i-1]*(dum=ans[i-1])-fftbuf[i]*ans[i])/no2;
tomwalters@0 323 ans[i]=(fftbuf[i]*dum+fftbuf[i-1]*ans[i])/no2;
tomwalters@0 324 } else if (isign == -1) {
tomwalters@0 325 if ((mag2=SQR(ans[i-1])+SQR(ans[i])) == 0.0)
tomwalters@0 326 fprintf( stderr, "warning: deconvolving at response zero\n" ) ;
tomwalters@0 327 ans[i-1]=(fftbuf[i-1]*(dum=ans[i-1])+fftbuf[i]*ans[i])/mag2/no2;
tomwalters@0 328 ans[i]=(fftbuf[i]*dum-fftbuf[i-1]*ans[i])/mag2/no2;
tomwalters@0 329 }
tomwalters@0 330 else {
tomwalters@0 331 fprintf( stderr, "No meaning for ISIGN in CONVLV\n" ) ;
tomwalters@0 332 exit( 1 ) ;
tomwalters@0 333 }
tomwalters@0 334 }
tomwalters@0 335 ans[2]=ans[n+1];
tomwalters@0 336 realft(ans,no2,-1);
tomwalters@0 337
tomwalters@0 338 free( fftbuf ) ;
tomwalters@0 339 }
tomwalters@0 340
tomwalters@0 341
tomwalters@0 342
tomwalters@0 343 /************************ fft ********************************************/
tomwalters@0 344
tomwalters@0 345 /*
tomwalters@0 346 In-place FFT/IFFT routine for real-valued data.
tomwalters@0 347 (Ref Numerical recipes, pp417).
tomwalters@0 348
tomwalters@0 349 Arguments:
tomwalters@0 350 data = Input array of 2n floats,
tomwalters@0 351 also output data array of n complex numbers.
tomwalters@0 352 n = Number of data points, (must be a power of two).
tomwalters@0 353 Input data is 2n real numbers.
tomwalters@0 354 Output data is n complex numbers.
tomwalters@0 355 isign = FFT when 1; IFFT when -1.
tomwalters@0 356
tomwalters@0 357 Each complex number occupies two consecutive locations: real and imag.
tomwalters@0 358 The output data is n real and imag parts which are the positive frequency
tomwalters@0 359 half of the symmetric Fourier transform.
tomwalters@0 360
tomwalters@0 361 Indexing conversion:
tomwalters@0 362
tomwalters@0 363 Both input and output data are indexed: 1,..,n.
tomwalters@0 364 where: Input data is 2n real numbers.
tomwalters@0 365 Output data is n complex numbers, (ie 2n floats).
tomwalters@0 366 To convert to conventional indexing: 0,..,m-1
tomwalters@0 367 where: Input data is m real numbers (eg. input framesize).
tomwalters@0 368 Output data is m/2 complex numbers, (ie m floats).
tomwalters@0 369
tomwalters@0 370 allocated space for "data" of:
tomwalters@0 371
tomwalters@0 372 (m+1)*sizeof(float).
tomwalters@0 373
tomwalters@0 374 call to routine "realft":
tomwalters@0 375
tomwalters@0 376 realft( data-1, m/2, isign ) ;
tomwalters@0 377
tomwalters@0 378 for example via the define:
tomwalters@0 379
tomwalters@0 380 #define fft(data,m,isign) ( realft((float *)(data)-1, m>>1, isign) )
tomwalters@0 381
tomwalters@0 382 This works because the location (data-1) is never indexed in routine realft.
tomwalters@0 383 Output data will then be data[0] to data[m/2-1] complex numbers,
tomwalters@0 384 ie data[0] to data[m-1] floats, to be interpreted as m/2 (real,imag) pairs.
tomwalters@0 385
tomwalters@0 386 The first of the m/2 points of the magnitude spectrum is then:
tomwalters@0 387 sqrt( sq( data[0] ) + sq( data[1] ) )
tomwalters@0 388
tomwalters@0 389
tomwalters@0 390 The results of the IFFT are not normalized by multplication by 1/N.
tomwalters@0 391 The user should multiply each returned element by 1/n.
tomwalters@0 392
tomwalters@0 393 Routine realft returns the first and last real components in data[1] and
tomwalters@0 394 data[2]. To make this correspond with the return from twofft, the mod below
tomwalters@0 395 sets data[2]=0.
tomwalters@0 396 */
tomwalters@0 397
tomwalters@0 398
tomwalters@0 399 realft(data,n,isign)
tomwalters@0 400 float data[];
tomwalters@0 401 int n,isign;
tomwalters@0 402 {
tomwalters@0 403 int i,i1,i2,i3,i4,n2p3;
tomwalters@0 404 float c1=0.5,c2,h1r,h1i,h2r,h2i;
tomwalters@0 405 double wr,wi,wpr,wpi,wtemp,theta;
tomwalters@0 406
tomwalters@0 407 theta=3.141592653589793/(double) n;
tomwalters@0 408 if (isign == 1) {
tomwalters@0 409 c2 = -0.5;
tomwalters@0 410 four1(data,n,1);
tomwalters@0 411 } else {
tomwalters@0 412 c2=0.5;
tomwalters@0 413 theta = -theta;
tomwalters@0 414 }
tomwalters@0 415 wtemp=sin(0.5*theta);
tomwalters@0 416 wpr = -2.0*wtemp*wtemp;
tomwalters@0 417 wpi=sin(theta);
tomwalters@0 418 wr=1.0+wpr;
tomwalters@0 419 wi=wpi;
tomwalters@0 420 n2p3=2*n+3;
tomwalters@0 421 for (i=2;i<=n/2;i++) {
tomwalters@0 422 i4=1+(i3=n2p3-(i2=1+(i1=i+i-1)));
tomwalters@0 423 h1r=c1*(data[i1]+data[i3]);
tomwalters@0 424 h1i=c1*(data[i2]-data[i4]);
tomwalters@0 425 h2r = -c2*(data[i2]+data[i4]);
tomwalters@0 426 h2i=c2*(data[i1]-data[i3]);
tomwalters@0 427 data[i1]=h1r+wr*h2r-wi*h2i;
tomwalters@0 428 data[i2]=h1i+wr*h2i+wi*h2r;
tomwalters@0 429 data[i3]=h1r-wr*h2r+wi*h2i;
tomwalters@0 430 data[i4] = -h1i+wr*h2i+wi*h2r;
tomwalters@0 431 wr=(wtemp=wr)*wpr-wi*wpi+wr;
tomwalters@0 432 wi=wi*wpr+wtemp*wpi+wi;
tomwalters@0 433 }
tomwalters@0 434 if (isign == 1) {
tomwalters@0 435 data[1] = (h1r=data[1])+data[2];
tomwalters@0 436 data[2] = h1r-data[2];
tomwalters@0 437 } else {
tomwalters@0 438 data[1]=c1*((h1r=data[1])+data[2]);
tomwalters@0 439 data[2]=c1*(h1r-data[2]);
tomwalters@0 440 four1(data,n,-1);
tomwalters@0 441 }
tomwalters@0 442 }
tomwalters@0 443
tomwalters@0 444
tomwalters@0 445 #define SWAP(a,b) tempr=(a);(a)=(b);(b)=tempr
tomwalters@0 446
tomwalters@0 447 four1(data,nn,isign)
tomwalters@0 448 float data[];
tomwalters@0 449 int nn,isign;
tomwalters@0 450 {
tomwalters@0 451 int n,mmax,m,j,istep,i;
tomwalters@0 452 double wtemp,wr,wpr,wpi,wi,theta;
tomwalters@0 453 float tempr,tempi;
tomwalters@0 454
tomwalters@0 455 n=nn << 1;
tomwalters@0 456 j=1;
tomwalters@0 457 for (i=1;i<n;i+=2) {
tomwalters@0 458 if (j > i) {
tomwalters@0 459 SWAP(data[j],data[i]);
tomwalters@0 460 SWAP(data[j+1],data[i+1]);
tomwalters@0 461 }
tomwalters@0 462 m=n >> 1;
tomwalters@0 463 while (m >= 2 && j > m) {
tomwalters@0 464 j -= m;
tomwalters@0 465 m >>= 1;
tomwalters@0 466 }
tomwalters@0 467 j += m;
tomwalters@0 468 }
tomwalters@0 469 mmax=2;
tomwalters@0 470 while (n > mmax) {
tomwalters@0 471 istep=2*mmax;
tomwalters@0 472 theta=6.28318530717959/(isign*mmax);
tomwalters@0 473 wtemp=sin(0.5*theta);
tomwalters@0 474 wpr = -2.0*wtemp*wtemp;
tomwalters@0 475 wpi=sin(theta);
tomwalters@0 476 wr=1.0;
tomwalters@0 477 wi=0.0;
tomwalters@0 478 for (m=1;m<mmax;m+=2) {
tomwalters@0 479 for (i=m;i<=n;i+=istep) {
tomwalters@0 480 j=i+mmax;
tomwalters@0 481 tempr=wr*data[j]-wi*data[j+1];
tomwalters@0 482 tempi=wr*data[j+1]+wi*data[j];
tomwalters@0 483 data[j]=data[i]-tempr;
tomwalters@0 484 data[j+1]=data[i+1]-tempi;
tomwalters@0 485 data[i] += tempr;
tomwalters@0 486 data[i+1] += tempi;
tomwalters@0 487 }
tomwalters@0 488 wr=(wtemp=wr)*wpr-wi*wpi+wr;
tomwalters@0 489 wi=wi*wpr+wtemp*wpi+wi;
tomwalters@0 490 }
tomwalters@0 491 mmax=istep;
tomwalters@0 492 }
tomwalters@0 493 }
tomwalters@0 494
tomwalters@0 495
tomwalters@0 496 twofft(data1,data2,fft1,fft2,n)
tomwalters@0 497 float data1[],data2[],fft1[],fft2[];
tomwalters@0 498 int n;
tomwalters@0 499 {
tomwalters@0 500 int nn3,nn2,jj,j;
tomwalters@0 501 float rep,rem,aip,aim;
tomwalters@0 502
tomwalters@0 503 nn3=1+(nn2=2+n+n);
tomwalters@0 504 for (j=1,jj=2;j<=n;j++,jj+=2) {
tomwalters@0 505 fft1[jj-1]=data1[j];
tomwalters@0 506 fft1[jj]=data2[j];
tomwalters@0 507 }
tomwalters@0 508 four1(fft1,n,1);
tomwalters@0 509 fft2[1]=fft1[2];
tomwalters@0 510 fft1[2]=fft2[2]=0.0;
tomwalters@0 511 for (j=3;j<=n+1;j+=2) {
tomwalters@0 512 rep=0.5*(fft1[j]+fft1[nn2-j]);
tomwalters@0 513 rem=0.5*(fft1[j]-fft1[nn2-j]);
tomwalters@0 514 aip=0.5*(fft1[j+1]+fft1[nn3-j]);
tomwalters@0 515 aim=0.5*(fft1[j+1]-fft1[nn3-j]);
tomwalters@0 516 fft1[j]=rep;
tomwalters@0 517 fft1[j+1]=aim;
tomwalters@0 518 fft1[nn2-j]=rep;
tomwalters@0 519 fft1[nn3-j] = -aim;
tomwalters@0 520 fft2[j]=aip;
tomwalters@0 521 fft2[j+1] = -rem;
tomwalters@0 522 fft2[nn2-j]=aip;
tomwalters@0 523 fft2[nn3-j]=rem;
tomwalters@0 524 }
tomwalters@0 525 }
tomwalters@0 526
tomwalters@0 527
tomwalters@0 528 /*********************** windows *******************************************/
tomwalters@0 529
tomwalters@0 530 /*
tomwalters@0 531 Allocate space for and compute an n-point Hann or raised cosine window,
tomwalters@0 532 returning array.
tomwalters@0 533 */
tomwalters@0 534
tomwalters@0 535 float *raised_cosine( n )
tomwalters@0 536 int n ;
tomwalters@0 537 {
tomwalters@0 538 float *W ;
tomwalters@0 539 register int i ;
tomwalters@0 540 register double k ;
tomwalters@0 541
tomwalters@0 542 W = (float *)malloc( n * sizeof(float) ) ;
tomwalters@0 543
tomwalters@0 544 k = TWOPI/(double)(n-1);
tomwalters@0 545 for (i=0 ; i<n ; i++)
tomwalters@0 546 W[i] = 0.5 * ( 1.0 - cos(k*i) ) ;
tomwalters@0 547
tomwalters@0 548 return W ;
tomwalters@0 549 }
tomwalters@0 550
tomwalters@0 551
tomwalters@0 552 /*
tomwalters@0 553 Allocate space for and compute an n-point Hamming window, returning array.
tomwalters@0 554 */
tomwalters@0 555
tomwalters@0 556 float *hamming( n )
tomwalters@0 557 int n ;
tomwalters@0 558 {
tomwalters@0 559 float *W ;
tomwalters@0 560 register int i ;
tomwalters@0 561 register double k ;
tomwalters@0 562
tomwalters@0 563 W = (float *)malloc( n * sizeof(float) ) ;
tomwalters@0 564
tomwalters@0 565 k = TWOPI/(double)(n-1);
tomwalters@0 566 for (i=0 ; i<n ; i++)
tomwalters@0 567 W[i] = 0.54 - 0.46*cos(k*i) ;
tomwalters@0 568
tomwalters@0 569 return W ;
tomwalters@0 570 }
tomwalters@0 571
tomwalters@0 572
tomwalters@0 573 /*
tomwalters@0 574 Allocate space for and compute a Gaussian window with given standard deviation
tomwalters@0 575 `s' (samples) over a range of `n' standard deviations either side of a zero
tomwalters@0 576 mean. The size of the returned window (returned via variable `num') will be:
tomwalters@0 577 2 * n * s + 1 [points]
tomwalters@0 578 (This is always odd as the window is symmetrical).
tomwalters@0 579 */
tomwalters@0 580
tomwalters@0 581 float *gauss_window( s, n, num )
tomwalters@0 582 float s, n ;
tomwalters@0 583 int *num ;
tomwalters@0 584 {
tomwalters@0 585 float x, *y, var ;
tomwalters@0 586 int i, points ;
tomwalters@0 587
tomwalters@0 588 points = 2 * n * s + 1 ;
tomwalters@0 589 y = (float *)malloc( points * sizeof(float) ) ;
tomwalters@0 590
tomwalters@0 591 x = ( - n * s ) ;
tomwalters@0 592 var = s * s ;
tomwalters@0 593 for ( i = 0 ; i < points ; i++, x++ )
tomwalters@0 594 y[i] = exp( -(double)( 0.5 * x * x / var ) ) ;
tomwalters@0 595
tomwalters@0 596 *num = points ;
tomwalters@0 597 return y ;
tomwalters@0 598 }
tomwalters@0 599
tomwalters@0 600
tomwalters@0 601 /*********************** frames *******************************************/
tomwalters@0 602
tomwalters@0 603 /*
tomwalters@0 604 Return a ptr to the n'th frame (numbered 1,2,3,...,n), with given
tomwalters@0 605 framewidth (size) and frameshift (step). Return the null ptr if eof before
tomwalters@0 606 the n'th frame. Frame number n=0 refers to the last frame before eof.
tomwalters@0 607 Successive calls to getframe must request increasing frame numbers.
tomwalters@0 608
tomwalters@0 609 Data (binary shorts) is buffered in an array of "blocksize" shorts,
tomwalters@0 610 allocated internally, where:
tomwalters@0 611 blocksize = size + ( frames_per_block - 1 ) * step
tomwalters@0 612 This means that the buffer can hold "frames_per_block" frames of the given
tomwalters@0 613 size and step, and ensures that no frame crosses the boundary between
tomwalters@0 614 successive buffers. At the buffer boundary, the overlap part
tomwalters@0 615 (where overlap = size - step) of the last frame in the buffer must
tomwalters@0 616 be shifted to the start of the buffer, and the step part of the next frame
tomwalters@0 617 must be read so as to follow it in the buffer, completing the first frame of
tomwalters@0 618 the next buffer.
tomwalters@0 619 To protect the last frame (in the event that the next step part is actually
tomwalters@0 620 the eof), the first frame of the next buffer must not corrupt the last frame
tomwalters@0 621 of the previous buffer. This is ensured by arranging that:
tomwalters@0 622 size <= ( frames_per_block - 1 ) * step
tomwalters@0 623 This constrains frames_per_block to be:
tomwalters@0 624 frames_per_block >= ( size / step ) + 1
tomwalters@0 625 Therefore the minimum number of frames_per_block (when step = size, and there
tomwalters@0 626 is no overlap) is 2.
tomwalters@0 627 The actual value you give to frames_per_block is an efficiency issue, being
tomwalters@0 628 a trade-off between space usage and the number of times a shift is necessary
tomwalters@0 629 at a buffer boundary. A reasonable guess would be (see define below):
tomwalters@0 630 frames_per_block = ( size / step ) + 1 + FRAMES_PER_BLOCK
tomwalters@0 631
tomwalters@0 632 An example of a shifting frame buffer, from frame a to b inclusive in steps
tomwalters@0 633 of 1 frame, would be:
tomwalters@0 634
tomwalters@0 635 while ( ( buf = getframe( fp, a, size, step ) ) != (short *)0 && ( a<=b || b==0 ) ) {
tomwalters@0 636 process( buf, size ) ;
tomwalters@0 637 a++ ;
tomwalters@0 638 }
tomwalters@0 639 if ( a<=b && b>0 )
tomwalters@0 640 fprintf(stderr,"warning: not enough frames for request\n");
tomwalters@0 641
tomwalters@0 642 */
tomwalters@0 643
tomwalters@0 644 #define FRAMES_PER_BLOCK 10
tomwalters@0 645
tomwalters@0 646 short *getframe( fp, n, size, step )
tomwalters@0 647 FILE *fp ;
tomwalters@0 648 int n, size, step ;
tomwalters@0 649 {
tomwalters@0 650 static int first = 1 ;
tomwalters@0 651 static short *buf, *endptr ;
tomwalters@0 652 static short *bptr = (short *) 0 ;
tomwalters@0 653 static int blocksize, overlap, frames_per_block ;
tomwalters@0 654 static int m = 0 ; /* frame counter */
tomwalters@0 655 int startsize, i ;
tomwalters@0 656
tomwalters@0 657 if ( n < m ) /* catches invalid calls and also case of n==0 */
tomwalters@0 658 return (short *) 0 ;
tomwalters@0 659
tomwalters@0 660 if ( first ) {
tomwalters@0 661 first = 0 ;
tomwalters@0 662 frames_per_block = ( size / step ) + 1 + FRAMES_PER_BLOCK ;
tomwalters@0 663 blocksize = size + ( frames_per_block - 1 ) * step ;
tomwalters@0 664 overlap = size - step ;
tomwalters@0 665 bptr = buf = (short *)malloc( blocksize * sizeof(short) ) ;
tomwalters@0 666 endptr = buf + blocksize ;
tomwalters@0 667
tomwalters@0 668 if ( n > 0 ) {
tomwalters@0 669
tomwalters@0 670 /* seek the n'th frame in blocks of blocksize. */
tomwalters@0 671
tomwalters@0 672 startsize = ( n - 1 ) * step ;
tomwalters@0 673 for ( i = blocksize ; i < startsize ; i += blocksize )
tomwalters@0 674 if ( fread( buf, sizeof(short), blocksize, fp ) < blocksize )
tomwalters@0 675 return (short *) 0 ;
tomwalters@0 676 if ( ( startsize -= ( i - blocksize ) ) > 0 )
tomwalters@0 677 if ( fread( buf, sizeof(short), startsize, fp ) < startsize )
tomwalters@0 678 return (short *) 0 ;
tomwalters@0 679
tomwalters@0 680 if ( ( fread( bptr, sizeof(short), size, fp ) ) < size )
tomwalters@0 681 return (short *) 0 ;
tomwalters@0 682 m = n ;
tomwalters@0 683 }
tomwalters@0 684 else {
tomwalters@0 685
tomwalters@0 686 /* seek the last frame in blocks of blocksize */
tomwalters@0 687
tomwalters@0 688 if ( fread( buf, sizeof(short), size, fp ) < size )
tomwalters@0 689 return (short *) 0 ;
tomwalters@0 690 startsize = blocksize - size ;
tomwalters@0 691 for ( m = 1 ; ( i = fread( buf+size, sizeof(short), startsize, fp ) ) == startsize ; m += frames_per_block - 1 ) {
tomwalters@0 692 bptr = endptr-size ;
tomwalters@0 693 while ( bptr < endptr )
tomwalters@0 694 *buf++ = *bptr++ ;
tomwalters@0 695 buf -= size ;
tomwalters@0 696 }
tomwalters@0 697 bptr = buf + ( i / step) * step ;
tomwalters@0 698 m += i / step ;
tomwalters@0 699 }
tomwalters@0 700 return ( bptr ) ;
tomwalters@0 701 }
tomwalters@0 702
tomwalters@0 703 for ( ; m < n || n == 0 ; m++ ) {
tomwalters@0 704
tomwalters@0 705 if ( bptr + size >= endptr ) { /* shift last overlap to buf start */
tomwalters@0 706 while ( bptr < endptr )
tomwalters@0 707 *buf++ = *bptr++ ;
tomwalters@0 708 buf -= overlap ;
tomwalters@0 709 bptr = buf - step ;
tomwalters@0 710 }
tomwalters@0 711
tomwalters@0 712 if ( ( fread( bptr+size, sizeof(short), step, fp ) ) < step ) {
tomwalters@0 713 if ( n == 0 ) {
tomwalters@0 714 if ( bptr < buf ) return ( endptr - size ) ;
tomwalters@0 715 else return ( bptr ) ;
tomwalters@0 716 }
tomwalters@0 717 return (short *) 0 ;
tomwalters@0 718 }
tomwalters@0 719 bptr += step ;
tomwalters@0 720 }
tomwalters@0 721 return ( bptr ) ;
tomwalters@0 722 }
tomwalters@0 723
tomwalters@0 724
tomwalters@0 725 /*************************************************************************/
tomwalters@0 726
tomwalters@0 727 /*
tomwalters@0 728 Seek past n frames in blocks of blocksize.
tomwalters@0 729 Frames have width=size and shift=step.
tomwalters@0 730 When step == size, the seek reads ( n * size ) shorts from the i/p stream.
tomwalters@0 731 When step < size, the seek reads ( size + ( n - 1 ) * step ) shorts.
tomwalters@0 732 Return 1, or otherwise 0 for an improper seek (insufficient data in stream).
tomwalters@0 733 */
tomwalters@0 734
tomwalters@0 735 seekframes( fp, n, size, step )
tomwalters@0 736 FILE *fp ;
tomwalters@0 737 int n, size, step ;
tomwalters@0 738 {
tomwalters@0 739 static short *buf ;
tomwalters@0 740 static int first = 1 ;
tomwalters@0 741 static int blocksize, frames_per_block ;
tomwalters@0 742 int startsize = size + ( n - 1 ) * step ;
tomwalters@0 743 int i ;
tomwalters@0 744
tomwalters@0 745 if ( first ) {
tomwalters@0 746 first = 0 ;
tomwalters@0 747 frames_per_block = ( size / step ) + 1 + FRAMES_PER_BLOCK ;
tomwalters@0 748 blocksize = size + ( frames_per_block - 1 ) * step ;
tomwalters@0 749 buf = (short *)malloc( blocksize * sizeof(short) ) ;
tomwalters@0 750 }
tomwalters@0 751 for ( i = blocksize ; i < startsize ; i += blocksize )
tomwalters@0 752 if ( fread( buf, sizeof(short), blocksize, fp ) < blocksize )
tomwalters@0 753 return 0 ;
tomwalters@0 754 if ( (startsize -= (i - blocksize)) > 0 )
tomwalters@0 755 if ( fread( buf, sizeof(short), startsize, fp ) < startsize )
tomwalters@0 756 return 0 ;
tomwalters@0 757
tomwalters@0 758 return 1 ;
tomwalters@0 759 }
tomwalters@0 760
tomwalters@0 761 /*************************************************************************/
tomwalters@0 762
tomwalters@0 763 /*
tomwalters@0 764 Seek past n bytes from current position in stream.
tomwalters@0 765 Return 1, or otherwise 0 for an improper seek (insufficient data in stream).
tomwalters@0 766 */
tomwalters@0 767
tomwalters@0 768 seekbytes( fp, n )
tomwalters@0 769 FILE *fp ;
tomwalters@0 770 int n ;
tomwalters@0 771 {
tomwalters@0 772 static char *buf ;
tomwalters@0 773 static int first = 1 ;
tomwalters@0 774
tomwalters@0 775 if ( n > 0 ) {
tomwalters@0 776 if ( first ) {
tomwalters@0 777 first = 0 ;
tomwalters@0 778 buf = (char *)malloc( n ) ;
tomwalters@0 779 }
tomwalters@0 780
tomwalters@0 781 if ( fread( buf, 1, n, fp ) < n )
tomwalters@0 782 return 0 ;
tomwalters@0 783 }
tomwalters@0 784 return 1 ;
tomwalters@0 785 }
tomwalters@0 786
tomwalters@0 787
tomwalters@0 788
tomwalters@0 789 /*********************** normalizing **************************************/
tomwalters@0 790
tomwalters@0 791 /*
tomwalters@0 792 Normalize the n-array y so that the sum of the points (ie the area) is unity.
tomwalters@0 793 */
tomwalters@0 794
tomwalters@0 795 normalize_area( y, n )
tomwalters@0 796 float *y ;
tomwalters@0 797 int n ;
tomwalters@0 798 {
tomwalters@0 799 float sum = 0 ;
tomwalters@0 800 int i ;
tomwalters@0 801
tomwalters@0 802 for ( i=0 ; i < n ; i++ )
tomwalters@0 803 sum += y[i] ;
tomwalters@0 804 for ( i=0 ; i < n ; i++ )
tomwalters@0 805 y[i] /= sum ;
tomwalters@0 806 }
tomwalters@0 807
tomwalters@0 808
tomwalters@0 809 /*
tomwalters@0 810 Normalize the n-array y so that the range of y[i] is [0,1].
tomwalters@0 811 */
tomwalters@0 812
tomwalters@0 813 normalize_range( y, n )
tomwalters@0 814 float *y ;
tomwalters@0 815 int n ;
tomwalters@0 816 {
tomwalters@0 817 int i ;
tomwalters@0 818 float max = ( -256000. ) ;
tomwalters@0 819 float min = 256000. ;
tomwalters@0 820
tomwalters@0 821 for ( i = 0 ; i < n ; i++ ) { /* find max and min */
tomwalters@0 822 if ( y[i] > max ) max = y[i] ;
tomwalters@0 823 if ( y[i] < min ) min = y[i] ;
tomwalters@0 824 }
tomwalters@0 825
tomwalters@0 826 for ( i = 0 ; i < n ; i++ )
tomwalters@0 827 y[i] = ( y[i] - min ) / ( max - min ) ;
tomwalters@0 828 }
tomwalters@0 829
tomwalters@0 830