NBIS cleanup
[libfprint.git] / libfprint / nbis / mindtct / init.c
blob50dc0d7ecee31bfedb980b24dafb5a0d126a27e3
1 /*******************************************************************************
3 License:
4 This software was developed at the National Institute of Standards and
5 Technology (NIST) by employees of the Federal Government in the course
6 of their official duties. Pursuant to title 17 Section 105 of the
7 United States Code, this software is not subject to copyright protection
8 and is in the public domain. NIST assumes no responsibility whatsoever for
9 its use by other parties, and makes no guarantees, expressed or implied,
10 about its quality, reliability, or any other characteristic.
12 Disclaimer:
13 This software was developed to promote biometric standards and biometric
14 technology testing for the Federal Government in accordance with the USA
15 PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act.
16 Specific hardware and software products identified in this software were used
17 in order to perform the software development. In no case does such
18 identification imply recommendation or endorsement by the National Institute
19 of Standards and Technology, nor does it imply that the products and equipment
20 identified are necessarily the best available for the purpose.
22 *******************************************************************************/
24 /***********************************************************************
25 LIBRARY: LFS - NIST Latent Fingerprint System
27 FILE: INIT.C
28 AUTHOR: Michael D. Garris
29 DATE: 03/16/1999
30 UPDATED: 10/04/1999 Version 2 by MDG
31 UPDATED: 03/16/2005 by MDG
33 Contains routines responsible for allocation and/or initialization
34 of memories required by the NIST Latent Fingerprint System.
36 ***********************************************************************
37 ROUTINES:
38 init_dir2rad()
39 init_dftwaves()
40 get_max_padding_V2()
41 init_rotgrids()
42 alloc_dir_powers()
43 alloc_power_stats()
44 ***********************************************************************/
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <lfs.h>
50 /*************************************************************************
51 **************************************************************************
52 #cat: init_dir2rad - Allocates and initializes a lookup table containing
53 #cat: cosine and sine values needed to convert integer IMAP
54 #cat: directions to angles in radians.
56 Input:
57 ndirs - the number of integer directions to be defined in a
58 semicircle
59 Output:
60 optr - points to the allocated/initialized DIR2RAD structure
61 Return Code:
62 Zero - successful completion
63 Negative - system error
64 **************************************************************************/
65 int init_dir2rad(DIR2RAD **optr, const int ndirs)
67 DIR2RAD *dir2rad;
68 int i;
69 double theta, pi_factor;
70 double cs, sn;
72 /* Allocate structure */
73 dir2rad = (DIR2RAD *)malloc(sizeof(DIR2RAD));
74 if(dir2rad == (DIR2RAD *)NULL){
75 fprintf(stderr, "ERROR : init_dir2rad : malloc : dir2rad\n");
76 return(-10);
79 /* Assign number of directions */
80 dir2rad->ndirs = ndirs;
82 /* Allocate cosine vector */
83 dir2rad->cos = (double *)malloc(ndirs * sizeof(double));
84 if(dir2rad->cos == (double *)NULL){
85 /* Free memory allocated to this point. */
86 free(dir2rad);
87 fprintf(stderr, "ERROR : init_dir2rad : malloc : dir2rad->cos\n");
88 return(-11);
91 /* Allocate sine vector */
92 dir2rad->sin = (double *)malloc(ndirs * sizeof(double));
93 if(dir2rad->sin == (double *)NULL){
94 /* Free memory allocated to this point. */
95 free(dir2rad->cos);
96 free(dir2rad);
97 fprintf(stderr, "ERROR : init_dir2rad : malloc : dir2rad->sin\n");
98 return(-12);
101 /* Pi_factor sets the period of the trig functions to NDIRS units in x. */
102 /* For example, if NDIRS==16, then pi_factor = 2(PI/16) = .3926... */
103 pi_factor = 2.0*M_PI/(double)ndirs;
105 /* Now compute cos and sin values for each direction. */
106 for (i = 0; i < ndirs; ++i) {
107 theta = (double)(i * pi_factor);
108 cs = cos(theta);
109 sn = sin(theta);
110 /* Need to truncate precision so that answers are consistent */
111 /* on different computer architectures. */
112 cs = trunc_dbl_precision(cs, TRUNC_SCALE);
113 sn = trunc_dbl_precision(sn, TRUNC_SCALE);
114 dir2rad->cos[i] = cs;
115 dir2rad->sin[i] = sn;
118 *optr = dir2rad;
119 return(0);
122 /*************************************************************************
123 **************************************************************************
124 #cat: init_dftwaves - Allocates and initializes a set of wave forms needed
125 #cat: to conduct DFT analysis on blocks of the input image
127 Input:
128 dft_coefs - array of multipliers used to define the frequency for
129 each wave form to be computed
130 nwaves - number of wave forms to be computed
131 blocksize - the width and height of each block of image data to
132 be DFT analyzed
133 Output:
134 optr - points to the allocated/initialized DFTWAVES structure
135 Return Code:
136 Zero - successful completion
137 Negative - system error
138 **************************************************************************/
139 int init_dftwaves(DFTWAVES **optr, const double *dft_coefs,
140 const int nwaves, const int blocksize)
142 DFTWAVES *dftwaves;
143 int i, j;
144 double pi_factor, freq, x;
145 double *cptr, *sptr;
147 /* Allocate structure */
148 dftwaves = (DFTWAVES *)malloc(sizeof(DFTWAVES));
149 if(dftwaves == (DFTWAVES *)NULL){
150 fprintf(stderr, "ERROR : init_dftwaves : malloc : dftwaves\n");
151 return(-20);
154 /* Set number of DFT waves */
155 dftwaves->nwaves = nwaves;
156 /* Set wave length of the DFT waves (they all must be the same length) */
157 dftwaves->wavelen = blocksize;
159 /* Allocate list of wave pointers */
160 dftwaves->waves = (DFTWAVE **)malloc(nwaves * sizeof(DFTWAVE *));
161 if(dftwaves == (DFTWAVES *)NULL){
162 /* Free memory allocated to this point. */
163 free(dftwaves);
164 fprintf(stderr, "ERROR : init_dftwaves : malloc : dftwaves->waves\n");
165 return(-21);
168 /* Pi_factor sets the period of the trig functions to BLOCKSIZE units */
169 /* in x. For example, if BLOCKSIZE==24, then */
170 /* pi_factor = 2(PI/24) = .26179... */
171 pi_factor = 2.0*M_PI/(double)blocksize;
173 /* Foreach of 4 DFT frequency coef ... */
174 for (i = 0; i < nwaves; ++i) {
175 /* Allocate wave structure */
176 dftwaves->waves[i] = (DFTWAVE *)malloc(sizeof(DFTWAVE));
177 if(dftwaves->waves[i] == (DFTWAVE *)NULL){
178 /* Free memory allocated to this point. */
179 { int _j; for(_j = 0; _j < i; _j++){
180 free(dftwaves->waves[_j]->cos);
181 free(dftwaves->waves[_j]->sin);
182 free(dftwaves->waves[_j]);
184 free(dftwaves->waves);
185 free(dftwaves);
186 fprintf(stderr,
187 "ERROR : init_dftwaves : malloc : dftwaves->waves[i]\n");
188 return(-22);
190 /* Allocate cosine vector */
191 dftwaves->waves[i]->cos = (double *)malloc(blocksize * sizeof(double));
192 if(dftwaves->waves[i]->cos == (double *)NULL){
193 /* Free memory allocated to this point. */
194 { int _j; for(_j = 0; _j < i; _j++){
195 free(dftwaves->waves[_j]->cos);
196 free(dftwaves->waves[_j]->sin);
197 free(dftwaves->waves[_j]);
199 free(dftwaves->waves[i]);
200 free(dftwaves->waves);
201 free(dftwaves);
202 fprintf(stderr,
203 "ERROR : init_dftwaves : malloc : dftwaves->waves[i]->cos\n");
204 return(-23);
206 /* Allocate sine vector */
207 dftwaves->waves[i]->sin = (double *)malloc(blocksize * sizeof(double));
208 if(dftwaves->waves[i]->sin == (double *)NULL){
209 /* Free memory allocated to this point. */
210 { int _j; for(_j = 0; _j < i; _j++){
211 free(dftwaves->waves[_j]->cos);
212 free(dftwaves->waves[_j]->sin);
213 free(dftwaves->waves[_j]);
215 free(dftwaves->waves[i]->cos);
216 free(dftwaves->waves[i]);
217 free(dftwaves->waves);
218 free(dftwaves);
219 fprintf(stderr,
220 "ERROR : init_dftwaves : malloc : dftwaves->waves[i]->sin\n");
221 return(-24);
224 /* Assign pointer nicknames */
225 cptr = dftwaves->waves[i]->cos;
226 sptr = dftwaves->waves[i]->sin;
228 /* Compute actual frequency */
229 freq = pi_factor * dft_coefs[i];
231 /* Used as a 1D DFT on a 24 long vector of pixel sums */
232 for (j = 0; j < blocksize; ++j) {
233 /* Compute sample points from frequency */
234 x = freq * (double)j;
235 /* Store cos and sin components of sample point */
236 *cptr++ = cos(x);
237 *sptr++ = sin(x);
241 *optr = dftwaves;
242 return(0);
245 /*************************************************************************
246 **************************************************************************
247 #cat: get_max_padding_V2 - Deterines the maximum amount of image pixel padding
248 #cat: required by all LFS (Version 2) processes. Padding is currently
249 #cat: required by the rotated grids used in DFT analyses and in
250 #cat: directional binarization. The NIST generalized code enables
251 #cat: the parameters governing these processes to be redefined, so a
252 #cat: check at runtime is required to determine which process
253 #cat: requires the most padding. By using the maximum as the padding
254 #cat: factor, all processes will run safely with a single padding of
255 #cat: the input image avoiding the need to repad for further processes.
257 Input:
258 map_windowsize - the size (in pixels) of each window centered about
259 each block in the image used in DFT analyses
260 map_windowoffset - the offset (in pixels) from the orgin of the
261 surrounding window to the origin of the block
262 dirbin_grid_w - the width (in pixels) of the rotated grids used in
263 directional binarization
264 dirbin_grid_h - the height (in pixels) of the rotated grids used in
265 directional binarization
266 Return Code:
267 Non-negative - the maximum padding required for all processes
268 **************************************************************************/
269 int get_max_padding_V2(const int map_windowsize, const int map_windowoffset,
270 const int dirbin_grid_w, const int dirbin_grid_h)
272 int dft_pad, dirbin_pad, max_pad;
273 double diag;
274 double pad;
277 /* 1. Compute pad required for rotated windows used in DFT analyses. */
279 /* Explanation of DFT padding:
281 B---------------------
282 | window |
285 | A.......______|__________
286 | : : |
287 |<-C-->: block: |
288 <--|--D-->: : | image
289 | ........ |
290 | | |
291 | | |
292 | | |
293 ----------------------
298 Pixel A = Origin of entire fingerprint image
299 = Also origin of first block in image. Each pixel in
300 this block gets the same DFT results computed from
301 the surrounding window. Note that in general
302 blocks are adjacent and non-overlapping.
304 Pixel B = Origin of surrounding window in which DFT
305 analysis is conducted. Note that this window is not
306 completely contained in the image but extends to the
307 top and to the right.
309 Distance C = Number of pixels in which the window extends
310 beyond the image (map_windowoffset).
312 Distance D = Amount of padding required to hold the entire
313 rotated window in memory.
317 /* Compute pad as difference between the MAP windowsize */
318 /* and the diagonal distance of the window. */
319 /* (DFT grids are computed with pixel offsets RELATIVE2ORIGIN.) */
320 diag = sqrt((double)(2.0 * map_windowsize * map_windowsize));
321 pad = (diag-map_windowsize)/(double)2.0;
322 /* Need to truncate precision so that answers are consistent */
323 /* on different computer architectures when rounding doubles. */
324 pad = trunc_dbl_precision(pad, TRUNC_SCALE);
325 /* Must add the window offset to the rotational padding. */
326 dft_pad = sround(pad) + map_windowoffset;
328 /* 2. Compute pad required for rotated blocks used in directional */
329 /* binarization. Binarization blocks are applied to each pixel */
330 /* in the input image. */
331 diag = sqrt((double)((dirbin_grid_w*dirbin_grid_w)+
332 (dirbin_grid_h*dirbin_grid_h)));
333 /* Assumption: all grid centers reside in valid/allocated memory. */
334 /* (Dirbin grids are computed with pixel offsets RELATIVE2CENTER.) */
335 pad = (diag-1)/(double)2.0;
336 /* Need to truncate precision so that answers are consistent */
337 /* on different computer architectures when rounding doubles. */
338 pad = trunc_dbl_precision(pad, TRUNC_SCALE);
339 dirbin_pad = sround(pad);
341 max_pad = max(dft_pad, dirbin_pad);
343 /* Return the maximum of the two required paddings. This padding will */
344 /* be sufficiently large for all purposes, so that padding of the */
345 /* input image will only be required once. */
346 return(max_pad);
349 /*************************************************************************
350 **************************************************************************
351 #cat: init_rotgrids - Allocates and initializes a set of offsets that address
352 #cat: individual rotated pixels within a grid.
353 #cat: These rotated grids are used to conduct DFT analyses
354 #cat: on blocks of input image data, and they are used
355 #cat: in isotropic binarization.
357 Input:
358 iw - width (in pixels) of the input image
359 ih - height (in pixels) of the input image
360 pad - designates the number of pixels to be padded to the perimeter
361 of the input image. May be passed as UNDEFINED, in which
362 case the specific padding required by the rotated grids
363 will be computed and returned in ROTGRIDS.
364 start_dir_angle - angle from which rotations are to start
365 ndirs - number of rotations to compute (within a semicircle)
366 grid_w - width of the grid in pixels to be rotated
367 grid_h - height of the grid in pixels to be rotated
368 relative2 - designates whether pixel offsets whould be computed
369 relative to the ORIGIN or the CENTER of the grid
370 Output:
371 optr - points to the allcated/initialized ROTGRIDS structure
372 Return Code:
373 Zero - successful completion
374 Negative - system error
375 **************************************************************************/
376 int init_rotgrids(ROTGRIDS **optr, const int iw, const int ih, const int ipad,
377 const double start_dir_angle, const int ndirs,
378 const int grid_w, const int grid_h, const int relative2)
380 ROTGRIDS *rotgrids;
381 double pi_offset, pi_incr;
382 int dir, ix, iy, grid_size, pw, grid_pad, min_dim;
383 int *grid;
384 double diag, theta, cs, sn, cx, cy;
385 double fxm, fym, fx, fy;
386 int ixt, iyt;
387 double pad;
389 /* Allocate structure */
390 rotgrids = (ROTGRIDS *)malloc(sizeof(ROTGRIDS));
391 if(rotgrids == (ROTGRIDS *)NULL){
392 fprintf(stderr, "ERROR : init_rotgrids : malloc : rotgrids\n");
393 return(-30);
396 /* Set rotgrid attributes */
397 rotgrids->ngrids = ndirs;
398 rotgrids->grid_w = grid_w;
399 rotgrids->grid_h = grid_h;
400 rotgrids->start_angle = start_dir_angle;
401 rotgrids->relative2 = relative2;
403 /* Compute pad based on diagonal of the grid */
404 diag = sqrt((double)((grid_w*grid_w)+(grid_h*grid_h)));
405 switch(relative2){
406 case RELATIVE2CENTER:
407 /* Assumption: all grid centers reside in valid/allocated memory. */
408 pad = (diag-1)/(double)2.0;
409 /* Need to truncate precision so that answers are consistent */
410 /* on different computer architectures when rounding doubles. */
411 pad = trunc_dbl_precision(pad, TRUNC_SCALE);
412 grid_pad = sround(pad);
413 break;
414 case RELATIVE2ORIGIN:
415 /* Assumption: all grid origins reside in valid/allocated memory. */
416 min_dim = min(grid_w, grid_h);
417 /* Compute pad as difference between the smallest grid dimension */
418 /* and the diagonal distance of the grid. */
419 pad = (diag-min_dim)/(double)2.0;
420 /* Need to truncate precision so that answers are consistent */
421 /* on different computer architectures when rounding doubles. */
422 pad = trunc_dbl_precision(pad, TRUNC_SCALE);
423 grid_pad = sround(pad);
424 break;
425 default:
426 fprintf(stderr,
427 "ERROR : init_rotgrids : Illegal relative flag : %d\n",
428 relative2);
429 free(rotgrids);
430 return(-31);
433 /* If input padding is UNDEFINED ... */
434 if(ipad == UNDEFINED)
435 /* Use the padding specifically required by the rotated grids herein. */
436 rotgrids->pad = grid_pad;
437 else{
438 /* Otherwise, input pad was specified, so check to make sure it is */
439 /* sufficiently large to handle the rotated grids herein. */
440 if(ipad < grid_pad){
441 /* If input pad is NOT large enough, then ERROR. */
442 fprintf(stderr, "ERROR : init_rotgrids : Pad passed is too small\n");
443 free(rotgrids);
444 return(-32);
446 /* Otherwise, use the specified input pad in computing grid offsets. */
447 rotgrids->pad = ipad;
450 /* Total number of points in grid */
451 grid_size = grid_w * grid_h;
453 /* Compute width of "padded" image */
454 pw = iw + (rotgrids->pad<<1);
456 /* Center coord of grid (0-oriented). */
457 cx = (grid_w-1)/(double)2.0;
458 cy = (grid_h-1)/(double)2.0;
460 /* Allocate list of rotgrid pointers */
461 rotgrids->grids = (int **)malloc(ndirs * sizeof(int *));
462 if(rotgrids->grids == (int **)NULL){
463 /* Free memory allocated to this point. */
464 free(rotgrids);
465 fprintf(stderr, "ERROR : init_rotgrids : malloc : rotgrids->grids\n");
466 return(-33);
469 /* Pi_offset is the offset in radians from which angles are to begin. */
470 pi_offset = start_dir_angle;
471 pi_incr = M_PI/(double)ndirs; /* if ndirs == 16, incr = 11.25 degrees */
473 /* For each direction to rotate a grid ... */
474 for (dir = 0, theta = pi_offset;
475 dir < ndirs; dir++, theta += pi_incr) {
477 /* Allocate a rotgrid */
478 rotgrids->grids[dir] = (int *)malloc(grid_size * sizeof(int));
479 if(rotgrids->grids[dir] == (int *)NULL){
480 /* Free memory allocated to this point. */
481 { int _j; for(_j = 0; _j < dir; _j++){
482 free(rotgrids->grids[_j]);
484 free(rotgrids);
485 fprintf(stderr,
486 "ERROR : init_rotgrids : malloc : rotgrids->grids[dir]\n");
487 return(-34);
490 /* Set pointer to current grid */
491 grid = rotgrids->grids[dir];
493 /* Compute cos and sin of current angle */
494 cs = cos(theta);
495 sn = sin(theta);
497 /* This next section of nested FOR loops precomputes a */
498 /* rotated grid. The rotation is set up to rotate a GRID_W X */
499 /* GRID_H grid on its center point at C=(Cx,Cy). The current */
500 /* pixel being rotated is P=(Ix,Iy). Therefore, we have a */
501 /* rotation transformation of point P about pivot point C. */
502 /* The rotation transformation about a pivot point in matrix */
503 /* form is: */
505 +- -+
506 | cos(T) sin(T) 0 |
507 [Ix Iy 1] | -sin(T) cos(T) 0 |
508 | (1-cos(T))*Cx + Cy*sin(T) (1-cos(T))*Cy - Cx*sin(T) 1 |
509 +- -+
511 /* Multiplying the 2 matrices and combining terms yeilds the */
512 /* equations for rotated coordinates (Rx, Ry): */
513 /* Rx = Cx + (Ix - Cx)*cos(T) - (Iy - Cy)*sin(T) */
514 /* Ry = Cy + (Ix - Cx)*sin(T) + (Iy - Cy)*cos(T) */
515 /* */
516 /* Care has been taken to ensure that (for example) when */
517 /* BLOCKSIZE==24 the rotated indices stay within a centered */
518 /* 34X34 area. */
519 /* This is important for computing an accurate padding of */
520 /* the input image. The rotation occurs "in-place" so that */
521 /* outer pixels in the grid are mapped at times from */
522 /* adjoining blocks. As a result, to keep from accessing */
523 /* "unknown" memory or pixels wrapped from the other side of */
524 /* the image, the input image should first be padded by */
525 /* PAD=round((DIAG - BLOCKSIZE)/2.0) where DIAG is the */
526 /* diagonal distance of the grid. */
527 /* For example, when BLOCKSIZE==24, Dx=34, so PAD=5. */
529 /* Foreach each y coord in block ... */
530 for (iy = 0; iy < grid_h; ++iy) {
531 /* Compute rotation factors dependent on Iy (include constant) */
532 fxm = -1.0 * ((iy - cy) * sn);
533 fym = ((iy - cy) * cs);
535 /* If offsets are to be relative to the grids origin, then */
536 /* we need to subtract CX and CY. */
537 if(relative2 == RELATIVE2ORIGIN){
538 fxm += cx;
539 fym += cy;
542 /* foreach each x coord in block ... */
543 for (ix = 0; ix < grid_w; ++ix) {
545 /* Now combine factors dependent on Iy with those of Ix */
546 fx = fxm + ((ix - cx) * cs);
547 fy = fym + ((ix - cx) * sn);
548 /* Need to truncate precision so that answers are consistent */
549 /* on different computer architectures when rounding doubles. */
550 fx = trunc_dbl_precision(fx, TRUNC_SCALE);
551 fy = trunc_dbl_precision(fy, TRUNC_SCALE);
552 ixt = sround(fx);
553 iyt = sround(fy);
555 /* Store the current pixels relative */
556 /* rotated offset. Make sure to */
557 /* multiply the y-component of the */
558 /* offset by the "padded" image width! */
559 *grid++ = ixt + (iyt * pw);
560 }/* ix */
561 }/* iy */
562 }/* dir */
564 *optr = rotgrids;
565 return(0);
568 /*************************************************************************
569 **************************************************************************
570 #cat: alloc_dir_powers - Allocates the memory associated with DFT power
571 #cat: vectors. The DFT analysis is conducted block by block in the
572 #cat: input image, and within each block, N wave forms are applied
573 #cat: at M different directions.
575 Input:
576 nwaves - number of DFT wave forms
577 ndirs - number of orientations (directions) used in DFT analysis
578 Output:
579 opowers - pointer to the allcated power vectors
580 Return Code:
581 Zero - successful completion
582 Negative - system error
583 **************************************************************************/
584 int alloc_dir_powers(double ***opowers, const int nwaves, const int ndirs)
586 int w;
587 double **powers;
589 /* Allocate list of double pointers to hold power vectors */
590 powers = (double **)malloc(nwaves * sizeof(double*));
591 if(powers == (double **)NULL){
592 fprintf(stderr, "ERROR : alloc_dir_powers : malloc : powers\n");
593 return(-40);
595 /* Foreach DFT wave ... */
596 for(w = 0; w < nwaves; w++){
597 /* Allocate power vector for all directions */
598 powers[w] = (double *)malloc(ndirs * sizeof(double));
599 if(powers[w] == (double *)NULL){
600 /* Free memory allocated to this point. */
601 { int _j; for(_j = 0; _j < w; _j++){
602 free(powers[_j]);
604 free(powers);
605 fprintf(stderr, "ERROR : alloc_dir_powers : malloc : powers[w]\n");
606 return(-41);
610 *opowers = powers;
611 return(0);
614 /*************************************************************************
615 **************************************************************************
616 #cat: alloc_power_stats - Allocates memory associated with set of statistics
617 #cat: derived from DFT power vectors computed in a block of the
618 #cat: input image. Statistics are not computed for the lowest DFT
619 #cat: wave form, so the length of the statistics arrays is 1 less
620 #cat: than the number of DFT wave forms used. The staistics
621 #cat: include the Maximum power for each wave form, the direction
622 #cat: at which the maximum power occured, and a normalized value
623 #cat: for the maximum power. In addition, the statistics are
624 #cat: ranked in descending order based on normalized squared
625 #cat: maximum power.
627 Input:
628 nstats - the number of waves forms from which statistics are to be
629 derived (N Waves - 1)
630 Output:
631 owis - points to an array to hold the ranked wave form indicies
632 of the corresponding statistics
633 opowmaxs - points to an array to hold the maximum DFT power for each
634 wave form
635 opowmax_dirs - points to an array to hold the direction corresponding to
636 each maximum power value
637 opownorms - points to an array to hold the normalized maximum power
638 Return Code:
639 Zero - successful completion
640 Negative - system error
641 **************************************************************************/
642 int alloc_power_stats(int **owis, double **opowmaxs, int **opowmax_dirs,
643 double **opownorms, const int nstats)
645 int *wis, *powmax_dirs;
646 double *powmaxs, *pownorms;
648 /* Allocate DFT wave index vector */
649 wis = (int *)malloc(nstats * sizeof(int));
650 if(wis == (int *)NULL){
651 fprintf(stderr, "ERROR : alloc_power_stats : malloc : wis\n");
652 return(-50);
655 /* Allocate max power vector */
656 powmaxs = (double *)malloc(nstats * sizeof(double));
657 if(powmaxs == (double *)NULL){
658 /* Free memory allocated to this point. */
659 free(wis);
660 fprintf(stderr, "ERROR : alloc_power_stats : malloc : powmaxs\n");
661 return(-51);
664 /* Allocate max power direction vector */
665 powmax_dirs = (int *)malloc(nstats * sizeof(int));
666 if(powmax_dirs == (int *)NULL){
667 /* Free memory allocated to this point. */
668 free(wis);
669 free(powmaxs);
670 fprintf(stderr, "ERROR : alloc_power_stats : malloc : powmax_dirs\n");
671 return(-52);
674 /* Allocate normalized power vector */
675 pownorms = (double *)malloc(nstats * sizeof(double));
676 if(pownorms == (double *)NULL){
677 /* Free memory allocated to this point. */
678 free(wis);
679 free(powmaxs);
680 free(pownorms);
681 fprintf(stderr, "ERROR : alloc_power_stats : malloc : pownorms\n");
682 return(-53);
685 *owis = wis;
686 *opowmaxs = powmaxs;
687 *opowmax_dirs = powmax_dirs;
688 *opownorms = pownorms;
689 return(0);