Changeset 7132 for trunk/psLib/src/math/psStats.c
- Timestamp:
- May 17, 2006, 3:20:51 PM (20 years ago)
- File:
-
- 1 edited
-
trunk/psLib/src/math/psStats.c (modified) (66 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psLib/src/math/psStats.c
r7055 r7132 16 16 * use ->min and ->max (PS_STAT_USE_RANGE) 17 17 * 18 * @version $Revision: 1.17 1$ $Name: not supported by cvs2svn $19 * @date $Date: 2006-05- 03 23:16:16$18 * @version $Revision: 1.172 $ $Name: not supported by cvs2svn $ 19 * @date $Date: 2006-05-18 01:20:50 $ 20 20 * 21 21 * Copyright 2004 Maui High Performance Computing Center, University of Hawaii … … 28 28 #include <float.h> 29 29 #include <math.h> 30 #include <limits.h> 30 31 31 32 /*****************************************************************************/ … … 50 51 /* DEFINE STATEMENTS */ 51 52 /*****************************************************************************/ 52 #define PS_GAUSS_WIDTH 5// The width of the Gaussian smoothing.53 #define PS_GAUSS_WIDTH 3 // The width of the Gaussian smoothing. 53 54 // This corresponds to N in the ADD. 54 55 #define PS_CLIPPED_NUM_ITER_LB 1 … … 63 64 /* TYPE DEFINITIONS */ 64 65 /*****************************************************************************/ 65 psVector* p_psConvertToF32(psVector* in); 66 67 // None 68 66 69 /*****************************************************************************/ 67 70 /* GLOBAL VARIABLES */ … … 154 157 *****************************************************************************/ 155 158 /****************************************************************************** 156 p_psVectorSampleMean(myVector, maskVector, maskVal, stats): calculates the159 vectorSampleMean(myVector, maskVector, maskVal, stats): calculates the 157 160 mean of the input vector. If there was a problem with the mean calculation, 158 161 this routine sets stats->sampleMean to NAN. 159 162 *****************************************************************************/ 160 psS32 p_psVectorSampleMean(const psVector* myVector,161 const psVector* errors,162 const psVector* maskVector,163 psU32maskVal,164 psStats* stats)163 static bool vectorSampleMean(const psVector* myVector, 164 const psVector* errors, 165 const psVector* maskVector, 166 psMaskType maskVal, 167 psStats* stats) 165 168 { 166 169 psTrace(__func__, 4, "---- %s() begin ----\n", __func__); 167 170 168 psS32 i = 0; // Loop index variable 169 psF32 mean = 0.0; // The mean 170 psS32 count = 0; // # of points in this mean 171 172 // If PS_STAT_USE_RANGE is requested, then we enter a slightly different 173 // loop. 174 if (errors == NULL) { 171 psF32 mean = 0.0; // The mean 172 long count = 0; // Number of points contributing to this mean 173 174 // If PS_STAT_USE_RANGE is requested, then we enter a slightly different loop. 175 if (!errors) { 175 176 if (stats->options & PS_STAT_USE_RANGE) { 176 if (maskVector != NULL) { 177 for (i = 0; i < myVector->n; i++) { 177 if (maskVector) { 178 // No errors, check range, check mask 179 for (long i = 0; i < myVector->n; i++) { 178 180 // Check if the data is with the specified range 179 181 if (!(maskVal & maskVector->data.U8[i]) && … … 184 186 } 185 187 } 186 if (count != 0) {187 mean /= (psF32)count;188 } else {189 mean = NAN;190 }191 188 192 189 } else { 193 for (i = 0; i < myVector->n; i++) { 190 // No errors, check range, no mask 191 for (long i = 0; i < myVector->n; i++) { 194 192 if ((stats->min <= myVector->data.F32[i]) && 195 193 (myVector->data.F32[i] <= stats->max)) { … … 198 196 } 199 197 } 200 if (count != 0) { 201 mean /= (psF32)count; 202 } else { 203 mean = NAN; 204 } 205 } 206 } else { 207 if (maskVector != NULL) { 208 for (i = 0; i < myVector->n; i++) { 198 } 199 } else { 200 if (maskVector) { 201 // No errors, no range check, check mask 202 for (long i = 0; i < myVector->n; i++) { 209 203 if (!(maskVal & maskVector->data.U8[i])) { 210 204 mean += myVector->data.F32[i]; … … 212 206 } 213 207 } 214 if (count != 0) { 215 mean /= (psF32)count; 216 } else { 217 mean = NAN; 218 } 208 219 209 } else { 220 for (i = 0; i < myVector->n; i++) { 210 // No errors, no range check, no mask 211 for (long i = 0; i < myVector->n; i++) { 221 212 mean += myVector->data.F32[i]; 222 213 } 223 mean /= (psF32)myVector->n; 224 } 225 } 214 count = myVector->n; 215 } 216 } 217 218 if (count > 0) { 219 mean /= (psF32)count; 220 } else { 221 mean = NAN; 222 } 223 226 224 } else { 227 psF32 errorDivisor = 0.0; 228 psF32 errorSqr = 0.0; 225 psF32 sumWeights = 0.0; // The sum of the weights 229 226 if (stats->options & PS_STAT_USE_RANGE) { 230 227 if (maskVector != NULL) { 231 for ( i = 0; i < myVector->n; i++) {228 for (long i = 0; i < myVector->n; i++) { 232 229 // Check if the data is with the specified range 233 230 if (!(maskVal & maskVector->data.U8[i]) && 234 231 (stats->min <= myVector->data.F32[i]) && 235 232 (myVector->data.F32[i] <= stats->max)) { 236 errorSqr = errors->data.F32[i]*errors->data.F32[i];237 mean += myVector->data.F32[i] /errorSqr;238 errorDivisor+= (1.0 / errorSqr);233 float weight = 1.0 / PS_SQR(errors->data.F32[i]); 234 mean += myVector->data.F32[i] * weight; 235 sumWeights += weight; 239 236 count++; 240 237 } 241 238 } 242 if (count != 0) {243 mean /= errorDivisor;244 } else {245 mean = NAN;246 }247 248 239 } else { 249 for ( i = 0; i < myVector->n; i++) {240 for (long i = 0; i < myVector->n; i++) { 250 241 if ((stats->min <= myVector->data.F32[i]) && 251 242 (myVector->data.F32[i] <= stats->max)) { 252 errorSqr = errors->data.F32[i]*errors->data.F32[i];253 mean += myVector->data.F32[i] /errorSqr;254 errorDivisor+= (1.0 / errorSqr);243 float weight = 1.0 / PS_SQR(errors->data.F32[i]); 244 mean += myVector->data.F32[i] * weight; 245 sumWeights += weight; 255 246 count++; 256 247 } 257 248 } 258 if (count != 0) {259 mean /= errorDivisor;260 } else {261 mean = NAN;262 }263 249 } 264 250 } else { 265 251 if (maskVector != NULL) { 266 for ( i = 0; i < myVector->n; i++) {252 for (long i = 0; i < myVector->n; i++) { 267 253 if (!(maskVal & maskVector->data.U8[i])) { 268 errorSqr = errors->data.F32[i]*errors->data.F32[i];269 mean += myVector->data.F32[i] /errorSqr;270 errorDivisor+= (1.0 / errorSqr);254 float weight = 1.0 / PS_SQR(errors->data.F32[i]); 255 mean += myVector->data.F32[i] * weight; 256 sumWeights += weight; 271 257 count++; 272 258 } 273 259 } 274 if (count != 0) {275 mean /= errorDivisor;276 } else {277 mean = NAN;278 }279 260 } else { 280 for (i = 0; i < myVector->n; i++) { 281 errorSqr = errors->data.F32[i]*errors->data.F32[i]; 282 mean += myVector->data.F32[i]/errorSqr; 283 errorDivisor+= (1.0 / errorSqr); 284 } 285 mean /= errorDivisor; 286 } 261 for (long i = 0; i < myVector->n; i++) { 262 float weight = 1.0 / PS_SQR(errors->data.F32[i]); 263 mean += myVector->data.F32[i] * weight; 264 sumWeights += weight; 265 } 266 count = myVector->n; 267 } 268 } 269 270 if (count > 0) { 271 mean /= sumWeights; 272 } else { 273 mean = NAN; 287 274 } 288 275 } … … 290 277 stats->sampleMean = mean; 291 278 if (isnan(mean)) { 292 psTrace(__func__, 4, "---- %s(-1) end ----\n", __func__); 293 return(-1); 294 } else { 295 psTrace(__func__, 4, "---- %s(0) end ----\n", __func__); 296 return(0); 297 } 298 279 psTrace(__func__, 4, "---- %s(false) end ----\n", __func__); 280 return false; 281 } 282 283 psTrace(__func__, 4, "---- %s(true) end ----\n", __func__); 284 return true; 299 285 } 300 286 301 287 /****************************************************************************** 302 p_psVectorSampleMax(myVector, maskVector, maskVal, stats): calculates the 303 max of the input vector. If there was a problem with the max calculation, 304 this routine sets stats->max to NAN.288 vectorMinMax(myVector, maskVector, maskVal, stats): calculates the minimum and maximum of the input vector. 289 If there was a problem with the calculation, this routine sets stats->max and stats->min to NAN. Return the 290 number of valid values in the vector (those not masked or outside the specified range. 305 291 *****************************************************************************/ 306 psS32 p_psVectorMax(const psVector* myVector, 307 const psVector* maskVector, 308 psU32 maskVal, 309 psStats* stats) 292 static long vectorMinMax(const psVector* myVector, 293 const psVector* maskVector, 294 psMaskType maskVal, 295 psStats* stats 296 ) 310 297 { 311 298 psTrace(__func__, 4, "---- %s() begin ----\n", __func__); 312 psS32 i = 0; // Loop index variable 313 psF32 max = -PS_MAX_F32; // The calculated maximum 314 psS32 empty = true; // Does this vector have valid elements? 299 psF32 max = -PS_MAX_F32; // The calculated maximum 300 psF32 min = PS_MAX_F32; // The calculated minimum 301 psF32 *vector = myVector->data.F32; // Dereference the vector 302 psU8 *mask = NULL; // Dereference the mask 303 if (maskVector) { 304 mask = maskVector->data.U8; 305 } 306 int num = myVector->n; // Number of values 307 int numValid = 0; // Number of valid values 315 308 316 309 // If PS_STAT_USE_RANGE is requested, then we enter a different loop. 317 310 if (stats->options & PS_STAT_USE_RANGE) { 318 if (maskVector != NULL) { 319 for (i = 0; i < myVector->n; i++) { 320 if (!(maskVal & maskVector->data.U8[i])) { 321 if ((myVector->data.F32[i] > max) && 322 (stats->min <= myVector->data.F32[i]) && 323 (myVector->data.F32[i] <= stats->max)) { 324 max = myVector->data.F32[i]; 325 empty = false; 311 if (mask) { 312 // Need to check range and mask 313 for (long i = 0; i < num; i++) { 314 if (!(maskVal & mask[i]) && vector[i] >= stats->min && vector[i] <= stats->max) { 315 numValid++; 316 if (vector[i] > max) { 317 max = vector[i]; 326 318 } 327 } 328 } 329 } else { 330 for (i = 0; i < myVector->n; i++) { 331 if ((myVector->data.F32[i] > max) && 332 (stats->min <= myVector->data.F32[i]) && 333 (myVector->data.F32[i] <= stats->max)) { 334 max = myVector->data.F32[i]; 335 empty = false; 319 if (vector[i] < min) { 320 min = vector[i]; 321 } 322 } 323 } 324 } else { 325 // Need to check range 326 for (long i = 0; i < num; i++) { 327 if (vector[i] >= stats->min && vector[i] <= stats->max) { 328 numValid++; 329 if (vector[i] > max) { 330 max = vector[i]; 331 } 332 if (vector[i] < min) { 333 min = vector[i]; 334 } 336 335 } 337 336 } 338 337 } 339 338 } else { 340 if (maskVector != NULL) { 341 for (i = 0; i < myVector->n; i++) { 342 if (!(maskVal & maskVector->data.U8[i])) { 343 if (myVector->data.F32[i] > max) { 344 max = myVector->data.F32[i]; 345 empty = false; 339 if (mask) { 340 // Need to check mask 341 for (long i = 0; i < num; i++) { 342 if (!(maskVal & mask[i])) { 343 numValid++; 344 if (vector[i] > max) { 345 max = vector[i]; 346 346 } 347 } 348 } 349 } else { 350 for (i = 0; i < myVector->n; i++) { 351 if (myVector->data.F32[i] > max) { 352 max = myVector->data.F32[i]; 353 empty = false; 354 } 355 } 356 } 357 } 358 if (empty == false) { 347 if (vector[i] < min) { 348 min = vector[i]; 349 } 350 } 351 } 352 } else { 353 // No checks 354 for (long i = 0; i < num; i++) { 355 if (vector[i] > max) { 356 max = vector[i]; 357 } 358 if (vector[i] < min) { 359 min = vector[i]; 360 } 361 } 362 numValid = num; 363 } 364 } 365 366 367 if (numValid == 0) { 368 stats->max = NAN; 369 stats->min = NAN; 370 } else { 359 371 stats->max = max; 360 } else { 361 stats->max = NAN; 362 psTrace(__func__, 4, "---- %s(1) end ----\n", __func__); 363 return(1); 364 } 365 psTrace(__func__, 4, "---- %s(0) end ----\n", __func__); 366 return(0); 372 stats->min = min; 373 } 374 psTrace(__func__, 4, "---- %s(%d) end ----\n", __func__, numValid); 375 return numValid; 367 376 } 368 377 378 #if 0 369 379 /****************************************************************************** 370 p_psVectorSampleMin(myVector, maskVector, maskVal, stats): calculates the 371 minimum of the input vector. If there was a problem with the min calculation, 372 this routine sets stats->min to NAN. 373 *****************************************************************************/ 374 psS32 p_psVectorMin(const psVector* myVector, 375 const psVector* maskVector, 376 psU32 maskVal, 377 psStats* stats) 378 { 379 psTrace(__func__, 4, "---- %s() begin ----\n", __func__); 380 psS32 i = 0; // Loop index variable 381 psF32 min = PS_MAX_F32; // The calculated maximum 382 psS32 empty = true; // Does this vector have valid elements? 383 384 if (stats->options & PS_STAT_USE_RANGE) { 385 if (maskVector != NULL) { 386 for (i = 0; i < myVector->n; i++) { 387 if (!(maskVal & maskVector->data.U8[i])) { 388 if ((myVector->data.F32[i] < min) && 389 (stats->min <= myVector->data.F32[i]) && 390 (myVector->data.F32[i] <= stats->max)) { 391 min = myVector->data.F32[i]; 392 empty = false; 393 } 394 } 395 } 396 } else { 397 for (i = 0; i < myVector->n; i++) { 398 if ((myVector->data.F32[i] < min) && 399 (stats->min <= myVector->data.F32[i]) && 400 (myVector->data.F32[i] <= stats->max)) { 401 min = myVector->data.F32[i]; 402 empty = false; 403 } 404 } 405 } 406 } else { 407 if (maskVector != NULL) { 408 for (i = 0; i < myVector->n; i++) { 409 if (!(maskVal & maskVector->data.U8[i])) { 410 if (myVector->data.F32[i] < min) { 411 min = myVector->data.F32[i]; 412 empty = false; 413 } 414 } 415 } 416 } else { 417 for (i = 0; i < myVector->n; i++) { 418 if (myVector->data.F32[i] < min) { 419 min = myVector->data.F32[i]; 420 empty = false; 421 } 422 } 423 } 424 } 425 426 if (empty == false) { 427 stats->min = min; 428 } else { 429 stats->min = NAN; 430 psTrace(__func__, 4, "---- %s(1) end ----\n", __func__); 431 return(1); 432 } 433 psTrace(__func__, 4, "---- %s(0) end ----\n", __func__); 434 return(0); 435 } 436 437 /****************************************************************************** 438 p_psVectorNValues(myVector, maskVector, maskVal, stats): This routine returns 380 vectorCheckNonEmpty(myVector, maskVector, maskVal, stats): This routine returns 439 381 "true" if the inputPsVector has 1 or more valid elements (a valid element is an 440 382 unmasked element within the specified min/max range). Otherwise, return 441 383 "false". 442 384 *****************************************************************************/ 443 bool p_psVectorCheckNonEmpty( 444 const psVector* myVector, 445 const psVector* maskVector, 446 psU32 maskVal, 447 psStats* stats) 385 static bool vectorCheckNonEmpty(const psVector* myVector, 386 const psVector* maskVector, 387 psMaskType maskVal, 388 psStats* stats) 448 389 { 449 390 psTrace(__func__, 4, "---- %s() begin ----\n", __func__); 450 PS_ASSERT_VECTOR_NON_NULL(myVector, -1); 451 PS_ASSERT_PTR_NON_NULL(stats, -1); 452 psS32 i = 0; // Loop index variable 391 PS_ASSERT_VECTOR_NON_NULL(myVector, false); 392 PS_ASSERT_PTR_NON_NULL(stats, false); 453 393 454 394 if (stats->options & PS_STAT_USE_RANGE) { 455 if (maskVector != NULL) {456 for ( i = 0; i < myVector->n; i++) {395 if (maskVector) { 396 for (long i = 0; i < myVector->n; i++) { 457 397 if (!(maskVal & maskVector->data.U8[i]) && 458 398 (stats->min <= myVector->data.F32[i]) && 459 399 (myVector->data.F32[i] <= stats->max)) { 460 400 psTrace(__func__, 4, "---- %s(true) end ----\n", __func__); 461 return (true);462 } 463 } 464 } else { 465 for ( i = 0; i < myVector->n; i++) {401 return true; 402 } 403 } 404 } else { 405 for (long i = 0; i < myVector->n; i++) { 466 406 if ((stats->min <= myVector->data.F32[i]) && 467 407 (myVector->data.F32[i] <= stats->max)) { 468 408 psTrace(__func__, 4, "---- %s(true) end ----\n", __func__); 469 return (true);409 return true; 470 410 } 471 411 } … … 473 413 } else { 474 414 if (maskVector != NULL) { 475 for ( i = 0; i < myVector->n; i++) {415 for (long i = 0; i < myVector->n; i++) { 476 416 if (!(maskVal & maskVector->data.U8[i])) { 477 417 psTrace(__func__, 4, "---- %s(true) end ----\n", __func__); 478 return (true);418 return true; 479 419 } 480 420 } … … 482 422 if (myVector->n > 0) { 483 423 psTrace(__func__, 4, "---- %s(true) end ----\n", __func__); 484 return (true);424 return true; 485 425 } 486 426 } … … 489 429 return(false); 490 430 } 491 431 #endif 492 432 493 433 /****************************************************************************** 494 p_psVectorNValues(myVector, maskVector, maskVal, stats): calculates the 495 number of non-masked pixels in the vector that fall within the min/max 496 range, if specified.434 vectorSampleMedian(myVector, maskVector, maskVal, stats): calculates the median 435 and quartiles of the input vector. Returns true on success (including if there 436 were no valid input vector elements). 497 437 *****************************************************************************/ 498 psS32 p_psVectorNValues(const psVector* myVector,499 const psVector* maskVector,500 psU32maskVal,501 psStats* stats)438 static bool vectorSampleMedian(const psVector* myVector, 439 const psVector* maskVector, 440 psMaskType maskVal, 441 psStats* stats) 502 442 { 503 443 psTrace(__func__, 4, "---- %s() begin ----\n", __func__); 504 PS_ASSERT_VECTOR_NON_NULL(myVector, -1);505 PS_ASSERT_PTR_NON_NULL(stats, -1);506 psS32 i = 0; // Loop index variable507 psS32 numData = 0; // The number of data points508 509 if (stats->options & PS_STAT_USE_RANGE) {510 if (maskVector != NULL) {511 for (i = 0; i < myVector->n; i++) {512 if (!(maskVal & maskVector->data.U8[i]) &&513 (stats->min <= myVector->data.F32[i]) &&514 (myVector->data.F32[i] <= stats->max)) {515 numData++;516 }517 }518 } else {519 for (i = 0; i < myVector->n; i++) {520 if ((stats->min <= myVector->data.F32[i]) &&521 (myVector->data.F32[i] <= stats->max)) {522 numData++;523 }524 }525 }526 } else {527 if (maskVector != NULL) {528 for (i = 0; i < myVector->n; i++) {529 if (!(maskVal & maskVector->data.U8[i])) {530 numData++;531 }532 }533 } else {534 numData = myVector->n;535 }536 }537 538 psTrace(__func__, 4, "---- %s(%d) end ----\n", __func__, numData);539 return (numData);540 }541 542 /******************************************************************************543 p_psVectorSampleMedian(myVector, maskVector, maskVal, stats): calculates the544 median of the input vector. Returns true on success (including if there were545 no valid input vector elements).546 *****************************************************************************/547 bool p_psVectorSampleMedian(const psVector* myVector,548 const psVector* maskVector,549 psU32 maskVal,550 psStats* stats)551 {552 psTrace(__func__, 4, "---- %s() begin ----\n", __func__);553 psVector* unsortedVector = NULL; // Temporary vector554 psVector* sortedVector = NULL; // Temporary vector555 psS32 i = 0; // Loop index variable556 psS32 count = 0;557 psS32 nValues = 0;558 559 // Determine how many data points fit inside this min/max range560 // and are not masked, if the maskVector is not NULL.561 nValues = p_psVectorNValues(myVector, maskVector, maskVal, stats);562 563 if (nValues <= 0) {564 psLogMsg(__func__, PS_LOG_WARN, "WARNING: p_psVectorSampleMedian(): no valid elements in input vector.\n");565 return(true);566 stats->sampleMedian = NAN;567 }568 444 569 445 // Allocate temporary vectors for the data. 570 unsortedVector = psVectorAlloc(nValues, PS_TYPE_F32);571 unsortedVector->n = nValues;446 psVector* vector = psVectorAlloc(myVector->n, PS_TYPE_F32); // Vector containing the unmasked values 447 long count = 0; // Number of valid entries 572 448 573 449 // Determine if we must only use data points within a min/max range. … … 575 451 // Store all non-masked data points within the min/max range 576 452 // into the temporary vectors. 577 count = 0;578 453 if (maskVector != NULL) { 579 for ( i = 0; i < myVector->n; i++) {454 for (long i = 0; i < myVector->n; i++) { 580 455 if (!(maskVal & maskVector->data.U8[i]) && 581 456 (stats->min <= myVector->data.F32[i]) && 582 457 (myVector->data.F32[i] <= stats->max)) { 583 unsortedVector->data.F32[count] = myVector->data.F32[i];458 vector->data.F32[count] = myVector->data.F32[i]; 584 459 count++; 585 460 } 586 461 } 587 462 } else { 588 for ( i = 0; i < myVector->n; i++) {463 for (long i = 0; i < myVector->n; i++) { 589 464 if ((stats->min <= myVector->data.F32[i]) && 590 465 (myVector->data.F32[i] <= stats->max)) { 591 unsortedVector->data.F32[count] = myVector->data.F32[i];466 vector->data.F32[count] = myVector->data.F32[i]; 592 467 count++; 593 468 } … … 596 471 } else { 597 472 // Store all non-masked data points into the temporary vectors. 598 count = 0; 599 if (maskVector != NULL) { 600 for (i = 0; i < myVector->n; i++) { 473 if (maskVector) { 474 for (long i = 0; i < myVector->n; i++) { 601 475 if (!(maskVal & maskVector->data.U8[i])) { 602 unsortedVector->data.F32[count] = myVector->data.F32[i];476 vector->data.F32[count] = myVector->data.F32[i]; 603 477 count++; 604 478 } 605 479 } 606 480 } else { 607 for (i = 0; i < myVector->n; i++) { 608 unsortedVector->data.F32[i] = myVector->data.F32[i]; 609 } 610 } 611 } 612 // Sort the temporary vectors. 613 sortedVector = psVectorSort(sortedVector, unsortedVector); 614 if (sortedVector == NULL) { 481 vector = psVectorCopy(vector, myVector, PS_TYPE_F32); 482 count = myVector->n; 483 } 484 } 485 vector->n = count; 486 if (count == 0) { 487 psError(PS_ERR_BAD_PARAMETER_SIZE, true, "No valid data in input vector.\n"); 488 psFree(vector); 489 stats->sampleMedian = NAN; 490 return false; 491 } 492 493 // Sort the temporary vector. 494 vector = psVectorSort(vector, vector); // Sort in-place (since it's a copy, it's OK) 495 if (!vector) { 615 496 psError(PS_ERR_UNEXPECTED_NULL, 616 497 false, 617 498 PS_ERRORTEXT_psStats_STATS_SAMPLE_MEDIAN_SORT_PROBLEM); 618 499 psTrace(__func__, 4, "---- %s(false) end ----\n", __func__); 619 psFree( unsortedVector);620 return (false);500 psFree(vector); 501 return false; 621 502 } 622 503 623 504 // Calculate the median exactly. Use the average if the number of samples 624 505 // is even. 625 if ( 0 == (nValues % 2)) {626 stats->sampleMedian = 0.5 * ( sortedVector->data.F32[(nValues/ 2) - 1] +627 sortedVector->data.F32[nValues/ 2]);506 if (count % 2 == 0) { 507 stats->sampleMedian = 0.5 * (vector->data.F32[(count / 2) - 1] + 508 vector->data.F32[count / 2]); 628 509 } else { 629 stats->sampleMedian = sortedVector->data.F32[nValues / 2]; 630 } 510 stats->sampleMedian = vector->data.F32[count / 2]; 511 } 512 513 // Calculate the quartile points exactly. 514 stats->sampleUQ = vector->data.F32[3 * (count / 4)]; 515 stats->sampleLQ = vector->data.F32[count / 4]; 631 516 632 517 // Free the temporary data structures. 633 psFree(unsortedVector); 634 psFree(sortedVector); 518 psFree(vector); 635 519 636 520 // Return "true" on success. 637 521 psTrace(__func__, 4, "---- %s(true) end ----\n", __func__); 638 return (true);522 return true; 639 523 } 640 524 641 525 /****************************************************************************** 642 p_psVectorSmoothHistGaussian(): This routine smoothes the data in the input526 vectorSmoothHistGaussian(): This routine smoothes the data in the input 643 527 robustHistogram with a Gaussian of width sigma. It returns a psVector of the 644 528 smoothed data. 645 529 *****************************************************************************/ 646 psVector *p_psVectorSmoothHistGaussian( 647 psHistogram *histogram, 648 psF32 sigma) 530 psVector *vectorSmoothHistGaussian(psHistogram *histogram, 531 psF32 sigma) 649 532 { 650 533 psTrace(__func__, 4, "---- %s() begin ----\n", __func__); … … 657 540 } 658 541 659 psS32 numBins = histogram->nums->n;660 psVector *smooth = psVectorAlloc(numBins, PS_TYPE_F32); 542 long numBins = histogram->nums->n; // Number of histogram bins 543 psVector *smooth = psVectorAlloc(numBins, PS_TYPE_F32); // Smoothed version of histogram bins 661 544 smooth->n = smooth->nalloc; 662 psS32 jMin = 0; 663 psS32 jMax = 0; 664 665 if (histogram->uniform == false) { 545 const psVector *bounds = histogram->bounds; // The bounds for the histogram bins 546 547 if (!histogram->uniform) { 666 548 // 667 549 // We get here if the histogram is non-uniform. This code is not tested. 668 550 // However, it is also not used anywhere, yet. 669 551 // 670 psLogMsg(__func__, PS_LOG_WARN, "WARNING: p_psVectorSmoothHistGaussian() on non-uniform histograms has not been tested or used.\n");671 672 for ( psS32i = 0; i < numBins; i++) {552 psLogMsg(__func__, PS_LOG_WARN, "WARNING: vectorSmoothHistGaussian() on non-uniform histograms has not been tested or used.\n"); 553 554 for (long i = 0; i < numBins; i++) { 673 555 // Determine the midpoint of bin i. 674 psS32iMid = PS_BIN_MIDPOINT(histogram, i);556 float iMid = PS_BIN_MIDPOINT(histogram, i); 675 557 676 558 // … … 678 560 // range of data values surrounding iMid. The range is of size: 679 561 // 2*PS_GAUSS_WIDTH*sigma 562 long jMin, jMax; 680 563 psF32 x = iMid - (PS_GAUSS_WIDTH * sigma); 681 jMin = i; 682 while (jMin > 0) { 683 if ((histogram->bounds->data.F32[jMin] <= x) && 684 (histogram->bounds->data.F32[jMin+1] >= x)) { 685 break; 686 } 687 jMin--; 688 } 689 564 for (jMin = i; jMin > 0 && bounds->data.F32[jMin] > x; jMin--) 565 ; 690 566 x = iMid + (PS_GAUSS_WIDTH * sigma); 691 jMax = i; 692 while (jMax < (histogram->bounds->n - 1)) { 693 if ((histogram->bounds->data.F32[jMax] <= x) && 694 (histogram->bounds->data.F32[jMax+1] >= x)) { 695 break; 696 } 697 jMax++; 698 } 699 567 for (jMax = i; jMax < bounds->n - 1 && bounds->data.F32[jMax + 1] > x; jMax++) 568 ; 700 569 701 570 // … … 703 572 // 704 573 smooth->data.F32[i] = 0.0; 705 for ( psS32j = jMin ; j <= jMax ; j++) {706 psS32jMid = PS_BIN_MIDPOINT(histogram, j);574 for (long j = jMin ; j <= jMax ; j++) { 575 float jMid = PS_BIN_MIDPOINT(histogram, j); 707 576 smooth->data.F32[i] += 708 577 histogram->nums->data.F32[j] * psGaussian(jMid, iMid, sigma, true); … … 713 582 // We get here if the histogram is uniform. 714 583 // 715 for ( psS32i = 0; i < numBins; i++) {716 psF32 binSize = histogram->bounds->data.F32[1] - histogram->bounds->data.F32[0];717 psS32 gaussWidth = ( psS32) ((PS_GAUSS_WIDTH * sigma) / binSize);584 for (long i = 0; i < numBins; i++) { 585 psF32 binSize = bounds->data.F32[1] - bounds->data.F32[0]; 586 psS32 gaussWidth = ((PS_GAUSS_WIDTH * sigma) / binSize); 718 587 719 588 // … … 723 592 // took way too long. 724 593 // 594 #if 0 595 725 596 gaussWidth = 10; 597 #endif 726 598 // 727 599 // We determine the bin numbers (jMin:jMax) corresponding to a … … 729 601 // 2*PS_GAUSS_WIDTH*sigma 730 602 // 731 psS32 jMin = i - gaussWidth; 732 if (jMin < 0 ) { 733 jMin = 0; 734 } 735 psS32 jMax = i + gaussWidth; 736 if (jMax > (histogram->bounds->n - 1)) { 737 jMax = (histogram->bounds->n - 1); 738 } 603 psS32 jMin = PS_MAX(i - gaussWidth, 0); 604 psS32 jMax = PS_MIN(i + gaussWidth, bounds->n - 1); 739 605 740 606 // … … 742 608 // 743 609 smooth->data.F32[i] = 0.0; 744 psS32iMid = PS_BIN_MIDPOINT(histogram, i);745 for ( psS32j = jMin ; j <= jMax ; j++) {746 psS32jMid = PS_BIN_MIDPOINT(histogram, j);610 float iMid = PS_BIN_MIDPOINT(histogram, i); 611 for (long j = jMin ; j <= jMax ; j++) { 612 float jMid = PS_BIN_MIDPOINT(histogram, j); 747 613 smooth->data.F32[i] += 748 614 histogram->nums->data.F32[j] * psGaussian(jMid, iMid, sigma, true); … … 757 623 return(smooth); 758 624 } 625 759 626 /****************************************************************************** 760 p_psVectorSampleQuartiles(myVector, maskVector, maskVal, statsalculates 761 the upper and/or lower quartiles of the input vector. 762 Inputs 763 myVector 764 maskVector 765 maskVal 766 stats 767 Returns 768 NULL 769 *****************************************************************************/ 770 bool p_psVectorSampleQuartiles(const psVector* myVector, 771 const psVector* maskVector, 772 psU32 maskVal, 773 psStats* stats) 774 { 775 psTrace(__func__, 4, "---- %s() begin ----\n", __func__); 776 psVector* unsortedVector = NULL; 777 psVector* sortedVector = NULL; 778 psS32 i = 0; 779 psS32 count = 0; 780 psS32 nValues = 0; 781 782 // Determine how many data points fit inside this min/max range 783 // and are not masked, if the maskVector is not NULL. 784 nValues = p_psVectorNValues(myVector, maskVector, maskVal, stats); 785 786 // Allocate temporary vectors for the data. 787 unsortedVector = psVectorAlloc(nValues, PS_TYPE_F32); 788 unsortedVector->n = unsortedVector->nalloc; 789 790 if (stats->options & PS_STAT_USE_RANGE) { 791 // Store all non-masked data points within the min/max range 792 // into the temporary vectors. 793 count = 0; 794 if (maskVector != NULL) { 795 for (i = 0; i < myVector->n; i++) { 796 if (!(maskVal & maskVector->data.U8[i]) && 797 (stats->min <= myVector->data.F32[i]) && (myVector->data.F32[i] <= stats->max)) { 798 unsortedVector->data.F32[count++] = myVector->data.F32[i]; 799 } 800 } 801 } else { 802 for (i = 0; i < myVector->n; i++) { 803 if ((stats->min <= myVector->data.F32[i]) && (myVector->data.F32[i] <= stats->max)) { 804 unsortedVector->data.F32[count++] = myVector->data.F32[i]; 805 } 806 } 807 } 808 } else { 809 // Store all non-masked data points into the temporary vectors. 810 count = 0; 811 if (maskVector != NULL) { 812 for (i = 0; i < myVector->n; i++) { 813 if (!(maskVal & maskVector->data.U8[i])) { 814 unsortedVector->data.F32[count++] = myVector->data.F32[i]; 815 } 816 } 817 } else { 818 for (i = 0; i < myVector->n; i++) { 819 unsortedVector->data.F32[i] = myVector->data.F32[i]; 820 } 821 } 822 } 823 824 // Sort the temporary vectors. 825 sortedVector = psVectorSort(sortedVector, unsortedVector); 826 if (sortedVector == NULL) { 827 psError(PS_ERR_UNEXPECTED_NULL, 828 false, 829 PS_ERRORTEXT_psStats_STATS_SAMPLE_MEDIAN_SORT_PROBLEM); 830 psTrace(__func__, 4, "---- %s(false) end ----\n", __func__); 831 return(false); 832 } 833 834 // Calculate the quartile points exactly. 835 stats->sampleUQ = sortedVector->data.F32[3 * (nValues / 4)]; 836 stats->sampleLQ = sortedVector->data.F32[nValues / 4]; 837 838 // Free the temporary data structures. 839 psFree(unsortedVector); 840 psFree(sortedVector); 841 psTrace(__func__, 4, "---- %s(true) end ----\n", __func__); 842 return(true); 843 } 844 845 /****************************************************************************** 846 p_psVectorSampleStdev(myVector, maskVector, maskVal, stats): calculates the 627 vectorSampleStdev(myVector, maskVector, maskVal, stats): calculates the 847 628 stdev of the input vector. 848 629 Inputs … … 855 636 856 637 *****************************************************************************/ 857 void p_psVectorSampleStdev(const psVector* myVector,858 const psVector* errors,859 const psVector* maskVector,860 psU32maskVal,861 psStats* stats)638 static bool vectorSampleStdev(const psVector* myVector, 639 const psVector* errors, 640 const psVector* maskVector, 641 psMaskType maskVal, 642 psStats* stats) 862 643 { 863 644 psTrace(__func__, 4, "---- %s() begin ----\n", __func__); 864 psS32 i = 0; // Loop index variable865 psS32 countInt = 0; // # of data points being used866 psF32 countFloat = 0.0; // # of data points being used867 psF32 mean = 0.0; // The mean868 psF32 diff = 0.0; // Used in calculating stdev869 psF32 sumSquares = 0.0; // temporary variable870 psF32 sumDiffs = 0.0; // temporary variable871 psF32 errorDivisor = 0.0f;872 645 873 646 // This procedure requires the mean. If it has not been already 874 // calculated, then call p_psVectorSampleMean()875 if ( 0 !=isnan(stats->sampleMean)) {876 p_psVectorSampleMean(myVector, errors, maskVector, maskVal, stats);647 // calculated, then call vectorSampleMean() 648 if (isnan(stats->sampleMean)) { 649 vectorSampleMean(myVector, errors, maskVector, maskVal, stats); 877 650 } 878 651 // If the mean is NAN, then generate a warning and set the stdev to NAN. 879 if ( 0 !=isnan(stats->sampleMean)) {652 if (isnan(stats->sampleMean)) { 880 653 stats->sampleStdev = NAN; 881 psLogMsg(__func__, PS_LOG_WARN, "WARNING: p_psVectorSampleStdev(): p_psVectorSampleMean() reported a NAN mean.\n");654 psLogMsg(__func__, PS_LOG_WARN, "WARNING: vectorSampleStdev(): vectorSampleMean() reported a NAN mean.\n"); 882 655 psTrace(__func__, 4, "---- %s() end ----\n", __func__); 883 return; 884 } 885 886 mean = stats->sampleMean; 656 return false; 657 } 658 659 // Accumulate the sums 660 double mean = stats->sampleMean; // The mean 661 double sumSquares = 0.0; // Sum of the squares 662 double sumDiffs = 0.0; // Sum of the differences 663 double errorDivisor = 0.0; // Division for errors 664 long count = 0; // Number of data points being used 887 665 if (stats->options & PS_STAT_USE_RANGE) { 888 if (maskVector != NULL) {889 for ( i = 0; i < myVector->n; i++) {666 if (maskVector) { 667 for (long i = 0; i < myVector->n; i++) { 890 668 if (!(maskVal & maskVector->data.U8[i]) && 891 669 (stats->min <= myVector->data.F32[i]) && 892 670 (myVector->data.F32[i] <= stats->max)) { 893 d iff = myVector->data.F32[i] - mean;894 sumSquares += (diff *diff);671 double diff = myVector->data.F32[i] - mean; 672 sumSquares += PS_SQR(diff); 895 673 sumDiffs += diff; 896 count Int++;897 if (errors != NULL) {898 errorDivisor += (1.0 / PS_SQR(errors->data.F32[i]));674 count++; 675 if (errors) { 676 errorDivisor += 1.0 / PS_SQR(errors->data.F32[i]); 899 677 } 900 678 } 901 679 } 902 680 } else { 903 for ( i = 0; i < myVector->n; i++) {681 for (long i = 0; i < myVector->n; i++) { 904 682 if ((stats->min <= myVector->data.F32[i]) && (myVector->data.F32[i] <= stats->max)) { 905 d iff = myVector->data.F32[i] - mean;906 sumSquares += (diff *diff);683 double diff = myVector->data.F32[i] - mean; 684 sumSquares += PS_SQR(diff); 907 685 sumDiffs += diff; 908 count Int++;909 if (errors != NULL) {910 errorDivisor += (1.0 / PS_SQR(errors->data.F32[i]));686 count++; 687 if (errors) { 688 errorDivisor += 1.0 / PS_SQR(errors->data.F32[i]); 911 689 } 912 690 } 913 691 } 914 count Int= myVector->n;692 count = myVector->n; 915 693 } 916 694 } else { 917 if (maskVector != NULL) {918 for ( i = 0; i < myVector->n; i++) {695 if (maskVector) { 696 for (long i = 0; i < myVector->n; i++) { 919 697 if (!(maskVal & maskVector->data.U8[i])) { 920 d iff = myVector->data.F32[i] - mean;921 sumSquares += (diff *diff);698 double diff = myVector->data.F32[i] - mean; 699 sumSquares += PS_SQR(diff); 922 700 sumDiffs += diff; 923 count Int++;924 if (errors != NULL) {925 errorDivisor += (1.0 / PS_SQR(errors->data.F32[i]));701 count++; 702 if (errors) { 703 errorDivisor += 1.0 / PS_SQR(errors->data.F32[i]); 926 704 } 927 705 } 928 706 } 929 707 } else { 930 for ( i = 0; i < myVector->n; i++) {931 d iff = myVector->data.F32[i] - mean;932 sumSquares += (diff *diff);708 for (long i = 0; i < myVector->n; i++) { 709 double diff = myVector->data.F32[i] - mean; 710 sumSquares += PS_SQR(diff); 933 711 sumDiffs += diff; 934 count Int++;935 }936 countInt = myVector->n;937 if (errors != NULL) {938 errorDivisor+= (1.0 / PS_SQR(errors->data.F32[i]));939 }940 } 941 } 942 943 if (count Int== 0) {712 count++; 713 if (errors) { 714 errorDivisor += 1.0 / PS_SQR(errors->data.F32[i]); 715 } 716 } 717 count = myVector->n; 718 } 719 } 720 721 if (count == 0) { 944 722 stats->sampleStdev = NAN; 945 psLogMsg(__func__, PS_LOG_WARN, "WARNING: p_psVectorSampleStdev(): no valid psVector elements (%d). Setting stats->sampleStdev = NAN.\n", countInt); 946 } else if (countInt == 1) { 723 psLogMsg(__func__, PS_LOG_WARN, "WARNING: vectorSampleStdev(): no valid psVector elements (%d). Setting stats->sampleStdev = NAN.\n", count); 724 return false; 725 } 726 if (count == 1) { 947 727 stats->sampleStdev = 0.0; 948 psLogMsg(__func__, PS_LOG_WARN, "WARNING: p_psVectorSampleStdev(): only one valid psVector elements (%d). Setting stats->sampleStdev = 0.0.\n", countInt); 949 } else { 728 psLogMsg(__func__, PS_LOG_WARN, "WARNING: vectorSampleStdev(): only one valid psVector elements (%d). Setting stats->sampleStdev = 0.0.\n", count); 729 return false; 730 } 731 732 if (errors) { 733 #if 1 950 734 // XXX: The ADD specifies this as the definition of the standard 951 735 // deviation if the errors are known. Verify this with IfA: none of 952 736 // the data points in the vector are used. Verify that the masks and 953 737 // data ranges are used correctly. 954 if (errors != NULL) { 955 if (0) { 956 stats->sampleStdev = (1.0 / sqrtf(errorDivisor)); 957 } else { 958 countFloat = (psF32)countInt; 959 stats->sampleStdev = sqrtf((sumSquares - (sumDiffs * sumDiffs / countFloat)) / (countFloat - 1)); 960 } 961 } else { 962 countFloat = (psF32)countInt; 963 stats->sampleStdev = sqrtf((sumSquares - (sumDiffs * sumDiffs / countFloat)) / (countFloat - 1)); 964 965 } 738 stats->sampleStdev = (1.0 / sqrtf(errorDivisor)); 739 #else 740 741 stats->sampleStdev = sqrt((sumSquares - (sumDiffs * sumDiffs / (float)count)) / 742 (float)(count - 1)); 743 #endif 744 745 } else { 746 stats->sampleStdev = sqrt((sumSquares - (sumDiffs * sumDiffs / (float)count)) / 747 (float)(count - 1)); 748 966 749 } 967 750 psTrace(__func__, 4, "---- %s() end ----\n", __func__); 751 752 return true; 968 753 } 969 754 970 755 /****************************************************************************** 971 p_psVectorClippedStats(myVector, errors, maskVector, maskVal, stats): calculates the756 vectorClippedStats(myVector, errors, maskVector, maskVal, stats): calculates the 972 757 clipped stats (mean or stdev) of the input vector. 973 758 … … 978 763 stats 979 764 Returns 980 0 for success. 981 -1: error 982 -2: warning 765 true for success; false otherwise 983 766 *****************************************************************************/ 984 psS32 p_psVectorClippedStats(const psVector* myVector, 985 const psVector* errors, 986 const psVector* maskVector, 987 psU32 maskVal, 988 psStats* stats) 767 static bool vectorClippedStats(const psVector* myVector, 768 const psVector* errors, 769 psVector* maskVector, 770 psMaskType maskVal, 771 psStats* stats 772 ) 989 773 { 990 774 psTrace(__func__, 4, "---- %s() begin ----\n", __func__); 991 775 psTrace(__func__, 4, "Trace level is %d\n", psTraceGetLevel(__func__)); 992 psF32 clippedMean = 0.0;993 psF32 clippedStdev = 0.0;994 psVector* tmpMask = NULL;995 static psStats *statsTmp = NULL;996 psS32 rc = 0;997 776 998 777 // Ensure that stats->clipIter is within the proper range. … … 1008 787 // Allocate a psStats structure for calculating the mean, median, and 1009 788 // stdev. 1010 if (statsTmp == NULL) { 1011 statsTmp = psStatsAlloc(PS_STAT_SAMPLE_MEAN); 1012 p_psMemSetPersistent(statsTmp, true); 789 psStats *statsTmp = psStatsAlloc(PS_STAT_SAMPLE_MEAN | PS_STAT_SAMPLE_STDEV); 790 791 // We've already copied the mask vector, so it's safe to simply increment the reference counter. 792 psVector *tmpMask = NULL; 793 if (maskVector) { 794 tmpMask = psMemIncrRefCounter(maskVector); 1013 795 } else { 1014 // Initialize structure if already allocated 1015 statsTmp->sampleMean = NAN; 1016 statsTmp->sampleMedian = NAN; 1017 statsTmp->sampleStdev = NAN; 1018 statsTmp->sampleUQ = NAN; 1019 statsTmp->sampleLQ = NAN; 1020 statsTmp->robustMedian = NAN; 1021 statsTmp->robustStdev = NAN; 1022 statsTmp->robustUQ = NAN; 1023 statsTmp->robustLQ = NAN; 1024 statsTmp->robustN50 = -1; 1025 statsTmp->fittedMean = NAN; 1026 statsTmp->fittedStdev = NAN; 1027 statsTmp->fittedNfit = -1; 1028 statsTmp->clippedMean = NAN; 1029 statsTmp->clippedStdev = NAN; 1030 statsTmp->clippedNvalues = -1; 1031 statsTmp->clipSigma = 3.0; 1032 statsTmp->clipIter = 3; 1033 statsTmp->min = NAN; 1034 statsTmp->max = NAN; 1035 statsTmp->binsize = NAN; 1036 statsTmp->nSubsample = 100000; 1037 } 1038 1039 // We allocate a temporary mask vector since during the iterative 1040 // steps that follow, we will be masking off additional data points. 1041 // However, we do no want to modify the original mask vector. 1042 tmpMask = psVectorAlloc(myVector->n, PS_TYPE_U8); 1043 tmpMask->n = tmpMask->nalloc; 1044 1045 // If we were called with a mask vector, then initialize the temporary 1046 // mask vector with those values. Otherwise, initialize to zero. 1047 if (maskVector != NULL) { 1048 for (psS32 i = 0; i < tmpMask->n; i++) { 1049 tmpMask->data.U8[i] = maskVector->data.U8[i]; 1050 } 1051 } else { 1052 for (psS32 i = 0; i < tmpMask->n; i++) { 1053 tmpMask->data.U8[i] = 0; 1054 } 796 tmpMask = psVectorAlloc(myVector->n, PS_TYPE_U8); 797 tmpMask->n = tmpMask->nalloc; 798 psVectorInit(tmpMask, 0); 1055 799 } 1056 800 1057 801 // 1. Compute the sample median. 1058 p_psVectorSampleMedian(myVector, maskVector, maskVal, statsTmp);802 vectorSampleMedian(myVector, tmpMask, maskVal, statsTmp); 1059 803 if (isnan(statsTmp->sampleMedian)) { 1060 psLogMsg(__func__, PS_LOG_WARN, "Call to p_psVectorSampleMedian returned NAN\n");804 psLogMsg(__func__, PS_LOG_WARN, "Call to vectorSampleMedian returned NAN\n"); 1061 805 stats->clippedMean = NAN; 1062 806 stats->clippedStdev = NAN; 1063 psTrace(__func__, 4, "---- %s(-2) end ----\n", __func__); 1064 return(-2); 807 psTrace(__func__, 4, "---- %s(false) end ----\n", __func__); 808 psFree(tmpMask); 809 psFree(statsTmp); 810 return false; 1065 811 } 1066 812 psTrace(__func__, 6, "The initial sample median is %f\n", statsTmp->sampleMedian); 1067 813 1068 814 // 2. Compute the sample standard deviation. 1069 p_psVectorSampleStdev(myVector, errors, maskVector, maskVal, statsTmp);815 vectorSampleStdev(myVector, errors, tmpMask, maskVal, statsTmp); 1070 816 if (isnan(statsTmp->sampleStdev)) { 1071 psLogMsg(__func__, PS_LOG_WARN, "Call to p_psVectorSampleStdev returned NAN\n");817 psLogMsg(__func__, PS_LOG_WARN, "Call to vectorSampleStdev returned NAN\n"); 1072 818 stats->clippedMean = NAN; 1073 819 stats->clippedStdev = NAN; 1074 psTrace(__func__, 4, "---- %s(-2) end ----\n", __func__); 1075 return(-2); 820 psTrace(__func__, 4, "---- %s(false) end ----\n", __func__); 821 psFree(tmpMask); 822 psFree(statsTmp); 823 return false; 1076 824 } 1077 825 psTrace(__func__, 6, "The initial sample stdev is %f\n", statsTmp->sampleStdev); 1078 826 1079 827 // 3. Use the sample median as the first estimator of the mean X. 1080 clippedMean = statsTmp->sampleMedian;828 psF32 clippedMean = statsTmp->sampleMedian; 1081 829 1082 830 // 4. Use the sample stdev as the first estimator of the mean stdev. 1083 clippedStdev = statsTmp->sampleStdev;831 psF32 clippedStdev = statsTmp->sampleStdev; 1084 832 1085 833 // 5. Repeat N (stats->clipIter) times: 1086 for (psS32 iter = 0; iter < stats->clipIter; iter++) { 834 long numClipped = LONG_MAX; // Number of values clipped in this iteration 835 for (int iter = 0; iter < stats->clipIter && numClipped > 0; iter++) { 836 numClipped = 0; 1087 837 psTrace(__func__, 6, "------------ Iteration %d ------------\n", iter); 1088 838 // a) Exclude all values x_i for which |x_i - x| > K * stdev 1089 if (errors != NULL) {1090 for ( psS32j = 0; j < myVector->n; j++) {1091 if (fabs (myVector->data.F32[j] - clippedMean) > (stats->clipSigma * errors->data.F32[j])) {839 if (errors) { 840 for (long j = 0; j < myVector->n; j++) { 841 if (fabsf(myVector->data.F32[j] - clippedMean) > (stats->clipSigma * errors->data.F32[j])) { 1092 842 tmpMask->data.U8[j] = 0xff; 1093 } 1094 } 1095 } else { 1096 for (psS32 j = 0; j < myVector->n; j++) { 1097 if (fabs(myVector->data.F32[j] - clippedMean) > 1098 (stats->clipSigma * clippedStdev)) { 843 psTrace(__func__, 10, "Clipped %d: %f +/- %f\n", j, 844 myVector->data.F32[j], errors->data.F32[j]); 845 numClipped++; 846 } 847 } 848 } else { 849 for (long j = 0; j < myVector->n; j++) { 850 if (fabsf(myVector->data.F32[j] - clippedMean) > (stats->clipSigma * clippedStdev)) { 1099 851 tmpMask->data.U8[j] = 0xff; 852 psTrace(__func__, 10, "Clipped %d: %f\n", j, myVector->data.F32[j]); 853 numClipped++; 1100 854 } 1101 855 } … … 1103 857 1104 858 // b) compute new mean and stdev 1105 p_psVectorSampleMean(myVector, errors, tmpMask, 0xff, statsTmp);1106 p_psVectorSampleStdev(myVector, errors, tmpMask, 0xff, statsTmp);859 vectorSampleMean(myVector, errors, tmpMask, maskVal, statsTmp); 860 vectorSampleStdev(myVector, errors, tmpMask, maskVal, statsTmp); 1107 861 psTrace(__func__, 6, "The new sample mean is %f\n", statsTmp->sampleMean); 1108 862 psTrace(__func__, 6, "The new sample stdev is %f\n", statsTmp->sampleStdev); … … 1113 867 // Exit loop. 1114 868 iter = stats->clipIter; 1115 psError(PS_ERR_UNKNOWN, true, " p_psVectorSampleMean() or p_psVectorSampleStdev() returned a NAN.\n");869 psError(PS_ERR_UNKNOWN, true, "vectorSampleMean() or vectorSampleStdev() returned a NAN.\n"); 1116 870 psFree(tmpMask); 1117 return (-1);871 return false; 1118 872 } else { 1119 873 clippedMean = statsTmp->sampleMean; … … 1122 876 } 1123 877 1124 // 7. The last calcuated value of x is the clip ed mean.878 // 7. The last calcuated value of x is the clipped mean. 1125 879 if (stats->options & PS_STAT_CLIPPED_MEAN) { 1126 880 stats->clippedMean = clippedMean; 1127 881 psTrace(__func__, 6, "The final clipped mean is %f\n", clippedMean); 1128 882 } 1129 // 8. The last calcuated value of stdev is the clip ed stdev.883 // 8. The last calcuated value of stdev is the clipped stdev. 1130 884 if (stats->options & PS_STAT_CLIPPED_STDEV) { 1131 885 stats->clippedStdev = clippedStdev; … … 1134 888 1135 889 psFree(tmpMask); 1136 psTrace(__func__, 4, "---- %s(%d) end ----\n", __func__, rc); 1137 return(rc); 890 psFree(statsTmp); 891 psTrace(__func__, 4, "---- %s(true) end ----\n", __func__); 892 return true; 1138 893 } 1139 894 1140 static psF32 QuadraticInverse( 1141 psF32 a,1142 psF32 b,1143 psF32 c,1144 psF32 y,1145 psF32 xLo,1146 psF32 xHi)895 static psF32 QuadraticInverse(psF32 a, 896 psF32 b, 897 psF32 c, 898 psF32 y, 899 psF32 xLo, 900 psF32 xHi 901 ) 1147 902 { 1148 903 psF64 tmp = sqrt((y - c)/a + (b*b)/(4.0 * a * a)); … … 1151 906 psF64 x2 = -b/(2.0*a) - tmp; 1152 907 1153 if (0) { 1154 psF64 y1 = (a * x1 * x1) + (b * x1) + c; 1155 psF64 y2 = (a * x2 * x2) + (b * x2) + c; 1156 printf("QuadraticInverse: %fx^2 + %fx + %f\n", a, b, c); 1157 printf("QuadraticInverse: y is %f\n", y); 1158 printf("QuadraticInverse: (x1, x2) is (%f %f)\n", x1, x2); 1159 printf("QuadraticInverse: (y1, y2) is (%f %f)\n", y1, y2); 1160 } 1161 1162 if ((xLo <= x1) && (x1 <= xHi)) { 1163 return(x1); 1164 } else if ((xLo <= x2) && (x2 <= xHi)) { 1165 return(x2); 1166 } else { 1167 return(0.5 * (xLo + xHi)); 1168 } 908 #if 0 909 910 psF64 y1 = (a * x1 * x1) + (b * x1) + c; 911 psF64 y2 = (a * x2 * x2) + (b * x2) + c; 912 printf("QuadraticInverse: %fx^2 + %fx + %f\n", a, b, c); 913 printf("QuadraticInverse: y is %f\n", y); 914 printf("QuadraticInverse: (x1, x2) is (%f %f)\n", x1, x2); 915 printf("QuadraticInverse: (y1, y2) is (%f %f)\n", y1, y2); 916 #endif 917 918 if (xLo <= x1 && x1 <= xHi) { 919 return x1; 920 } 921 if (xLo <= x2 && x2 <= xHi) { 922 return x2; 923 } 924 return 0.5 * (xLo + xHi); 1169 925 } 1170 926 … … 1180 936 1181 937 *****************************************************************************/ 1182 psF32 fitQuadraticSearchForYThenReturnX( 1183 psVector *xVec,1184 psVector *yVec,1185 psS32 binNum,1186 psF32 yVal)938 static psF32 fitQuadraticSearchForYThenReturnX(const psVector *xVec, 939 psVector *yVec, 940 psS32 binNum, 941 psF32 yVal 942 ) 1187 943 { 1188 944 psTrace(__func__, 4, "---- %s() begin ----\n", __func__); … … 1235 991 if (((y->data.F64[0] < y->data.F64[1]) && !(y->data.F64[1] <= y->data.F64[2])) || 1236 992 ((y->data.F64[0] > y->data.F64[1]) && !(y->data.F64[1] >= y->data.F64[2]))) { 1237 psError(PS_ERR_UNKNOWN, true, "This routine must be called with monotonically increasing or decreasing data points.\n"); 993 psError(PS_ERR_UNKNOWN, true, 994 "This routine must be called with monotonically increasing or decreasing data points.\n"); 1238 995 psFree(x); 1239 996 psFree(y); 1240 997 psTrace(__func__, 5, "---- %s() end ----\n", __func__); 1241 return (NAN);998 return NAN; 1242 999 } 1243 1000 … … 1251 1008 psFree(y); 1252 1009 psTrace(__func__, 5, "---- %s(NAN) end ----\n", __func__); 1253 return (NAN);1010 return NAN; 1254 1011 } 1255 1012 psTrace(__func__, 6, "myPoly->coeff[0] is %f\n", myPoly->coeff[0]); … … 1262 1019 1263 1020 psTrace(__func__, 6, "We fit the polynomial, now find x such that f(x) equals %f\n", yVal); 1264 tmpFloat = QuadraticInverse(myPoly->coeff[2], myPoly->coeff[1], myPoly->coeff[0], yVal, x->data.F64[0], x->data.F64[2]); 1021 tmpFloat = QuadraticInverse(myPoly->coeff[2], myPoly->coeff[1], myPoly->coeff[0], yVal, 1022 x->data.F64[0], x->data.F64[2]); 1265 1023 psFree(myPoly); 1266 1024 … … 1295 1053 1296 1054 psTrace(__func__, 5, "---- %s(%f) end ----\n", __func__, tmpFloat); 1297 return (tmpFloat);1055 return tmpFloat; 1298 1056 } 1299 1057 … … 1301 1059 NOTE: We assume unnormalized gaussians. 1302 1060 *****************************************************************************/ 1303 psF32 psMinimizeLMChi2Gauss1D( 1304 psVector *deriv,1305 const psVector *params,1306 const psVector *coords)1061 static psF32 minimizeLMChi2Gauss1D(psVector *deriv, 1062 const psVector *params, 1063 const psVector *coords 1064 ) 1307 1065 { 1308 1066 psTrace(__func__, 4, "---- %s() begin ----\n", __func__); … … 1318 1076 psF32 stdev = params->data.F32[1]; 1319 1077 1320 if (deriv == NULL) { 1321 deriv = psVectorAlloc(2, PS_TYPE_F32); 1322 deriv->n = 2; 1323 } else { 1078 psF32 gauss = psGaussian(x, mean, stdev, false); 1079 if (deriv) { 1324 1080 PS_ASSERT_VECTOR_SIZE(deriv, 2, NAN); 1325 1081 PS_ASSERT_VECTOR_TYPE(deriv, PS_TYPE_F32, NAN); 1326 } 1327 1328 psF32 tmp = (x - mean) * psGaussian(x, mean, stdev, false); 1329 deriv->data.F32[0] = tmp / (stdev * stdev); 1330 tmp = (x - mean) * (x - mean) * psGaussian(x, mean, stdev, 0); 1331 deriv->data.F32[1] = tmp / (stdev * stdev * stdev); 1082 psF32 tmp = (x - mean) * gauss; 1083 deriv->data.F32[0] = tmp / (stdev * stdev); 1084 deriv->data.F32[1] = (x - mean) * tmp / (stdev * stdev * stdev); 1085 } 1086 1332 1087 1333 1088 psTrace(__func__, 4, "---- %s() end ----\n", __func__); 1334 return (psGaussian(x, mean, stdev, false));1089 return gauss; 1335 1090 } 1336 1091 1337 1092 /****************************************************************************** 1338 p_psVectorRobustStats(myVector, maskVector, maskVal, stats): This is the new1093 vectorRobustStats(myVector, maskVector, maskVal, stats): This is the new 1339 1094 version of the robust stats routine. 1340 1095 … … 1354 1109 *****************************************************************************/ 1355 1110 #define INITIAL_NUM_BINS 1000.0 1356 psS32 p_psVectorRobustStats(const psVector* myVector,1357 const psVector* errors,1358 constpsVector* maskVector,1359 psU32maskVal,1360 psStats* stats)1111 static bool vectorRobustStats(const psVector* myVector, 1112 const psVector* errors, 1113 psVector* maskVector, 1114 psMaskType maskVal, 1115 psStats* stats) 1361 1116 { 1362 1117 psTrace(__func__, 4, "---- %s() begin ----\n", __func__); … … 1364 1119 PS_VECTOR_PRINT_F32(myVector); 1365 1120 } 1366 psHistogram *robustHistogram = NULL; 1367 psHistogram *cumulativeRobustHistogram = NULL; 1368 psS32 numBins = 0; 1369 psScalar tmpScalar; 1121 1122 psScalar tmpScalar; // Temporary scalar variable, for p_psVectorBinDisect 1370 1123 tmpScalar.type.type = PS_TYPE_F32; 1371 psS32 totalDataPoints = 0; 1372 psS32 rc = 0; 1373 psS32 rcBool = false; 1374 psVector *tmpMaskVec = psVectorAlloc(myVector->n, PS_TYPE_U8); 1375 tmpMaskVec->n = tmpMaskVec->nalloc; 1376 if (maskVector != NULL) { 1377 for (psS32 i = 0 ; i < myVector->n ; i++) { 1378 tmpMaskVec->data.U8[i] = maskVector->data.U8[i]; 1379 } 1124 1125 // We need a mask for these statistics, so if the one we're given is NULL, make our own. 1126 psVector *mask = NULL; // The actual mask we will use 1127 if (maskVector) { 1128 mask = psMemIncrRefCounter(maskVector); 1380 1129 } else { 1381 for (psS32 i = 0 ; i < myVector->n ; i++) { 1382 tmpMaskVec->data.U8[i] = 0; 1383 } 1384 } 1385 psS32 iterate = 1; 1386 psF32 sigma; 1387 psStats *tmpStatsMinMax = psStatsAlloc(PS_STAT_MIN | PS_STAT_MAX); 1388 1389 while (iterate > 0) { 1390 psTrace(__func__, 6, "-------------------- Iterating on Bin size. Iteration number %d --------------------\n", iterate); 1391 psF32 binSize = 0.0; 1130 mask = psVectorAlloc(myVector->n, PS_TYPE_U8); 1131 mask->n = myVector->n; 1132 psVectorInit(mask, 0); 1133 } 1134 1135 psStats *statsMinMax = psStatsAlloc(PS_STAT_MIN | PS_STAT_MAX); // Statistics for min and max 1136 psHistogram *histogram = NULL; // Histogram of the data 1137 psHistogram *cumulative = NULL; // Cumulative histogram of the data 1138 float min = NAN, max = NAN; // Mimimum and maximum values 1139 float sigma = NAN; // The robust standard deviation 1140 long totalDataPoints = 0; // Total number of (unmasked) data points 1141 1142 // Iterate to get the best bin size 1143 for (int iterate = 1; iterate > 0; iterate++) { 1144 psTrace(__func__, 6, 1145 "-------------------- Iterating on Bin size. Iteration number %d --------------------\n", 1146 iterate); 1147 1148 // Get the minimum and maximum values 1149 int numValid = vectorMinMax(myVector, mask, maskVal, statsMinMax); // Number of valid values 1150 min = statsMinMax->min; 1151 max = statsMinMax->max; 1152 if (numValid == 0 || isnan(min) || isnan(max)) { 1153 // Data range calculation failed 1154 psError(PS_ERR_UNKNOWN, false, "Failed to calculate the min/max of the input vector.\n"); 1155 psFree(statsMinMax); 1156 psFree(mask); 1157 psTrace(__func__, 4, "---- %s(false) end ----\n", __func__); 1158 return false; 1159 } 1160 psTrace(__func__, 6, "Data min/max is (%.2f, %.2f)\n", min, max); 1161 1162 // If all data points have the same value, then we set the appropiate members of stats and return. 1163 if (fabs(max - min) <= FLT_EPSILON) { 1164 psTrace(__func__, 5, "All data points have the same value: %f.\n", min); 1165 if (stats->options & PS_STAT_ROBUST_MEDIAN) { 1166 stats->robustMedian = min; 1167 } 1168 if (stats->options & PS_STAT_ROBUST_QUARTILE) { 1169 stats->robustUQ = min; 1170 stats->robustLQ = min; 1171 } 1172 stats->robustN50 = numValid; 1173 psFree(statsMinMax); 1174 psFree(mask); 1175 1176 psTrace(__func__, 4, "---- %s(0) end ----\n", __func__); 1177 return false; 1178 } 1179 1180 float binSize = 0.0; // Size of bins for histogram 1392 1181 if ((iterate == 1) && (stats->options & PS_STAT_USE_BINSIZE)) { 1393 1182 // Set initial bin size to the specified value. … … 1395 1184 psTrace(__func__, 6, "Setting initial robust bin size to %.2f\n", binSize); 1396 1185 } else { 1397 // Determine the bin size of the robust histogram. This is done 1398 // by computing the total range of data values and dividing by 1000.0. 1399 1400 rc = p_psVectorMin(myVector, tmpMaskVec, 1, tmpStatsMinMax); 1401 rc|= p_psVectorMax(myVector, tmpMaskVec, 1, tmpStatsMinMax); 1402 if ((rc != 0) || isnan(tmpStatsMinMax->min) || isnan(tmpStatsMinMax->max)) { 1403 psError(PS_ERR_UNKNOWN, false, "Failed to calculate the min/max of the input vector.\n"); 1404 psFree(tmpStatsMinMax); 1405 psFree(tmpMaskVec); 1406 psTrace(__func__, 4, "---- %s(1) end ----\n", __func__); 1407 return(1); 1408 } 1409 psTrace(__func__, 6, "Data min/max is (%.2f, %.2f)\n", tmpStatsMinMax->min, tmpStatsMinMax->max); 1410 binSize = (tmpStatsMinMax->max - tmpStatsMinMax->min) / INITIAL_NUM_BINS; 1186 // Determine the bin size of the robust histogram, using the pre-defined number of bins 1187 binSize = (max - min) / INITIAL_NUM_BINS; 1411 1188 } 1412 1189 psTrace(__func__, 6, "Initial robust bin size is %.2f\n", binSize); 1413 1190 1414 // 1415 // If all data points have the same value, then we set the appropiate 1416 // members of stats and return. 1417 // 1418 if (fabs(tmpStatsMinMax->max - tmpStatsMinMax->min) <= FLT_EPSILON) { 1419 psTrace(__func__, 5, "All data points have the same value.\n", binSize); 1420 if (stats->options & PS_STAT_ROBUST_MEDIAN) { 1421 stats->robustMedian = tmpStatsMinMax->min; 1422 } 1423 if (stats->options & PS_STAT_ROBUST_QUARTILE) { 1424 stats->robustUQ = tmpStatsMinMax->min; 1425 stats->robustLQ = tmpStatsMinMax->min; 1426 } 1427 // XXX: Set these to the number of unmasked data points? 1428 stats->robustN50 = 0; 1429 psFree(tmpStatsMinMax); 1430 psFree(tmpMaskVec); 1431 1432 psTrace(__func__, 4, "---- %s(0) end ----\n", __func__); 1433 return(0); 1434 } 1435 1436 // 1437 // ADD: Step 0. 1438 // Construct the histogram with the specified bin size. 1439 // 1440 // NOTE: we can not specify the bin size precisely since the argument 1441 // to psHistogramAlloc() is the number of bins, not the binSize. 1442 // If we get here, we know that binSize != 0.0. 1443 // 1444 numBins = (psS32)((tmpStatsMinMax->max - tmpStatsMinMax->min) / binSize); 1191 // ADD step 0: Construct the histogram with the specified bin size. NOTE: we can not specify the bin 1192 // size precisely since the argument to psHistogramAlloc() is the number of bins, not the binSize. If 1193 // we get here, we know that binSize != 0.0. 1194 long numBins = (max - min) / binSize; // Number of bins 1445 1195 psTrace(__func__, 6, "Numbins is %d\n", numBins); 1446 psTrace(__func__, 6, "Creating a robust histogram from data range (%.2f - %.2f)\n", tmpStatsMinMax->min, tmpStatsMinMax->max); 1447 robustHistogram = psHistogramAlloc(tmpStatsMinMax->min, tmpStatsMinMax->max, numBins); 1448 cumulativeRobustHistogram = psHistogramAlloc(tmpStatsMinMax->min, tmpStatsMinMax->max, numBins); 1449 1450 // Populate the histogram array. 1451 robustHistogram = psVectorHistogram(robustHistogram, myVector, errors, tmpMaskVec, maskVal); 1196 psTrace(__func__, 6, "Creating a robust histogram from data range (%.2f - %.2f)\n", min, max); 1197 // Generate the histogram 1198 histogram = psHistogramAlloc(min, max, numBins); 1199 histogram = psVectorHistogram(histogram, myVector, errors, mask, maskVal); 1452 1200 if (psTraceGetLevel(__func__) >= 8) { 1453 PS_VECTOR_PRINT_F32(robustHistogram->bounds); 1454 PS_VECTOR_PRINT_F32(robustHistogram->nums); 1455 } 1456 // 1457 // ADD: Step 1. 1458 // Construct the cumulative histogram from the specific histogram 1459 // 1460 cumulativeRobustHistogram->nums->data.F32[0] = robustHistogram->nums->data.F32[0]; 1461 for (psS32 i = 1 ; i < robustHistogram->nums->n ; i++) { 1462 cumulativeRobustHistogram->nums->data.F32[i] = cumulativeRobustHistogram->nums->data.F32[i-1] + 1463 robustHistogram->nums->data.F32[i]; 1201 PS_VECTOR_PRINT_F32(histogram->bounds); 1202 PS_VECTOR_PRINT_F32(histogram->nums); 1203 } 1204 1205 // ADD step 1: Convert the specific histogram to a cumulative histogram 1206 cumulative = psHistogramAlloc(min, max, numBins); 1207 cumulative->nums->data.F32[0] = histogram->nums->data.F32[0]; 1208 for (long i = 1; i < histogram->nums->n; i++) { 1209 cumulative->nums->data.F32[i] = cumulative->nums->data.F32[i-1] + histogram->nums->data.F32[i]; 1464 1210 } 1465 1211 if (psTraceGetLevel(__func__) >= 8) { 1466 PS_VECTOR_PRINT_F32(cumulativeRobustHistogram->bounds); 1467 PS_VECTOR_PRINT_F32(cumulativeRobustHistogram->nums); 1468 } 1469 1470 // 1471 // ADD: Step 2. 1472 // Find the bin which contains the 50% data point. 1473 // 1474 totalDataPoints = cumulativeRobustHistogram->nums->data.F32[numBins - 1]; 1212 PS_VECTOR_PRINT_F32(cumulative->bounds); 1213 PS_VECTOR_PRINT_F32(cumulative->nums); 1214 } 1215 1216 // ADD step 2: Find the bin which contains the 50% data point. 1217 totalDataPoints = cumulative->nums->data.F32[numBins - 1]; 1475 1218 psTrace(__func__, 6, "Total data points is %d\n", totalDataPoints); 1476 psS32binMedian;1477 if (totalDataPoints/2.0 < cumulative RobustHistogram->nums->data.F32[0]) {1219 long binMedian; 1220 if (totalDataPoints/2.0 < cumulative->nums->data.F32[0]) { 1478 1221 // Special case: the median is in the first bin. Perhaps we should recode this. 1479 1222 // XXX: Must try a special case where the median in in the last bin. … … 1481 1224 } else { 1482 1225 tmpScalar.data.F32 = totalDataPoints/2.0; 1483 binMedian = 1 + p_psVectorBinDisect(cumulative RobustHistogram->nums, &tmpScalar);1226 binMedian = 1 + p_psVectorBinDisect(cumulative->nums, &tmpScalar); 1484 1227 if (binMedian < 0) { 1485 psError(PS_ERR_UNKNOWN, false, "Failed to calculate the 50 precent data point (%d).\n", binMedian); 1486 psFree(tmpStatsMinMax); 1487 psFree(robustHistogram); 1488 psFree(cumulativeRobustHistogram); 1489 psFree(tmpMaskVec); 1490 psTrace(__func__, 4, "---- %s(1) end ----\n", __func__); 1491 return(1); 1492 } 1493 } 1494 psTrace(__func__, 6, "The median bin is %d (%.2f to %.2f)\n", binMedian, cumulativeRobustHistogram->bounds->data.F32[binMedian], cumulativeRobustHistogram->bounds->data.F32[binMedian+1]); 1495 1496 // 1497 // ADD: Step 3. 1498 // Interpolate to the exact 50% position: this is the robust histogram median. 1499 // 1500 stats->robustMedian = fitQuadraticSearchForYThenReturnX( 1501 *(psVector* *)&cumulativeRobustHistogram->bounds, 1502 *(psVector* *)&cumulativeRobustHistogram->nums, 1503 binMedian, 1504 totalDataPoints/2.0); 1228 psError(PS_ERR_UNKNOWN, false, 1229 "Failed to calculate the 50 precent data point (%d).\n", binMedian); 1230 psFree(statsMinMax); 1231 psFree(histogram); 1232 psFree(cumulative); 1233 psFree(mask); 1234 psTrace(__func__, 4, "---- %s(false) end ----\n", __func__); 1235 return false; 1236 } 1237 } 1238 psTrace(__func__, 6, "The median bin is %d (%.2f to %.2f)\n", binMedian, 1239 cumulative->bounds->data.F32[binMedian], cumulative->bounds->data.F32[binMedian+1]); 1240 1241 // ADD step 3: Interpolate to the exact 50% position: this is the robust histogram median. 1242 stats->robustMedian = fitQuadraticSearchForYThenReturnX(cumulative->bounds, cumulative->nums, 1243 binMedian, totalDataPoints/2.0); 1505 1244 if (isnan(stats->robustMedian)) { 1506 psError(PS_ERR_UNKNOWN, false, "Failed to fit a quadratic and calculate the 50-percent position.\n"); 1507 psFree(tmpStatsMinMax); 1508 psFree(robustHistogram); 1509 psFree(cumulativeRobustHistogram); 1510 psFree(tmpMaskVec); 1511 psTrace(__func__, 4, "---- %s(1) end ----\n", __func__); 1512 return(1); 1245 psError(PS_ERR_UNKNOWN, false, 1246 "Failed to fit a quadratic and calculate the 50-percent position.\n"); 1247 psFree(statsMinMax); 1248 psFree(histogram); 1249 psFree(cumulative); 1250 psFree(mask); 1251 psTrace(__func__, 4, "---- %s(false) end ----\n", __func__); 1252 return false; 1513 1253 } 1514 1254 psTrace(__func__, 6, "Current robust median is %f\n", stats->robustMedian); 1515 1255 1516 // 1517 // ADD: Step 4. 1518 // Find the bins which contains the 15.8655% and 84.1345% data points. 1519 // 1520 psS32 binLo = 0; 1521 psS32 binHi = 0; 1256 // ADD step 4: Find the bins which contains the 15.8655% and 84.1345% data points. 1257 long binLo = 0; // Bin containing the 15.8655% mark 1522 1258 tmpScalar.data.F32 = totalDataPoints * 0.158655f; 1523 if (tmpScalar.data.F32 <= cumulativeRobustHistogram->nums->data.F32[0]) { 1524 binLo = 0; 1525 } else { 1259 if (tmpScalar.data.F32 > cumulative->nums->data.F32[0]) { 1526 1260 // NOTE: the (+1) here is because of the way p_psVectorBinDisect is defined. 1527 binLo = 1 + p_psVectorBinDisect(cumulativeRobustHistogram->nums, &tmpScalar); 1528 if (binLo > cumulativeRobustHistogram->nums->n-1) { 1529 binLo = cumulativeRobustHistogram->nums->n-1; 1530 } 1531 } 1261 binLo = 1 + p_psVectorBinDisect(cumulative->nums, &tmpScalar); 1262 if (binLo > cumulative->nums->n-1) { 1263 binLo = cumulative->nums->n-1; 1264 } 1265 } 1266 1267 long binHi = 0; // Bin containing the 84.1345% mark 1532 1268 tmpScalar.data.F32 = totalDataPoints * 0.841345f; 1533 if (tmpScalar.data.F32 <= cumulativeRobustHistogram->nums->data.F32[0]) { 1534 binHi = 0; 1535 } else { 1269 if (tmpScalar.data.F32 > cumulative->nums->data.F32[0]) { 1536 1270 // NOTE: the (+1) here is because of the way p_psVectorBinDisect is defined. 1537 binHi = 1 + p_psVectorBinDisect(cumulative RobustHistogram->nums, &tmpScalar);1538 if (binHi > cumulative RobustHistogram->nums->n-1) {1539 binHi = cumulative RobustHistogram->nums->n-1;1540 } 1541 } 1542 psTrace(__func__, 6, "The 15.8655 -percent and 84.1345-percentdata point bins are (%d, %d).\n",1271 binHi = 1 + p_psVectorBinDisect(cumulative->nums, &tmpScalar); 1272 if (binHi > cumulative->nums->n-1) { 1273 binHi = cumulative->nums->n-1; 1274 } 1275 } 1276 psTrace(__func__, 6, "The 15.8655%% and 84.1345%% data point bins are (%d, %d).\n", 1543 1277 binLo, binHi); 1544 psTrace(__func__, 6, "binLo midpoint is %f\n", PS_BIN_MIDPOINT(cumulative RobustHistogram, binLo));1545 psTrace(__func__, 6, "binHi midpoint is %f\n", PS_BIN_MIDPOINT(cumulative RobustHistogram, binHi));1278 psTrace(__func__, 6, "binLo midpoint is %f\n", PS_BIN_MIDPOINT(cumulative, binLo)); 1279 psTrace(__func__, 6, "binHi midpoint is %f\n", PS_BIN_MIDPOINT(cumulative, binHi)); 1546 1280 1547 1281 if ((binLo < 0) || (binHi < 0)) { 1548 psError(PS_ERR_UNKNOWN, false, "Failed to calculate the 15.8655 and 84.1345 percent data point\n"); 1549 psFree(tmpStatsMinMax); 1550 psFree(robustHistogram); 1551 psFree(cumulativeRobustHistogram); 1552 psFree(tmpMaskVec); 1553 psTrace(__func__, 4, "---- %s(1) end ----\n", __func__); 1554 return(1); 1555 } 1556 1557 // 1558 // ADD: Step 4b. 1559 // Interpolate Sigma to find these two positions exactly: these are the 1sigma positions. 1560 // 1561 // XXX: I am overriding the ADD for now. The following code implements 1562 // the ADD exactly and is having problems fitting a 2nd-order polynomial 1563 // to data y-values suchs as (1, 1, 100). Therefore, I commented out the 1564 // code and am doing simply linear interpolation. 1565 // 1566 psF32 binLoF32; 1567 psF32 binHiF32; 1568 if (0) { 1569 binLoF32 = fitQuadraticSearchForYThenReturnX( 1570 *(psVector* *)&cumulativeRobustHistogram->bounds, 1571 *(psVector* *)&cumulativeRobustHistogram->nums, 1572 binLo, 1573 totalDataPoints * 0.158655f); 1574 binHiF32 = fitQuadraticSearchForYThenReturnX( 1575 *(psVector* *)&cumulativeRobustHistogram->bounds, 1576 *(psVector* *)&cumulativeRobustHistogram->nums, 1577 binHi, 1578 totalDataPoints * 0.841345f); 1579 psTrace(__func__, 6, "The exact 15.8655 and 84.1345 percent data point positions are: (%f, %f)\n", 1580 binLoF32, binHiF32); 1581 } 1582 1583 // 1282 psError(PS_ERR_UNKNOWN, false, "Failed to calculate the 15.8655%% and 84.1345%% data points.\n"); 1283 psFree(statsMinMax); 1284 psFree(histogram); 1285 psFree(cumulative); 1286 psFree(mask); 1287 psTrace(__func__, 4, "---- %s(false) end ----\n", __func__); 1288 return false; 1289 } 1290 1291 // ADD step 4b: Interpolate Sigma to find these two positions exactly: these are the 1sigma positions. 1292 #if 0 1293 // XXX: I am overriding the ADD for now. The following code implements the ADD exactly and is having 1294 // problems fitting a 2nd-order polynomial to data y-values suchs as (1, 1, 100). Therefore, I 1295 // commented out the code and am doing simply linear interpolation. 1296 1297 // Value for the 15.8655% mark 1298 float binLoF32 = fitQuadraticSearchForYThenReturnX(cumulative->bounds, cumulative->nums, binLo, 1299 totalDataPoints * 0.158655f); 1300 // Value for the 84.1345% mark 1301 float binHiF32 = fitQuadraticSearchForYThenReturnX(cumulative->bounds, cumulative->nums, binHi, 1302 totalDataPoints * 0.841345f); 1303 psTrace(__func__, 6, "The exact 15.8655%% and 84.1345%% data point positions are: (%f, %f)\n", 1304 binLoF32, binHiF32); 1305 #else 1584 1306 // This code basically interpolates to find the positions exactly. 1585 // 1586 if (1) { 1587 psTrace(__func__, 6, "binLo is %d. Nums at that bin and the next are (%.2f, %.2f)\n", 1588 binLo, cumulativeRobustHistogram->nums->data.F32[binLo], 1589 cumulativeRobustHistogram->nums->data.F32[binLo+1]); 1590 psTrace(__func__, 6, "binHi is %d. Nums at that bin and the next are (%.2f, %.2f)\n", 1591 binHi, cumulativeRobustHistogram->nums->data.F32[binHi], 1592 cumulativeRobustHistogram->nums->data.F32[binHi+1]); 1593 1594 psF32 deltaNums; 1595 psF32 deltaBounds; 1596 psF32 prevPixels; 1597 psF32 percentNums; 1598 psF32 base; 1599 deltaBounds = cumulativeRobustHistogram->bounds->data.F32[binLo+1] - cumulativeRobustHistogram->bounds->data.F32[binLo]; 1600 if (binLo == 0) { 1601 deltaNums = cumulativeRobustHistogram->nums->data.F32[0]; 1602 prevPixels = 0; 1603 } else { 1604 deltaNums = cumulativeRobustHistogram->nums->data.F32[binLo] - cumulativeRobustHistogram->nums->data.F32[binLo-1]; 1605 prevPixels = cumulativeRobustHistogram->nums->data.F32[binLo-1]; 1606 } 1607 percentNums = (totalDataPoints * 0.158655f) - prevPixels; 1608 base = cumulativeRobustHistogram->bounds->data.F32[binLo]; 1609 binLoF32 = base + (deltaBounds / deltaNums) * percentNums; 1610 psTrace(__func__, 6, "(base, deltaBounds, deltaNums, prevPixels, percentNums) is (%.2f %.2f %.2f %.2f %.2f)\n", 1611 base, deltaBounds, deltaNums, prevPixels, percentNums); 1612 1613 deltaBounds = cumulativeRobustHistogram->bounds->data.F32[binHi+1] - cumulativeRobustHistogram->bounds->data.F32[binHi]; 1614 if (binHi == 0) { 1615 deltaNums = cumulativeRobustHistogram->nums->data.F32[0]; 1616 prevPixels = 0; 1617 } else { 1618 deltaNums = cumulativeRobustHistogram->nums->data.F32[binHi] - cumulativeRobustHistogram->nums->data.F32[binHi-1]; 1619 prevPixels = cumulativeRobustHistogram->nums->data.F32[binHi-1]; 1620 } 1621 percentNums = (totalDataPoints * 0.841345f) - prevPixels; 1622 base = cumulativeRobustHistogram->bounds->data.F32[binHi]; 1623 binHiF32 = base + (deltaBounds / deltaNums) * percentNums; 1624 psTrace(__func__, 6, "(base, deltaBounds, deltaNums, prevPixels, percentNums) is (%.2f %.2f %.2f %.2f %.2f)\n", 1625 base, deltaBounds, deltaNums, prevPixels, percentNums); 1626 psTrace(__func__, 6, "The exact 15.8655 and 84.1345 percent data point positions are: (%f, %f)\n", binLoF32, binHiF32); 1627 } 1628 1629 // 1630 // ADD: Step 5. 1631 // Determine SIGMA as 1/2 of the distance between these positions. 1632 // 1307 psTrace(__func__, 6, "binLo is %d. Nums at that bin and the next are (%.2f, %.2f)\n", 1308 binLo, cumulative->nums->data.F32[binLo], cumulative->nums->data.F32[binLo+1]); 1309 psTrace(__func__, 6, "binHi is %d. Nums at that bin and the next are (%.2f, %.2f)\n", 1310 binHi, cumulative->nums->data.F32[binHi], cumulative->nums->data.F32[binHi+1]); 1311 1312 float deltaBounds = cumulative->bounds->data.F32[binLo+1] - cumulative->bounds->data.F32[binLo]; 1313 float deltaNums; 1314 float prevPixels; 1315 if (binLo == 0) { 1316 deltaNums = cumulative->nums->data.F32[0]; 1317 prevPixels = 0; 1318 } else { 1319 deltaNums = cumulative->nums->data.F32[binLo] - cumulative->nums->data.F32[binLo-1]; 1320 prevPixels = cumulative->nums->data.F32[binLo-1]; 1321 } 1322 float percentNums = (totalDataPoints * 0.158655f) - prevPixels; 1323 float base = cumulative->bounds->data.F32[binLo]; 1324 float binLoF32 = base + (deltaBounds / deltaNums) * percentNums; // Value for the 15.8655% mark 1325 psTrace(__func__, 6, 1326 "(base, deltaBounds, deltaNums, prevPixels, percentNums) is (%.2f %.2f %.2f %.2f %.2f)\n", 1327 base, deltaBounds, deltaNums, prevPixels, percentNums); 1328 1329 deltaBounds = cumulative->bounds->data.F32[binHi+1] - cumulative->bounds->data.F32[binHi]; 1330 if (binHi == 0) { 1331 deltaNums = cumulative->nums->data.F32[0]; 1332 prevPixels = 0; 1333 } else { 1334 deltaNums = cumulative->nums->data.F32[binHi] - cumulative->nums->data.F32[binHi-1]; 1335 prevPixels = cumulative->nums->data.F32[binHi-1]; 1336 } 1337 percentNums = (totalDataPoints * 0.841345f) - prevPixels; 1338 base = cumulative->bounds->data.F32[binHi]; 1339 float binHiF32 = base + (deltaBounds / deltaNums) * percentNums; // Value for the 84.1345% mark 1340 psTrace(__func__, 6, 1341 "(base, deltaBounds, deltaNums, prevPixels, percentNums) is (%.2f %.2f %.2f %.2f %.2f)\n", 1342 base, deltaBounds, deltaNums, prevPixels, percentNums); 1343 psTrace(__func__, 6, 1344 "The exact 15.8655 and 84.1345 percent data point positions are: (%f, %f)\n", 1345 binLoF32, binHiF32); 1346 #endif 1347 1348 // ADD step 5: Determine SIGMA as 1/2 of the distance between these positions. 1633 1349 sigma = (binHiF32 - binLoF32) / 2.0; 1634 1350 psTrace(__func__, 6, "The current sigma is %f.\n", sigma); 1635 1351 stats->robustStdev = sigma; 1636 1352 1637 // 1638 // ADD: Step 6. 1639 // If the measured SIGMA is less than 2 times the bin size, exclude 1640 // points which are more than 25 bins from the median, 1641 // recalculate the bin size, and perform the algorithm again. 1642 // 1353 // ADD step 6: If the measured SIGMA is less than 2 times the bin size, exclude points which are more 1354 // than 25 bins from the median, recalculate the bin size, and perform the algorithm again. 1643 1355 if (sigma < (2 * binSize)) { 1644 1356 psTrace(__func__, 6, "*************: Do another iteration (%f %f).\n", sigma, binSize); 1645 psS32 maskLo = PS_MAX(0, (binMedian - 25)); 1646 psS32 maskHi = PS_MIN(robustHistogram->bounds->n - 1, (binMedian + 25)); 1647 psF32 medianLo = robustHistogram->bounds->data.F32[maskLo]; 1648 psF32 medianHi = robustHistogram->bounds->data.F32[maskHi]; 1649 psTrace(__func__, 6, "Masking data more than 25 bins from the median (%.2f)\n", stats->robustMedian); 1650 psTrace(__func__, 6, "The median is at bin number %d. We mask bins outside the bin range (%d:%d)\n", 1357 long maskLo = PS_MAX(0, (binMedian - 25)); // Low index for masking region 1358 long maskHi = PS_MIN(histogram->bounds->n - 1, (binMedian + 25)); // High index for masking 1359 psF32 medianLo = histogram->bounds->data.F32[maskLo]; // Value at low index 1360 psF32 medianHi = histogram->bounds->data.F32[maskHi]; // Value at high index 1361 psTrace(__func__, 6, "Masking data more than 25 bins from the median\n"); 1362 psTrace(__func__, 6, 1363 "The median is at bin number %d. We mask bins outside the bin range (%d:%d)\n", 1651 1364 binMedian, maskLo, maskHi); 1652 1365 psTrace(__func__, 6, "Masking data outside (%f %f)\n", medianLo, medianHi); 1653 for ( psS32i = 0 ; i < myVector->n ; i++) {1366 for (long i = 0 ; i < myVector->n ; i++) { 1654 1367 if ((myVector->data.F32[i] < medianLo) || (myVector->data.F32[i] > medianHi)) { 1655 tmpMaskVec->data.U8[i] = 1;1368 mask->data.U8[i] = 0xff; 1656 1369 psTrace(__func__, 6, "Masking element %d is %f\n", i, myVector->data.F32[i]); 1657 1370 } 1658 1371 } 1659 psFree(robustHistogram); 1660 psFree(cumulativeRobustHistogram); 1661 iterate++; 1662 } else { 1372 // Free the histograms; they will be recreated on the next iteration, with new bounds 1373 psFree(histogram); 1374 psFree(cumulative); 1375 } else { 1376 // We've got the bin size correct now 1663 1377 psTrace(__func__, 6, "*************: No more iteration. sigma is %f\n", sigma); 1664 iterate = 0; 1665 } 1666 } 1667 1668 // 1669 // ADD: Step 7. 1670 // Find the bins which contains the 25% and 75% data points. 1671 // 1672 psS32 binLo25 = 0; 1673 psS32 binHi25 = 0; 1378 iterate = -1; 1379 } 1380 } 1381 psFree(histogram); 1382 1383 // ADD step 7: Find the bins which contains the 25% and 75% data points. 1384 long binLo25 = 0; // Bin containing the 25% value 1385 long binHi25 = 0; // Bin containing the 75% value 1674 1386 1675 1387 tmpScalar.data.F32 = totalDataPoints * 0.25f; 1676 if (tmpScalar.data.F32 <= cumulative RobustHistogram->nums->data.F32[0]) {1388 if (tmpScalar.data.F32 <= cumulative->nums->data.F32[0]) { 1677 1389 // Special case where its in first bin. The last bin should be handled automatically. 1678 1390 binLo25 = 0; 1679 1391 } else { 1680 binLo25 = 1 + p_psVectorBinDisect(cumulative RobustHistogram->nums, &tmpScalar);1392 binLo25 = 1 + p_psVectorBinDisect(cumulative->nums, &tmpScalar); 1681 1393 } 1682 1394 tmpScalar.data.F32 = totalDataPoints * 0.75f; 1683 if (tmpScalar.data.F32 <= cumulative RobustHistogram->nums->data.F32[0]) {1395 if (tmpScalar.data.F32 <= cumulative->nums->data.F32[0]) { 1684 1396 // Special case where its in first bin. The last bin should be handled automatically. 1685 1397 binHi25 = 0; 1686 1398 } else { 1687 binHi25 = 1 + p_psVectorBinDisect(cumulative RobustHistogram->nums, &tmpScalar);1399 binHi25 = 1 + p_psVectorBinDisect(cumulative->nums, &tmpScalar); 1688 1400 } 1689 1401 if ((binLo25 < 0) || (binHi25 < 0)) { 1690 1402 psError(PS_ERR_UNKNOWN, false, "Failed to calculate the 25 and 75 percent data points\n"); 1691 psFree(tmpStatsMinMax); 1692 psFree(robustHistogram); 1693 psFree(cumulativeRobustHistogram); 1694 psFree(tmpMaskVec); 1403 psFree(statsMinMax); 1404 psFree(cumulative); 1405 psFree(mask); 1406 psTrace(__func__, 4, "---- %s(false) end ----\n", __func__); 1407 return false; 1408 } 1409 psTrace(__func__, 6, "The 25-percent and 75-precent data point bins are (%d, %d).\n", binLo25, binHi25); 1410 1411 // ADD step 8: Interpolate to find these two positions exactly: these are the upper and lower quartile 1412 // positions. 1413 psF32 binLo25F32 = fitQuadraticSearchForYThenReturnX(cumulative->bounds, cumulative->nums, 1414 binLo25, totalDataPoints * 0.25f); 1415 psF32 binHi25F32 = fitQuadraticSearchForYThenReturnX(cumulative->bounds, cumulative->nums, 1416 binHi25, totalDataPoints * 0.75f); 1417 psFree(cumulative); 1418 1419 if (isnan(binLo25F32) || isnan(binHi25F32)) { 1420 psError(PS_ERR_UNKNOWN, false, 1421 "could not determine the robustUQ: fitQuadraticSearchForYThenReturnX() returned a NAN.\n"); 1422 psFree(statsMinMax); 1423 psFree(mask); 1695 1424 psTrace(__func__, 4, "---- %s(1) end ----\n", __func__); 1696 return(1); 1697 } 1698 psTrace(__func__, 6, "The 25-percent and 75-precent data point bins are (%d, %d).\n", binLo25, binHi25); 1699 1700 // 1701 // ADD: Step 8. 1702 // Interpolate to find these two positions exactly: these are the upper 1703 // and lower quartile positions. 1704 // 1705 psF32 binLo25F32 = fitQuadraticSearchForYThenReturnX( 1706 *(psVector* *)&cumulativeRobustHistogram->bounds, 1707 *(psVector* *)&cumulativeRobustHistogram->nums, 1708 binLo25, 1709 totalDataPoints * 0.25f); 1710 1711 psF32 binHi25F32 = fitQuadraticSearchForYThenReturnX( 1712 *(psVector* *)&cumulativeRobustHistogram->bounds, 1713 *(psVector* *)&cumulativeRobustHistogram->nums, 1714 binHi25, 1715 totalDataPoints * 0.75f); 1716 1717 if (isnan(binLo25F32) || isnan(binHi25F32)) { 1718 psError(PS_ERR_UNKNOWN, false, "could not determine the robustUQ: fitQuadraticSearchForYThenReturnX() returned a NAN.\n"); 1719 psFree(tmpStatsMinMax); 1720 psFree(robustHistogram); 1721 psFree(cumulativeRobustHistogram); 1722 psFree(tmpMaskVec); 1723 psTrace(__func__, 4, "---- %s(1) end ----\n", __func__); 1724 return(1); 1425 return false; 1725 1426 } 1726 1427 1727 1428 stats->robustLQ = binLo25F32; 1728 1429 stats->robustUQ = binHi25F32; 1729 psTrace(__func__, 6, "The 25 and 75 percent data point exact positions are (%f, %f).\n", binLo25F32, binHi25F32); 1730 psS32 N50 = 0; 1731 for (psS32 i = 0 ; i < myVector->n ; i++) { 1732 // XXX: use maskVal here? 1733 if ((0 == tmpMaskVec->data.U8[i]) && 1734 (binLo25F32 <= myVector->data.F32[i]) && 1735 (binHi25F32 >= myVector->data.F32[i])) { 1430 psTrace(__func__, 6, "The 25 and 75 percent data point exact positions are (%f, %f).\n", 1431 binLo25F32, binHi25F32); 1432 long N50 = 0; 1433 for (long i = 0 ; i < myVector->n ; i++) { 1434 if (!(mask->data.U8[i] & maskVal) && 1435 (binLo25F32 <= myVector->data.F32[i]) && (binHi25F32 >= myVector->data.F32[i])) { 1736 1436 N50++; 1737 1437 } … … 1740 1440 psTrace(__func__, 6, "The robustN50 is %d.\n", N50); 1741 1441 1742 // ************************************************************************ 1743 if ((stats->options & PS_STAT_FITTED_MEAN) || 1744 (stats->options & PS_STAT_FITTED_STDEV)) { 1745 // 1442 1443 // Fitted statistics 1444 if (stats->options & PS_STAT_FITTED_MEAN || stats->options & PS_STAT_FITTED_STDEV) { 1746 1445 // New algorithm for calculated mean and stdev. 1747 //1748 1446 1749 1447 // XXX: Where is this documented? 1750 psF32 dN = (psF32) (0.17 * N50);1448 psF32 dN = 0.17 * N50; 1751 1449 if (dN < 1.0) { 1752 1450 dN = 1.0; … … 1756 1454 psF32 newBinSize = sigma / dN; 1757 1455 1758 //1759 1456 // Determine the min/max of the vector (which prior outliers masked out) 1760 //1761 rc = p_psVectorMin(myVector, tmpMaskVec, 1 | maskVal, tmpStatsMinMax);1762 rc|= p_psVectorMax(myVector, tmpMaskVec, 1 | maskVal, tmpStatsMinMax);1763 if ( (rc != 0) || isnan(tmpStatsMinMax->min) || isnan(tmpStatsMinMax->max)) {1457 int numValid = vectorMinMax(myVector, mask, maskVal, statsMinMax); // Number of values 1458 min = statsMinMax->min; 1459 max = statsMinMax->max; 1460 if (numValid == 0 || isnan(min) || isnan(max)) { 1764 1461 psError(PS_ERR_UNKNOWN, false, "Failed to calculate the min/max of the input vector.\n"); 1765 psFree(tmpStatsMinMax); 1766 psFree(robustHistogram); 1767 psFree(cumulativeRobustHistogram); 1768 psFree(tmpMaskVec); 1769 psTrace(__func__, 4, "---- %s(1) end ----\n", __func__); 1770 return(1); 1771 } 1772 1773 // 1462 psFree(statsMinMax); 1463 psFree(mask); 1464 psTrace(__func__, 4, "---- %s(false) end ----\n", __func__); 1465 return false; 1466 } 1467 1774 1468 // Calculate the number of bins. 1775 // 1776 numBins = (psS32)((tmpStatsMinMax->max - tmpStatsMinMax->min) / newBinSize); 1777 psTrace(__func__, 6, "The new min/max values are (%f, %f).\n", tmpStatsMinMax->min, tmpStatsMinMax->max); 1469 long numBins = (max - min) / newBinSize; 1470 psTrace(__func__, 6, "The new min/max values are (%f, %f).\n", min, max); 1778 1471 psTrace(__func__, 6, "The new bin size is %f.\n", newBinSize); 1779 1472 psTrace(__func__, 6, "The numBins is %d\n", numBins); 1780 1473 1781 psHistogram * newHistogram = psHistogramAlloc(tmpStatsMinMax->min, tmpStatsMinMax->max, numBins);1782 newHistogram = psVectorHistogram(newHistogram, myVector, errors, tmpMaskVec, maskVal|1);1474 psHistogram *histogram = psHistogramAlloc(min, max, numBins); // A new histogram (without outliers) 1475 histogram = psVectorHistogram(histogram, myVector, errors, mask, maskVal); 1783 1476 if (psTraceGetLevel(__func__) >= 8) { 1784 PS_VECTOR_PRINT_F32(newHistogram->nums); 1785 } 1786 1787 // 1788 // FITTED STATISTICS HERE 1789 // 1790 // Smooth the resulting histogram with a Gaussian with sigma_s = 1 1791 // bin. 1792 // 1793 psF32 sigma_s = newBinSize; 1794 1795 psVector *newHistogramSmoothed = p_psVectorSmoothHistGaussian(newHistogram, sigma_s); 1477 PS_VECTOR_PRINT_F32(histogram->nums); 1478 } 1479 1480 // Smooth the resulting histogram with a Gaussian with sigma_s = 1 bin. 1481 psVector *smoothed = vectorSmoothHistGaussian(histogram, newBinSize); // Smoothed histogram 1796 1482 if (psTraceGetLevel(__func__) >= 8) { 1797 PS_VECTOR_PRINT_F32(newHistogramSmoothed); 1798 } 1799 1800 // 1801 // Find the bin with the peak value in the range 2 sigma of the 1802 // robust histogram median. 1803 // 1804 1805 psS32 binMin = 0; 1806 psS32 binMax = 0; 1483 PS_VECTOR_PRINT_F32(smoothed); 1484 } 1485 1486 // Find the bin with the peak value in the range 2 sigma of the robust histogram median. 1487 long binMin = 0; // Low bin to check 1488 long binMax = 0; // High bin to check 1807 1489 tmpScalar.data.F32 = stats->robustMedian - (2.0 * sigma); 1808 if (tmpScalar.data.F32 <= newHistogram->bounds->data.F32[0]) {1490 if (tmpScalar.data.F32 <= histogram->bounds->data.F32[0]) { 1809 1491 binMin = 0; 1810 1492 } else { 1811 binMin = p_psVectorBinDisect( (psVector *) newHistogram->bounds, &tmpScalar);1493 binMin = p_psVectorBinDisect(histogram->bounds, &tmpScalar); 1812 1494 } 1813 1495 1814 1496 tmpScalar.data.F32 = stats->robustMedian + (2.0 + sigma); 1815 if (tmpScalar.data.F32 >= newHistogram->bounds->data.F32[newHistogram->bounds->n-1]) {1816 binMax = newHistogram->bounds->n-1;1817 } else { 1818 binMax = p_psVectorBinDisect( (psVector *) newHistogram->bounds, &tmpScalar);1497 if (tmpScalar.data.F32 >= histogram->bounds->data.F32[histogram->bounds->n-1]) { 1498 binMax = histogram->bounds->n-1; 1499 } else { 1500 binMax = p_psVectorBinDisect(histogram->bounds, &tmpScalar); 1819 1501 } 1820 1502 if ((binMin < 0) || (binMax < 0)) { 1821 psError(PS_ERR_UNKNOWN, false, "Failed to calculate the +- 2.0 * sigma bins\n"); 1822 psFree(tmpMaskVec); 1823 psFree(robustHistogram); 1824 psFree(cumulativeRobustHistogram); 1825 psFree(tmpStatsMinMax); 1826 psTrace(__func__, 4, "---- %s(1) end ----\n", __func__); 1827 return(1); 1828 } 1829 1830 psS32 binNum = binMin; 1831 psF32 binMaxNums = newHistogramSmoothed->data.F32[binNum]; 1503 psError(PS_ERR_UNKNOWN, false, "Failed to calculate the +/- 2.0 * sigma bins\n"); 1504 psFree(statsMinMax); 1505 psFree(histogram); 1506 psFree(mask); 1507 psTrace(__func__, 4, "---- %s(false) end ----\n", __func__); 1508 return false; 1509 } 1510 1511 long binNum = binMin; // Bin number containing the peak 1512 psF32 binMaxNums = smoothed->data.F32[binNum]; // The peak value 1832 1513 for (psS32 i = binMin+1 ; i <= binMax ; i++) { 1833 if ( newHistogramSmoothed->data.F32[i] > binMaxNums) {1514 if (smoothed->data.F32[i] > binMaxNums) { 1834 1515 binNum = i; 1835 binMaxNums = newHistogramSmoothed->data.F32[i];1516 binMaxNums = smoothed->data.F32[i]; 1836 1517 } 1837 1518 } 1838 1519 psTrace(__func__, 6, "The peak bin is %d, with %f data.n", binNum, binMaxNums); 1839 1520 1840 // 1841 // Fit a Gaussian to the bins in the range 20 sigma of the robust 1842 // histogram median. 1843 // 1521 // Fit a Gaussian to the bins in the range 20 sigma of the robust histogram median. 1844 1522 tmpScalar.data.F32 = stats->robustMedian - (20.0 * sigma); 1845 if (tmpScalar.data.F32 < tmpStatsMinMax->min) {1523 if (tmpScalar.data.F32 < min) { 1846 1524 binMin = 0; 1847 1525 } else { 1848 binMin = p_psVectorBinDisect((psVector *) newHistogram->bounds, &tmpScalar); 1849 // XXX: check for errors here. 1526 binMin = p_psVectorBinDisect(histogram->bounds, &tmpScalar); 1850 1527 } 1851 1528 tmpScalar.data.F32 = stats->robustMedian + (20.0 * sigma); 1852 if (tmpScalar.data.F32 > tmpStatsMinMax->max) { 1853 binMax = newHistogramSmoothed->n - 1; 1854 } else { 1855 binMax = p_psVectorBinDisect((psVector *) newHistogram->bounds, &tmpScalar); 1856 // XXX: check for errors here. 1857 } 1858 psVector *y = psVectorAlloc((1 + (binMax - binMin)), PS_TYPE_F32); 1859 psArray *x = psArrayAlloc((1 + (binMax - binMin))); 1860 psS32 j = 0; 1529 if (tmpScalar.data.F32 > max) { 1530 binMax = smoothed->n - 1; 1531 } else { 1532 binMax = p_psVectorBinDisect(histogram->bounds, &tmpScalar); 1533 } 1534 if (binMin < 0 || binMax < 0) { 1535 psError(PS_ERR_UNKNOWN, false, "Failed to calculate the +/- 20.0 * sigma bins\n"); 1536 psFree(statsMinMax); 1537 psFree(histogram); 1538 psFree(mask); 1539 psTrace(__func__, 4, "---- %s(false) end ----\n", __func__); 1540 return false; 1541 } 1542 1543 // Generate the variables that will be used in the Gaussian fitting 1544 psVector *y = psVectorAlloc((1 + (binMax - binMin)), PS_TYPE_F32); // Vector of coordinates 1545 psArray *x = psArrayAlloc((1 + (binMax - binMin))); // Array of ordinates 1861 1546 y->n = y->nalloc; 1862 1863 for (psS32 i = binMin ; i <= binMax ; i++) { 1864 y->data.F32[j] = newHistogramSmoothed->data.F32[i]; 1865 x->data[j] = (psPtr *) psVectorAlloc(1, PS_TYPE_F32); 1866 x->n++; 1867 ((psVector *) x->data[j])->data.F32[0] = PS_BIN_MIDPOINT(newHistogram, i); 1868 ((psVector *) x->data[j])->n++; 1869 j++; 1547 x->n = x->nalloc; 1548 for (long i = binMin, j = 0; i <= binMax ; i++, j++) { 1549 y->data.F32[j] = smoothed->data.F32[i]; 1550 psVector *ordinate = psVectorAlloc(1, PS_TYPE_F32); // The ordinate value 1551 ordinate->n = 1; 1552 ordinate->data.F32[0] = PS_BIN_MIDPOINT(histogram, i); 1553 x->data[j] = ordinate; 1870 1554 } 1871 1555 if (psTraceGetLevel(__func__) >= 8) { … … 1873 1557 PS_VECTOR_PRINT_F32(y); 1874 1558 } 1875 1876 rc = p_psVectorMin(y, NULL, 0, tmpStatsMinMax); 1877 rc|= p_psVectorMax(y, NULL, 0, tmpStatsMinMax); 1878 if ((rc != 0) || isnan(tmpStatsMinMax->min) || isnan(tmpStatsMinMax->max)) { 1559 psFree(smoothed); 1560 psFree(histogram); 1561 1562 numValid = vectorMinMax(y, NULL, 0, statsMinMax); // Number of valid values 1563 min = statsMinMax->min; 1564 max = statsMinMax->max; 1565 if (numValid == 0 || isnan(min) || isnan(max)) { 1879 1566 psError(PS_ERR_UNKNOWN, false, "Failed to calculate the min/max of the input vector.\n"); 1880 psFree(tmpMaskVec); 1881 psFree(robustHistogram); 1882 psFree(cumulativeRobustHistogram); 1883 psFree(tmpStatsMinMax); 1884 psTrace(__func__, 4, "---- %s(1) end ----\n", __func__); 1885 return(1); 1886 } 1887 1888 // 1567 psFree(mask); 1568 psFree(histogram); 1569 psFree(statsMinMax); 1570 psTrace(__func__, 4, "---- %s(false) end ----\n", __func__); 1571 return false; 1572 } 1573 1889 1574 // Normalize y to [0.0:1.0] (since the psMinimizeLMChi2Gauss1D() functions is [0.0:1.0]) 1890 // XXX: Use the normalize routines for this. 1891 // 1892 for (psS32 i = 0 ; i < y->n ; i++) { 1893 y->data.F32[i]= (y->data.F32[i] - tmpStatsMinMax->min) / (tmpStatsMinMax->max - tmpStatsMinMax->min); 1894 } 1895 1896 // 1897 psMinimization *min = psMinimizationAlloc(100, 0.01); 1898 psVector *params = psVectorAlloc(2, PS_TYPE_F32); 1575 p_psNormalizeVectorRange(y, 0.0, 1.0); 1576 1577 // Fit a Gaussian to the data. 1578 psMinimization *minimizer = psMinimizationAlloc(100, 0.01); // The minimizer information 1579 psVector *params = psVectorAlloc(2, PS_TYPE_F32); // Parameters for the Gaussian 1899 1580 params->n = params->nalloc; 1900 // Initial guess for the mean ( [0]) and standard dev.1581 // Initial guess for the mean (index 0) and standard dev (index 1). 1901 1582 params->data.F32[0] = stats->robustMedian; 1902 1583 params->data.F32[1] = sigma; … … 1905 1586 PS_VECTOR_PRINT_F32(y); 1906 1587 } 1907 1908 // 1909 // Fit a Gaussian to the data. 1910 // 1911 rcBool = psMinimizeLMChi2(min, NULL, params, NULL, x, y, NULL, psMinimizeLMChi2Gauss1D); 1912 if (rcBool != true) { 1588 if (!psMinimizeLMChi2(minimizer, NULL, params, NULL, x, y, NULL, minimizeLMChi2Gauss1D)) { 1913 1589 psError(PS_ERR_UNKNOWN, false, "Failed to fit a gaussian to the robust histogram.\n"); 1914 psFree(tmpStatsMinMax); 1915 psFree(robustHistogram); 1916 psFree(cumulativeRobustHistogram); 1917 psFree(newHistogram); 1590 psFree(statsMinMax); 1918 1591 psFree(x); 1919 1592 psFree(y); 1920 psFree(min );1593 psFree(minimizer); 1921 1594 psFree(params); 1922 psFree( tmpMaskVec);1923 psTrace(__func__, 4, "---- %s( 1) end ----\n", __func__);1924 return (1);1595 psFree(mask); 1596 psTrace(__func__, 4, "---- %s(false) end ----\n", __func__); 1597 return false; 1925 1598 } 1926 1599 if (psTraceGetLevel(__func__) >= 8) { … … 1928 1601 } 1929 1602 1930 // 1931 // The fitted mean mean_r is derived directly from the fitted 1932 // Gaussian mean. 1933 // 1603 // The fitted mean is the Gaussian mean. 1934 1604 stats->fittedMean = params->data.F32[0]; 1935 1605 psTrace(__func__, 6, "The fitted mean is %f.\n", params->data.F32[0]); 1936 1606 1937 // 1938 // The fitted standard deviation, SIGMA_r is determined by 1939 // subtracting the smoothing scale in quadrature: 1940 // SIGMA_r^2 = SIGMA^2 - sigma_s^2 1941 // 1942 stats->fittedStdev = sqrt(PS_SQR(params->data.F32[1]) - PS_SQR(sigma_s)); 1607 // The fitted standard deviation, SIGMA_r is determined by subtracting the smoothing scale in 1608 // quadrature: SIGMA_r^2 = SIGMA^2 - sigma_s^2 1609 stats->fittedStdev = sqrt(PS_SQR(params->data.F32[1]) - PS_SQR(newBinSize)); 1943 1610 psTrace(__func__, 6, "The fitted stdev is %f.\n", stats->fittedStdev); 1944 1611 1945 psFree(newHistogramSmoothed); 1946 psFree(newHistogram); 1612 // Clean up after fitting 1947 1613 psFree(x); 1948 1614 psFree(y); 1949 psFree(min );1615 psFree(minimizer); 1950 1616 psFree(params); 1951 1617 } 1952 1618 1953 psFree(tmpStatsMinMax); 1954 psFree(cumulativeRobustHistogram); 1955 psFree(tmpMaskVec); 1956 psFree(robustHistogram); 1619 // Clean up 1620 psFree(statsMinMax); 1621 psFree(mask); 1957 1622 1958 1623 psTrace(__func__, 4, "---- %s(0) end ----\n", __func__); 1959 return (0);1624 return true; 1960 1625 } 1961 1626 … … 1968 1633 static void histogramFree(psHistogram* myHist); 1969 1634 1635 // We keep statsFree so that we can identify statistics pointers from the memblock 1970 1636 static void statsFree(psStats *newStruct) 1971 1637 { … … 2038 1704 PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(upper, lower, NULL); 2039 1705 2040 psS32 i = 0; // Loop index variable 2041 psHistogram* newHist = NULL; // The new histogram structure 2042 psF32 binSize = 0.0; // The histogram bin size 2043 2044 // Allocate memory for the new histogram structure. If there are N 2045 // bins, then there are N+1 bounds to those bins. 2046 newHist = (psHistogram* ) psAlloc(sizeof(psHistogram)); 1706 // Allocate memory for the new histogram structure. If there are N bins, then there are N+1 bounds to 1707 // those bins. 1708 psHistogram *newHist = (psHistogram* ) psAlloc(sizeof(psHistogram)); // The new histogram structure 2047 1709 psMemSetDeallocator(newHist, (psFreeFunc) histogramFree); 2048 1710 psVector* newBounds = psVectorAlloc(n + 1, PS_TYPE_F32); … … 2051 1713 2052 1714 // Calculate the bounds for each bin. 2053 binSize = (upper - lower) / (psF32)n; 2054 // XXX: Is the following necessary? It prevents the max data point 2055 // from being in a non-existant bin. 1715 psF32 binSize = (upper - lower) / (psF32)n; // The histogram bin size 1716 // XXX: Is the following necessary? It prevents the max data point from being in a non-existant bin. 2056 1717 binSize += FLT_EPSILON; 2057 for ( i = 0; i < n + 1; i++) {1718 for (long i = 0; i < n + 1; i++) { 2058 1719 newBounds->data.F32[i] = lower + (binSize * (psF32)i); 2059 1720 } … … 2061 1722 // Allocate the bins, and initialize them to zero. 2062 1723 newHist->nums = psVectorAlloc(n, PS_TYPE_F32); 2063 for ( i = 0; i < newHist->nums->nalloc; i++) {1724 for (long i = 0; i < newHist->nums->nalloc; i++) { 2064 1725 newHist->nums->data.F32[i] = 0.0; 2065 1726 newHist->nums->n++; … … 2072 1733 2073 1734 psTrace(__func__, 3, "---- %s() end ----\n", __func__); 2074 return (newHist);1735 return newHist; 2075 1736 } 2076 1737 … … 2091 1752 PS_ASSERT_INT_LARGER_THAN_OR_EQUAL(bounds->n, 2, NULL); 2092 1753 2093 psHistogram* newHist = NULL; // The new histogram structure2094 psS32 i; // Loop index variable2095 2096 1754 // Allocate memory for the new histogram structure. 2097 newHist = (psHistogram* ) psAlloc(sizeof(psHistogram));1755 psHistogram *newHist = (psHistogram* ) psAlloc(sizeof(psHistogram)); // The new histogram structure 2098 1756 psMemSetDeallocator(newHist, (psFreeFunc) histogramFree); 2099 1757 psVector* newBounds = psVectorAlloc(bounds->n, PS_TYPE_F32); 2100 1758 newHist->bounds = newBounds; 2101 1759 newBounds->n = newHist->bounds->nalloc; 2102 for ( i = 0; i < bounds->n; i++) {1760 for (long i = 0; i < bounds->n; i++) { 2103 1761 newBounds->data.F32[i] = bounds->data.F32[i]; 2104 1762 } … … 2107 1765 // then there are N-1 bins. 2108 1766 newHist->nums = psVectorAlloc((bounds->n) - 1, PS_TYPE_F32); 2109 for ( i = 0; i < newHist->nums->nalloc; i++) {1767 for (long i = 0; i < newHist->nums->nalloc; i++) { 2110 1768 newHist->nums->data.F32[i] = 0.0; 2111 1769 newHist->nums->n++; … … 2140 1798 the data point as a boxcar PDF and update a range of points surrounding the 2141 1799 histogram bin which contains the point. The width of that boxcar is defined 2142 as 2.35 * error. Inputs: 2143 binNum: the bin number of the data point in the histogram 2144 out: the histogram structure 2145 data: the data point value 2146 error: the error in that data point 1800 as 2.35 * error. 2147 1801 2148 1802 XXX: Must test this. 2149 1803 *****************************************************************************/ 2150 psS32 UpdateHistogramBins(psS32 binNum, 2151 psHistogram* out, 2152 psF32 data, 2153 psF32 error) 1804 static bool UpdateHistogramBins(long binNum, // Bin number of the data point 1805 psHistogram* out, // The histogram to be updated 1806 psF32 data, // The data point value 1807 psF32 error // The error in the data point 1808 ) 2154 1809 { 2155 1810 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 2156 PS_ASSERT_PTR_NON_NULL(out, -1);2157 PS_ASSERT_PTR_NON_NULL(out->bounds, -1);2158 PS_ASSERT_PTR_NON_NULL(out->nums, -1);2159 PS_ASSERT_INT_WITHIN_RANGE(binNum, 0, ((out->nums->n)-1), -2);2160 PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(error, 0.0, -3);2161 2162 PS_ASSERT_FLOAT_WITHIN_RANGE(data, out->bounds->data.F32[0], out->bounds->data.F32[(out->bounds->n)-1], -4);2163 2164 psF32 boxcarWidth = 2.35 * error; 1811 PS_ASSERT_PTR_NON_NULL(out, false); 1812 PS_ASSERT_PTR_NON_NULL(out->bounds, false); 1813 PS_ASSERT_PTR_NON_NULL(out->nums, false); 1814 PS_ASSERT_INT_WITHIN_RANGE(binNum, 0, ((out->nums->n)-1), false); 1815 PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(error, 0.0, false); 1816 PS_ASSERT_FLOAT_WITHIN_RANGE(data, out->bounds->data.F32[0], 1817 out->bounds->data.F32[(out->bounds->n)-1], false); 1818 1819 psF32 boxcarWidth = 2.35 * error; // Width of the boxcar 2165 1820 psF32 boxcarCenter = (out->bounds->data.F32[binNum] + 2166 out->bounds->data.F32[binNum+1]) / 2.0; 2167 psF32 boxcarLeft = boxcarCenter - (boxcarWidth / 2.0); 2168 psF32 boxcarRight = boxcarCenter + (boxcarWidth / 2.0); 2169 psS32 bin; 2170 psS32 boxcarLeftBinNum = 0; 2171 psS32 boxcarRightBinNum = 0; 1821 out->bounds->data.F32[binNum+1]) / 2.0; // Centre of the boxcar 1822 psF32 boxcarLeft = boxcarCenter - (boxcarWidth / 2.0); // Left endpoint of the boxcar for the PDF 1823 psF32 boxcarRight = boxcarCenter + (boxcarWidth / 2.0); // Right endpoint of the boxcar for the PDF 1824 psS32 boxcarLeftBinNum = 0; // Bin number for left endpoint 1825 psS32 boxcarRightBinNum = 0; // Bin number for right endpoint 2172 1826 2173 1827 // Determine the left endpoint of the boxcar for the PDF. 2174 for ( bin=binNum ; bin >= 0; bin--) {1828 for (long bin = binNum; bin >= 0; bin--) { 2175 1829 if (out->nums->data.F32[bin] <= boxcarLeft) { 2176 1830 boxcarLeftBinNum = bin; … … 2180 1834 2181 1835 // Determine the right endpoint of the boxcar for the PDF. 2182 for ( bin=binNum ; bin < out->nums->n; bin++) {1836 for (long bin = binNum; bin < out->nums->n; bin++) { 2183 1837 if (out->nums->data.F32[bin] >= boxcarRight) { 2184 1838 boxcarRightBinNum = bin; … … 2187 1841 } 2188 1842 2189 //2190 1843 // If the boxcar fits entirely inside this bin, then simply add 1.0 to the 2191 1844 // bin and return. 2192 //2193 1845 if (boxcarLeftBinNum == boxcarRightBinNum) { 2194 out->nums->data.F32[binNum]+= 1.0; 2195 psTrace(__func__, 3, "---- %s(0) end ----\n", __func__); 2196 return(0); 2197 } 2198 2199 // 2200 // If we get here, multiple bins must be updated. We handle the left 2201 // endpoint, and right endpoint differently. 2202 // 2203 out->nums->data.F32[boxcarLeftBinNum]+= 1846 out->nums->data.F32[binNum] += 1.0; 1847 psTrace(__func__, 3, "---- %s(true) end ----\n", __func__); 1848 return true; 1849 } 1850 1851 // If we get here, multiple bins must be updated. We handle the left-most endpoint, and right-most 1852 // endpoints differently. 1853 out->nums->data.F32[boxcarLeftBinNum] += 2204 1854 (out->bounds->data.F32[boxcarLeftBinNum+1] - boxcarLeft) / boxcarWidth; 2205 1855 2206 //2207 1856 // Loop through the center bins, if any. 2208 // 2209 for (bin = boxcarLeftBinNum + 1 ; bin < (boxcarRightBinNum - 1) ; bin++) { 2210 out->nums->data.F32[bin]+= 1857 for (long bin = boxcarLeftBinNum + 1; bin < (boxcarRightBinNum - 1); bin++) { 1858 out->nums->data.F32[bin] += 2211 1859 (out->bounds->data.F32[bin+1] - out->bounds->data.F32[bin]) / boxcarWidth; 2212 1860 } 2213 1861 2214 //2215 1862 // Handle the right endpoint differently. 2216 //2217 1863 out->nums->data.F32[boxcarRightBinNum]+= 2218 1864 (boxcarRight - out->bounds->data.F32[boxcarRightBinNum]) / boxcarWidth; 2219 1865 2220 // 2221 // Return 0 on success. 2222 // 2223 psTrace(__func__, 3, "---- %s(0) end ----\n", __func__); 2224 return(0); 1866 psTrace(__func__, 3, "---- %s(true) end ----\n", __func__); 1867 return true; 2225 1868 } 2226 1869 … … 2255 1898 PS_ASSERT_INT_NONNEGATIVE(out->nums->n, NULL); 2256 1899 PS_ASSERT_VECTOR_NON_NULL(values, out); 2257 if (mask != NULL) {1900 if (mask) { 2258 1901 PS_ASSERT_VECTORS_SIZE_EQUAL(values, mask, NULL); 2259 1902 PS_ASSERT_VECTOR_TYPE(mask, PS_TYPE_U8, NULL); 2260 1903 } 2261 if (errors != NULL) {1904 if (errors) { 2262 1905 PS_ASSERT_VECTORS_SIZE_EQUAL(values, errors, NULL); 2263 1906 PS_ASSERT_VECTOR_TYPE(errors, values->type.type, NULL); 2264 1907 } 2265 1908 2266 psS32 i = 0; // Loop index variable 2267 psF32 binSize = 0.0; // Histogram bin size 2268 psS32 binNum = 0; // A temporary bin number 2269 psS32 numBins = 0; // The total number of bins 1909 long binNum = 0; // A temporary bin number 1910 long numBins = out->nums->n; // The total number of bins 2270 1911 psScalar tmpScalar; 2271 1912 tmpScalar.type.type = PS_TYPE_F32; 2272 psVector* inF32 = NULL;2273 psVector* errorsF32 = NULL;2274 psS32 mustFreeVectorIn = 1;2275 psS32 mustFreeVectorErrors = 1;2276 1913 2277 1914 // Convert input and errors vectors to F32 if necessary. 2278 inF32 = p_psConvertToF32((psVector *) values); 2279 if (inF32 == NULL) { 2280 inF32 = (psVector *) values; 2281 mustFreeVectorIn = 0; 2282 } 2283 errorsF32 = p_psConvertToF32((psVector *) errors); 2284 if (errorsF32 == NULL) { 2285 errorsF32 = (psVector *) errors; 2286 mustFreeVectorErrors = 0; 2287 } 2288 2289 numBins = out->nums->n; 2290 for (i = 0; i < inF32->n; i++) { 1915 psVector* inF32 = NULL; // F32 version of input vector 1916 if (values->type.type == PS_TYPE_F32) { 1917 inF32 = psMemIncrRefCounter((psPtr)values); 1918 } else { 1919 values = psVectorCopy(NULL, values, PS_TYPE_F32); 1920 } 1921 psVector* errorsF32 = NULL; // F32 version of errors vector 1922 if (errors) { 1923 if (errors->type.type == PS_TYPE_F32) { 1924 errorsF32 = psMemIncrRefCounter((psPtr)errors); 1925 } else { 1926 errorsF32 = psVectorCopy(NULL, errors, PS_TYPE_F32); 1927 } 1928 } 1929 1930 for (long i = 0; i < inF32->n; i++) { 2291 1931 // Check if this pixel is masked, and if so, skip it. 2292 if ( (mask == NULL) || ((mask != NULL)&& (!(mask->data.U8[i] & maskVal)))) {1932 if (!mask || (mask && (!(mask->data.U8[i] & maskVal)))) { 2293 1933 if (inF32->data.F32[i] < out->bounds->data.F32[0]) { 2294 1934 // If this pixel is below minimum value, count it, then skip. … … 2301 1941 // number is trivial. 2302 1942 if (out->uniform == true) { 2303 binSize = out->bounds->data.F32[1] - out->bounds->data.F32[0]; 2304 binNum = (psS32)((inF32->data.F32[i] - out->bounds->data.F32[0]) / binSize); 2305 if (errorsF32 != NULL) { 2306 psS32 rc = UpdateHistogramBins(binNum, out, inF32->data.F32[i], 2307 errorsF32->data.F32[i]); 2308 if (rc < 0) { 2309 psLogMsg(__func__, PS_LOG_WARN, "WARNING: Failed to update the histogram bins with the errors vector.\n"); 1943 float binSize = out->bounds->data.F32[1] - out->bounds->data.F32[0]; // Histogram bin size 1944 binNum = (inF32->data.F32[i] - out->bounds->data.F32[0]) / binSize; 1945 if (errorsF32) { 1946 if (!UpdateHistogramBins(binNum, out, inF32->data.F32[i], errorsF32->data.F32[i])) { 1947 psLogMsg(__func__, PS_LOG_WARN, "WARNING: Failed to update the histogram " 1948 "bins with the errors vector.\n"); 2310 1949 } 2311 1950 } else { … … 2329 1968 } else { 2330 1969 if (errorsF32 != NULL) { 2331 psS32 rc = UpdateHistogramBins(binNum, out, 2332 inF32->data.F32[i], 2333 errors->data.F32[i]); 2334 if (rc < 0) { 2335 psLogMsg(__func__, PS_LOG_WARN, "WARNING: Failed to update the histogram bins with the errors vector.\n"); 1970 if (!UpdateHistogramBins(binNum, out, inF32->data.F32[i], errors->data.F32[i])) { 1971 psLogMsg(__func__, PS_LOG_WARN, "WARNING: Failed to update the histogram " 1972 "bins with the errors vector.\n"); 2336 1973 } 2337 1974 } else { 2338 (out->nums->data.F32[binNum])+= 1.0;1975 out->nums->data.F32[binNum] += 1.0; 2339 1976 } 2340 1977 } … … 2344 1981 } 2345 1982 2346 if (mustFreeVectorIn == 1) { 2347 psFree(inF32); 2348 } 2349 if (mustFreeVectorErrors == 1) { 2350 psFree(errorsF32); 2351 } 1983 psFree(inF32); 1984 psFree(errorsF32); 2352 1985 2353 1986 psTrace(__func__, 3, "---- %s() end ----\n", __func__); 2354 1987 return (out); 2355 }2356 2357 /******************************************************************************2358 p_psConvertToF32(in): this is the cheap way to support a variety of vector2359 data types: we simply convert the input vector to F32 at the beginning, and2360 write all of our functions in F32. If the vast majority of all vector stat2361 operations are F32 (or any other single type), then this is probably the2362 best way to go. Otherwise, when the algorithms stablize, we will then macro2363 everything and put type support in the various stat functions.2364 2365 XXX: Should the default data type be F64? Since we are buying Opterons...2366 2367 XXX: Use psLib functions instead.2368 *****************************************************************************/2369 psVector* p_psConvertToF32(psVector* in)2370 {2371 psTrace(__func__, 4,"---- %s() begin ----\n", __func__);2372 if (in == NULL) {2373 return(NULL);2374 }2375 psS32 i = 0;2376 psVector* tmp = NULL;2377 2378 if (in->type.type == PS_TYPE_S8) {2379 tmp = psVectorAlloc(in->n, PS_TYPE_F32);2380 for (i = 0; i < in->n; i++) {2381 tmp->data.F32[i] = (psF32)in->data.S8[i];2382 tmp->n++;2383 }2384 } else if (in->type.type == PS_TYPE_S16) {2385 tmp = psVectorAlloc(in->n, PS_TYPE_F32);2386 for (i = 0; i < in->n; i++) {2387 tmp->data.F32[i] = (psF32) in->data.S16[i];2388 tmp->n++;2389 }2390 } else if (in->type.type == PS_TYPE_S32) {2391 tmp = psVectorAlloc(in->n, PS_TYPE_F32);2392 for (i = 0; i < in->n; i++) {2393 tmp->data.F32[i] = (psF32)in->data.S32[i];2394 tmp->n++;2395 }2396 } else if (in->type.type == PS_TYPE_S64) {2397 tmp = psVectorAlloc(in->n, PS_TYPE_F32);2398 for (i = 0; i < in->n; i++) {2399 tmp->data.F32[i] = (psF32)in->data.S64[i];2400 tmp->n++;2401 }2402 } else if (in->type.type == PS_TYPE_U8) {2403 tmp = psVectorAlloc(in->n, PS_TYPE_F32);2404 for (i = 0; i < in->n; i++) {2405 tmp->data.F32[i] = (psF32)in->data.U8[i];2406 tmp->n++;2407 }2408 } else if (in->type.type == PS_TYPE_U16) {2409 tmp = psVectorAlloc(in->n, PS_TYPE_F32);2410 for (i = 0; i < in->n; i++) {2411 tmp->data.F32[i] = (psF32)in->data.U16[i];2412 tmp->n++;2413 }2414 } else if (in->type.type == PS_TYPE_U32) {2415 tmp = psVectorAlloc(in->n, PS_TYPE_F32);2416 for (i = 0; i < in->n; i++) {2417 tmp->data.F32[i] = (psF32)in->data.U32[i];2418 tmp->n++;2419 }2420 } else if (in->type.type == PS_TYPE_U64) {2421 tmp = psVectorAlloc(in->n, PS_TYPE_F32);2422 for (i = 0; i < in->n; i++) {2423 tmp->data.F32[i] = (psF32)in->data.U64[i];2424 tmp->n++;2425 }2426 } else if (in->type.type == PS_TYPE_F64) {2427 tmp = psVectorAlloc(in->n, PS_TYPE_F32);2428 for (i = 0; i < in->n; i++) {2429 tmp->data.F32[i] = (psF32)in->data.F64[i];2430 tmp->n++;2431 }2432 } else if (in->type.type == PS_TYPE_F32) {2433 // do nothing2434 } else {2435 char* strType;2436 PS_TYPE_NAME(strType, in->type.type);2437 psError(PS_ERR_BAD_PARAMETER_TYPE, true,2438 PS_ERRORTEXT_psStats_VECTOR_TYPE_UNSUPPORTED,2439 strType);2440 }2441 2442 psTrace(__func__, 4,"---- %s() end ----\n", __func__);2443 return (tmp);2444 1988 } 2445 1989 … … 2469 2013 PS_ASSERT_PTR_NON_NULL(stats, NULL); 2470 2014 PS_ASSERT_VECTOR_NON_NULL(in, NULL); 2471 if (mask != NULL) {2015 if (mask) { 2472 2016 PS_ASSERT_VECTORS_SIZE_EQUAL(mask, in, stats); 2473 2017 PS_ASSERT_VECTOR_TYPE(mask, PS_TYPE_U8, stats); 2474 2018 } 2475 if (errors != NULL) {2019 if (errors) { 2476 2020 PS_ASSERT_VECTORS_SIZE_EQUAL(errors, in, stats); 2477 2021 PS_ASSERT_VECTOR_TYPE(errors, in->type.type, stats); 2478 2022 } 2479 // XXX: Assert that "in" is F64, F32, U16, or S8 2480 2481 psVector* inF32 = NULL; 2482 psVector* errorsF32 = NULL; 2483 psS32 mustFreeVectorIn = 1; 2484 psS32 mustFreeVectorErrors = 1; 2485 2486 inF32 = p_psConvertToF32((psVector *) in); 2487 if (inF32 == NULL) { 2488 // printf("\n\ninF32 is NULL\n\n"); 2489 // inF32 = (psVector *) in; 2490 // mustFreeVectorIn = 0; 2491 inF32 = psVectorCopy(inF32, in, PS_TYPE_F32); 2492 inF32->n = inF32->nalloc; 2493 mustFreeVectorIn = 1; 2494 } 2495 // else printf("\ninF32 has n=%ld, nalloc=%ld\n", inF32->n, inF32->nalloc); 2496 errorsF32 = p_psConvertToF32((psVector *) errors); 2497 if (errorsF32 == NULL) { 2498 errorsF32 = (psVector *) errors; 2499 mustFreeVectorErrors = 0; 2500 } 2501 // inF32->n = inF32->nalloc; 2502 // errorsF32->n = errorsF32->nalloc; 2023 2024 // Convert types, as necessary 2025 psVector *inF32 = NULL; // Input vector of values, F32 version 2026 if (in->type.type == PS_TYPE_F32) { 2027 inF32 = psMemIncrRefCounter((psPtr)in); 2028 } else { 2029 inF32 = psVectorCopy(NULL, in, PS_TYPE_F32); 2030 } 2031 psVector *errorsF32 = NULL; // Input vector of errors, F32 version 2032 if (errors) { 2033 if (errors->type.type == PS_TYPE_F32) { 2034 errorsF32 = psMemIncrRefCounter((psPtr)errors); 2035 } else { 2036 errorsF32 = psVectorCopy(NULL, errors, PS_TYPE_F32); 2037 } 2038 } 2039 psVector *maskU8 = NULL; // Input mask vector, U8 version 2040 if (mask) { 2041 // We want a copy of the mask, since we may change values 2042 maskU8 = psVectorCopy(NULL, mask, PS_TYPE_U8); 2043 } 2044 2045 2503 2046 if ((stats->options & PS_STAT_USE_RANGE) && (stats->min >= stats->max)) { 2504 2047 PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(stats->max, stats->min, stats); … … 2511 2054 // ************************************************************************ 2512 2055 if (stats->options & PS_STAT_SAMPLE_MEAN) { 2513 if ( 0 != p_psVectorSampleMean(inF32, errorsF32, mask, maskVal, stats)) {2514 psLogMsg(__func__, PS_LOG_WARN, "WARNING: p_psVectorSampleMean() returned an error.\n");2056 if (!vectorSampleMean(inF32, errorsF32, maskU8, maskVal, stats)) { 2057 psLogMsg(__func__, PS_LOG_WARN, "WARNING: vectorSampleMean() returned an error.\n"); 2515 2058 stats->sampleMean = NAN; 2516 2059 } … … 2518 2061 2519 2062 // ************************************************************************ 2520 if (stats->options & PS_STAT_SAMPLE_MEDIAN) {2521 if ( false == p_psVectorSampleMedian(inF32, mask, maskVal, stats)) {2522 psLogMsg(__func__, PS_LOG_WARN, "WARNING: p_psVectorSampleMedian() returned an error.\n");2063 if (stats->options & (PS_STAT_SAMPLE_MEDIAN | PS_STAT_SAMPLE_QUARTILE)) { 2064 if (!vectorSampleMedian(inF32, maskU8, maskVal, stats)) { 2065 psLogMsg(__func__, PS_LOG_WARN, "WARNING: vectorSampleMedian() returned an error.\n"); 2523 2066 stats->sampleMedian = NAN; 2067 stats->sampleUQ = NAN; 2068 stats->sampleLQ = NAN; 2524 2069 } 2525 2070 } … … 2527 2072 // ************************************************************************ 2528 2073 if (stats->options & PS_STAT_SAMPLE_STDEV) { 2529 if ( 0 != p_psVectorSampleMean(inF32, errorsF32, mask, maskVal, stats)) {2530 psLogMsg(__func__, PS_LOG_WARN, "WARNING: p_psVectorSampleMean() returned an error.\n");2074 if (!vectorSampleMean(inF32, errorsF32, maskU8, maskVal, stats)) { 2075 psLogMsg(__func__, PS_LOG_WARN, "WARNING: vectorSampleMean() returned an error.\n"); 2531 2076 stats->sampleMean = NAN; 2532 2077 } else { 2533 p_psVectorSampleStdev(inF32, errorsF32, mask, maskVal, stats);2078 vectorSampleStdev(inF32, errorsF32, maskU8, maskVal, stats); 2534 2079 } 2535 2080 } 2536 2081 2537 2082 // ************************************************************************ 2538 if (stats->options & PS_STAT_SAMPLE_QUARTILE) { 2539 if (false == p_psVectorSampleQuartiles(inF32, mask, maskVal, stats)) { 2540 psLogMsg(__func__, PS_LOG_WARN, "WARNING: p_psVectorSampleQuartiles() returned an error.\n"); 2541 stats->sampleLQ = NAN; 2542 stats->sampleUQ = NAN; 2543 } 2544 } 2545 2546 // ************************************************************************ 2547 if ((stats->options & PS_STAT_ROBUST_MEDIAN) || 2548 (stats->options & PS_STAT_ROBUST_STDEV) || 2549 (stats->options & PS_STAT_ROBUST_QUARTILE) || 2550 (stats->options & PS_STAT_FITTED_MEAN) || 2551 (stats->options & PS_STAT_FITTED_STDEV)) { 2552 if (0 != p_psVectorRobustStats(inF32, errorsF32, mask, maskVal, stats)) { 2083 if (stats->options & (PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV | PS_STAT_ROBUST_QUARTILE | 2084 PS_STAT_FITTED_MEAN | PS_STAT_FITTED_STDEV)) { 2085 if (!vectorRobustStats(inF32, errorsF32, maskU8, maskVal, stats)) { 2553 2086 psError(PS_ERR_UNKNOWN, false, PS_ERRORTEXT_psStats_STATS_FAILED); 2554 2087 psFree(stats); 2088 psFree(inF32); 2089 psFree(errorsF32); 2555 2090 psTrace(__func__, 3,"---- %s(NULL) end ----\n", __func__); 2556 2091 return(NULL); … … 2560 2095 // ************************************************************************ 2561 2096 if ((stats->options & PS_STAT_CLIPPED_MEAN) || (stats->options & PS_STAT_CLIPPED_STDEV)) { 2562 psS32 rc = p_psVectorClippedStats(inF32, errorsF32, mask, maskVal, stats); 2563 if (rc < 0) { 2097 if (!vectorClippedStats(inF32, errorsF32, maskU8, maskVal, stats)) { 2564 2098 psError(PS_ERR_UNKNOWN, false, "Failed to calculate clipped statistics for input psVector.\n"); 2565 2099 stats->clippedMean = NAN; … … 2569 2103 2570 2104 // ************************************************************************ 2571 if (stats->options & PS_STAT_MAX) { 2572 if (0 != p_psVectorMax(inF32, mask, maskVal, stats)) { 2573 psError(PS_ERR_UNKNOWN, false, "Failed to calculate vector maximum"); 2574 stats->max = NAN; 2575 } 2576 } 2577 2578 // ************************************************************************ 2579 if (stats->options & PS_STAT_MIN) { 2580 if (0 != p_psVectorMin(inF32, mask, maskVal, stats)) { 2581 psError(PS_ERR_UNKNOWN, false, "Failed to calculate vector minimum"); 2582 stats->min = NAN; 2583 } 2584 } 2585 2586 if (mustFreeVectorIn == 1) { 2587 psFree(inF32); 2588 } 2589 if (mustFreeVectorErrors == 1) { 2590 psFree(errorsF32); 2591 } 2105 if (stats->options & (PS_STAT_MAX | PS_STAT_MIN)) { 2106 if (vectorMinMax(inF32, maskU8, maskVal, stats) == 0) { 2107 psError(PS_ERR_UNKNOWN, false, "Failed to calculate vector minimum and maximum"); 2108 } 2109 } 2110 2111 psFree(inF32); 2112 psFree(errorsF32); 2113 psFree(maskU8); 2592 2114 psTrace(__func__, 3,"---- %s() end ----\n", __func__); 2593 2115 return (stats);
Note:
See TracChangeset
for help on using the changeset viewer.
