Changeset 1385 for trunk/psLib/src/math/psStats.c
- Timestamp:
- Aug 4, 2004, 1:37:39 PM (22 years ago)
- File:
-
- 1 edited
-
trunk/psLib/src/math/psStats.c (modified) (44 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psLib/src/math/psStats.c
r1361 r1385 36 36 unsigned int maskVal, 37 37 psStats *stats ); 38 38 39 39 /** Preprocessor macro to generate error on an incorrect type */ 40 40 #define PS_CHECK_VECTOR_TYPE(NAME, TYPE) \ 41 41 if (NAME->type.type != TYPE) { \ 42 psError(__func__,"Invalid operation: %s has incorrect type.", #NAME); \43 }44 42 psError(__func__,"Invalid operation: %s has incorrect type.", #NAME); \ 43 } 44 45 45 /** Preprocessor macro to generate error on a NULL vector */ 46 46 #define PS_CHECK_NULL_VECTOR(NAME) \ 47 47 if (NAME == NULL || NAME->data.V == NULL) { \ 48 psError(__func__,"Invalid operation: %s or its data is NULL.", #NAME); \49 }50 48 psError(__func__,"Invalid operation: %s or its data is NULL.", #NAME); \ 49 } 50 51 51 /** Preprocessor macro to generate error for zero length vector */ 52 52 #define PS_CHECK_EMPTY_VECTOR(NAME) \ 53 53 if (NAME->n < 1) { \ 54 psError(__func__,"Invalid operation: %s has zero n value.", #NAME); \55 }56 54 psError(__func__,"Invalid operation: %s has zero n value.", #NAME); \ 55 } 56 57 57 /** Preprocessor macro to generate error on differing size vectors */ 58 58 #define PS_CHECK_VECTOR_SIZE_EQUAL(VEC1, VEC2) \ 59 59 if (VEC1->n != VEC2->n) { \ 60 psError(__func__,"Vector %s has size %d, Vector %s has size %d.", #VEC1, VEC1->n, #VEC2, VEC2->n); \61 }62 60 psError(__func__,"Vector %s has size %d, Vector %s has size %d.", #VEC1, VEC1->n, #VEC2, VEC2->n); \ 61 } 62 63 63 #define PS_PRINT_VECTOR(NAME) \ 64 64 for (int my_i=0;my_i<NAME->n;my_i++) { \ 65 printf("%s->data.F32[%d] is %f\n", #NAME, my_i, NAME->data.F32[my_i]); \66 } \65 printf("%s->data.F32[%d] is %f\n", #NAME, my_i, NAME->data.F32[my_i]); \ 66 } \ 67 67 printf("\n"); \ 68 68 … … 92 92 switch ( stats->options & 93 93 ~ ( PS_STAT_USE_RANGE | PS_STAT_USE_BINSIZE | PS_STAT_ROBUST_FOR_SAMPLE ) ) { 94 case PS_STAT_SAMPLE_MEAN:95 *value = stats->sampleMean;96 return true;97 98 case PS_STAT_SAMPLE_MEDIAN:99 *value = stats->sampleMedian;100 return true;101 102 case PS_STAT_SAMPLE_STDEV:103 *value = stats->sampleStdev;104 return true;105 106 case PS_STAT_ROBUST_MEAN:107 *value = stats->robustMean;108 return true;109 110 case PS_STAT_ROBUST_MEDIAN:111 *value = stats->robustMedian;112 return true;113 114 case PS_STAT_ROBUST_MODE:115 *value = stats->robustMode;116 return true;117 118 case PS_STAT_ROBUST_STDEV:119 *value = stats->robustStdev;120 return true;121 122 case PS_STAT_CLIPPED_MEAN:123 *value = stats->clippedMean;124 return true;125 126 case PS_STAT_CLIPPED_STDEV:127 *value = stats->clippedStdev;128 return true;129 130 case PS_STAT_MAX:131 *value = stats->max;132 return true;133 134 case PS_STAT_MIN:135 *value = stats->min;136 return true;137 138 default:139 return false;140 }94 case PS_STAT_SAMPLE_MEAN: 95 *value = stats->sampleMean; 96 return true; 97 98 case PS_STAT_SAMPLE_MEDIAN: 99 *value = stats->sampleMedian; 100 return true; 101 102 case PS_STAT_SAMPLE_STDEV: 103 *value = stats->sampleStdev; 104 return true; 105 106 case PS_STAT_ROBUST_MEAN: 107 *value = stats->robustMean; 108 return true; 109 110 case PS_STAT_ROBUST_MEDIAN: 111 *value = stats->robustMedian; 112 return true; 113 114 case PS_STAT_ROBUST_MODE: 115 *value = stats->robustMode; 116 return true; 117 118 case PS_STAT_ROBUST_STDEV: 119 *value = stats->robustStdev; 120 return true; 121 122 case PS_STAT_CLIPPED_MEAN: 123 *value = stats->clippedMean; 124 return true; 125 126 case PS_STAT_CLIPPED_STDEV: 127 *value = stats->clippedStdev; 128 return true; 129 130 case PS_STAT_MAX: 131 *value = stats->max; 132 return true; 133 134 case PS_STAT_MIN: 135 *value = stats->min; 136 return true; 137 138 default: 139 return false; 140 } 141 141 } 142 142 … … 153 153 { 154 154 int i = 0; // Loop index variable. 155 155 156 156 for ( i = 0;i < myVector->n;i++ ) { 157 if ( maskVector != NULL )158 printf( "Element %d is %f (mask is %d)\n", i, myVector->data.F32[ i ], maskVector->data.U8[ i ] );159 else160 printf( "Element %d is %f\n", i, myVector->data.F32[ i ] );161 }157 if ( maskVector != NULL ) 158 printf( "Element %d is %f (mask is %d)\n", i, myVector->data.F32[ i ], maskVector->data.U8[ i ] ); 159 else 160 printf( "Element %d is %f\n", i, myVector->data.F32[ i ] ); 161 } 162 162 } 163 163 … … 204 204 float rangeMin = 0.0; // Exclude data below this 205 205 float rangeMax = 0.0; // Exclude date above this 206 206 207 207 // If PS_STAT_USE_RANGE is requested, then we enter a slightly different 208 208 // loop. 209 209 if ( stats->options & PS_STAT_USE_RANGE ) { 210 rangeMin = stats->min; 211 rangeMax = stats->max; 212 if ( maskVector != NULL ) { 213 for ( i = 0;i < myVector->n;i++ ) { 214 // Check if the data is with the specified range 215 if ( !( maskVal & maskVector->data.U8[ i ] ) && 216 ( rangeMin <= myVector->data.F32[ i ] ) && 217 ( myVector->data.F32[ i ] <= rangeMax ) ) { 218 mean += myVector->data.F32[ i ]; 219 count++; 220 } 221 } 222 mean /= ( float ) count; 223 } else { 224 for ( i = 0;i < myVector->n;i++ ) { 225 if ( ( rangeMin <= myVector->data.F32[ i ] ) && 226 ( myVector->data.F32[ i ] <= rangeMax ) ) { 227 mean += myVector->data.F32[ i ]; 228 count++; 229 } 230 } 231 mean /= ( float ) count; 232 } 210 rangeMin = stats->min; 211 rangeMax = stats->max; 212 if ( maskVector != NULL ) { 213 for ( i = 0;i < myVector->n;i++ ) { 214 // Check if the data is with the specified range 215 if ( !( maskVal & maskVector->data.U8[ i ] ) && 216 ( rangeMin <= myVector->data.F32[ i ] ) && 217 ( myVector->data.F32[ i ] <= rangeMax ) ) { 218 mean += myVector->data.F32[ i ]; 219 count++; 220 } 221 } 222 mean /= ( float ) count; 233 223 } else { 234 if ( maskVector != NULL ) { 235 for ( i = 0;i < myVector->n;i++ ) { 236 if ( !( maskVal & maskVector->data.U8[ i ] ) ) { 237 mean += myVector->data.F32[ i ]; 238 count++; 239 } 240 } 241 mean /= ( float ) count; 242 } else { 243 for ( i = 0;i < myVector->n;i++ ) { 244 mean += myVector->data.F32[ i ]; 245 } 246 mean /= ( float ) myVector->n; 247 } 248 } 249 224 for ( i = 0;i < myVector->n;i++ ) { 225 if ( ( rangeMin <= myVector->data.F32[ i ] ) && 226 ( myVector->data.F32[ i ] <= rangeMax ) ) { 227 mean += myVector->data.F32[ i ]; 228 count++; 229 } 230 } 231 mean /= ( float ) count; 232 } 233 } else { 234 if ( maskVector != NULL ) { 235 for ( i = 0;i < myVector->n;i++ ) { 236 if ( !( maskVal & maskVector->data.U8[ i ] ) ) { 237 mean += myVector->data.F32[ i ]; 238 count++; 239 } 240 } 241 mean /= ( float ) count; 242 } else { 243 for ( i = 0;i < myVector->n;i++ ) { 244 mean += myVector->data.F32[ i ]; 245 } 246 mean /= ( float ) myVector->n; 247 } 248 } 249 250 250 stats->sampleMean = mean; 251 251 } … … 271 271 float rangeMin = 0.0; // Exclude data below this 272 272 float rangeMax = 0.0; // Exclude date above this 273 273 274 274 // If PS_STAT_USE_RANGE is requested, then we enter a different loop. 275 275 if ( stats->options & PS_STAT_USE_RANGE ) { 276 rangeMin = stats->min; 277 rangeMax = stats->max; 278 if ( maskVector != NULL ) { 279 for ( i = 0;i < myVector->n;i++ ) { 280 if ( !( maskVal & maskVector->data.U8[ i ] ) ) { 281 if ( ( myVector->data.F32[ i ] > max ) && 282 ( rangeMin <= myVector->data.F32[ i ] ) && 283 ( myVector->data.F32[ i ] <= rangeMax ) ) { 284 max = myVector->data.F32[ i ]; 285 } 286 } 287 } 288 } else { 289 for ( i = 0;i < myVector->n;i++ ) { 290 if ( ( myVector->data.F32[ i ] > max ) && 291 ( rangeMin <= myVector->data.F32[ i ] ) && 292 ( myVector->data.F32[ i ] <= rangeMax ) ) { 293 max = myVector->data.F32[ i ]; 294 } 295 } 296 } 276 rangeMin = stats->min; 277 rangeMax = stats->max; 278 if ( maskVector != NULL ) { 279 for ( i = 0;i < myVector->n;i++ ) { 280 if ( !( maskVal & maskVector->data.U8[ i ] ) ) { 281 if ( ( myVector->data.F32[ i ] > max ) && 282 ( rangeMin <= myVector->data.F32[ i ] ) && 283 ( myVector->data.F32[ i ] <= rangeMax ) ) { 284 max = myVector->data.F32[ i ]; 285 } 286 } 287 } 297 288 } else { 298 if ( maskVector != NULL ) { 299 for ( i = 0;i < myVector->n;i++ ) { 300 if ( !( maskVal & maskVector->data.U8[ i ] ) ) { 301 if ( myVector->data.F32[ i ] > max ) { 302 max = myVector->data.F32[ i ]; 303 } 304 } 305 } 306 } else { 307 for ( i = 0;i < myVector->n;i++ ) { 308 if ( myVector->data.F32[ i ] > max ) { 309 max = myVector->data.F32[ i ]; 310 } 311 } 312 } 313 } 314 289 for ( i = 0;i < myVector->n;i++ ) { 290 if ( ( myVector->data.F32[ i ] > max ) && 291 ( rangeMin <= myVector->data.F32[ i ] ) && 292 ( myVector->data.F32[ i ] <= rangeMax ) ) { 293 max = myVector->data.F32[ i ]; 294 } 295 } 296 } 297 } else { 298 if ( maskVector != NULL ) { 299 for ( i = 0;i < myVector->n;i++ ) { 300 if ( !( maskVal & maskVector->data.U8[ i ] ) ) { 301 if ( myVector->data.F32[ i ] > max ) { 302 max = myVector->data.F32[ i ]; 303 } 304 } 305 } 306 } else { 307 for ( i = 0;i < myVector->n;i++ ) { 308 if ( myVector->data.F32[ i ] > max ) { 309 max = myVector->data.F32[ i ]; 310 } 311 } 312 } 313 } 314 315 315 stats->max = max; 316 316 } … … 336 336 float rangeMin = 0.0; // Exclude data below this 337 337 float rangeMax = 0.0; // Exclude date above this 338 338 339 339 if ( stats->options & PS_STAT_USE_RANGE ) { 340 rangeMin = stats->min; 341 rangeMax = stats->max; 342 if ( maskVector != NULL ) { 343 for ( i = 0;i < myVector->n;i++ ) { 344 if ( !( maskVal & maskVector->data.U8[ i ] ) ) { 345 if ( ( myVector->data.F32[ i ] < min ) && 346 ( rangeMin <= myVector->data.F32[ i ] ) && 347 ( myVector->data.F32[ i ] <= rangeMax ) ) { 348 min = myVector->data.F32[ i ]; 349 } 350 } 351 } 352 } else { 353 for ( i = 0;i < myVector->n;i++ ) { 354 if ( ( myVector->data.F32[ i ] < min ) && 355 ( rangeMin <= myVector->data.F32[ i ] ) && 356 ( myVector->data.F32[ i ] <= rangeMax ) ) { 357 min = myVector->data.F32[ i ]; 358 } 359 } 360 } 340 rangeMin = stats->min; 341 rangeMax = stats->max; 342 if ( maskVector != NULL ) { 343 for ( i = 0;i < myVector->n;i++ ) { 344 if ( !( maskVal & maskVector->data.U8[ i ] ) ) { 345 if ( ( myVector->data.F32[ i ] < min ) && 346 ( rangeMin <= myVector->data.F32[ i ] ) && 347 ( myVector->data.F32[ i ] <= rangeMax ) ) { 348 min = myVector->data.F32[ i ]; 349 } 350 } 351 } 361 352 } else { 362 if ( maskVector != NULL ) { 363 for ( i = 0;i < myVector->n;i++ ) { 364 if ( !( maskVal & maskVector->data.U8[ i ] ) ) { 365 if ( myVector->data.F32[ i ] < min ) { 366 min = myVector->data.F32[ i ]; 367 } 368 } 369 } 370 } else { 371 for ( i = 0;i < myVector->n;i++ ) { 372 if ( myVector->data.F32[ i ] < min ) { 373 min = myVector->data.F32[ i ]; 374 } 375 } 376 } 377 } 378 353 for ( i = 0;i < myVector->n;i++ ) { 354 if ( ( myVector->data.F32[ i ] < min ) && 355 ( rangeMin <= myVector->data.F32[ i ] ) && 356 ( myVector->data.F32[ i ] <= rangeMax ) ) { 357 min = myVector->data.F32[ i ]; 358 } 359 } 360 } 361 } else { 362 if ( maskVector != NULL ) { 363 for ( i = 0;i < myVector->n;i++ ) { 364 if ( !( maskVal & maskVector->data.U8[ i ] ) ) { 365 if ( myVector->data.F32[ i ] < min ) { 366 min = myVector->data.F32[ i ]; 367 } 368 } 369 } 370 } else { 371 for ( i = 0;i < myVector->n;i++ ) { 372 if ( myVector->data.F32[ i ] < min ) { 373 min = myVector->data.F32[ i ]; 374 } 375 } 376 } 377 } 378 379 379 stats->min = min; 380 380 } … … 401 401 float rangeMin = 0.0; // Exclude data below this 402 402 float rangeMax = 0.0; // Exclude date above this 403 403 404 404 if ( stats->options & PS_STAT_USE_RANGE ) { 405 rangeMin = stats->min; 406 rangeMax = stats->max; 407 if ( maskVector != NULL ) { 408 for ( i = 0;i < myVector->n;i++ ) { 409 if ( !( maskVal & maskVector->data.U8[ i ] ) && 410 ( rangeMin <= myVector->data.F32[ i ] ) && 411 ( myVector->data.F32[ i ] <= rangeMax ) ) { 412 numData++; 413 } 414 } 415 } else { 416 for ( i = 0;i < myVector->n;i++ ) { 417 if ( ( rangeMin <= myVector->data.F32[ i ] ) && 418 ( myVector->data.F32[ i ] <= rangeMax ) ) { 419 numData++; 420 } 421 } 422 } 405 rangeMin = stats->min; 406 rangeMax = stats->max; 407 if ( maskVector != NULL ) { 408 for ( i = 0;i < myVector->n;i++ ) { 409 if ( !( maskVal & maskVector->data.U8[ i ] ) && 410 ( rangeMin <= myVector->data.F32[ i ] ) && 411 ( myVector->data.F32[ i ] <= rangeMax ) ) { 412 numData++; 413 } 414 } 423 415 } else { 424 rangeMin = stats->min; 425 rangeMax = stats->max; 426 if ( maskVector != NULL ) { 427 for ( i = 0;i < myVector->n;i++ ) { 428 if ( !( maskVal & maskVector->data.U8[ i ] ) ) { 429 numData++; 430 } 431 } 432 } else { 433 numData = myVector->n; 434 } 435 } 416 for ( i = 0;i < myVector->n;i++ ) { 417 if ( ( rangeMin <= myVector->data.F32[ i ] ) && 418 ( myVector->data.F32[ i ] <= rangeMax ) ) { 419 numData++; 420 } 421 } 422 } 423 } else { 424 rangeMin = stats->min; 425 rangeMax = stats->max; 426 if ( maskVector != NULL ) { 427 for ( i = 0;i < myVector->n;i++ ) { 428 if ( !( maskVal & maskVector->data.U8[ i ] ) ) { 429 numData++; 430 } 431 } 432 } else { 433 numData = myVector->n; 434 } 435 } 436 436 return ( numData ); 437 437 } … … 462 462 float rangeMin = 0.0; // Exclude data below this 463 463 float rangeMax = 0.0; // Exclude date above this 464 465 464 465 466 466 // Determine if the number of data points exceed a threshold which will 467 467 // cause to generate robust stats, as opposed to exact stats. … … 488 488 } 489 489 */ 490 490 491 491 // Determine how many data points fit inside this min/max range 492 492 // and are not masked, IF the maskVector is not NULL> 493 493 nValues = p_psVectorNValues( myVector, maskVector, maskVal, stats ); 494 494 495 495 // Allocate temporary vectors for the data. 496 496 unsortedVector = psVectorAlloc( nValues, PS_TYPE_F32 ); 497 497 unsortedVector->n = unsortedVector->nalloc; 498 498 499 499 sortedVector = psVectorAlloc( nValues, PS_TYPE_F32 ); 500 500 sortedVector->n = sortedVector->nalloc; 501 501 502 502 // Determine if we must only use data points within a min/max range. 503 503 if ( stats->options & PS_STAT_USE_RANGE ) { 504 rangeMin = stats->min; 505 rangeMax = stats->max; 506 507 // Store all non-masked data points within the min/max range 508 // into the temporary vectors. 509 count = 0; 510 if ( maskVector != NULL ) { 511 for ( i = 0;i < myVector->n;i++ ) { 512 if ( !( maskVal & maskVector->data.U8[ i ] ) && 513 ( rangeMin <= myVector->data.F32[ i ] ) && 514 ( myVector->data.F32[ i ] <= rangeMax ) ) { 515 unsortedVector->data.F32[ count++ ] = maskVector->data.F32[ i ]; 516 } 517 } 518 } else { 519 for ( i = 0;i < myVector->n;i++ ) { 520 if ( ( rangeMin <= myVector->data.F32[ i ] ) && 521 ( myVector->data.F32[ i ] <= rangeMax ) ) { 522 unsortedVector->data.F32[ count++ ] = myVector->data.F32[ i ]; 523 } 524 } 525 } 504 rangeMin = stats->min; 505 rangeMax = stats->max; 506 507 // Store all non-masked data points within the min/max range 508 // into the temporary vectors. 509 count = 0; 510 if ( maskVector != NULL ) { 511 for ( i = 0;i < myVector->n;i++ ) { 512 if ( !( maskVal & maskVector->data.U8[ i ] ) && 513 ( rangeMin <= myVector->data.F32[ i ] ) && 514 ( myVector->data.F32[ i ] <= rangeMax ) ) { 515 unsortedVector->data.F32[ count++ ] = maskVector->data.F32[ i ]; 516 } 517 } 526 518 } else { 527 // Store all non-masked data points into the temporary vectors. 528 count = 0; 529 if ( maskVector != NULL ) { 530 for ( i = 0;i < myVector->n;i++ ) { 531 if ( !( maskVal & maskVector->data.U8[ i ] ) ) { 532 unsortedVector->data.F32[ count++ ] = myVector->data.F32[ i ]; 533 } 534 } 535 } else { 536 for ( i = 0;i < myVector->n;i++ ) { 537 unsortedVector->data.F32[ i ] = myVector->data.F32[ i ]; 538 } 539 } 540 } 519 for ( i = 0;i < myVector->n;i++ ) { 520 if ( ( rangeMin <= myVector->data.F32[ i ] ) && 521 ( myVector->data.F32[ i ] <= rangeMax ) ) { 522 unsortedVector->data.F32[ count++ ] = myVector->data.F32[ i ]; 523 } 524 } 525 } 526 } else { 527 // Store all non-masked data points into the temporary vectors. 528 count = 0; 529 if ( maskVector != NULL ) { 530 for ( i = 0;i < myVector->n;i++ ) { 531 if ( !( maskVal & maskVector->data.U8[ i ] ) ) { 532 unsortedVector->data.F32[ count++ ] = myVector->data.F32[ i ]; 533 } 534 } 535 } else { 536 for ( i = 0;i < myVector->n;i++ ) { 537 unsortedVector->data.F32[ i ] = myVector->data.F32[ i ]; 538 } 539 } 540 } 541 541 // Sort the temporary vectors. 542 542 psVectorSort( sortedVector, unsortedVector ); 543 543 544 544 // Calculate the median exactly. 545 545 // XXX: Is this the correct action? 546 546 if ( 0 == ( nValues % 2 ) ) { 547 stats->sampleMedian = 0.5 * ( sortedVector->data.F32[ ( nValues / 2 ) - 1 ] +548 sortedVector->data.F32[ nValues / 2 ] );549 } else {550 stats->sampleMedian = sortedVector->data.F32[ nValues / 2 ];551 }552 547 stats->sampleMedian = 0.5 * ( sortedVector->data.F32[ ( nValues / 2 ) - 1 ] + 548 sortedVector->data.F32[ nValues / 2 ] ); 549 } else { 550 stats->sampleMedian = sortedVector->data.F32[ nValues / 2 ]; 551 } 552 553 553 // Free the temporary data structures. 554 554 psFree( unsortedVector ); … … 577 577 float gaussianCoefs[ 1 + ( 2 * GAUSS_WIDTH ) ]; // The Gaussian Coefficients 578 578 psVector *smooth = psVectorAlloc( robustHistogram->nums->n, PS_TYPE_F32 ); 579 579 580 580 for ( i = 0;i < ( 1 + ( 2 * GAUSS_WIDTH ) );i++ ) { 581 if ( fabs( sigma ) >= FLT_EPSILON ) {582 // If sigma does not equal zero, then we use Gaussian smoothing.583 #ifdef DARWIN584 denom = ( float ) sqrt( 2.0 * M_PI * sigma * sigma );585 #else586 587 denom = sqrtf( 2.0 * M_PI * sigma * sigma );588 #endif589 590 expo = - ( float ) ( ( i - GAUSS_WIDTH ) * ( i - GAUSS_WIDTH ) );591 expo /= ( 2.0 * sigma * sigma );592 gaussianCoefs[ i ] = exp( expo / denom );593 594 // NOTE: Gaussian smoothing just isn't working with low sigma595 // values. The problem is that the Gaussian coefficients are596 // all zero, except for the middle coefficient, which is exactly597 // one. Therefore, I'm using boxcar smoothing.598 gaussianCoefs[ i ] = 1.0 / ( 1.0 + ( 2.0 * ( float ) GAUSS_WIDTH ) );599 // printf("gaussianCoefs[%d] is %f\n", i, gaussianCoefs[i]);600 } else {601 /* If sigma equals zero (all pixels have the same value)602 * the above code will divide by zero. Therefore, we don't need603 * to smooth the data.604 */605 for ( i = 0;i < robustHistogram->nums->n;i++ ) {606 smooth->data.F32[ i ] = ( float ) robustHistogram->nums->data.S32[ i ];607 }608 return ( smooth );609 }610 }611 581 if ( fabs( sigma ) >= FLT_EPSILON ) { 582 // If sigma does not equal zero, then we use Gaussian smoothing. 583 #ifdef DARWIN 584 denom = ( float ) sqrt( 2.0 * M_PI * sigma * sigma ); 585 #else 586 587 denom = sqrtf( 2.0 * M_PI * sigma * sigma ); 588 #endif 589 590 expo = - ( float ) ( ( i - GAUSS_WIDTH ) * ( i - GAUSS_WIDTH ) ); 591 expo /= ( 2.0 * sigma * sigma ); 592 gaussianCoefs[ i ] = exp( expo / denom ); 593 594 // NOTE: Gaussian smoothing just isn't working with low sigma 595 // values. The problem is that the Gaussian coefficients are 596 // all zero, except for the middle coefficient, which is exactly 597 // one. Therefore, I'm using boxcar smoothing. 598 gaussianCoefs[ i ] = 1.0 / ( 1.0 + ( 2.0 * ( float ) GAUSS_WIDTH ) ); 599 // printf("gaussianCoefs[%d] is %f\n", i, gaussianCoefs[i]); 600 } else { 601 /* If sigma equals zero (all pixels have the same value) 602 * the above code will divide by zero. Therefore, we don't need 603 * to smooth the data. 604 */ 605 for ( i = 0;i < robustHistogram->nums->n;i++ ) { 606 smooth->data.F32[ i ] = ( float ) robustHistogram->nums->data.S32[ i ]; 607 } 608 return ( smooth ); 609 } 610 } 611 612 612 // Perform the actual smoothing. 613 613 for ( i = 0;i < robustHistogram->nums->n;i++ ) { 614 smooth->data.F32[ i ] = 0.0;615 for ( j = -GAUSS_WIDTH;j <= + GAUSS_WIDTH;j++ ) {616 if ( ( ( j + i ) >= 0 ) && ( ( j + i ) < smooth->n ) ) {617 smooth->data.F32[ i ] += ( gaussianCoefs[ j + GAUSS_WIDTH ] *618 ( float ) robustHistogram->nums->data.S32[ j + i ] );619 }620 }621 }614 smooth->data.F32[ i ] = 0.0; 615 for ( j = -GAUSS_WIDTH;j <= + GAUSS_WIDTH;j++ ) { 616 if ( ( ( j + i ) >= 0 ) && ( ( j + i ) < smooth->n ) ) { 617 smooth->data.F32[ i ] += ( gaussianCoefs[ j + GAUSS_WIDTH ] * 618 ( float ) robustHistogram->nums->data.S32[ j + i ] ); 619 } 620 } 621 } 622 622 return ( smooth ); 623 623 } … … 646 646 float rangeMin = 0.0; // Exclude data below this 647 647 float rangeMax = 0.0; // Exclude date above this 648 648 649 649 // Determine how many data points fit inside this min/max range 650 650 // and are not maxed, IF the maskVector is not NULL> 651 651 nValues = p_psVectorNValues( myVector, maskVector, maskVal, stats ); 652 652 653 653 // Allocate temporary vectors for the data. 654 654 unsortedVector = psVectorAlloc( nValues, PS_TYPE_F32 ); … … 656 656 sortedVector = psVectorAlloc( nValues, PS_TYPE_F32 ); 657 657 sortedVector->n = sortedVector->nalloc; 658 658 659 659 // Determine if we must only use data points within a min/max range. 660 660 if ( stats->options & PS_STAT_USE_RANGE ) { 661 rangeMin = stats->min; 662 rangeMax = stats->max; 663 // Store all non-masked data points within the min/max range 664 // into the temporary vectors. 665 count = 0; 666 if ( maskVector != NULL ) { 667 for ( i = 0;i < myVector->n;i++ ) { 668 if ( !( maskVal & maskVector->data.U8[ i ] ) && 669 ( rangeMin <= myVector->data.F32[ i ] ) && 670 ( myVector->data.F32[ i ] <= rangeMax ) ) { 671 unsortedVector->data.F32[ count++ ] = myVector->data.F32[ i ]; 672 } 673 } 674 } else { 675 for ( i = 0;i < myVector->n;i++ ) { 676 if ( ( rangeMin <= myVector->data.F32[ i ] ) && 677 ( myVector->data.F32[ i ] <= rangeMax ) ) { 678 unsortedVector->data.F32[ count++ ] = myVector->data.F32[ i ]; 679 } 680 } 681 } 661 rangeMin = stats->min; 662 rangeMax = stats->max; 663 // Store all non-masked data points within the min/max range 664 // into the temporary vectors. 665 count = 0; 666 if ( maskVector != NULL ) { 667 for ( i = 0;i < myVector->n;i++ ) { 668 if ( !( maskVal & maskVector->data.U8[ i ] ) && 669 ( rangeMin <= myVector->data.F32[ i ] ) && 670 ( myVector->data.F32[ i ] <= rangeMax ) ) { 671 unsortedVector->data.F32[ count++ ] = myVector->data.F32[ i ]; 672 } 673 } 682 674 } else { 683 // Store all non-masked data points into the temporary vectors. 684 count = 0; 685 if ( maskVector != NULL ) { 686 for ( i = 0;i < myVector->n;i++ ) { 687 if ( !( maskVal & maskVector->data.U8[ i ] ) ) { 688 unsortedVector->data.F32[ count++ ] = myVector->data.F32[ i ]; 689 } 690 } 691 } else { 692 for ( i = 0;i < myVector->n;i++ ) { 693 unsortedVector->data.F32[ i ] = myVector->data.F32[ i ]; 694 } 695 } 696 } 697 675 for ( i = 0;i < myVector->n;i++ ) { 676 if ( ( rangeMin <= myVector->data.F32[ i ] ) && 677 ( myVector->data.F32[ i ] <= rangeMax ) ) { 678 unsortedVector->data.F32[ count++ ] = myVector->data.F32[ i ]; 679 } 680 } 681 } 682 } else { 683 // Store all non-masked data points into the temporary vectors. 684 count = 0; 685 if ( maskVector != NULL ) { 686 for ( i = 0;i < myVector->n;i++ ) { 687 if ( !( maskVal & maskVector->data.U8[ i ] ) ) { 688 unsortedVector->data.F32[ count++ ] = myVector->data.F32[ i ]; 689 } 690 } 691 } else { 692 for ( i = 0;i < myVector->n;i++ ) { 693 unsortedVector->data.F32[ i ] = myVector->data.F32[ i ]; 694 } 695 } 696 } 697 698 698 // Sort the temporary vectors. 699 699 psVectorSort( sortedVector, unsortedVector ); 700 700 701 701 // Calculate the quartile points exactly. 702 702 stats->sampleUQ = sortedVector->data.F32[ 3 * ( nValues / 4 ) ]; 703 703 stats->sampleLQ = sortedVector->data.F32[ nValues / 4 ]; 704 704 705 705 // Free the temporary data structures. 706 706 psFree( unsortedVector ); … … 735 735 float rangeMin = 0.0; // Exclude data below this 736 736 float rangeMax = 0.0; // Exclude date above this 737 737 738 738 // This procedure requires the mean. If it has not been already 739 739 // calculated, then call p_psVectorSampleMean() 740 740 if ( 0 != isnan( stats->sampleMean ) ) { 741 p_psVectorSampleMean( myVector, maskVector, maskVal, stats );742 }741 p_psVectorSampleMean( myVector, maskVector, maskVal, stats ); 742 } 743 743 mean = stats->sampleMean; 744 744 745 745 if ( stats->options & PS_STAT_USE_RANGE ) { 746 if ( maskVector != NULL ) { 747 for ( i = 0;i < myVector->n;i++ ) { 748 if ( !( maskVal & maskVector->data.U8[ i ] ) && 749 ( rangeMin <= myVector->data.F32[ i ] ) && 750 ( myVector->data.F32[ i ] <= rangeMax ) ) { 751 diff = myVector->data.F32[ i ] - mean; 752 sumSquares += ( diff * diff ); 753 sumDiffs += diff; 754 countInt++; 755 } 756 } 757 } else { 758 for ( i = 0;i < myVector->n;i++ ) { 759 if ( ( rangeMin <= myVector->data.F32[ i ] ) && 760 ( myVector->data.F32[ i ] <= rangeMax ) ) { 761 diff = myVector->data.F32[ i ] - mean; 762 sumSquares += ( diff * diff ); 763 sumDiffs += diff; 764 countInt++; 765 } 766 } 767 countInt = myVector->n; 768 } 746 if ( maskVector != NULL ) { 747 for ( i = 0;i < myVector->n;i++ ) { 748 if ( !( maskVal & maskVector->data.U8[ i ] ) && 749 ( rangeMin <= myVector->data.F32[ i ] ) && 750 ( myVector->data.F32[ i ] <= rangeMax ) ) { 751 diff = myVector->data.F32[ i ] - mean; 752 sumSquares += ( diff * diff ); 753 sumDiffs += diff; 754 countInt++; 755 } 756 } 769 757 } else { 770 if ( maskVector != NULL ) { 771 for ( i = 0;i < myVector->n;i++ ) { 772 if ( !( maskVal & maskVector->data.U8[ i ] ) ) { 773 diff = myVector->data.F32[ i ] - mean; 774 sumSquares += ( diff * diff ); 775 sumDiffs += diff; 776 countInt++; 777 } 778 } 779 } else { 780 for ( i = 0;i < myVector->n;i++ ) { 781 diff = myVector->data.F32[ i ] - mean; 782 sumSquares += ( diff * diff ); 783 sumDiffs += diff; 784 countInt++; 785 } 786 countInt = myVector->n; 787 } 788 } 758 for ( i = 0;i < myVector->n;i++ ) { 759 if ( ( rangeMin <= myVector->data.F32[ i ] ) && 760 ( myVector->data.F32[ i ] <= rangeMax ) ) { 761 diff = myVector->data.F32[ i ] - mean; 762 sumSquares += ( diff * diff ); 763 sumDiffs += diff; 764 countInt++; 765 } 766 } 767 countInt = myVector->n; 768 } 769 } else { 770 if ( maskVector != NULL ) { 771 for ( i = 0;i < myVector->n;i++ ) { 772 if ( !( maskVal & maskVector->data.U8[ i ] ) ) { 773 diff = myVector->data.F32[ i ] - mean; 774 sumSquares += ( diff * diff ); 775 sumDiffs += diff; 776 countInt++; 777 } 778 } 779 } else { 780 for ( i = 0;i < myVector->n;i++ ) { 781 diff = myVector->data.F32[ i ] - mean; 782 sumSquares += ( diff * diff ); 783 sumDiffs += diff; 784 countInt++; 785 } 786 countInt = myVector->n; 787 } 788 } 789 789 countFloat = ( float ) countInt; 790 790 791 791 #ifdef DARWIN 792 792 793 793 stats->sampleStdev = ( float ) sqrt( ( sumSquares - ( sumDiffs * 794 794 sumDiffs / countFloat ) ) / ( countFloat - 1 ) ); 795 795 #else 796 796 797 797 stats->sampleStdev = sqrtf( ( sumSquares - ( sumDiffs * 798 798 sumDiffs / countFloat ) ) / ( countFloat - 1 ) ); … … 824 824 float oldStanStdev = 0.0; // Temporary variable 825 825 psVector *tmpMask = NULL; // Temporary vector 826 826 827 827 // Endure that stats->clipIter is within the proper range. 828 828 if ( !( ( CLIPPED_NUM_ITER_LB <= stats->clipIter ) && 829 829 ( stats->clipIter <= CLIPPED_NUM_ITER_UB ) ) ) { 830 psAbort( __func__, "Unallowed value for clipIter (%d).\n",831 stats->clipIter );832 }833 830 psAbort( __func__, "Unallowed value for clipIter (%d).\n", 831 stats->clipIter ); 832 } 833 834 834 // Endure that stats->clipSigma is within the proper range. 835 835 if ( !( ( CLIPPED_SIGMA_LB <= stats->clipSigma ) && 836 836 ( stats->clipSigma <= CLIPPED_SIGMA_UB ) ) ) { 837 psAbort( __func__, "Unallowed value for clipSigma (%f).\n",838 stats->clipSigma );839 }840 837 psAbort( __func__, "Unallowed value for clipSigma (%f).\n", 838 stats->clipSigma ); 839 } 840 841 841 // We allocate a temporary mask vector since during the iterative 842 842 // steps that follow, we will be masking off additional data points. … … 844 844 tmpMask = psVectorAlloc( myVector->n, PS_TYPE_U8 ); 845 845 tmpMask->n = myVector->n; 846 846 847 847 // If we were called with a mask vector, then initialize the temporary 848 848 // mask vector with those values. 849 849 if ( maskVector != NULL ) { 850 for ( i = 0;i < tmpMask->n;i++ ) {851 tmpMask->data.U8[ i ] = maskVector->data.U8[ i ];852 }853 }854 850 for ( i = 0;i < tmpMask->n;i++ ) { 851 tmpMask->data.U8[ i ] = maskVector->data.U8[ i ]; 852 } 853 } 854 855 855 // 1. Compute the sample median. 856 856 // NOTE: This seems odd. Verify with IfA that we want to calculate the 857 857 // median here, not the mean. 858 858 p_psVectorSampleMedian( myVector, maskVector, maskVal, stats ); 859 859 860 860 // 2. Compute the sample standard deviation. 861 861 p_psVectorSampleStdev( myVector, maskVector, maskVal, stats ); 862 862 863 863 // 3. Use the sample median as the first estimator of the mean X. 864 864 clippedMean = stats->sampleMean; 865 865 866 866 // 4. Use the sample stdev as the first estimator of the mean stdev. 867 867 clippedStdev = stats->sampleStdev; 868 868 869 869 // Must save the old sampleMean and sampleStdev since the following code 870 870 // block overwrites them. 871 871 oldStanMean = stats->sampleMean; 872 872 oldStanStdev = stats->sampleStdev; 873 873 874 874 // 5. Repeat N times: 875 875 for ( i = 0;i < stats->clipIter;i++ ) { 876 for ( j = 0;j < myVector->n;j++ ) {877 // a) Exclude all values x_i for which |x_i - x| > K * stdev878 if ( fabs( myVector->data.F32[ j ] - clippedMean ) >879 ( stats->clipSigma * clippedStdev ) ) {880 tmpMask->data.U8[ i ] = 0xff;881 }882 // b) compute new mean and stdev883 p_psVectorSampleMedian( myVector, tmpMask, maskVal, stats );884 p_psVectorSampleStdev( myVector, tmpMask, maskVal, stats );885 886 // c) Use the new mean for x887 clippedMean = stats->sampleMean;888 889 // d) Use the new stdev for stdev890 clippedStdev = stats->sampleStdev;891 }892 893 }876 for ( j = 0;j < myVector->n;j++ ) { 877 // a) Exclude all values x_i for which |x_i - x| > K * stdev 878 if ( fabs( myVector->data.F32[ j ] - clippedMean ) > 879 ( stats->clipSigma * clippedStdev ) ) { 880 tmpMask->data.U8[ i ] = 0xff; 881 } 882 // b) compute new mean and stdev 883 p_psVectorSampleMedian( myVector, tmpMask, maskVal, stats ); 884 p_psVectorSampleStdev( myVector, tmpMask, maskVal, stats ); 885 886 // c) Use the new mean for x 887 clippedMean = stats->sampleMean; 888 889 // d) Use the new stdev for stdev 890 clippedStdev = stats->sampleStdev; 891 } 892 893 } 894 894 stats->sampleMean = oldStanMean; 895 895 stats->sampleStdev = oldStanStdev; 896 896 897 897 // 7. The last calcuated value of x is the cliped mean. 898 898 if ( stats->options & PS_STAT_CLIPPED_MEAN ) { 899 stats->clippedMean = clippedMean;900 }901 899 stats->clippedMean = clippedMean; 900 } 901 902 902 // 8. The last calcuated value of stdev is the cliped stdev. 903 903 if ( stats->options & PS_STAT_CLIPPED_STDEV ) { 904 stats->clippedStdev = clippedStdev;905 }906 904 stats->clippedStdev = clippedStdev; 905 } 906 907 907 psFree( tmpMask ); 908 908 } … … 918 918 float range = 0.0; 919 919 int i = 0; 920 920 921 921 for ( i = 0;i < myData->n;i++ ) { 922 if ( myData->data.F32[ i ] < min ) {923 min = myData->data.F32[ i ];924 }925 if ( myData->data.F32[ i ] > max ) {926 max = myData->data.F32[ i ];927 }928 }929 922 if ( myData->data.F32[ i ] < min ) { 923 min = myData->data.F32[ i ]; 924 } 925 if ( myData->data.F32[ i ] > max ) { 926 max = myData->data.F32[ i ]; 927 } 928 } 929 930 930 range = max - min; 931 931 for ( i = 0;i < myData->n;i++ ) { 932 myData->data.F32[ i ] = ( myData->data.F32[ i ] - min ) / range;933 }932 myData->data.F32[ i ] = ( myData->data.F32[ i ] - min ) / range; 933 } 934 934 } 935 935 … … 948 948 float tmp = exp( -( ( x - mean ) * ( x - mean ) ) / ( 2.0 * stdev * stdev ) ); 949 949 tmp /= ( ( float ) sqrt( 2.0 * M_PI * ( stdev * stdev ) ) ); 950 950 951 951 // printf("p_psGaussian((%.2f), %.2f, %.2f) is %.2f\n", x, mean, stdev, tmp); 952 952 return ( tmp ); … … 965 965 float stdev = myParams->data.F32[ 1 ]; 966 966 float tmp = 0.0; 967 967 968 968 if ( whichParam == 0 ) { 969 // Return the derivative w.r.t. the mean. 970 tmp = ( x - mean ) * p_psGaussian( myData, myParams ); 971 tmp /= ( stdev * stdev ); 972 } else if ( whichParam == 1 ) { 969 // Return the derivative w.r.t. the mean. 970 tmp = ( x - mean ) * p_psGaussian( myData, myParams ); 971 tmp /= ( stdev * stdev ); 972 } else 973 if ( whichParam == 1 ) { 973 974 // Return the derivative w.r.t. the stdev. 974 975 tmp = ( x - mean ) * ( x - mean ) * p_psGaussian( myData, myParams ); … … 976 977 } 977 978 printf( "p_psGaussianDeriv((%.2f), %.2f, %.2f, (%d)) is %.2f\n", x, mean, stdev, whichParam, tmp ); 978 979 979 980 return ( tmp ); 980 981 } … … 994 995 float C = myParams->data.F32[ 2 ]; 995 996 float tmp = 0.0; 996 997 997 998 tmp = ( A * x * x ) + ( B * x ) + C; 998 999 return ( tmp ); … … 1009 1010 float x = myCoords->data.F32[ 0 ]; 1010 1011 float tmp = 0.0; 1011 1012 1012 1013 if ( whichParamDeriv == 0 ) { 1013 tmp = x * x; 1014 } else if ( whichParamDeriv == 1 ) { 1014 tmp = x * x; 1015 } else 1016 if ( whichParamDeriv == 1 ) { 1015 1017 tmp = x; 1016 } else if ( whichParamDeriv == 2 ) { 1017 tmp = 1.0; 1018 } 1019 1018 } else 1019 if ( whichParamDeriv == 2 ) { 1020 tmp = 1.0; 1021 } 1022 1020 1023 return ( tmp ); 1021 1024 } … … 1039 1042 float oldMidpoint = 1.0; 1040 1043 float f = 0.0; 1041 1044 1042 1045 // printf("p_ps1DPolyMedian(%f, %f, %f) \n", rangeLow, rangeHigh, getThisValue); 1043 1046 1044 1047 while ( numIterations < MAX_ITERATIONS ) { 1045 midpoint = ( rangeHigh + rangeLow ) / 2.0;1046 if ( fabs( midpoint - oldMidpoint ) <= FLT_EPSILON ) {1047 return ( midpoint );1048 }1049 oldMidpoint = midpoint;1050 1051 f = psPolynomial1DEval( midpoint, myPoly );1052 // printf("p_ps1DPolyMedian() iteration %d. f(%f) is %f\n", numIterations, midpoint, f);1053 if ( fabs( f - getThisValue ) <= FLT_EPSILON ) {1054 return ( midpoint );1055 }1056 1057 if ( f > getThisValue ) {1058 rangeHigh = midpoint;1059 } else {1060 rangeLow = midpoint;1061 }1062 numIterations++;1063 }1048 midpoint = ( rangeHigh + rangeLow ) / 2.0; 1049 if ( fabs( midpoint - oldMidpoint ) <= FLT_EPSILON ) { 1050 return ( midpoint ); 1051 } 1052 oldMidpoint = midpoint; 1053 1054 f = psPolynomial1DEval( midpoint, myPoly ); 1055 // printf("p_ps1DPolyMedian() iteration %d. f(%f) is %f\n", numIterations, midpoint, f); 1056 if ( fabs( f - getThisValue ) <= FLT_EPSILON ) { 1057 return ( midpoint ); 1058 } 1059 1060 if ( f > getThisValue ) { 1061 rangeHigh = midpoint; 1062 } else { 1063 rangeLow = midpoint; 1064 } 1065 numIterations++; 1066 } 1064 1067 return ( midpoint ); 1065 1068 } … … 1082 1085 psVector *yErr = psVectorAlloc( 3, PS_TYPE_F64 ); 1083 1086 psPolynomial1D *myPoly = psPolynomial1DAlloc( 2 ); 1084 1087 1085 1088 if ( ( binNum > 0 ) && 1086 1089 ( binNum < ( histogram->nums->n + 1 ) ) ) { 1087 x->data.F64[ 0 ] = ( double ) 0.5 *1088 ( histogram->bounds->data.F32[ binNum - 1 ] +1089 histogram->bounds->data.F32[ binNum ] );1090 x->data.F64[ 1 ] = ( double ) 0.5 *1091 ( histogram->bounds->data.F32[ binNum ] +1092 histogram->bounds->data.F32[ binNum + 1 ] );1093 x->data.F64[ 2 ] = ( double ) 0.5 *1094 ( histogram->bounds->data.F32[ binNum + 1 ] +1095 histogram->bounds->data.F32[ binNum + 2 ] );1096 1097 y->data.F64[ 0 ] = cumulativeSums->data.F32[ binNum - 1 ];1098 y->data.F64[ 1 ] = cumulativeSums->data.F32[ binNum ];1099 y->data.F64[ 2 ] = cumulativeSums->data.F32[ binNum + 1 ];1100 1101 if ( !( ( y->data.F64[ 0 ] <= fitFloat ) &&1102 ( fitFloat <= y->data.F64[ 2 ] ) ) ) {1103 psAbort( __func__, "p_psVectorRobustStats(0): midpoint not within y-range\n" );1104 }1105 1106 yErr->data.F64[ 0 ] = 1.0;1107 yErr->data.F64[ 1 ] = 1.0;1108 yErr->data.F64[ 2 ] = 1.0;1109 1110 myPoly = psVectorFitPolynomial1D( myPoly, x, y, yErr );1111 return ( p_ps1DPolyMedian( myPoly, x->data.F64[ 0 ], x->data.F64[ 2 ],1112 fitFloat ) );1113 } else {1114 return ( 0.5 * ( histogram->bounds->data.F32[ binNum + 1 ] +1115 histogram->bounds->data.F32[ binNum ] ) );1116 }1117 1090 x->data.F64[ 0 ] = ( double ) 0.5 * 1091 ( histogram->bounds->data.F32[ binNum - 1 ] + 1092 histogram->bounds->data.F32[ binNum ] ); 1093 x->data.F64[ 1 ] = ( double ) 0.5 * 1094 ( histogram->bounds->data.F32[ binNum ] + 1095 histogram->bounds->data.F32[ binNum + 1 ] ); 1096 x->data.F64[ 2 ] = ( double ) 0.5 * 1097 ( histogram->bounds->data.F32[ binNum + 1 ] + 1098 histogram->bounds->data.F32[ binNum + 2 ] ); 1099 1100 y->data.F64[ 0 ] = cumulativeSums->data.F32[ binNum - 1 ]; 1101 y->data.F64[ 1 ] = cumulativeSums->data.F32[ binNum ]; 1102 y->data.F64[ 2 ] = cumulativeSums->data.F32[ binNum + 1 ]; 1103 1104 if ( !( ( y->data.F64[ 0 ] <= fitFloat ) && 1105 ( fitFloat <= y->data.F64[ 2 ] ) ) ) { 1106 psAbort( __func__, "p_psVectorRobustStats(0): midpoint not within y-range\n" ); 1107 } 1108 1109 yErr->data.F64[ 0 ] = 1.0; 1110 yErr->data.F64[ 1 ] = 1.0; 1111 yErr->data.F64[ 2 ] = 1.0; 1112 1113 myPoly = psVectorFitPolynomial1D( myPoly, x, y, yErr ); 1114 return ( p_ps1DPolyMedian( myPoly, x->data.F64[ 0 ], x->data.F64[ 2 ], 1115 fitFloat ) ); 1116 } else { 1117 return ( 0.5 * ( histogram->bounds->data.F32[ binNum + 1 ] + 1118 histogram->bounds->data.F32[ binNum ] ) ); 1119 } 1120 1118 1121 psFree( x ); 1119 1122 psFree( y ); … … 1187 1190 float sumNfit = 0.0; 1188 1191 float cumulativeMedian = 0.0; 1189 1192 1190 1193 // Compute the initial bin size of the robust histogram. This is done 1191 1194 // by computing the clipped standard deviation of the vector, and dividing … … 1193 1196 p_psVectorClippedStats( myVector, maskVector, maskVal, tmpStats ); 1194 1197 binSize = tmpStats->clippedStdev / 10.0f; 1195 1198 1196 1199 // If stats->clippedStdev == 0.0, then all data elements have the same 1197 1200 // value. Therefore, we can set the appropiate results and return. 1198 1201 if ( fabs( binSize ) <= FLT_EPSILON ) { 1199 if ( stats->options & PS_STAT_ROBUST_MEAN ) {1200 stats->robustMean = stats->clippedMean;1201 }1202 if ( stats->options & PS_STAT_ROBUST_MEDIAN ) {1203 stats->robustMedian = stats->clippedMean;1204 }1205 if ( stats->options & PS_STAT_ROBUST_MODE ) {1206 stats->robustMode = stats->clippedMean;1207 }1208 if ( stats->options & PS_STAT_ROBUST_STDEV ) {1209 stats->robustStdev = 0.0;1210 }1211 if ( stats->options & PS_STAT_ROBUST_QUARTILE ) {1212 stats->robustUQ = stats->clippedMean;1213 stats->robustLQ = stats->clippedMean;1214 }1215 // XXX: Set these to the number of unmasked data points?1216 stats->robustNfit = 0.0;1217 stats->robustN50 = 0.0;1218 psFree( tmpStats );1219 return ;1220 }1221 1202 if ( stats->options & PS_STAT_ROBUST_MEAN ) { 1203 stats->robustMean = stats->clippedMean; 1204 } 1205 if ( stats->options & PS_STAT_ROBUST_MEDIAN ) { 1206 stats->robustMedian = stats->clippedMean; 1207 } 1208 if ( stats->options & PS_STAT_ROBUST_MODE ) { 1209 stats->robustMode = stats->clippedMean; 1210 } 1211 if ( stats->options & PS_STAT_ROBUST_STDEV ) { 1212 stats->robustStdev = 0.0; 1213 } 1214 if ( stats->options & PS_STAT_ROBUST_QUARTILE ) { 1215 stats->robustUQ = stats->clippedMean; 1216 stats->robustLQ = stats->clippedMean; 1217 } 1218 // XXX: Set these to the number of unmasked data points? 1219 stats->robustNfit = 0.0; 1220 stats->robustN50 = 0.0; 1221 psFree( tmpStats ); 1222 return ; 1223 } 1224 1222 1225 // Determine minimum and maximum values in the data vector. 1223 1226 if ( isnan( stats->min ) ) { 1224 p_psVectorMin( myVector, maskVector, maskVal, stats );1225 }1227 p_psVectorMin( myVector, maskVector, maskVal, stats ); 1228 } 1226 1229 if ( isnan( stats->max ) ) { 1227 p_psVectorMax( myVector, maskVector, maskVal, stats );1228 }1229 1230 p_psVectorMax( myVector, maskVector, maskVal, stats ); 1231 } 1232 1230 1233 // Create the histogram structure. NOTE: we can not specify the bin size 1231 1234 // precisely since the argument to psHistogramAlloc() is the number of … … 1236 1239 stats->max, 1237 1240 numBins ); 1238 1241 1239 1242 // Populate the histogram array. 1240 1243 psVectorHistogram( robustHistogram, myVector, maskVector, maskVal ); 1241 1244 1242 1245 // Smooth the histogram. 1243 1246 // XXX: is that the right stdev? 1244 1247 robustHistogramVector = p_psVectorsmoothHistGaussian( robustHistogram, 1245 1248 tmpStats->clippedStdev / 4.0f ); 1246 1249 1247 1250 // The following was necessary to fit a gaussian to the data, since 1248 1251 // gaussian functions produce data between 0.0 and 1.0. 1249 1252 // p_psNormalizeVector(robustHistogramVector); 1250 1253 1251 1254 /************************************************************************** 1252 1255 Determine the lower/upper quartiles. 1253 **************************************************************************/ 1256 **************************************************************************/ 1254 1257 // We define a vector called "cumulativeRobustSums..." where the value at 1255 1258 // index position i is equal to the sum of bins 0:i. This will be used … … 1258 1261 cumulativeRobustSumsFullRange->data.F32[ 0 ] = robustHistogramVector->data.F32[ 0 ]; 1259 1262 for ( i = 1;i < robustHistogramVector->n;i++ ) { 1260 cumulativeRobustSumsFullRange->data.F32[ i ] =1261 cumulativeRobustSumsFullRange->data.F32[ i - 1 ] +1262 robustHistogramVector->data.F32[ i ];1263 }1263 cumulativeRobustSumsFullRange->data.F32[ i ] = 1264 cumulativeRobustSumsFullRange->data.F32[ i - 1 ] + 1265 robustHistogramVector->data.F32[ i ]; 1266 } 1264 1267 sumRobust = cumulativeRobustSumsFullRange->data.F32[ robustHistogramVector->n - 1 ]; 1265 1268 1266 1269 // Determine the bin number containing the lower quartile point. 1267 1270 LQBinNum = -1; 1268 1271 for ( i = 0;i < cumulativeRobustSumsFullRange->n;i++ ) { 1269 if ( cumulativeRobustSumsFullRange->data.F32[ i ] >= ( sumRobust / 4.0 ) ) {1270 LQBinNum = i;1271 break;1272 }1273 }1274 1272 if ( cumulativeRobustSumsFullRange->data.F32[ i ] >= ( sumRobust / 4.0 ) ) { 1273 LQBinNum = i; 1274 break; 1275 } 1276 } 1277 1275 1278 // Determine the bin number containing the upper quartile point. 1276 1279 UQBinNum = -1; 1277 1280 for ( i = cumulativeRobustSumsFullRange->n - 1;i >= 0;i-- ) { 1278 if ( cumulativeRobustSumsFullRange->data.F32[ i ] <= ( 3.0 * sumRobust / 4.0 ) ) {1279 UQBinNum = i;1280 break;1281 }1282 }1283 1281 if ( cumulativeRobustSumsFullRange->data.F32[ i ] <= ( 3.0 * sumRobust / 4.0 ) ) { 1282 UQBinNum = i; 1283 break; 1284 } 1285 } 1286 1284 1287 if ( ( LQBinNum == -1 ) || 1285 1288 ( UQBinNum == -1 ) ) { 1286 psAbort( __func__, "Could not determine the robust lower/upper quartiles." );1287 }1289 psAbort( __func__, "Could not determine the robust lower/upper quartiles." ); 1290 } 1288 1291 /************************************************************************** 1289 1292 Determine the mode in the range LQ:UQ. 1290 **************************************************************************/ 1293 **************************************************************************/ 1291 1294 // Determine the bin with the peak value in the range LQ to UQ. 1292 1295 maxBinNum = LQBinNum; … … 1294 1297 sumN50 = ( float ) robustHistogram->nums->data.S32[ LQBinNum ]; 1295 1298 for ( i = LQBinNum + 1;i <= UQBinNum;i++ ) { 1296 if ( robustHistogramVector->data.F32[ i ] > maxBinCount ) {1297 maxBinNum = i;1298 maxBinCount = robustHistogramVector->data.F32[ i ];1299 }1300 sumN50 += ( float ) robustHistogram->nums->data.S32[ i ];1301 }1302 1299 if ( robustHistogramVector->data.F32[ i ] > maxBinCount ) { 1300 maxBinNum = i; 1301 maxBinCount = robustHistogramVector->data.F32[ i ]; 1302 } 1303 sumN50 += ( float ) robustHistogram->nums->data.S32[ i ]; 1304 } 1305 1303 1306 // XXX: is dL defined as the value at the LQ/UQ, or the bin number? 1304 1307 dL = ( UQBinNum - LQBinNum ) / 4; 1305 1308 1306 1309 printf( "(LQBinNum, UQBinNum, maxBinNum) is (%d, %d, %d)\n", LQBinNum, UQBinNum, maxBinNum ); 1307 1310 1308 1311 /************************************************************************** 1309 1312 Determine the mean/stdev for the bins in the range mode-dL to mode+dL … … 1311 1314 cumulativeRobustSumsDlRange = psVectorAlloc( robustHistogramVector->n, PS_TYPE_F32 ); 1312 1315 for ( i = 0;i < robustHistogramVector->n;i++ ) { 1313 cumulativeRobustSumsDlRange->data.F32[ i ] = 0.0;1314 }1316 cumulativeRobustSumsDlRange->data.F32[ i ] = 0.0; 1317 } 1315 1318 sumNfit = 0.0; 1316 1319 cumulativeMedian = 0.0; 1317 1320 for ( i = maxBinNum - dL;i <= maxBinNum + dL;i++ ) { 1318 if ( ( 0 <= i ) && ( i < robustHistogramVector->n ) ) {1319 cumulativeRobustSumsDlRange->data.F32[ i ] =1320 cumulativeRobustSumsDlRange->data.F32[ i - 1 ] +1321 robustHistogramVector->data.F32[ i ];1322 cumulativeMedian += robustHistogramVector->data.F32[ i ];1323 sumNfit += ( float ) robustHistogram->nums->data.S32[ i ];1324 }1325 }1326 1321 if ( ( 0 <= i ) && ( i < robustHistogramVector->n ) ) { 1322 cumulativeRobustSumsDlRange->data.F32[ i ] = 1323 cumulativeRobustSumsDlRange->data.F32[ i - 1 ] + 1324 robustHistogramVector->data.F32[ i ]; 1325 cumulativeMedian += robustHistogramVector->data.F32[ i ]; 1326 sumNfit += ( float ) robustHistogram->nums->data.S32[ i ]; 1327 } 1328 } 1329 1327 1330 // Calculate the mean of the smoothed robust histogram in the range 1328 1331 // mode-dL to mode+dL. We use the midpoint of each bin as the mean for … … 1330 1333 myMean = 0.0; 1331 1334 for ( i = maxBinNum - dL;i <= maxBinNum + dL;i++ ) { 1332 if ( ( 0 <= i ) && ( i < robustHistogramVector->n ) ) {1333 myMean += ( robustHistogramVector->data.F32[ i ] ) * 0.5 *1334 ( robustHistogram->bounds->data.F32[ i + 1 ] +1335 robustHistogram->bounds->data.F32[ i ] );1336 countFloat += robustHistogramVector->data.F32[ i ];1337 }1338 }1335 if ( ( 0 <= i ) && ( i < robustHistogramVector->n ) ) { 1336 myMean += ( robustHistogramVector->data.F32[ i ] ) * 0.5 * 1337 ( robustHistogram->bounds->data.F32[ i + 1 ] + 1338 robustHistogram->bounds->data.F32[ i ] ); 1339 countFloat += robustHistogramVector->data.F32[ i ]; 1340 } 1341 } 1339 1342 myMean /= countFloat; 1340 1343 1341 1344 // Calculate the stdev of the smoothed robust histogram in the range 1342 1345 // mode-dL to mode+dL. We use the midpoint of each bin as the mean for 1343 1346 // that bin. 1344 1347 for ( i = maxBinNum - dL;i <= maxBinNum + dL;i++ ) { 1345 if ( ( 0 <= i ) && ( i < robustHistogramVector->n ) ) {1346 diff = ( 0.5 * ( robustHistogram->bounds->data.F32[ i + 1 ] +1347 robustHistogram->bounds->data.F32[ i ] ) ) - myMean;1348 sumSquares += diff * diff * robustHistogramVector->data.F32[ i ];1349 sumDiffs += diff * robustHistogramVector->data.F32[ i ];1350 }1351 }1348 if ( ( 0 <= i ) && ( i < robustHistogramVector->n ) ) { 1349 diff = ( 0.5 * ( robustHistogram->bounds->data.F32[ i + 1 ] + 1350 robustHistogram->bounds->data.F32[ i ] ) ) - myMean; 1351 sumSquares += diff * diff * robustHistogramVector->data.F32[ i ]; 1352 sumDiffs += diff * robustHistogramVector->data.F32[ i ]; 1353 } 1354 } 1352 1355 myStdev = sqrt( ( sumSquares - ( sumDiffs * sumDiffs / countFloat ) ) / ( countFloat - 1 ) ); 1353 1356 1354 1357 /************************************************************************** 1355 1358 Set the appropriate members in the output stats struct. 1356 1359 **************************************************************************/ 1357 1360 if ( stats->options & PS_STAT_ROBUST_MEAN ) { 1358 stats->robustMean = myMean;1359 }1360 1361 stats->robustMean = myMean; 1362 } 1363 1361 1364 if ( stats->options & PS_STAT_ROBUST_MODE ) { 1362 stats->robustMode = 0.5 *1363 ( robustHistogram->bounds->data.F32[ maxBinNum ] +1364 robustHistogram->bounds->data.F32[ maxBinNum + 1 ] );1365 }1366 1365 stats->robustMode = 0.5 * 1366 ( robustHistogram->bounds->data.F32[ maxBinNum ] + 1367 robustHistogram->bounds->data.F32[ maxBinNum + 1 ] ); 1368 } 1369 1367 1370 if ( stats->options & PS_STAT_ROBUST_STDEV ) { 1368 stats->robustStdev = myStdev;1369 }1370 1371 stats->robustStdev = myStdev; 1372 } 1373 1371 1374 // To determine the median (and later, the lower/upper quartile), we fit 1372 1375 // a quadratic to the three bins surrounding the bin containing the median. … … 1374 1377 // the cumulative number of data points in all bins up to, and including, 1375 1378 // this bin. We then solve the quadratic for 1376 1379 1377 1380 if ( stats->options & PS_STAT_ROBUST_MEDIAN ) { 1378 if ( ( maxBinNum > 0 ) && ( maxBinNum < ( robustHistogram->nums->n - 1 ) ) ) {1379 x->data.F64[ 0 ] = ( double ) 0.5 *1380 ( robustHistogram->bounds->data.F32[ maxBinNum - 1 ] +1381 robustHistogram->bounds->data.F32[ maxBinNum ] );1382 x->data.F64[ 1 ] = ( double ) 0.5 *1383 ( robustHistogram->bounds->data.F32[ maxBinNum ] +1384 robustHistogram->bounds->data.F32[ maxBinNum + 1 ] );1385 x->data.F64[ 2 ] = ( double ) 0.5 *1386 ( robustHistogram->bounds->data.F32[ maxBinNum + 1 ] +1387 robustHistogram->bounds->data.F32[ maxBinNum + 2 ] );1388 1389 y->data.F64[ 0 ] = cumulativeRobustSumsDlRange->data.F32[ maxBinNum - 1 ];1390 y->data.F64[ 1 ] = cumulativeRobustSumsDlRange->data.F32[ maxBinNum ];1391 y->data.F64[ 2 ] = cumulativeRobustSumsDlRange->data.F32[ maxBinNum + 1 ];1392 1393 // Ensure that cumulativeMedian/2 is actually within the range of the bins1394 // we are using.1395 cumulativeMedian *= 0.5;1396 if ( !( ( y->data.F64[ 0 ] <= cumulativeMedian ) &&1397 ( cumulativeMedian <= y->data.F64[ 2 ] ) ) ) {1398 printf( "((%f), %f, %f)\n", cumulativeMedian, y->data.F64[ 0 ], y->data.F64[ 2 ] );1399 psAbort( __func__, "p_psVectorRobustStats(1): midpoint not within y-range\n" );1400 }1401 // XXX: yErr is not currently used by psVectorFitPolynomial1D(). We1402 // may have to set this meaningfully later.1403 yErr->data.F64[ 0 ] = 1.0;1404 yErr->data.F64[ 1 ] = 1.0;1405 yErr->data.F64[ 2 ] = 1.0;1406 1407 // Determine the coefficients of the polynomial.1408 myPoly = psVectorFitPolynomial1D( myPoly, x, y, yErr );1409 // Call p_ps1DPolyMedian(), which does a binary search on the1410 // polynomial, looking for the value x such that1411 // f(x) = cumulativeMedian.1412 stats->robustMedian = p_ps1DPolyMedian( myPoly, x->data.F64[ 0 ],1413 x->data.F64[ 2 ], cumulativeMedian );1414 } else {1415 // If the mode is the first/last histogram bin, then simply use1416 // the midpoint of that bin.1417 stats->robustMedian = 0.5 * ( robustHistogram->bounds->data.F32[ maxBinNum + 1 ] +1418 robustHistogram->bounds->data.F32[ maxBinNum ] );1419 }1420 }1421 1381 if ( ( maxBinNum > 0 ) && ( maxBinNum < ( robustHistogram->nums->n - 1 ) ) ) { 1382 x->data.F64[ 0 ] = ( double ) 0.5 * 1383 ( robustHistogram->bounds->data.F32[ maxBinNum - 1 ] + 1384 robustHistogram->bounds->data.F32[ maxBinNum ] ); 1385 x->data.F64[ 1 ] = ( double ) 0.5 * 1386 ( robustHistogram->bounds->data.F32[ maxBinNum ] + 1387 robustHistogram->bounds->data.F32[ maxBinNum + 1 ] ); 1388 x->data.F64[ 2 ] = ( double ) 0.5 * 1389 ( robustHistogram->bounds->data.F32[ maxBinNum + 1 ] + 1390 robustHistogram->bounds->data.F32[ maxBinNum + 2 ] ); 1391 1392 y->data.F64[ 0 ] = cumulativeRobustSumsDlRange->data.F32[ maxBinNum - 1 ]; 1393 y->data.F64[ 1 ] = cumulativeRobustSumsDlRange->data.F32[ maxBinNum ]; 1394 y->data.F64[ 2 ] = cumulativeRobustSumsDlRange->data.F32[ maxBinNum + 1 ]; 1395 1396 // Ensure that cumulativeMedian/2 is actually within the range of the bins 1397 // we are using. 1398 cumulativeMedian *= 0.5; 1399 if ( !( ( y->data.F64[ 0 ] <= cumulativeMedian ) && 1400 ( cumulativeMedian <= y->data.F64[ 2 ] ) ) ) { 1401 printf( "((%f), %f, %f)\n", cumulativeMedian, y->data.F64[ 0 ], y->data.F64[ 2 ] ); 1402 psAbort( __func__, "p_psVectorRobustStats(1): midpoint not within y-range\n" ); 1403 } 1404 // XXX: yErr is not currently used by psVectorFitPolynomial1D(). We 1405 // may have to set this meaningfully later. 1406 yErr->data.F64[ 0 ] = 1.0; 1407 yErr->data.F64[ 1 ] = 1.0; 1408 yErr->data.F64[ 2 ] = 1.0; 1409 1410 // Determine the coefficients of the polynomial. 1411 myPoly = psVectorFitPolynomial1D( myPoly, x, y, yErr ); 1412 // Call p_ps1DPolyMedian(), which does a binary search on the 1413 // polynomial, looking for the value x such that 1414 // f(x) = cumulativeMedian. 1415 stats->robustMedian = p_ps1DPolyMedian( myPoly, x->data.F64[ 0 ], 1416 x->data.F64[ 2 ], cumulativeMedian ); 1417 } else { 1418 // If the mode is the first/last histogram bin, then simply use 1419 // the midpoint of that bin. 1420 stats->robustMedian = 0.5 * ( robustHistogram->bounds->data.F32[ maxBinNum + 1 ] + 1421 robustHistogram->bounds->data.F32[ maxBinNum ] ); 1422 } 1423 } 1424 1422 1425 // The lower/upper quartile calculations are very similar to the median 1423 1426 // calculations. We fit a quadratic to the array containing the … … 1426 1429 // 1427 1430 if ( stats->options & PS_STAT_ROBUST_QUARTILE ) { 1428 countFloat = cumulativeRobustSumsFullRange->data.F32[ robustHistogramVector->n - 1 ];1429 1430 if ( ( LQBinNum > 0 ) && ( LQBinNum < ( robustHistogram->nums->n - 1 ) ) ) {1431 x->data.F64[ 0 ] = ( double ) 0.5 *1432 ( robustHistogram->bounds->data.F32[ LQBinNum - 1 ] +1433 robustHistogram->bounds->data.F32[ LQBinNum ] );1434 x->data.F64[ 1 ] = ( double ) 0.5 *1435 ( robustHistogram->bounds->data.F32[ LQBinNum ] +1436 robustHistogram->bounds->data.F32[ LQBinNum + 1 ] );1437 x->data.F64[ 2 ] = ( double ) 0.5 *1438 ( robustHistogram->bounds->data.F32[ LQBinNum + 1 ] +1439 robustHistogram->bounds->data.F32[ LQBinNum + 2 ] );1440 1441 y->data.F64[ 0 ] = cumulativeRobustSumsFullRange->data.F32[ LQBinNum - 1 ];1442 y->data.F64[ 1 ] = cumulativeRobustSumsFullRange->data.F32[ LQBinNum ];1443 y->data.F64[ 2 ] = cumulativeRobustSumsFullRange->data.F32[ LQBinNum + 1 ];1444 1445 if ( !( ( y->data.F64[ 0 ] <= ( countFloat / 4.0 ) ) &&1446 ( ( countFloat / 4.0 ) <= y->data.F64[ 2 ] ) ) ) {1447 psAbort( __func__, "p_psVectorRobustStats(2): midpoint not within y-range\n" );1448 }1449 1450 yErr->data.F64[ 0 ] = 1.0;1451 yErr->data.F64[ 1 ] = 1.0;1452 yErr->data.F64[ 2 ] = 1.0;1453 1454 myPoly = psVectorFitPolynomial1D( myPoly, x, y, yErr );1455 stats->robustLQ = p_ps1DPolyMedian( myPoly,1456 x->data.F64[ 0 ],1457 x->data.F64[ 2 ],1458 countFloat / 4.0 );1459 1460 } else {1461 // If the LQ is the first/last histogram bin, then simply use1462 // the midpoint of that bin.1463 stats->robustLQ = 0.5 * ( robustHistogram->bounds->data.F32[ LQBinNum + 1 ] +1464 robustHistogram->bounds->data.F32[ LQBinNum ] );1465 }1466 1467 if ( ( UQBinNum > 0 ) && ( UQBinNum < ( robustHistogram->nums->n - 1 ) ) ) {1468 x->data.F64[ 0 ] = ( double ) 0.5 *1469 ( robustHistogram->bounds->data.F32[ UQBinNum - 1 ] +1470 robustHistogram->bounds->data.F32[ UQBinNum ] );1471 x->data.F64[ 1 ] = ( double ) 0.5 *1472 ( robustHistogram->bounds->data.F32[ UQBinNum ] +1473 robustHistogram->bounds->data.F32[ UQBinNum + 1 ] );1474 x->data.F64[ 2 ] = ( double ) 0.5 *1475 ( robustHistogram->bounds->data.F32[ UQBinNum + 1 ] +1476 robustHistogram->bounds->data.F32[ UQBinNum + 2 ] );1477 1478 y->data.F64[ 0 ] = cumulativeRobustSumsFullRange->data.F32[ UQBinNum - 1 ];1479 y->data.F64[ 1 ] = cumulativeRobustSumsFullRange->data.F32[ UQBinNum ];1480 y->data.F64[ 2 ] = cumulativeRobustSumsFullRange->data.F32[ UQBinNum + 1 ];1481 1482 if ( !( ( y->data.F64[ 0 ] <= ( 3.0 * countFloat / 4.0 ) ) &&1483 ( ( 3.0 * countFloat / 4.0 ) <= y->data.F64[ 2 ] ) ) ) {1484 psAbort( __func__, "p_psVectorRobustStats(3): midpoint not within y-range\n" );1485 }1486 1487 yErr->data.F64[ 0 ] = 1.0;1488 yErr->data.F64[ 1 ] = 1.0;1489 yErr->data.F64[ 2 ] = 1.0;1490 1491 myPoly = psVectorFitPolynomial1D( myPoly, x, y, yErr );1492 stats->robustUQ = p_ps1DPolyMedian( myPoly,1493 x->data.F64[ 0 ],1494 x->data.F64[ 2 ],1495 3.0 * countFloat / 4.0 );1496 } else {1497 // If the UQ is the first/last histogram bin, then simply use1498 // the midpoint of that bin.1499 stats->robustUQ = 0.5 * ( robustHistogram->bounds->data.F32[ UQBinNum + 1 ] +1500 robustHistogram->bounds->data.F32[ UQBinNum ] );1501 }1502 }1431 countFloat = cumulativeRobustSumsFullRange->data.F32[ robustHistogramVector->n - 1 ]; 1432 1433 if ( ( LQBinNum > 0 ) && ( LQBinNum < ( robustHistogram->nums->n - 1 ) ) ) { 1434 x->data.F64[ 0 ] = ( double ) 0.5 * 1435 ( robustHistogram->bounds->data.F32[ LQBinNum - 1 ] + 1436 robustHistogram->bounds->data.F32[ LQBinNum ] ); 1437 x->data.F64[ 1 ] = ( double ) 0.5 * 1438 ( robustHistogram->bounds->data.F32[ LQBinNum ] + 1439 robustHistogram->bounds->data.F32[ LQBinNum + 1 ] ); 1440 x->data.F64[ 2 ] = ( double ) 0.5 * 1441 ( robustHistogram->bounds->data.F32[ LQBinNum + 1 ] + 1442 robustHistogram->bounds->data.F32[ LQBinNum + 2 ] ); 1443 1444 y->data.F64[ 0 ] = cumulativeRobustSumsFullRange->data.F32[ LQBinNum - 1 ]; 1445 y->data.F64[ 1 ] = cumulativeRobustSumsFullRange->data.F32[ LQBinNum ]; 1446 y->data.F64[ 2 ] = cumulativeRobustSumsFullRange->data.F32[ LQBinNum + 1 ]; 1447 1448 if ( !( ( y->data.F64[ 0 ] <= ( countFloat / 4.0 ) ) && 1449 ( ( countFloat / 4.0 ) <= y->data.F64[ 2 ] ) ) ) { 1450 psAbort( __func__, "p_psVectorRobustStats(2): midpoint not within y-range\n" ); 1451 } 1452 1453 yErr->data.F64[ 0 ] = 1.0; 1454 yErr->data.F64[ 1 ] = 1.0; 1455 yErr->data.F64[ 2 ] = 1.0; 1456 1457 myPoly = psVectorFitPolynomial1D( myPoly, x, y, yErr ); 1458 stats->robustLQ = p_ps1DPolyMedian( myPoly, 1459 x->data.F64[ 0 ], 1460 x->data.F64[ 2 ], 1461 countFloat / 4.0 ); 1462 1463 } else { 1464 // If the LQ is the first/last histogram bin, then simply use 1465 // the midpoint of that bin. 1466 stats->robustLQ = 0.5 * ( robustHistogram->bounds->data.F32[ LQBinNum + 1 ] + 1467 robustHistogram->bounds->data.F32[ LQBinNum ] ); 1468 } 1469 1470 if ( ( UQBinNum > 0 ) && ( UQBinNum < ( robustHistogram->nums->n - 1 ) ) ) { 1471 x->data.F64[ 0 ] = ( double ) 0.5 * 1472 ( robustHistogram->bounds->data.F32[ UQBinNum - 1 ] + 1473 robustHistogram->bounds->data.F32[ UQBinNum ] ); 1474 x->data.F64[ 1 ] = ( double ) 0.5 * 1475 ( robustHistogram->bounds->data.F32[ UQBinNum ] + 1476 robustHistogram->bounds->data.F32[ UQBinNum + 1 ] ); 1477 x->data.F64[ 2 ] = ( double ) 0.5 * 1478 ( robustHistogram->bounds->data.F32[ UQBinNum + 1 ] + 1479 robustHistogram->bounds->data.F32[ UQBinNum + 2 ] ); 1480 1481 y->data.F64[ 0 ] = cumulativeRobustSumsFullRange->data.F32[ UQBinNum - 1 ]; 1482 y->data.F64[ 1 ] = cumulativeRobustSumsFullRange->data.F32[ UQBinNum ]; 1483 y->data.F64[ 2 ] = cumulativeRobustSumsFullRange->data.F32[ UQBinNum + 1 ]; 1484 1485 if ( !( ( y->data.F64[ 0 ] <= ( 3.0 * countFloat / 4.0 ) ) && 1486 ( ( 3.0 * countFloat / 4.0 ) <= y->data.F64[ 2 ] ) ) ) { 1487 psAbort( __func__, "p_psVectorRobustStats(3): midpoint not within y-range\n" ); 1488 } 1489 1490 yErr->data.F64[ 0 ] = 1.0; 1491 yErr->data.F64[ 1 ] = 1.0; 1492 yErr->data.F64[ 2 ] = 1.0; 1493 1494 myPoly = psVectorFitPolynomial1D( myPoly, x, y, yErr ); 1495 stats->robustUQ = p_ps1DPolyMedian( myPoly, 1496 x->data.F64[ 0 ], 1497 x->data.F64[ 2 ], 1498 3.0 * countFloat / 4.0 ); 1499 } else { 1500 // If the UQ is the first/last histogram bin, then simply use 1501 // the midpoint of that bin. 1502 stats->robustUQ = 0.5 * ( robustHistogram->bounds->data.F32[ UQBinNum + 1 ] + 1503 robustHistogram->bounds->data.F32[ UQBinNum ] ); 1504 } 1505 } 1503 1506 stats->robustNfit = sumNfit; 1504 1507 stats->robustN50 = sumN50; 1505 1508 1506 1509 psFree( x ); 1507 1510 psFree( y ); … … 1576 1579 { 1577 1580 psStats * newStruct = NULL; 1578 1581 1579 1582 newStruct = ( psStats * ) psAlloc( sizeof( psStats ) ); 1580 1583 newStruct->sampleMean = NAN; … … 1600 1603 newStruct->binsize = NAN; 1601 1604 newStruct->options = options; 1602 1605 1603 1606 return ( newStruct ); 1604 1607 } … … 1623 1626 psHistogram *newHist = NULL; // The new histogram structure 1624 1627 float binSize = 0.0; // The histogram bin size 1625 1628 1626 1629 // NOTE: Verify that this is the correct action. 1627 1630 if ( n == 0 ) { 1628 return ( NULL );1629 }1631 return ( NULL ); 1632 } 1630 1633 if ( n < 0 ) { 1631 psAbort( __func__, "psHistogramAlloc() called with bin size %d.\n", n );1632 }1633 1634 psAbort( __func__, "psHistogramAlloc() called with bin size %d.\n", n ); 1635 } 1636 1634 1637 // NOTE: Verify that this is the correct action. 1635 1638 if ( lower > upper ) { 1636 return ( NULL );1637 }1638 1639 return ( NULL ); 1640 } 1641 1639 1642 // Allocate memory for the new histogram structure. If there are N 1640 1643 // bins, then there are N+1 bounds to those bins. … … 1643 1646 newHist->bounds = psVectorAlloc( n + 1, PS_TYPE_F32 ); 1644 1647 newHist->bounds->n = newHist->bounds->nalloc; 1645 1648 1646 1649 // Calculate the bounds for each bin. 1647 1650 binSize = ( upper - lower ) / ( float ) n; … … 1650 1653 binSize += FLT_EPSILON; 1651 1654 for ( i = 0;i < n + 1;i++ ) { 1652 newHist->bounds->data.F32[ i ] = lower + ( binSize * ( float ) i );1653 }1654 1655 newHist->bounds->data.F32[ i ] = lower + ( binSize * ( float ) i ); 1656 } 1657 1655 1658 // Allocate the bins, and initialize them to zero. 1656 1659 newHist->nums = psVectorAlloc( n, PS_TYPE_U32 ); 1657 1660 newHist->nums->n = newHist->nums->nalloc; 1658 1661 for ( i = 0;i < newHist->nums->n;i++ ) { 1659 newHist->nums->data.U32[ i ] = 0;1660 }1661 1662 newHist->nums->data.U32[ i ] = 0; 1663 } 1664 1662 1665 // Initialize the other members. 1663 1666 newHist->minNum = 0; 1664 1667 newHist->maxNum = 0; 1665 1668 newHist->uniform = true; 1666 1669 1667 1670 return ( newHist ); 1668 1671 } … … 1681 1684 psHistogram * newHist = NULL; // The new histogram structure 1682 1685 int i; // Loop index variable 1683 1686 1684 1687 // NOTE: Verify that this is the correct action. 1685 1688 if ( bounds == NULL ) { 1686 // psAbort(__func__, "psHistogram requested with NULL bounds");1687 return ( NULL );1688 }1689 1689 // psAbort(__func__, "psHistogram requested with NULL bounds"); 1690 return ( NULL ); 1691 } 1692 1690 1693 // NOTE: Verify that this is the correct action. 1691 1694 if ( bounds->n <= 1 ) { 1692 // psAbort(__func__, "psHistogram requested with NULL bounds");1693 return ( NULL );1694 }1695 1695 // psAbort(__func__, "psHistogram requested with NULL bounds"); 1696 return ( NULL ); 1697 } 1698 1696 1699 if ( bounds->type.type != PS_TYPE_F32 ) { 1697 // psAbort(__func__, "psHistogram request a bound which is not type F32");1698 return ( NULL );1699 }1700 1700 // psAbort(__func__, "psHistogram request a bound which is not type F32"); 1701 return ( NULL ); 1702 } 1703 1701 1704 // Allocate memory for the new histogram structure. 1702 1705 newHist = ( psHistogram * ) psAlloc( sizeof( psHistogram ) ); … … 1705 1708 newHist->bounds->n = newHist->bounds->nalloc; 1706 1709 for ( i = 0;i < bounds->n;i++ ) { 1707 newHist->bounds->data.F32[ i ] = bounds->data.F32[ i ];1708 }1709 1710 newHist->bounds->data.F32[ i ] = bounds->data.F32[ i ]; 1711 } 1712 1710 1713 // Allocate the bins, and initialize them to zero. If there are N bounds, 1711 1714 // then there are N-1 bins. … … 1713 1716 newHist->nums->n = newHist->nums->nalloc; 1714 1717 for ( i = 0;i < newHist->nums->n;i++ ) { 1715 newHist->nums->data.U32[ i ] = 0;1716 }1717 1718 newHist->nums->data.U32[ i ] = 0; 1719 } 1720 1718 1721 // Initialize the other members. 1719 1722 newHist->minNum = 0; 1720 1723 newHist->maxNum = 0; 1721 1724 newHist->uniform = false; 1722 1725 1723 1726 return ( newHist ); 1724 1727 } … … 1755 1758 int binNum = 0; // A temporary bin number 1756 1759 int numBins = 0; // The total number of bins 1757 1760 1758 1761 // NOTE: Verify that this is the correct action. 1759 1762 if ( out == NULL ) { 1760 return ( NULL );1761 }1762 1763 return ( NULL ); 1764 } 1765 1763 1766 // Check the specified output histogram for type psF32 1764 1767 if ( out->bounds->type.type != PS_TYPE_F32 ) { 1765 psAbort( __func__,1766 "Only data type PS_TYPE_F32 for the output.bounds member." );1767 }1768 1768 psAbort( __func__, 1769 "Only data type PS_TYPE_F32 for the output.bounds member." ); 1770 } 1771 1769 1772 if ( out->nums->type.type != PS_TYPE_U32 ) { 1770 psAbort( __func__,1771 "Only data type PS_TYPE_U32 for output.nums member." );1772 }1773 1773 psAbort( __func__, 1774 "Only data type PS_TYPE_U32 for output.nums member." ); 1775 } 1776 1774 1777 // NOTE: Verify that this is the correct action. 1775 1778 if ( in == NULL ) { 1776 return ( out );1777 }1778 1779 return ( out ); 1780 } 1781 1779 1782 if ( in->type.type != PS_TYPE_F32 ) { 1783 psAbort( __func__, 1784 "Only data type PS_TYPE_F32 is currently supported (0x%x).", 1785 in->type.type ); 1786 } 1787 1788 if ( mask != NULL ) { 1789 if ( in->n != mask->n ) { 1780 1790 psAbort( __func__, 1781 "Only data type PS_TYPE_F32 is currently supported (0x%x).", 1782 in->type.type ); 1783 } 1784 1785 if ( mask != NULL ) { 1786 if ( in->n != mask->n ) { 1787 psAbort( __func__, 1788 "Vector data and vector mask are of different sizes." ); 1789 } 1790 if ( mask->type.type != PS_TYPE_U8 ) { 1791 psAbort( __func__, "Vector mask must be type PS_TYPE_U8" ); 1792 } 1793 } 1791 "Vector data and vector mask are of different sizes." ); 1792 } 1793 if ( mask->type.type != PS_TYPE_U8 ) { 1794 psAbort( __func__, "Vector mask must be type PS_TYPE_U8" ); 1795 } 1796 } 1794 1797 // NOTE: determine the correct action for a variety of other cases: 1795 1798 // in vector has 0 elements, and histogram structure has zero bins. 1796 1799 1797 1800 numBins = out->nums->n; 1798 1801 for ( i = 0;i < in->n;i++ ) { 1799 // Check if this pixel is masked, and if so, skip it. 1800 if ( ( mask == NULL ) || 1801 ( ( mask != NULL ) && ( !( mask->data.U8[ i ] & maskVal ) ) ) ) { 1802 // Check if this pixel is below the minimum value, and if so 1803 // count it, then skip it. 1804 if ( in->data.F32[ i ] < out->bounds->data.F32[ 0 ] ) { 1805 out->minNum++; 1806 // Check if this pixel is above the maximum value, and if so 1807 // count it, then skip it. 1808 } else if ( in->data.F32[ i ] > out->bounds->data.F32[ numBins ] ) { 1809 out->maxNum++; 1810 } else { 1811 // If this is a uniform histogram, determining the correct 1812 // number is trivial. 1813 if ( out->uniform == true ) { 1814 binSize = out->bounds->data.F32[ 1 ] - out->bounds->data.F32[ 0 ]; 1815 binNum = ( int ) ( ( in->data.F32[ i ] - out->bounds->data.F32[ 0 ] ) / 1816 binSize ); 1817 1818 // NOTE: This next if-statement really shouldn't be necessary. 1819 // However, do to numerical lack of precision, we occasionally 1820 // produce a binNum outside the range of bins. 1821 if ( binNum >= out->nums->n ) { 1822 binNum = out->nums->n - 1; 1823 } 1824 1825 ( out->nums->data.S32[ binNum ] ) ++; 1826 1827 // If this is a non-uniform histogram, determining the correct 1828 // bin number requires a bit more work. 1829 } else { 1830 // NOTE: This is slow. Put a smarter algorithm here to 1831 // find the correct bin number (bin search, probably) 1832 for ( j = 0;j < ( out->bounds->n ) - 1;j++ ) { 1833 if ( ( out->bounds->data.S32[ j ] <= in->data.F32[ i ] ) && 1834 ( in->data.F32[ i ] <= out->bounds->data.S32[ j + 1 ] ) ) { 1835 ( out->nums->data.S32[ j ] ) ++; 1836 } 1837 } 1838 } 1802 // Check if this pixel is masked, and if so, skip it. 1803 if ( ( mask == NULL ) || 1804 ( ( mask != NULL ) && ( !( mask->data.U8[ i ] & maskVal ) ) ) ) { 1805 // Check if this pixel is below the minimum value, and if so 1806 // count it, then skip it. 1807 if ( in->data.F32[ i ] < out->bounds->data.F32[ 0 ] ) { 1808 out->minNum++; 1809 // Check if this pixel is above the maximum value, and if so 1810 // count it, then skip it. 1811 } else 1812 if ( in->data.F32[ i ] > out->bounds->data.F32[ numBins ] ) { 1813 out->maxNum++; 1814 } else { 1815 // If this is a uniform histogram, determining the correct 1816 // number is trivial. 1817 if ( out->uniform == true ) { 1818 binSize = out->bounds->data.F32[ 1 ] - out->bounds->data.F32[ 0 ]; 1819 binNum = ( int ) ( ( in->data.F32[ i ] - out->bounds->data.F32[ 0 ] ) / 1820 binSize ); 1821 1822 // NOTE: This next if-statement really shouldn't be necessary. 1823 // However, do to numerical lack of precision, we occasionally 1824 // produce a binNum outside the range of bins. 1825 if ( binNum >= out->nums->n ) { 1826 binNum = out->nums->n - 1; 1839 1827 } 1840 } 1841 } 1828 1829 ( out->nums->data.S32[ binNum ] ) ++; 1830 1831 // If this is a non-uniform histogram, determining the correct 1832 // bin number requires a bit more work. 1833 } else { 1834 // NOTE: This is slow. Put a smarter algorithm here to 1835 // find the correct bin number (bin search, probably) 1836 for ( j = 0;j < ( out->bounds->n ) - 1;j++ ) { 1837 if ( ( out->bounds->data.S32[ j ] <= in->data.F32[ i ] ) && 1838 ( in->data.F32[ i ] <= out->bounds->data.S32[ j + 1 ] ) ) { 1839 ( out->nums->data.S32[ j ] ) ++; 1840 } 1841 } 1842 } 1843 } 1844 } 1845 } 1842 1846 return ( out ); 1843 1847 } … … 1859 1863 int i = 0; 1860 1864 psVector *tmp = NULL; 1861 1865 1862 1866 if ( in->type.type == PS_TYPE_S32 ) { 1867 tmp = psVectorAlloc( in->n, PS_TYPE_F32 ); 1868 for ( i = 0;i < in->n;i++ ) { 1869 tmp->data.F32[ i ] = ( float ) in->data.S32[ i ]; 1870 } 1871 } else 1872 if ( in->type.type == PS_TYPE_U32 ) { 1863 1873 tmp = psVectorAlloc( in->n, PS_TYPE_F32 ); 1864 1874 for ( i = 0;i < in->n;i++ ) { 1865 tmp->data.F32[ i ] = ( float ) in->data.S32[ i ]; 1866 } 1867 } else if ( in->type.type == PS_TYPE_U32 ) { 1868 tmp = psVectorAlloc( in->n, PS_TYPE_F32 ); 1869 for ( i = 0;i < in->n;i++ ) { 1870 tmp->data.F32[ i ] = ( float ) in->data.U32[ i ]; 1871 } 1872 } else if ( in->type.type == PS_TYPE_F64 ) { 1873 tmp = psVectorAlloc( in->n, PS_TYPE_F32 ); 1874 for ( i = 0;i < in->n;i++ ) { 1875 tmp->data.F32[ i ] = ( float ) in->data.U32[ i ]; 1876 } 1877 } else 1878 if ( in->type.type == PS_TYPE_F64 ) { 1879 tmp = psVectorAlloc( in->n, PS_TYPE_F32 ); 1880 for ( i = 0;i < in->n;i++ ) { 1875 1881 tmp->data.F32[ i ] = ( float ) in->data.F64[ i ]; 1876 1882 } 1877 } else if ( in->type.type == PS_TYPE_F32 ) { 1878 // do nothing 1879 } else { 1880 psAbort( __func__, "unsupported vector type 0x%x\n", in->type.type ); 1881 } 1883 } else 1884 if ( in->type.type == PS_TYPE_F32 ) { 1885 // do nothing 1886 } else { 1887 psAbort( __func__, "unsupported vector type 0x%x\n", in->type.type ); 1888 } 1882 1889 return ( tmp ); 1883 1890 } … … 1908 1915 psVector * inF32; 1909 1916 int mustFreeTmp = 1; 1910 1917 1911 1918 // NOTE: Verify that this is the correct action. 1912 1919 if ( in == NULL ) { 1913 return ( stats );1914 }1920 return ( stats ); 1921 } 1915 1922 if ( stats == NULL ) { 1916 return ( NULL );1917 }1918 1923 return ( NULL ); 1924 } 1925 1919 1926 inF32 = p_psConvertToF32( stats, in, mask, maskVal ); 1920 1927 if ( inF32 == NULL ) { 1921 inF32 = in;1922 mustFreeTmp = 0;1923 }1924 1928 inF32 = in; 1929 mustFreeTmp = 0; 1930 } 1931 1925 1932 // XXX: Should we abort if (stats->min == stats->max)? 1926 1933 if ( ( stats->options & PS_STAT_USE_RANGE ) && 1927 1934 ( stats->min >= stats->max ) ) { 1928 psAbort( __func__, "psVectorStats() called with range: %f to %f\n",1929 stats->min, stats->max );1930 }1931 1935 psAbort( __func__, "psVectorStats() called with range: %f to %f\n", 1936 stats->min, stats->max ); 1937 } 1938 1932 1939 // PS_CHECK_VECTOR_TYPE(in, PS_TYPE_F32); 1933 1940 if ( mask != NULL ) { 1934 PS_CHECK_NULL_VECTOR( mask );1935 PS_CHECK_EMPTY_VECTOR( mask );1936 PS_CHECK_VECTOR_SIZE_EQUAL( mask, in );1937 PS_CHECK_VECTOR_TYPE( mask, PS_TYPE_U8 );1938 }1939 1941 PS_CHECK_NULL_VECTOR( mask ); 1942 PS_CHECK_EMPTY_VECTOR( mask ); 1943 PS_CHECK_VECTOR_SIZE_EQUAL( mask, in ); 1944 PS_CHECK_VECTOR_TYPE( mask, PS_TYPE_U8 ); 1945 } 1946 1940 1947 // ************************************************************************ 1941 1948 if ( stats->options & PS_STAT_SAMPLE_MEAN ) { 1942 p_psVectorSampleMean( in, mask, maskVal, stats );1943 }1944 1949 p_psVectorSampleMean( in, mask, maskVal, stats ); 1950 } 1951 1945 1952 // ************************************************************************ 1946 1953 if ( stats->options & PS_STAT_SAMPLE_MEDIAN ) { 1947 p_psVectorSampleMedian( in, mask, maskVal, stats );1948 }1949 1954 p_psVectorSampleMedian( in, mask, maskVal, stats ); 1955 } 1956 1950 1957 // ************************************************************************ 1951 1958 // NOTE: The Stdev calculation requires the mean. Should we assume the 1952 1959 // mean has already been calculated? Or should we always calculate it? 1953 1960 if ( stats->options & PS_STAT_SAMPLE_STDEV ) { 1954 p_psVectorSampleMean( in, mask, maskVal, stats );1955 p_psVectorSampleStdev( in, mask, maskVal, stats );1956 }1957 1961 p_psVectorSampleMean( in, mask, maskVal, stats ); 1962 p_psVectorSampleStdev( in, mask, maskVal, stats ); 1963 } 1964 1958 1965 // ************************************************************************ 1959 1966 if ( stats->options & PS_STAT_SAMPLE_QUARTILE ) { 1960 p_psVectorSampleQuartiles( in, mask, maskVal, stats );1961 }1962 1967 p_psVectorSampleQuartiles( in, mask, maskVal, stats ); 1968 } 1969 1963 1970 // Since the various robust stats quantities share much computation, they 1964 1971 // are grouped together in a single private function: … … 1969 1976 ( stats->options & PS_STAT_ROBUST_STDEV ) || 1970 1977 ( stats->options & PS_STAT_ROBUST_QUARTILE ) ) { 1971 p_psVectorRobustStats( in, mask, maskVal, stats );1972 }1973 1978 p_psVectorRobustStats( in, mask, maskVal, stats ); 1979 } 1980 1974 1981 if ( ( stats->options & PS_STAT_CLIPPED_MEAN ) || 1975 1982 ( stats->options & PS_STAT_CLIPPED_STDEV ) ) { 1976 p_psVectorClippedStats( in, mask, maskVal, stats );1977 }1978 1983 p_psVectorClippedStats( in, mask, maskVal, stats ); 1984 } 1985 1979 1986 // ************************************************************************ 1980 1987 if ( stats->options & PS_STAT_MAX ) { 1981 p_psVectorMax( in, mask, maskVal, stats );1982 }1983 1988 p_psVectorMax( in, mask, maskVal, stats ); 1989 } 1990 1984 1991 // ************************************************************************ 1985 1992 if ( stats->options & PS_STAT_MIN ) { 1986 p_psVectorMin( in, mask, maskVal, stats );1987 }1988 1993 p_psVectorMin( in, mask, maskVal, stats ); 1994 } 1995 1989 1996 if ( mustFreeTmp == 1 ) { 1990 psFree( inF32 );1991 }1997 psFree( inF32 ); 1998 } 1992 1999 return ( stats ); 1993 2000 }
Note:
See TracChangeset
for help on using the changeset viewer.
