Changeset 42719
- Timestamp:
- Sep 13, 2024, 10:19:51 PM (22 months ago)
- Location:
- branches/2dbias
- Files:
-
- 6 edited
-
ippconfig/gpc1/format_20100723.config (modified) (1 diff)
-
ippconfig/gpc1/ppImage.config (modified) (2 diffs)
-
psLib/src/math/psStats.c (modified) (140 diffs)
-
psLib/src/math/psStats.h (modified) (5 diffs)
-
psLib/src/math/psVectorSmooth.c (modified) (1 diff)
-
psModules/src/detrend/pmOverscan.c (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branches/2dbias/ippconfig/gpc1/format_20100723.config
r42716 r42719 166 166 # 2D bias subtraction requires ppImage.config OVERSCAN.2D to be TRUE 167 167 CELL.BIASSEC.SOURCE STR VALUE 168 CELL.BIASSEC STR [591:624,1:598],[1:624,599:608] 168 # exclude the last row and column from the bias region 169 CELL.BIASSEC STR [591:623,1:598],[1:623,599:607] 169 170 # 170 171 # a single region will be used for constant and 1D bias subtraction -
branches/2dbias/ippconfig/gpc1/ppImage.config
r42679 r42719 6 6 BIN2.YBIN S32 150 7 7 8 OVERSCAN.SINGLE BOOL FALSE # Reduce overscan to a single value? 9 OVERSCAN.STAT STR MEDIAN 10 OVERSCAN.BOXCAR S32 3 8 OVERSCAN.SINGLE BOOL FALSE # Reduce overscan to a single value? 9 OVERSCAN.STAT STR MEAN # MEAN | MEDIAN 10 OVERSCAN.BOXCAR S32 10 # Boxcar smoothing radius 11 OVERSCAN.2D BOOL FALSE # use a 2D model for the overscan subtraction? 12 OVERSCAN.2D.STAT STR MEAN # MEAN | MEDIAN 13 OVERSCAN.2D.BOXCAR S32 30 # Boxcar smoothing radius 14 11 15 12 16 OVERSCAN.2D.SUBSET METADATA 13 XY00 BOOL TRUE14 17 XY01 BOOL TRUE 15 18 XY02 BOOL TRUE … … 74 77 XY75 BOOL TRUE 75 78 XY76 BOOL TRUE 76 XY77 BOOL TRUE77 79 END 78 80 -
branches/2dbias/psLib/src/math/psStats.c
r41520 r42719 19 19 */ 20 20 21 22 21 // Note: choice of return values in many places is quite grey. For example, calculating the sample standard 23 22 // deviation: here it's an error to get an array of size zero, but it's not an error to get an array of size … … 63 62 #include "psString.h" 64 63 65 66 67 64 /*****************************************************************************/ 68 65 /* DEFINE STATEMENTS */ 69 66 /*****************************************************************************/ 70 #define PS_GAUSS_WIDTH 3 // The width of the Gaussian smoothing.67 #define PS_GAUSS_WIDTH 3 // The width of the Gaussian smoothing. 71 68 #define PS_CLIPPED_NUM_ITER_LB 1 // This corresponds to N in the ADD. 72 69 #define PS_CLIPPED_NUM_ITER_UB 10 … … 77 74 #define TRACE "psLib.math" 78 75 79 #define MASK_MARK 0x80 // XXX : can we change this? bit to use internally to mark data as bad80 #define PS_ROBUST_MAX_ITERATIONS 20 // Maximum number of iterations for robust statistics76 #define MASK_MARK 0x80 // XXX : can we change this? bit to use internally to mark data as bad 77 #define PS_ROBUST_MAX_ITERATIONS 20 // Maximum number of iterations for robust statistics 81 78 82 79 #define PS_BIN_MIDPOINT(HISTOGRAM, BIN_NUM) \ 83 (0.5 * (HISTOGRAM->bounds->data.F32[(BIN_NUM)] + HISTOGRAM->bounds->data.F32[(BIN_NUM)+1]))80 (0.5 * (HISTOGRAM->bounds->data.F32[(BIN_NUM)] + HISTOGRAM->bounds->data.F32[(BIN_NUM) + 1])) 84 81 85 82 // set the bin closest to the corresponding value. if USE_END is +/- 1, 86 83 // out-of-range saturates on lower/upper bin REGARDLESS of actual value 87 #define PS_BIN_FOR_VALUE(RESULT, VECTOR, VALUE, USE_END) { \ 88 psVectorBinaryDisectResult result; \ 89 psScalar tmpScalar; \ 90 tmpScalar.type.type = PS_TYPE_F32; \ 91 tmpScalar.data.F32 = (VALUE); \ 92 RESULT = psVectorBinaryDisect (&result, VECTOR, &tmpScalar); \ 93 switch (result) { \ 94 case PS_BINARY_DISECT_PASS: \ 95 break; \ 96 case PS_BINARY_DISECT_OUTSIDE_RANGE: \ 97 psTrace(TRACE, 6, "selected bin outside range"); \ 98 if (USE_END == -1) { RESULT = 0; } \ 99 if (USE_END == +1) { RESULT = VECTOR->n - 1; } \ 100 break; \ 101 case PS_BINARY_DISECT_INVALID_INPUT: \ 102 case PS_BINARY_DISECT_INVALID_TYPE: \ 103 psAbort ("programming error"); \ 104 break; \ 105 } } 106 107 # define PS_BIN_INTERPOLATE(RESULT, VECTOR, BOUNDS, BIN, VALUE) { \ 108 float dX, dY, Xo, Yo, Xt; \ 109 if (BIN == BOUNDS->n - 1) { \ 110 dX = 0.5*(BOUNDS->data.F32[BIN+1] - BOUNDS->data.F32[BIN-1]); \ 111 dY = VECTOR->data.F32[BIN] - VECTOR->data.F32[BIN-1]; \ 112 Xo = 0.5*(BOUNDS->data.F32[BIN+1] + BOUNDS->data.F32[BIN]); \ 113 Yo = VECTOR->data.F32[BIN]; \ 114 } else { \ 115 dX = 0.5*(BOUNDS->data.F32[BIN+2] - BOUNDS->data.F32[BIN]); \ 116 dY = VECTOR->data.F32[BIN+1] - VECTOR->data.F32[BIN]; \ 117 Xo = 0.5*(BOUNDS->data.F32[BIN+1] + BOUNDS->data.F32[BIN]); \ 118 Yo = VECTOR->data.F32[BIN]; \ 119 } \ 120 if (dY != 0) { \ 121 Xt = (VALUE - Yo)*dX/dY + Xo; \ 122 } else { \ 123 Xt = Xo; \ 124 } \ 125 Xt = PS_MIN (BOUNDS->data.F32[BIN+1], PS_MAX(BOUNDS->data.F32[BIN], Xt)); \ 84 #define PS_BIN_FOR_VALUE(RESULT, VECTOR, VALUE, USE_END) \ 85 { \ 86 psVectorBinaryDisectResult result; \ 87 psScalar tmpScalar; \ 88 tmpScalar.type.type = PS_TYPE_F32; \ 89 tmpScalar.data.F32 = (VALUE); \ 90 RESULT = psVectorBinaryDisect(&result, VECTOR, &tmpScalar); \ 91 switch (result) \ 92 { \ 93 case PS_BINARY_DISECT_PASS: \ 94 break; \ 95 case PS_BINARY_DISECT_OUTSIDE_RANGE: \ 96 psTrace(TRACE, 6, "selected bin outside range"); \ 97 if (USE_END == -1) \ 98 { \ 99 RESULT = 0; \ 100 } \ 101 if (USE_END == +1) \ 102 { \ 103 RESULT = VECTOR->n - 1; \ 104 } \ 105 break; \ 106 case PS_BINARY_DISECT_INVALID_INPUT: \ 107 case PS_BINARY_DISECT_INVALID_TYPE: \ 108 psAbort("programming error"); \ 109 break; \ 110 } \ 111 } 112 113 #define PS_BIN_INTERPOLATE(RESULT, VECTOR, BOUNDS, BIN, VALUE) \ 114 { \ 115 float dX, dY, Xo, Yo, Xt; \ 116 if (BIN == BOUNDS->n - 1) \ 117 { \ 118 dX = 0.5 * (BOUNDS->data.F32[BIN + 1] - BOUNDS->data.F32[BIN - 1]); \ 119 dY = VECTOR->data.F32[BIN] - VECTOR->data.F32[BIN - 1]; \ 120 Xo = 0.5 * (BOUNDS->data.F32[BIN + 1] + BOUNDS->data.F32[BIN]); \ 121 Yo = VECTOR->data.F32[BIN]; \ 122 } \ 123 else \ 124 { \ 125 dX = 0.5 * (BOUNDS->data.F32[BIN + 2] - BOUNDS->data.F32[BIN]); \ 126 dY = VECTOR->data.F32[BIN + 1] - VECTOR->data.F32[BIN]; \ 127 Xo = 0.5 * (BOUNDS->data.F32[BIN + 1] + BOUNDS->data.F32[BIN]); \ 128 Yo = VECTOR->data.F32[BIN]; \ 129 } \ 130 if (dY != 0) \ 131 { \ 132 Xt = (VALUE - Yo) * dX / dY + Xo; \ 133 } \ 134 else \ 135 { \ 136 Xt = Xo; \ 137 } \ 138 Xt = PS_MIN(BOUNDS->data.F32[BIN + 1], PS_MAX(BOUNDS->data.F32[BIN], Xt)); \ 126 139 psTrace(TRACE, 6, "(Xo, Yo, dX, dY, Xt, Yt) is (%.2f %.2f %.2f %.2f %.2f %.2f)\n", \ 127 Xo, Yo, dX, dY, Xt, VALUE); \ 128 RESULT = Xt; } 129 130 # define COUNT_WARNING(LIMIT, INTERVAL, ...) { \ 131 static int nCalls = 1; \ 132 if (nCalls < LIMIT) { \ 133 psWarning(__VA_ARGS__); \ 134 } \ 135 if (!(nCalls % INTERVAL)) { \ 136 psWarning(__VA_ARGS__); \ 140 Xo, Yo, dX, dY, Xt, VALUE); \ 141 RESULT = Xt; \ 142 } 143 144 #define COUNT_WARNING(LIMIT, INTERVAL, ...) \ 145 { \ 146 static int nCalls = 1; \ 147 if (nCalls < LIMIT) \ 148 { \ 149 psWarning(__VA_ARGS__); \ 150 } \ 151 if (!(nCalls % INTERVAL)) \ 152 { \ 153 psWarning(__VA_ARGS__); \ 137 154 psWarning("(warning raised %d times)", nCalls); \ 138 } \139 nCalls ++;\140 }155 } \ 156 nCalls++; \ 157 } 141 158 142 159 // Debug information … … 195 212 To optmize this, use a macro and ifdef in or out the three states (errors, mask, range) 196 213 *****************************************************************************/ 197 static bool vectorSampleMean(const psVector*myVector,198 const psVector*errors,199 const psVector*maskVector,200 psVectorMaskType maskVal,201 psStats*stats)214 static bool vectorSampleMean(const psVector *myVector, 215 const psVector *errors, 216 const psVector *maskVector, 217 psVectorMaskType maskVal, 218 psStats *stats) 202 219 { 203 long count = 0; // Number of points contributing to this mean204 psF32 mean = 0.0; // The mean220 long count = 0; // Number of points contributing to this mean 221 psF32 mean = 0.0; // The mean 205 222 psF32 weight; 206 223 207 psF32 *data = myVector->data.F32; // Dereference208 int numData = myVector->n; // Number of data points224 psF32 *data = myVector->data.F32; // Dereference 225 int numData = myVector->n; // Number of data points 209 226 210 227 psVectorMaskType *maskData = (maskVector == NULL) ? NULL : maskVector->data.PS_TYPE_VECTOR_MASK_DATA; 211 228 bool useRange = stats->options & PS_STAT_USE_RANGE; 212 229 213 psF32 sumWeights = 0.0; // The sum of the weights230 psF32 sumWeights = 0.0; // The sum of the weights 214 231 psF32 *errorsData = (errors == NULL) ? NULL : errors->data.F32; 215 232 216 for (long i = 0; i < numData; i++) { 233 for (long i = 0; i < numData; i++) 234 { 217 235 // Check if the data is with the specified range 218 236 if (!isfinite(data[i])) … … 224 242 if (maskData && (maskData[i] & maskVal)) 225 243 continue; 226 if (errors) { 244 if (errors) 245 { 227 246 weight = (errorsData[i] == 0) ? 0.0 : PS_SQR(errorsData[i]); 228 247 mean += data[i] * weight; 229 248 sumWeights += weight; 230 } else { 249 } 250 else 251 { 231 252 mean += data[i]; 232 253 } 233 254 count++; 234 235 }236 if (errors){255 } 256 if (errors) 257 { 237 258 mean = (count > 0) ? mean / sumWeights : NAN; 238 } else { 259 } 260 else 261 { 239 262 mean = (count > 0) ? mean / count : NAN; 240 263 } 241 264 stats->sampleMean = mean; 242 265 243 if (!isnan(mean)) { 266 if (!isnan(mean)) 267 { 244 268 stats->results |= PS_STAT_SAMPLE_MEAN; 245 269 } … … 260 284 (mask: 1, range: 0): 0.200 sec 0.244 sec 261 285 *****************************************************************************/ 262 static long vectorMinMax(const psVector* myVector, 263 const psVector* maskVector, 264 psVectorMaskType maskVal, 265 psStats* stats 266 ) 286 static long vectorMinMax(const psVector *myVector, 287 const psVector *maskVector, 288 psVectorMaskType maskVal, 289 psStats *stats) 267 290 { 268 291 psF32 max = -PS_MAX_F32; // The calculated maximum … … 270 293 psF32 *vector = myVector->data.F32; // Dereference the vector 271 294 272 int num = myVector->n; // Number of values273 int numValid = 0; // Number of valid values295 int num = myVector->n; // Number of values 296 int numValid = 0; // Number of valid values 274 297 275 298 psVectorMaskType *maskData = (maskVector == NULL) ? NULL : maskVector->data.PS_TYPE_VECTOR_MASK_DATA; 276 299 bool useRange = stats->options & PS_STAT_USE_RANGE; 277 300 278 for (long i = 0; i < num; i++) { 301 for (long i = 0; i < num; i++) 302 { 279 303 // Check if the data is with the specified range 280 304 if (!isfinite(vector[i])) … … 288 312 289 313 numValid++; 290 max = PS_MAX (vector[i], max);291 min = PS_MIN (vector[i], min);314 max = PS_MAX(vector[i], max); 315 min = PS_MIN(vector[i], min); 292 316 } 293 317 294 318 // XXX save numValid in psStats? 295 if (numValid == 0) { 319 if (numValid == 0) 320 { 296 321 stats->max = NAN; 297 322 stats->min = NAN; 298 } else { 323 } 324 else 325 { 299 326 stats->max = max; 300 327 stats->min = min; … … 310 337 were no valid input vector elements). Expects F32 vector for input. 311 338 *****************************************************************************/ 312 static bool vectorSampleMedian(const psVector *inVector,313 const psVector *maskVector,339 static bool vectorSampleMedian(const psVector *inVector, 340 const psVector *maskVector, 314 341 psVectorMaskType maskVal, 315 psStats *stats)342 psStats *stats) 316 343 { 317 344 bool useRange = stats->options & PS_STAT_USE_RANGE; 318 345 psVectorMaskType *maskData = (maskVector == NULL) ? NULL : maskVector->data.PS_TYPE_VECTOR_MASK_DATA; // Dereference the vector 319 psF32 *input = inVector->data.F32; // Dereference the vector346 psF32 *input = inVector->data.F32; // Dereference the vector 320 347 321 348 // use the temporary vector for the sorted output 322 stats->tmpData = psVectorRecycle (stats->tmpData, inVector->n, PS_TYPE_F32);349 stats->tmpData = psVectorRecycle(stats->tmpData, inVector->n, PS_TYPE_F32); 323 350 psVector *outVector = stats->tmpData; 324 351 psF32 *output = outVector->data.F32; // Dereference the vector 325 352 326 if (maskData) psAssert (maskVector->n == inVector->n, "oops"); 327 328 long count = 0; // Number of valid entries 353 if (maskData) 354 psAssert(maskVector->n == inVector->n, "oops"); 355 356 long count = 0; // Number of valid entries 329 357 330 358 // Store all non-masked data points within the min/max range 331 359 // into the temporary vectors. 332 for (long i = 0; i < inVector->n; i++) { 333 psAssert (count >= 0, "oops"); 334 psAssert (count < outVector->n, "oops"); 335 psAssert (i >= 0, "oops"); 336 psAssert (i < inVector->n, "oops"); 337 338 if (!isfinite(input[i])) continue; 339 if (useRange && (input[i] < stats->min)) continue; 340 if (useRange && (input[i] > stats->max)) continue; 341 if (maskData && (maskData[i] & maskVal)) continue; 360 for (long i = 0; i < inVector->n; i++) 361 { 362 psAssert(count >= 0, "oops"); 363 psAssert(count < outVector->n, "oops"); 364 psAssert(i >= 0, "oops"); 365 psAssert(i < inVector->n, "oops"); 366 367 if (!isfinite(input[i])) 368 continue; 369 if (useRange && (input[i] < stats->min)) 370 continue; 371 if (useRange && (input[i] > stats->max)) 372 continue; 373 if (maskData && (maskData[i] & maskVal)) 374 continue; 342 375 343 376 output[count] = input[i]; … … 346 379 outVector->n = count; 347 380 348 if (count == 0) { 381 if (count == 0) 382 { 349 383 COUNT_WARNING(10, 100, "No valid data in input vector.\n"); 350 384 stats->sampleUQ = NAN; … … 355 389 356 390 // Sort the temporary vector. 357 if (!psVectorSort(outVector, outVector)) { // Sort in-place (since it's a copy, it's OK) 391 if (!psVectorSort(outVector, outVector)) 392 { // Sort in-place (since it's a copy, it's OK) 358 393 // an error in psVectorSort is a serious error: 359 // NULL input vector, psVectorCopy failure, invalid vector type394 // NULL input vector, psVectorCopy failure, invalid vector type 360 395 psError(PS_ERR_UNEXPECTED_NULL, false, _("Failed to sort input data.")); 361 396 stats->sampleUQ = NAN; … … 366 401 367 402 // Calculate the median. Use the average if the number of samples if even. 368 int midPt = (count/2); 369 psAssert (midPt >= 0, "oops"); 370 psAssert (midPt < outVector->n, "oops"); 371 if (count % 2 == 0) { 372 psAssert ((midPt - 1) >= 0, "oops"); 373 psAssert ((midPt - 1) < outVector->n, "oops"); 403 int midPt = (count / 2); 404 psAssert(midPt >= 0, "oops"); 405 psAssert(midPt < outVector->n, "oops"); 406 if (count % 2 == 0) 407 { 408 psAssert((midPt - 1) >= 0, "oops"); 409 psAssert((midPt - 1) < outVector->n, "oops"); 374 410 stats->sampleMedian = 0.5 * (output[midPt - 1] + output[midPt]); 375 } else { 411 } 412 else 413 { 376 414 stats->sampleMedian = output[midPt]; 377 415 } 378 416 379 int Qmin = (int)(0.25 *count);380 int Qmax = (int)(0.75 *count);381 psAssert (Qmin >=0, "oops");382 psAssert (Qmin < outVector->n, "oops");383 psAssert (Qmax >=0, "oops");384 psAssert (Qmax < outVector->n, "oops");417 int Qmin = (int)(0.25 * count); 418 int Qmax = (int)(0.75 * count); 419 psAssert(Qmin >= 0, "oops"); 420 psAssert(Qmin < outVector->n, "oops"); 421 psAssert(Qmax >= 0, "oops"); 422 psAssert(Qmax < outVector->n, "oops"); 385 423 386 424 // Calculate the quartile points exactly. 387 425 stats->sampleUQ = output[Qmax]; 388 426 stats->sampleLQ = output[Qmin]; 389 427 390 428 stats->results |= PS_STAT_SAMPLE_MEDIAN; 391 429 stats->results |= PS_STAT_SAMPLE_QUARTILE; … … 409 447 *****************************************************************************/ 410 448 411 static bool vectorSampleStdev(const psVector *myVector,412 const psVector *errors,413 const psVector *maskVector,449 static bool vectorSampleStdev(const psVector *myVector, 450 const psVector *errors, 451 const psVector *maskVector, 414 452 psVectorMaskType maskVal, 415 psStats *stats)453 psStats *stats) 416 454 { 417 455 // This procedure requires the mean. If it has not been already 418 456 // calculated, then call vectorSampleMean() 419 if (!(stats->results & PS_STAT_SAMPLE_MEAN)) { 457 if (!(stats->results & PS_STAT_SAMPLE_MEAN)) 458 { 420 459 vectorSampleMean(myVector, errors, maskVector, maskVal, stats); 421 460 } 422 461 423 462 // If the mean is NAN, then generate a warning and set the stdev to NAN. 424 if (isnan(stats->sampleMean)) { 463 if (isnan(stats->sampleMean)) 464 { 425 465 COUNT_WARNING(10, 100, "WARNING: vectorSampleStdev(): sample mean is NAN. Setting stats->sampleStdev = NAN."); 426 466 stats->sampleStdev = NAN; … … 428 468 } 429 469 430 psF32 *data = myVector->data.F32; // Dereference470 psF32 *data = myVector->data.F32; // Dereference 431 471 psVectorMaskType *maskData = (maskVector == NULL) ? NULL : maskVector->data.PS_TYPE_VECTOR_MASK_DATA; 432 472 bool useRange = stats->options & PS_STAT_USE_RANGE; … … 434 474 435 475 // Accumulate the sums 436 double mean = stats->sampleMean; // The mean 437 double sumSquares = 0.0; // Sum of the squares 438 double sumDiffs = 0.0; // Sum of the differences 439 double errorDivisor = 0.0; // Division for errors 440 long count = 0; // Number of data points being used 441 for (long i = 0; i < myVector->n; i++) { 476 double mean = stats->sampleMean; // The mean 477 double sumSquares = 0.0; // Sum of the squares 478 double sumDiffs = 0.0; // Sum of the differences 479 double errorDivisor = 0.0; // Division for errors 480 long count = 0; // Number of data points being used 481 for (long i = 0; i < myVector->n; i++) 482 { 442 483 // Check if the data is with the specified range 443 484 if (!isfinite(data[i])) 444 485 continue; 445 if (useRange && (data[i] < stats->min)) { 486 if (useRange && (data[i] < stats->min)) 487 { 446 488 continue; 447 489 } 448 if (useRange && (data[i] > stats->max)) { 490 if (useRange && (data[i] > stats->max)) 491 { 449 492 continue; 450 493 } 451 if (maskData && (maskData[i] & maskVal)) { 494 if (maskData && (maskData[i] & maskVal)) 495 { 452 496 continue; 453 497 } … … 457 501 sumDiffs += diff; 458 502 count++; 459 if (errors) { 503 if (errors) 504 { 460 505 errorDivisor += 1.0 / PS_SQR(errorsData[i]); 461 506 } 462 507 } 463 508 464 if (count == 0) { 509 if (count == 0) 510 { 465 511 // This is an ambiguous case: error or not? 466 512 // It's not an empty array (that's been asserted on previously), but everything's been masked out. … … 470 516 return true; 471 517 } 472 if (count == 1) { 518 if (count == 1) 519 { 473 520 stats->sampleStdev = 0.0; 474 521 COUNT_WARNING(10, 100, "WARNING: vectorSampleStdev(): only one valid psVector elements (%ld). Setting stats->sampleStdev = 0.0.\n", count); … … 476 523 } 477 524 478 if (errors) { 525 if (errors) 526 { 479 527 stats->sampleStdev = (1.0 / sqrtf(errorDivisor)); 480 } else { 528 } 529 else 530 { 481 531 stats->sampleStdev = sqrt((sumSquares - (sumDiffs * sumDiffs / (float)count)) / (float)(count - 1)); 482 532 } … … 486 536 } 487 537 488 static bool vectorSampleMoments(const psVector *myVector,489 const psVector *maskVector,538 static bool vectorSampleMoments(const psVector *myVector, 539 const psVector *maskVector, 490 540 psVectorMaskType maskVal, 491 psStats *stats)541 psStats *stats) 492 542 { 493 543 // This procedure requires the mean and standard deviation 494 if (!(stats->results & PS_STAT_SAMPLE_MEAN)) { 544 if (!(stats->results & PS_STAT_SAMPLE_MEAN)) 545 { 495 546 vectorSampleMean(myVector, NULL, maskVector, maskVal, stats); 496 547 } 497 if (isnan(stats->sampleMean)) { 548 if (isnan(stats->sampleMean)) 549 { 498 550 COUNT_WARNING(10, 100, "WARNING: vectorSampleMoments(): sample mean is NAN.\n"); 499 551 goto SAMPLE_MOMENTS_BAD; 500 552 } 501 if (!(stats->results & PS_STAT_SAMPLE_STDEV)) { 553 if (!(stats->results & PS_STAT_SAMPLE_STDEV)) 554 { 502 555 vectorSampleStdev(myVector, NULL, maskVector, maskVal, stats); 503 556 } 504 if (isnan(stats->sampleStdev) || stats->sampleStdev == 0.0) { 557 if (isnan(stats->sampleStdev) || stats->sampleStdev == 0.0) 558 { 505 559 COUNT_WARNING(10, 100, "WARNING: vectorSampleMoments(): sample stdev is NAN or 0.\n"); 506 560 goto SAMPLE_MOMENTS_BAD; 507 561 } 508 562 509 psF32 *data = myVector->data.F32; // Dereference563 psF32 *data = myVector->data.F32; // Dereference 510 564 psVectorMaskType *maskData = (maskVector == NULL) ? NULL : maskVector->data.PS_TYPE_VECTOR_MASK_DATA; 511 565 bool useRange = stats->options & PS_STAT_USE_RANGE; 512 566 513 567 // Accumulate the sums 514 double mean = stats->sampleMean; // The mean 515 double sum3 = 0.0; // Sum of the cubes of the differences 516 double sum4 = 0.0; // Sum of the fourth powers of the differences 517 long count = 0; // Number of data points being used 518 for (long i = 0; i < myVector->n; i++) { 568 double mean = stats->sampleMean; // The mean 569 double sum3 = 0.0; // Sum of the cubes of the differences 570 double sum4 = 0.0; // Sum of the fourth powers of the differences 571 long count = 0; // Number of data points being used 572 for (long i = 0; i < myVector->n; i++) 573 { 519 574 // Check if the data is with the specified range 520 575 if (!isfinite(data[i])) 521 576 continue; 522 if (useRange && (data[i] < stats->min)) { 577 if (useRange && (data[i] < stats->min)) 578 { 523 579 continue; 524 580 } 525 if (useRange && (data[i] > stats->max)) { 581 if (useRange && (data[i] > stats->max)) 582 { 526 583 continue; 527 584 } 528 if (maskData && (maskData[i] & maskVal)) { 585 if (maskData && (maskData[i] & maskVal)) 586 { 529 587 continue; 530 588 } 531 589 532 double diff = data[i] - mean; // Difference from the mean533 double temp; // Temporary variable for accumulating590 double diff = data[i] - mean; // Difference from the mean 591 double temp; // Temporary variable for accumulating 534 592 535 593 sum3 += temp = PS_SQR(diff); … … 539 597 } 540 598 541 psAssert(count > 1, "impossible"); // It should be, because we have a mean and standard deviation542 543 double stdev = stats->sampleStdev; // Standard deviation544 double variance = PS_SQR(stdev); // Variance599 psAssert(count > 1, "impossible"); // It should be, because we have a mean and standard deviation 600 601 double stdev = stats->sampleStdev; // Standard deviation 602 double variance = PS_SQR(stdev); // Variance 545 603 546 604 // Formula for skewness and kurtosis from Numerical Recipes in C, p 613. … … 552 610 return true; 553 611 554 SAMPLE_MOMENTS_BAD:612 SAMPLE_MOMENTS_BAD: 555 613 // stats->sampleStdev has already been set 556 614 stats->sampleSkewness = NAN; … … 571 629 true for success; false otherwise 572 630 *****************************************************************************/ 573 static bool vectorClippedStats(const psVector *myVector,574 const psVector *errors,575 psVector *maskInput,631 static bool vectorClippedStats(const psVector *myVector, 632 const psVector *errors, 633 psVector *maskInput, 576 634 psVectorMaskType maskValInput, 577 psStats* stats 578 ) 635 psStats *stats) 579 636 { 580 637 // Ensure that stats->clipIter is within the proper range. … … 590 647 // unless we succeed, these will have NAN values 591 648 stats->clippedMean = NAN; 649 stats->clippedMedian = NAN; 592 650 stats->clippedStdev = NAN; 593 651 stats->clippedNvalues = 0; … … 597 655 598 656 // use the temporary vector for local temporary mask 599 stats->tmpMask = psVectorRecycle (stats->tmpMask, myVector->n, PS_TYPE_VECTOR_MASK);657 stats->tmpMask = psVectorRecycle(stats->tmpMask, myVector->n, PS_TYPE_VECTOR_MASK); 600 658 psVector *tmpMask = stats->tmpMask; 601 659 psVectorInit(tmpMask, 0); 602 if (maskInput) { 603 for (long i = 0; i < myVector->n; i++) { 604 if (maskInput->data.PS_TYPE_VECTOR_MASK_DATA[i] & maskValInput) { 660 if (maskInput) 661 { 662 for (long i = 0; i < myVector->n; i++) 663 { 664 if (maskInput->data.PS_TYPE_VECTOR_MASK_DATA[i] & maskValInput) 665 { 605 666 tmpMask->data.PS_TYPE_VECTOR_MASK_DATA[i] = maskVal; 606 667 } … … 610 671 // 1. Compute the sample median, which we save for output 611 672 vectorSampleMedian(myVector, tmpMask, maskVal, stats); 612 if (isnan(stats->sampleMedian)) { 673 if (isnan(stats->sampleMedian)) 674 { 613 675 COUNT_WARNING(10, 100, "Call to vectorSampleMedian returned NAN\n"); 614 676 return true; … … 618 680 // 2. Compute the sample standard deviation, which we save for output 619 681 vectorSampleStdev(myVector, errors, tmpMask, maskVal, stats); 620 if (isnan(stats->sampleStdev)) { 682 if (isnan(stats->sampleStdev)) 683 { 621 684 COUNT_WARNING(10, 100, "Call to vectorSampleStdev returned NAN\n"); 622 685 return true; … … 625 688 626 689 // 3. Use the sample median as the first estimator of the mean X. 627 psF32 clippedMe an = stats->sampleMedian;628 690 psF32 clippedMedian = stats->sampleMedian; 691 629 692 // 4. Use the sample stdev as the first estimator of the mean stdev. 630 693 psF32 clippedStdev = stats->sampleStdev; 631 694 632 695 // 5. Repeat N (stats->clipIter) times: 633 long numClipped = 0; // Number of values clipped 634 bool clipped = true; // Have we clipped anything in this iteration 635 for (int iter = 0; iter < stats->clipIter && clipped; iter++) { 696 long numClipped = 0; // Number of values clipped 697 bool clipped = true; // Have we clipped anything in this iteration 698 for (int iter = 0; iter < stats->clipIter && clipped; iter++) 699 { 636 700 clipped = false; 637 701 psTrace(TRACE, 6, "------------ Iteration %d ------------\n", iter); 638 702 // a) Exclude all values x_i for which |x_i - x| > K * stdev 639 if (errors) { 703 if (errors) 704 { 640 705 // XXXX if we convert errors to variance, this should square the other terms (A*A faster than 641 706 // sqrt(A)) 642 for (long j = 0; j < myVector->n; j++) { 707 for (long j = 0; j < myVector->n; j++) 708 { 643 709 if (!tmpMask->data.PS_TYPE_VECTOR_MASK_DATA[j] && 644 fabsf(myVector->data.F32[j] - clippedMean) > stats->clipSigma * errors->data.F32[j]) { 710 fabsf(myVector->data.F32[j] - clippedMedian) > stats->clipSigma * errors->data.F32[j]) 711 { 645 712 tmpMask->data.PS_TYPE_VECTOR_MASK_DATA[j] = 0xff; 646 713 psTrace(TRACE, 10, "Clipped %ld: %f +/- %f\n", j, … … 650 717 } 651 718 } 652 } else { 653 for (long j = 0; j < myVector->n; j++) { 719 } 720 else 721 { 722 for (long j = 0; j < myVector->n; j++) 723 { 654 724 if (!tmpMask->data.PS_TYPE_VECTOR_MASK_DATA[j] && 655 fabsf(myVector->data.F32[j] - clippedMean) > (stats->clipSigma * clippedStdev)) { 725 fabsf(myVector->data.F32[j] - clippedMedian) > (stats->clipSigma * clippedStdev)) 726 { 656 727 tmpMask->data.PS_TYPE_VECTOR_MASK_DATA[j] = 0xff; 657 728 psTrace(TRACE, 10, "Clipped %ld: %f\n", j, myVector->data.F32[j]); … … 662 733 } 663 734 664 // b) compute new me an and stdev735 // b) compute new median and stdev 665 736 // Allocate a psStats structure for calculating the mean and stdev. 666 // XXX Can we just use this psStats structure to calculate the SAMPLE ME AN and STDEV?667 // psStats *statsTmp = psStatsAlloc(PS_STAT_SAMPLE_ME AN | PS_STAT_SAMPLE_STDEV);668 // vectorSampleMe an(myVector, errors, tmpMask, maskVal, statsTmp);737 // XXX Can we just use this psStats structure to calculate the SAMPLE MEDIAN and STDEV? 738 // psStats *statsTmp = psStatsAlloc(PS_STAT_SAMPLE_MEDIAN | PS_STAT_SAMPLE_STDEV); 739 // vectorSampleMedian(myVector, errors, tmpMask, maskVal, statsTmp); 669 740 // vectorSampleStdev(myVector, errors, tmpMask, maskVal, statsTmp); 670 vectorSampleMe an(myVector, errors, tmpMask, maskVal, stats);741 vectorSampleMedian(myVector, tmpMask, maskVal, stats); 671 742 vectorSampleStdev(myVector, errors, tmpMask, maskVal, stats); 672 psTrace(TRACE, 6, "The new sample mean is %f\n", stats->sampleMe an);743 psTrace(TRACE, 6, "The new sample mean is %f\n", stats->sampleMedian); 673 744 psTrace(TRACE, 6, "The new sample stdev is %f\n", stats->sampleStdev); 674 745 675 // If the new me an and stdev are NAN, we must exit the loop.746 // If the new median and stdev are NAN, we must exit the loop. 676 747 // Otherwise, use the new results and continue. 677 if (isnan(stats->sampleMean) || isnan(stats->sampleStdev)) { 748 if (isnan(stats->sampleMedian) || isnan(stats->sampleStdev)) 749 { 678 750 iter = stats->clipIter; 679 COUNT_WARNING(10, 100, "vectorSampleMe an() or vectorSampleStdev() returned a NAN.\n");680 clippedMe an = NAN;751 COUNT_WARNING(10, 100, "vectorSampleMedian() or vectorSampleStdev() returned a NAN.\n"); 752 clippedMedian = NAN; 681 753 clippedStdev = NAN; 682 754 return true; 683 } else { 684 clippedMean = stats->sampleMean; 755 } 756 else 757 { 758 clippedMedian = stats->sampleMedian; 685 759 clippedStdev = stats->sampleStdev; 686 760 } … … 690 764 // Number of values used in calculation is the total number of data values, minus those we clipped 691 765 stats->clippedNvalues = myVector->n - numClipped; 692 693 // 7. The last calcuated value of x is the clipped mean. 766 // calculate the clipped mean 767 psF32 clippedMean = stats->sampleMean; 768 vectorSampleMean(myVector, errors, tmpMask, maskVal, stats); 769 if (isnan(stats->sampleMean)) 770 { 771 COUNT_WARNING(10, 100, "vectorSampleMean() returned a NAN.\n"); 772 clippedMean = NAN; 773 return true; 774 } 775 else 776 { 777 clippedMean = stats->sampleMean; 778 } 779 780 // 7. The last calcuated value of x is the clipped median. 694 781 // 8. The last calcuated value of stdev is the clipped stdev. 695 // we always return bothstats even if only one was requested782 // we always return all stats even if only one was requested 696 783 stats->clippedMean = clippedMean; 784 stats->clippedMedian = clippedMedian; 697 785 stats->clippedStdev = clippedStdev; 698 786 699 787 stats->results |= PS_STAT_CLIPPED_MEAN; 788 stats->results |= PS_STAT_CLIPPED_MEDIAN; 700 789 stats->results |= PS_STAT_CLIPPED_STDEV; 701 790 702 791 psTrace(TRACE, 6, "The final clipped mean is %f\n", clippedMean); 792 psTrace(TRACE, 6, "The final clipped median is %f\n", clippedMedian); 703 793 psTrace(TRACE, 6, "The final clipped stdev is %f\n", clippedStdev); 704 794 … … 725 815 *****************************************************************************/ 726 816 #define INITIAL_NUM_BINS 1000.0 727 static bool vectorRobustStats(const psVector *myVector,728 const psVector *errors,729 psVector *maskInput,817 static bool vectorRobustStats(const psVector *myVector, 818 const psVector *errors, 819 psVector *maskInput, 730 820 psVectorMaskType maskValInput, 731 psStats *stats)821 psStats *stats) 732 822 { 733 if (psTraceGetLevel("psLib.math") >= 8) { 823 if (psTraceGetLevel("psLib.math") >= 8) 824 { 734 825 PS_VECTOR_PRINT_F32(myVector); 735 826 } … … 741 832 psVector *mask = psVectorAlloc(myVector->n, PS_TYPE_VECTOR_MASK); // The actual mask we will use 742 833 psVectorInit(mask, 0); 743 if (maskInput) { 744 for (long i = 0; i < myVector->n; i++) { 745 if (maskInput->data.PS_TYPE_VECTOR_MASK_DATA[i] & maskValInput) { 834 if (maskInput) 835 { 836 for (long i = 0; i < myVector->n; i++) 837 { 838 if (maskInput->data.PS_TYPE_VECTOR_MASK_DATA[i] & maskValInput) 839 { 746 840 mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = maskVal; 747 841 } … … 751 845 // statsMinMax is only applied to a subset of the data points 752 846 psStats *statsMinMax = psStatsAlloc(PS_STAT_MIN | PS_STAT_MAX); // Statistics for min and max 753 psHistogram *histogram = NULL; // Histogram of the data754 psHistogram *cumulative = NULL; // Cumulative histogram of the data755 float min = NAN, max = NAN; // Mimimum and maximum values756 float sigma = NAN; // The robust standard deviation757 long totalDataPoints = 0; // Total number of (unmasked) data points758 759 float binSize = 0.0; // Size of bins for histogram847 psHistogram *histogram = NULL; // Histogram of the data 848 psHistogram *cumulative = NULL; // Cumulative histogram of the data 849 float min = NAN, max = NAN; // Mimimum and maximum values 850 float sigma = NAN; // The robust standard deviation 851 long totalDataPoints = 0; // Total number of (unmasked) data points 852 853 float binSize = 0.0; // Size of bins for histogram 760 854 long binLo, binHi; 761 855 long binL2, binH2; … … 764 858 765 859 // Iterate to get the best bin size; an iteration limit is enforced at the bottom of the loop. 766 for (int iterate = 1; iterate > 0; iterate++) { 860 for (int iterate = 1; iterate > 0; iterate++) 861 { 767 862 psTrace(TRACE, 6, "-------------------- Iterating on Bin size. Iteration number %d --------------------\n", iterate); 768 863 769 if (iterate >= PS_ROBUST_MAX_ITERATIONS) { 770 // This occurs when a large number of the values are identical --- a bin size cannot be found 771 // that will spread out the distribution. Therefore, set what we can, and fall over 772 // gracefully. 773 COUNT_WARNING(10, 100, "Maximum number of iterations (%d) exceeded.", PS_ROBUST_MAX_ITERATIONS); 774 goto escape; 864 if (iterate >= PS_ROBUST_MAX_ITERATIONS) 865 { 866 // This occurs when a large number of the values are identical --- a bin size cannot be found 867 // that will spread out the distribution. Therefore, set what we can, and fall over 868 // gracefully. 869 COUNT_WARNING(10, 100, "Maximum number of iterations (%d) exceeded.", PS_ROBUST_MAX_ITERATIONS); 870 goto escape; 775 871 } 776 872 … … 779 875 min = statsMinMax->min; 780 876 max = statsMinMax->max; 781 if (numValid == 0 || isnan(min) || isnan(max)) { 877 if (numValid == 0 || isnan(min) || isnan(max)) 878 { 782 879 // Data range calculation failed 783 880 COUNT_WARNING(10, 100, "Failed to calculate the min/max of the input vector.\n"); 784 881 goto escape; 785 882 } 786 if (!isfinite(max - min)) { 787 COUNT_WARNING(10, 100, "Range of of the input vector is too large: %lf.\n", (double)max - (double) min); 883 if (!isfinite(max - min)) 884 { 885 COUNT_WARNING(10, 100, "Range of of the input vector is too large: %lf.\n", (double)max - (double)min); 788 886 goto escape; 789 887 } … … 791 889 792 890 // If all data points have the same value, then we set the appropriate members of stats and return. 793 if (fabs(max - min) <= FLT_EPSILON) { 891 if (fabs(max - min) <= FLT_EPSILON) 892 { 794 893 stats->robustMedian = min; 795 894 stats->robustStdev = 0.0; … … 807 906 } 808 907 809 if ((iterate == 1) && (stats->options & PS_STAT_USE_BINSIZE)) { 908 if ((iterate == 1) && (stats->options & PS_STAT_USE_BINSIZE)) 909 { 810 910 // Set initial bin size to the specified value. 811 911 binSize = stats->binsize; 812 912 psTrace(TRACE, 6, "Setting initial robust bin size to %.2f\n", binSize); 813 } else { 913 } 914 else 915 { 814 916 // Determine the bin size of the robust histogram, using the pre-defined number of bins 815 binSize = (max - min) / INITIAL_NUM_BINS;917 binSize = (max - min) / INITIAL_NUM_BINS; 816 918 } 817 919 psTrace(TRACE, 6, "Initial robust bin size is %.2f\n", binSize); … … 830 932 // Assert here so we can get more information about what is going wrong. 831 933 psAssert(numBins > 0, "Invalid numBins: %ld max: %f min: %f binSize: %f", numBins, max, min, binSize); 832 934 833 935 // Generate the histogram 834 histogram = psHistogramAlloc(min - 2.0 *binSize, max + 2.0*binSize, numBins);936 histogram = psHistogramAlloc(min - 2.0 * binSize, max + 2.0 * binSize, numBins); 835 937 // XXXXX we need to consider this step if errors -> variance 836 if (!psVectorHistogram(histogram, myVector, errors, mask, maskVal)) { 938 if (!psVectorHistogram(histogram, myVector, errors, mask, maskVal)) 939 { 837 940 // if psVectorHistogram returns false, we have a programming error 838 941 psError(PS_ERR_UNKNOWN, false, "Unable to generate histogram for robust statistics.\n"); … … 843 946 return false; 844 947 } 845 if (psTraceGetLevel("psLib.math") >= 8) { 948 if (psTraceGetLevel("psLib.math") >= 8) 949 { 846 950 PS_VECTOR_PRINT_F32(histogram->bounds); 847 951 PS_VECTOR_PRINT_F32(histogram->nums); … … 854 958 int nMaxBin = histogram->nums->data.F32[0]; 855 959 int iMaxBin = 0; 856 for (long i = 1; i < histogram->nums->n; i++) { 857 if (histogram->nums->data.F32[i] > nMaxBin) { 960 for (long i = 1; i < histogram->nums->n; i++) 961 { 962 if (histogram->nums->data.F32[i] > nMaxBin) 963 { 858 964 nMaxBin = histogram->nums->data.F32[i]; 859 965 iMaxBin = i; 860 966 } 861 967 } 862 if (nMaxBin > numValid / 2) { 863 float minKeep = histogram->bounds->data.F32[iMaxBin] - 10*binSize; 864 float maxKeep = histogram->bounds->data.F32[iMaxBin + 1] + 10*binSize; 968 if (nMaxBin > numValid / 2) 969 { 970 float minKeep = histogram->bounds->data.F32[iMaxBin] - 10 * binSize; 971 float maxKeep = histogram->bounds->data.F32[iMaxBin + 1] + 10 * binSize; 865 972 int nInvalid = 0; 866 for (long i = 0; i < myVector->n; i++) { 973 for (long i = 0; i < myVector->n; i++) 974 { 867 975 // skip the already-masked values 868 if (mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & maskVal) continue; 976 if (mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & maskVal) 977 continue; 869 978 bool invalid = false; 870 979 invalid |= (myVector->data.F32[i] < minKeep); 871 980 invalid |= (myVector->data.F32[i] > maxKeep); 872 981 invalid |= (!isfinite(myVector->data.F32[i])); 873 if (!invalid) continue; 982 if (!invalid) 983 continue; 874 984 mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = maskVal; 875 nInvalid ++; 876 } 877 878 if (nInvalid) { 879 psTrace(TRACE, 6, "data is concentrated in a single bin (%d = %f - %f), masking %d extreme outliers and retrying\n", 880 iMaxBin, histogram->bounds->data.F32[iMaxBin], histogram->bounds->data.F32[iMaxBin+1], nInvalid); 881 psFree(histogram); 882 psFree(cumulative); 883 histogram = NULL; 884 cumulative = NULL; 885 continue; 985 nInvalid++; 986 } 987 988 if (nInvalid) 989 { 990 psTrace(TRACE, 6, "data is concentrated in a single bin (%d = %f - %f), masking %d extreme outliers and retrying\n", 991 iMaxBin, histogram->bounds->data.F32[iMaxBin], histogram->bounds->data.F32[iMaxBin + 1], nInvalid); 992 psFree(histogram); 993 psFree(cumulative); 994 histogram = NULL; 995 cumulative = NULL; 996 continue; 886 997 } 887 998 // if we did not mask anything, give up. 888 999 } 889 1000 890 // We were causing psHistogramAlloc to assert. 1001 // We were causing psHistogramAlloc to assert. 891 1002 // Assert here so we can get more information about what is going wrong. 892 1003 psAssert(numBins > 0, "Invalid numBins %ld max: %f min: %f binSize: %f", numBins, max, min, binSize); … … 898 1009 cumulative->bounds->data.F32[0] = histogram->bounds->data.F32[1]; 899 1010 900 // Correctly fill the cumulative distribution with monotonically increasing values (skip zero valued bins). 901 long Nc = 1; // track the current bin of cumulative 902 // the boundaries for the current cumulative bin are from upper end of the last valid histogram bin to the 903 // upper end of the current histogram bin 904 for (long i = 1; i < histogram->nums->n - 1; i++) { 905 if (histogram->nums->data.F32[i] == 0.0) continue; 906 cumulative->nums->data.F32[Nc] = cumulative->nums->data.F32[Nc - 1] + histogram->nums->data.F32[i]; 907 cumulative->bounds->data.F32[Nc] = histogram->bounds->data.F32[i+1]; 908 Nc ++; 909 } 910 long Nlast = Nc - 1; // last valid cumulative bin 911 for (long i = Nc; i < histogram->nums->n; i++) { // Ensure the unused entries are filled. 912 cumulative->nums->data.F32[i] = cumulative->nums->data.F32[Nlast]; 913 cumulative->bounds->data.F32[i] = cumulative->bounds->data.F32[i-1] + 1.0; 914 } 915 916 if (psTraceGetLevel("psLib.math") >= 8) { 1011 // Correctly fill the cumulative distribution with monotonically increasing values (skip zero valued bins). 1012 long Nc = 1; // track the current bin of cumulative 1013 // the boundaries for the current cumulative bin are from upper end of the last valid histogram bin to the 1014 // upper end of the current histogram bin 1015 for (long i = 1; i < histogram->nums->n - 1; i++) 1016 { 1017 if (histogram->nums->data.F32[i] == 0.0) 1018 continue; 1019 cumulative->nums->data.F32[Nc] = cumulative->nums->data.F32[Nc - 1] + histogram->nums->data.F32[i]; 1020 cumulative->bounds->data.F32[Nc] = histogram->bounds->data.F32[i + 1]; 1021 Nc++; 1022 } 1023 long Nlast = Nc - 1; // last valid cumulative bin 1024 for (long i = Nc; i < histogram->nums->n; i++) 1025 { // Ensure the unused entries are filled. 1026 cumulative->nums->data.F32[i] = cumulative->nums->data.F32[Nlast]; 1027 cumulative->bounds->data.F32[i] = cumulative->bounds->data.F32[i - 1] + 1.0; 1028 } 1029 1030 if (psTraceGetLevel("psLib.math") >= 8) 1031 { 917 1032 PS_VECTOR_PRINT_F32(cumulative->bounds); 918 1033 PS_VECTOR_PRINT_F32(cumulative->nums); … … 924 1039 925 1040 // find bin which is the lower bound of median (value[binMedian] < median < value[binMedian+1] 926 PS_BIN_FOR_VALUE(binMedian, cumulative->nums, totalDataPoints /2.0, 0);927 928 psTrace(TRACE, 6, "The median bin is %ld (%.2f to %.2f)\n", binMedian, cumulative->bounds->data.F32[binMedian], cumulative->bounds->data.F32[binMedian +1]);1041 PS_BIN_FOR_VALUE(binMedian, cumulative->nums, totalDataPoints / 2.0, 0); 1042 1043 psTrace(TRACE, 6, "The median bin is %ld (%.2f to %.2f)\n", binMedian, cumulative->bounds->data.F32[binMedian], cumulative->bounds->data.F32[binMedian + 1]); 929 1044 930 1045 // ADD step 3: Interpolate to the exact 50% position in bin units 931 1046 // stats->robustMedian = fitQuadraticSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binMedian, totalDataPoints/2.0); 932 // float robustBin = fitQuadraticSearchForYThenReturnXusingValues(cumulative->bounds, cumulative->nums, binMedian, totalDataPoints/2.0);1047 // float robustBin = fitQuadraticSearchForYThenReturnXusingValues(cumulative->bounds, cumulative->nums, binMedian, totalDataPoints/2.0); 933 1048 // fprintf (stderr, "robustBin : %f vs %f\n", robustBin, stats->robustMedian); 934 // There's no reason to do a quadratic fit near the 50% bin, as it's approximately linear there.935 // Instead, do a 5-point linear fit.936 stats->robustMedian = fitLinearSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binMedian, totalDataPoints /2.0);1049 // There's no reason to do a quadratic fit near the 50% bin, as it's approximately linear there. 1050 // Instead, do a 5-point linear fit. 1051 stats->robustMedian = fitLinearSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binMedian, totalDataPoints / 2.0); 937 1052 938 1053 // convert bin to bin value: this is the robust histogram median. 939 if (isnan(stats->robustMedian)) { 1054 if (isnan(stats->robustMedian)) 1055 { 940 1056 COUNT_WARNING(10, 100, "Failed to fit a quadratic and calculate the 50-percent position.\n"); 941 1057 goto escape; … … 949 1065 PS_BIN_FOR_VALUE(binL2, cumulative->nums, totalDataPoints * 0.308538f, 0); 950 1066 PS_BIN_FOR_VALUE(binH2, cumulative->nums, totalDataPoints * 0.691462f, 0); 951 PS_BIN_FOR_VALUE(binL4, cumulative->nums, totalDataPoints * 0.022750f, 0); 952 PS_BIN_FOR_VALUE(binH4, cumulative->nums, totalDataPoints * 0.977250f, 0); 953 954 1067 PS_BIN_FOR_VALUE(binL4, cumulative->nums, totalDataPoints * 0.022750f, 0); 1068 PS_BIN_FOR_VALUE(binH4, cumulative->nums, totalDataPoints * 0.977250f, 0); 1069 955 1070 psTrace(TRACE, 6, "The 15.8655%% and 84.1345%% data point bins are (%ld, %ld).\n", 956 1071 binLo, binHi); … … 960 1075 psTrace(TRACE, 6, "binH2 midpoint is %f\n", PS_BIN_MIDPOINT(cumulative, binH2)); 961 1076 962 if ((binLo < 0) || (binHi < 0)) { 1077 if ((binLo < 0) || (binHi < 0)) 1078 { 963 1079 COUNT_WARNING(10, 100, "Failed to calculate the 15.8655%% and 84.1345%% data points.\n"); 964 1080 goto escape; 965 1081 } 966 1082 967 1083 // ADD step 4b: Interpolate Sigma (linearly) to find these two positions exactly: these are the 1sigma 968 1084 // positions. 969 1085 psTrace(TRACE, 6, "binLo is %ld. Nums at that bin and the next are (%.2f, %.2f)\n", 970 binLo, cumulative->nums->data.F32[binLo], cumulative->nums->data.F32[binLo +1]);1086 binLo, cumulative->nums->data.F32[binLo], cumulative->nums->data.F32[binLo + 1]); 971 1087 psTrace(TRACE, 6, "binHi is %ld. Nums at that bin and the next are (%.2f, %.2f)\n", 972 binHi, cumulative->nums->data.F32[binHi], cumulative->nums->data.F32[binHi +1]);1088 binHi, cumulative->nums->data.F32[binHi], cumulative->nums->data.F32[binHi + 1]); 973 1089 974 1090 // find the +0.5 and -0.5 sigma points with linear interpolation. binLo and binHi are the bins … … 977 1093 float binLoF32, binHiF32, binL2F32, binH2F32, binL4F32, binH4F32; 978 1094 #if (0) 979 PS_BIN_INTERPOLATE (binLoF32, cumulative->nums, cumulative->bounds, binLo,980 totalDataPoints * 0.158655f);981 PS_BIN_INTERPOLATE (binHiF32, cumulative->nums, cumulative->bounds, binHi,982 totalDataPoints * 0.841345f);983 PS_BIN_INTERPOLATE (binL2F32, cumulative->nums, cumulative->bounds, binL2,984 totalDataPoints * 0.308538f);985 PS_BIN_INTERPOLATE (binH2F32, cumulative->nums, cumulative->bounds, binH2,986 totalDataPoints * 0.691462f);987 PS_BIN_INTERPOLATE (binL4F32, cumulative->nums, cumulative->bounds, binL4,988 totalDataPoints * 0.022750f);989 PS_BIN_INTERPOLATE (binH4F32, cumulative->nums, cumulative->bounds, binH4,990 totalDataPoints * 0.977250f);1095 PS_BIN_INTERPOLATE(binLoF32, cumulative->nums, cumulative->bounds, binLo, 1096 totalDataPoints * 0.158655f); 1097 PS_BIN_INTERPOLATE(binHiF32, cumulative->nums, cumulative->bounds, binHi, 1098 totalDataPoints * 0.841345f); 1099 PS_BIN_INTERPOLATE(binL2F32, cumulative->nums, cumulative->bounds, binL2, 1100 totalDataPoints * 0.308538f); 1101 PS_BIN_INTERPOLATE(binH2F32, cumulative->nums, cumulative->bounds, binH2, 1102 totalDataPoints * 0.691462f); 1103 PS_BIN_INTERPOLATE(binL4F32, cumulative->nums, cumulative->bounds, binL4, 1104 totalDataPoints * 0.022750f); 1105 PS_BIN_INTERPOLATE(binH4F32, cumulative->nums, cumulative->bounds, binH4, 1106 totalDataPoints * 0.977250f); 991 1107 #else 992 1108 binLoF32 = fitLinearSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binLo, totalDataPoints * 0.158655); 993 binHiF32 = fitLinearSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binHi, totalDataPoints * 0.841345); 1109 binHiF32 = fitLinearSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binHi, totalDataPoints * 0.841345); 994 1110 binL2F32 = fitLinearSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binL2, totalDataPoints * 0.308538); 995 binH2F32 = fitLinearSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binH2, totalDataPoints * 0.691462); 1111 binH2F32 = fitLinearSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binH2, totalDataPoints * 0.691462); 996 1112 binL4F32 = fitLinearSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binL4, totalDataPoints * 0.022750); 997 binH4F32 = fitLinearSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binH4, totalDataPoints * 0.977250);998 #endif 1113 binH4F32 = fitLinearSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binH4, totalDataPoints * 0.977250); 1114 #endif 999 1115 // report +/- 1 sigma points 1000 1116 psTrace(TRACE, 5, … … 1008 1124 binL4F32, binH4F32); 1009 1125 1010 // If some of the fits failed, attempt to fix this 1011 if (!isfinite(binLoF32) && isfinite(binHiF32)) { binLoF32 = -1.0 * binHiF32; } 1012 if (!isfinite(binHiF32) && isfinite(binLoF32)) { binHiF32 = -1.0 * binLoF32; } 1013 if (!isfinite(binL2F32) && isfinite(binH2F32)) { binL2F32 = -1.0 * binH2F32; } 1014 if (!isfinite(binH2F32) && isfinite(binL2F32)) { binH2F32 = -1.0 * binL2F32; } 1015 if (!isfinite(binL4F32) && isfinite(binH4F32)) { binL4F32 = -1.0 * binH4F32; } 1016 if (!isfinite(binH4F32) && isfinite(binL4F32)) { binH4F32 = -1.0 * binL4F32; } 1017 1126 // If some of the fits failed, attempt to fix this 1127 if (!isfinite(binLoF32) && isfinite(binHiF32)) 1128 { 1129 binLoF32 = -1.0 * binHiF32; 1130 } 1131 if (!isfinite(binHiF32) && isfinite(binLoF32)) 1132 { 1133 binHiF32 = -1.0 * binLoF32; 1134 } 1135 if (!isfinite(binL2F32) && isfinite(binH2F32)) 1136 { 1137 binL2F32 = -1.0 * binH2F32; 1138 } 1139 if (!isfinite(binH2F32) && isfinite(binL2F32)) 1140 { 1141 binH2F32 = -1.0 * binL2F32; 1142 } 1143 if (!isfinite(binL4F32) && isfinite(binH4F32)) 1144 { 1145 binL4F32 = -1.0 * binH4F32; 1146 } 1147 if (!isfinite(binH4F32) && isfinite(binL4F32)) 1148 { 1149 binH4F32 = -1.0 * binL4F32; 1150 } 1151 1018 1152 // ADD step 5: Determine SIGMA as the distance between binL2 and binH2 (+/- 0.5 sigma) 1019 1020 1153 1021 1154 float sigma1 = (binH2F32 - binL2F32); … … 1023 1156 float sigma4 = (binH4F32 - binL4F32) / 4.0; 1024 1157 1025 // Fix again? 1026 if (!isfinite(sigma1) && isfinite(sigma2) && isfinite(sigma4)) { sigma1 = (sigma2 + sigma4) / 2.0; } 1027 if (!isfinite(sigma2) && isfinite(sigma1) && isfinite(sigma4)) { sigma2 = (sigma1 + sigma4) / 2.0; } 1028 if (!isfinite(sigma4) && isfinite(sigma2) && isfinite(sigma1)) { sigma4 = (sigma2 + sigma1) / 2.0; } 1029 1158 // Fix again? 1159 if (!isfinite(sigma1) && isfinite(sigma2) && isfinite(sigma4)) 1160 { 1161 sigma1 = (sigma2 + sigma4) / 2.0; 1162 } 1163 if (!isfinite(sigma2) && isfinite(sigma1) && isfinite(sigma4)) 1164 { 1165 sigma2 = (sigma1 + sigma4) / 2.0; 1166 } 1167 if (!isfinite(sigma4) && isfinite(sigma2) && isfinite(sigma1)) 1168 { 1169 sigma4 = (sigma2 + sigma1) / 2.0; 1170 } 1171 1030 1172 // take the smallest of the three: if we have a clump with wide outliers, sigma2 and 1031 1173 // sigma4 will be biased high; if we have a bi-modal distribution, sigma1 and sigma2 1032 1174 // will be biased high. 1033 // sigma = PS_MIN (sigma1, PS_MIN (sigma2, sigma4)); 1034 // CZW: Instead, take the median. Taking the MIN forces a bias on unbiased data. 1035 // It seems like occasionally getting the wrong answer on a complex distribution 1036 // is more acceptable than always getting the wrong answer for simple ones. 1037 1038 1039 sigma = PS_MAX( PS_MIN(sigma1,sigma2), 1040 PS_MIN( PS_MAX(sigma1,sigma2), 1041 sigma4)); 1175 // sigma = PS_MIN (sigma1, PS_MIN (sigma2, sigma4)); 1176 // CZW: Instead, take the median. Taking the MIN forces a bias on unbiased data. 1177 // It seems like occasionally getting the wrong answer on a complex distribution 1178 // is more acceptable than always getting the wrong answer for simple ones. 1179 1180 sigma = PS_MAX(PS_MIN(sigma1, sigma2), 1181 PS_MIN(PS_MAX(sigma1, sigma2), 1182 sigma4)); 1042 1183 1043 1184 psTrace(TRACE, 6, "The 1x sigma is %f.\n", sigma1); … … 1046 1187 1047 1188 psTrace(TRACE, 6, "The current sigma is %f.\n", sigma); 1048 // stats->robustStdev = sigma;1049 stats->robustStdev = sigma;1050 1051 #if (CZW && 0) 1052 // Skewness check: Find least biased sample for each pair.1053 sigma1 = 2.0 * PS_MIN(binH2F32 - stats->robustMedian,1054 stats->robustMedian - binL2F32);1055 sigma2 = 1.0 * PS_MIN(binHiF32 - stats->robustMedian,1056 stats->robustMedian - binLoF32);1057 sigma4 = 0.5 * PS_MIN(binH4F32 - stats->robustMedian,1058 stats->robustMedian - binL4F32);1059 // Kurtosis check: Take median sample as the solution.1060 stats->robustStdev = PS_MAX( PS_MIN(sigma1,sigma2),1061 PS_MIN( PS_MAX(sigma1,sigma2),1062 sigma4));1189 // stats->robustStdev = sigma; 1190 stats->robustStdev = sigma; 1191 1192 #if (CZW && 0) 1193 // Skewness check: Find least biased sample for each pair. 1194 sigma1 = 2.0 * PS_MIN(binH2F32 - stats->robustMedian, 1195 stats->robustMedian - binL2F32); 1196 sigma2 = 1.0 * PS_MIN(binHiF32 - stats->robustMedian, 1197 stats->robustMedian - binLoF32); 1198 sigma4 = 0.5 * PS_MIN(binH4F32 - stats->robustMedian, 1199 stats->robustMedian - binL4F32); 1200 // Kurtosis check: Take median sample as the solution. 1201 stats->robustStdev = PS_MAX(PS_MIN(sigma1, sigma2), 1202 PS_MIN(PS_MAX(sigma1, sigma2), 1203 sigma4)); 1063 1204 #endif 1064 1205 1065 1066 1206 #if (CZW) 1067 // printf("CZW: bad sigma?: %f %f %f %f %f %f %f %f %f %f\n",1068 // binH2F32,binL2F32,binHiF32,binLoF32,binH4F32,binL4F32,1069 // sigma1,sigma2,sigma4,sigma);1070 1071 printf("CZW Robust (%d): median %f sigma %f delta: %f \n\t %f %f %f %f %f %f %f \n\t %f %f %f %f %f %f %f\n",1072 iterate,1073 stats->robustMedian,stats->robustStdev,1074 fabs(cumulative->bounds->data.F32[binMedian] - cumulative->bounds->data.F32[binMedian + 1]),1075 1076 cumulative->bounds->data.F32[binMedian-3],cumulative->bounds->data.F32[binMedian-2],1077 cumulative->bounds->data.F32[binMedian-1],1078 cumulative->bounds->data.F32[binMedian],1079 cumulative->bounds->data.F32[binMedian+1],1080 cumulative->bounds->data.F32[binMedian+2],cumulative->bounds->data.F32[binMedian+3],1081 1082 cumulative->nums->data.F32[binMedian-3],cumulative->nums->data.F32[binMedian-2],1083 cumulative->nums->data.F32[binMedian-1],1084 cumulative->nums->data.F32[binMedian],1085 cumulative->nums->data.F32[binMedian+1],1086 cumulative->nums->data.F32[binMedian+2],cumulative->nums->data.F32[binMedian+3]);1087 // PS_VECTOR_PRINT_F32(histogram->bounds);1088 // PS_VECTOR_PRINT_F32(histogram->nums);1089 // PS_VECTOR_PRINT_F32(cumulative->bounds);1090 // PS_VECTOR_PRINT_F32(cumulative->nums);1207 // printf("CZW: bad sigma?: %f %f %f %f %f %f %f %f %f %f\n", 1208 // binH2F32,binL2F32,binHiF32,binLoF32,binH4F32,binL4F32, 1209 // sigma1,sigma2,sigma4,sigma); 1210 1211 printf("CZW Robust (%d): median %f sigma %f delta: %f \n\t %f %f %f %f %f %f %f \n\t %f %f %f %f %f %f %f\n", 1212 iterate, 1213 stats->robustMedian, stats->robustStdev, 1214 fabs(cumulative->bounds->data.F32[binMedian] - cumulative->bounds->data.F32[binMedian + 1]), 1215 1216 cumulative->bounds->data.F32[binMedian - 3], cumulative->bounds->data.F32[binMedian - 2], 1217 cumulative->bounds->data.F32[binMedian - 1], 1218 cumulative->bounds->data.F32[binMedian], 1219 cumulative->bounds->data.F32[binMedian + 1], 1220 cumulative->bounds->data.F32[binMedian + 2], cumulative->bounds->data.F32[binMedian + 3], 1221 1222 cumulative->nums->data.F32[binMedian - 3], cumulative->nums->data.F32[binMedian - 2], 1223 cumulative->nums->data.F32[binMedian - 1], 1224 cumulative->nums->data.F32[binMedian], 1225 cumulative->nums->data.F32[binMedian + 1], 1226 cumulative->nums->data.F32[binMedian + 2], cumulative->nums->data.F32[binMedian + 3]); 1227 // PS_VECTOR_PRINT_F32(histogram->bounds); 1228 // PS_VECTOR_PRINT_F32(histogram->nums); 1229 // PS_VECTOR_PRINT_F32(cumulative->bounds); 1230 // PS_VECTOR_PRINT_F32(cumulative->nums); 1091 1231 #endif 1092 1232 1093 1233 // ADD step 6: If the measured SIGMA is less than 2 times the bin size, exclude points which are more 1094 1234 // than 25 bins from the median, recalculate the bin size, and perform the algorithm again. 1095 if (sigma < (3.0 * binSize)) { 1235 if (sigma < (3.0 * binSize)) 1236 { 1096 1237 psTrace(TRACE, 6, "*************: Do another iteration (%f %f).\n", sigma, binSize); 1097 1238 1098 // these limits are supposed to be 25 x the raw bin size, NOT 25 of the cumulative histogram bins1099 psF32 medianLo = stats->robustMedian - 25*binSize;1100 psF32 medianHi = stats->robustMedian + 25*binSize;1239 // these limits are supposed to be 25 x the raw bin size, NOT 25 of the cumulative histogram bins 1240 psF32 medianLo = stats->robustMedian - 25 * binSize; 1241 psF32 medianHi = stats->robustMedian + 25 * binSize; 1101 1242 1102 1243 // long maskLo = PS_MAX(0, (binMedian - 25)); // Low index for masking region … … 1107 1248 // psTrace(TRACE, 6, "The median is at bin number %ld. We mask bins outside the bin range (%ld:%ld)\n", binMedian, maskLo, maskHi); 1108 1249 psTrace(TRACE, 6, "Masking data outside (%f %f)\n", medianLo, medianHi); 1109 int Nmasked = 0; 1110 for (long i = 0 ; i < myVector->n ; i++) { 1111 if ((myVector->data.F32[i] < medianLo) || (myVector->data.F32[i] > medianHi)) { 1112 if (mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & MASK_MARK) continue; 1250 int Nmasked = 0; 1251 for (long i = 0; i < myVector->n; i++) 1252 { 1253 if ((myVector->data.F32[i] < medianLo) || (myVector->data.F32[i] > medianHi)) 1254 { 1255 if (mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & MASK_MARK) 1256 continue; 1113 1257 mask->data.PS_TYPE_VECTOR_MASK_DATA[i] |= MASK_MARK; 1114 1258 psTrace(TRACE, 6, "Masking element %ld is %f\n", i, myVector->data.F32[i]); 1115 Nmasked++;1259 Nmasked++; 1116 1260 } 1117 1261 } 1118 1262 1119 if (Nmasked == 0) { 1120 // no significant change to the sigma & binsize -- we are done here 1121 iterate = -1; 1122 continue; 1123 } 1263 if (Nmasked == 0) 1264 { 1265 // no significant change to the sigma & binsize -- we are done here 1266 iterate = -1; 1267 continue; 1268 } 1124 1269 1125 1270 // Free the histograms; they will be recreated on the next iteration, with new bounds … … 1130 1275 cumulative = NULL; 1131 1276 1132 if (iterate >= PS_ROBUST_MAX_ITERATIONS) { 1277 if (iterate >= PS_ROBUST_MAX_ITERATIONS) 1278 { 1133 1279 // This occurs when a large number of the values are identical --- a bin size cannot be found 1134 1280 // that will spread out the distribution. Therefore, set what we can, and fall over … … 1147 1293 return true; 1148 1294 } 1149 } else { 1295 } 1296 else 1297 { 1150 1298 // We've got the bin size correct now 1151 1299 psTrace(TRACE, 6, "*************: No more iteration. sigma is %f\n", sigma); … … 1153 1301 } 1154 1302 } 1155 1303 1156 1304 // XXX test lines while studying algorithm errors 1157 1305 // fprintf (stderr, "robust stats test %7.1f +/- %7.1f : %4ld %4ld %4ld %4ld %4ld : %f %f %f\n", … … 1161 1309 // ADD step 7: Find the bins which contains the 25% and 75% data points. 1162 1310 long binLo25, binHi25; 1163 PS_BIN_FOR_VALUE (binLo25, cumulative->nums, totalDataPoints * 0.25f, 0);1164 PS_BIN_FOR_VALUE (binHi25, cumulative->nums, totalDataPoints * 0.75f, 0);1311 PS_BIN_FOR_VALUE(binLo25, cumulative->nums, totalDataPoints * 0.25f, 0); 1312 PS_BIN_FOR_VALUE(binHi25, cumulative->nums, totalDataPoints * 0.75f, 0); 1165 1313 psTrace(TRACE, 6, "The 25-percent and 75-percent data point bins are (%ld, %ld).\n", binLo25, binHi25); 1166 1314 … … 1169 1317 psF32 binLo25F32 = fitLinearSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binLo25, totalDataPoints * 0.25f); 1170 1318 psF32 binHi25F32 = fitLinearSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binHi25, totalDataPoints * 0.75f); 1171 if (isnan(binLo25F32) || isnan(binHi25F32)) { 1319 if (isnan(binLo25F32) || isnan(binHi25F32)) 1320 { 1172 1321 COUNT_WARNING(10, 100, "could not determine the robustUQ or LQ: fitLinearSearchForYThenReturnBin() returned a NAN.\n"); 1173 1322 goto escape; … … 1179 1328 binLo25F32, binHi25F32); 1180 1329 long N50 = 0; 1181 for (long i = 0 ; i < myVector->n ; i++) { 1330 for (long i = 0; i < myVector->n; i++) 1331 { 1182 1332 if (!mask->data.PS_TYPE_VECTOR_MASK_DATA[i] && 1183 (binLo25F32 <= myVector->data.F32[i]) && (binHi25F32 >= myVector->data.F32[i])) { 1333 (binLo25F32 <= myVector->data.F32[i]) && (binHi25F32 >= myVector->data.F32[i])) 1334 { 1184 1335 N50++; 1185 1336 } … … 1226 1377 * version follows the upper portion of the distribution until it passes 0.5*peak 1227 1378 ********************/ 1228 static bool vectorFittedStats (const psVector*myVector,1229 const psVector*errors,1230 psVector*mask,1231 psVectorMaskType maskVal,1232 psStats*stats)1379 static bool vectorFittedStats(const psVector *myVector, 1380 const psVector *errors, 1381 psVector *mask, 1382 psVectorMaskType maskVal, 1383 psStats *stats) 1233 1384 { 1234 1385 1235 1386 // This procedure requires the mean. If it has not been already 1236 1387 // calculated, then call vectorSampleMean() 1237 if (!(stats->results & PS_STAT_ROBUST_MEDIAN)) { 1238 if (!vectorRobustStats(myVector, errors, mask, maskVal, stats)) { 1388 if (!(stats->results & PS_STAT_ROBUST_MEDIAN)) 1389 { 1390 if (!vectorRobustStats(myVector, errors, mask, maskVal, stats)) 1391 { 1239 1392 psError(PS_ERR_UNKNOWN, false, "failure to measure robust stats\n"); 1240 1393 return false; … … 1243 1396 1244 1397 // If the mean is NAN, then generate a warning and set the stdev to NAN. 1245 if (isnan(stats->robustMedian)) { 1246 stats->fittedMean = NAN; 1247 stats->fittedStdev = NAN; 1248 stats->results |= PS_STAT_FITTED_MEAN; 1249 stats->results |= PS_STAT_FITTED_STDEV; 1398 if (isnan(stats->robustMedian)) 1399 { 1400 stats->fittedMean = NAN; 1401 stats->fittedStdev = NAN; 1402 stats->results |= PS_STAT_FITTED_MEAN; 1403 stats->results |= PS_STAT_FITTED_STDEV; 1250 1404 return true; 1251 1405 } 1252 1406 1253 if (stats->robustStdev <= FLT_EPSILON) { 1254 stats->fittedMean = stats->robustMedian; 1255 stats->fittedStdev = stats->robustStdev; 1256 stats->results |= PS_STAT_FITTED_MEAN; 1257 stats->results |= PS_STAT_FITTED_STDEV; 1407 if (stats->robustStdev <= FLT_EPSILON) 1408 { 1409 stats->fittedMean = stats->robustMedian; 1410 stats->fittedStdev = stats->robustStdev; 1411 stats->results |= PS_STAT_FITTED_MEAN; 1412 stats->results |= PS_STAT_FITTED_STDEV; 1258 1413 return true; 1259 1414 } 1260 if (myVector->n < 1) { printf("There are no elements in this vector.\n"); abort(); } 1261 float guessStdev = stats->robustStdev; // pass the guess sigma 1262 float guessMean = stats->robustMedian; // pass the guess mean 1415 if (myVector->n < 1) 1416 { 1417 printf("There are no elements in this vector.\n"); 1418 abort(); 1419 } 1420 float guessStdev = stats->robustStdev; // pass the guess sigma 1421 float guessMean = stats->robustMedian; // pass the guess mean 1263 1422 1264 1423 psTrace(TRACE, 6, "The ** starting ** guess mean is %f.\n", guessMean); … … 1266 1425 1267 1426 bool done = false; 1268 for (int iteration = 0; !done && (iteration < 2); iteration ++) { 1427 for (int iteration = 0; !done && (iteration < 2); iteration++) 1428 { 1269 1429 psStats *statsMinMax = psStatsAlloc(PS_STAT_MIN | PS_STAT_MAX); // Statistics for min and max 1270 1430 1271 1431 psF32 binSize = 1; 1272 if (stats->options & PS_STAT_USE_BINSIZE) { 1432 if (stats->options & PS_STAT_USE_BINSIZE) 1433 { 1273 1434 // Set initial bin size to the specified value. 1274 1435 binSize = stats->binsize; 1275 1436 psTrace(TRACE, 6, "Setting initial robust bin size to %.2f\n", binSize); 1276 } else { 1437 } 1438 else 1439 { 1277 1440 // construct a histogram with (sigma/2 < binsize < sigma) 1278 1441 // set roughly so that the lowest bins have about 2 cnts 1279 1442 // Nsmallest ~ N50 / (4*dN)) 1280 // psF32 dN = PS_MAX (1, PS_MIN (4, stats->robustN50 / 8));1281 1282 // CZW 2013-11-20: We know that the histogram is going to be basically Gaussian.1283 // Furthermore, we only use the inner +/- 2 sigma parts. Therefore, define the1284 // binsize such that the bin at 2 sigma contains ~50 points (S/N ~ 7). robustN501285 // contains half the total points, so 2 * robustN50 / 50 is the fraction of all1286 // points in the 2 sigma bin. Dance the erf() relations around, and it looks like1287 // there's a factor of about 1/20 to include. Keep the PS_MAX to ensure we never bin1288 // wider than 1 sigma when the number of points is small.1289 psF32 dN = PS_MAX(1, (stats->robustN50 / 500.0));1290 binSize = guessStdev / dN;1443 // psF32 dN = PS_MAX (1, PS_MIN (4, stats->robustN50 / 8)); 1444 1445 // CZW 2013-11-20: We know that the histogram is going to be basically Gaussian. 1446 // Furthermore, we only use the inner +/- 2 sigma parts. Therefore, define the 1447 // binsize such that the bin at 2 sigma contains ~50 points (S/N ~ 7). robustN50 1448 // contains half the total points, so 2 * robustN50 / 50 is the fraction of all 1449 // points in the 2 sigma bin. Dance the erf() relations around, and it looks like 1450 // there's a factor of about 1/20 to include. Keep the PS_MAX to ensure we never bin 1451 // wider than 1 sigma when the number of points is small. 1452 psF32 dN = PS_MAX(1, (stats->robustN50 / 500.0)); 1453 binSize = guessStdev / dN; 1291 1454 } 1292 1455 … … 1295 1458 float min = statsMinMax->min; 1296 1459 float max = statsMinMax->max; 1297 if (numValid == 0 || isnan(min) || isnan(max)) { 1460 if (numValid == 0 || isnan(min) || isnan(max)) 1461 { 1298 1462 COUNT_WARNING(10, 100, "Failed to calculate the min/max of the input vector.\n"); 1299 1463 psFree(statsMinMax); … … 1302 1466 1303 1467 // If all data points have the same value, then we set the appropriate members of stats and return. 1304 if (fabs(max - min) <= FLT_EPSILON) { 1468 if (fabs(max - min) <= FLT_EPSILON) 1469 { 1305 1470 COUNT_WARNING(10, 100, "All data points have the same value: %f.\n", min); 1306 1471 stats->fittedMean = min; … … 1314 1479 // XXX can we calculate the binMin, binMax **before** building this histogram? 1315 1480 // if the range is too absurd, adjust numBins & binSize 1316 // We no longer want to reset the binSize here, as it can cause odd things. Better to select1317 // a number of bins, and then set the min/max values to put those bins sanely around the mean.1318 // long numBins = PS_MAX (50, PS_MIN (10000, (max - min) / binSize));1319 // binSize = (max - min) / (float) numBins;1481 // We no longer want to reset the binSize here, as it can cause odd things. Better to select 1482 // a number of bins, and then set the min/max values to put those bins sanely around the mean. 1483 // long numBins = PS_MAX (50, PS_MIN (10000, (max - min) / binSize)); 1484 // binSize = (max - min) / (float) numBins; 1320 1485 psTrace(TRACE, 6, "The new min/max values are (%f, %f).\n", min, max); 1321 1486 psTrace(TRACE, 6, "The new bin size is %f.\n", binSize); 1322 // psTrace(TRACE, 6, "The numBins is %ld\n", numBins); 1323 1487 // psTrace(TRACE, 6, "The numBins is %ld\n", numBins); 1324 1488 1325 1489 #define FITTED_CLIPPING_NUM 5.0 1326 if (min < guessMean - FITTED_CLIPPING_NUM * guessStdev) { 1327 min = guessMean - FITTED_CLIPPING_NUM * guessStdev; 1328 } 1329 if (max > guessMean + FITTED_CLIPPING_NUM * guessStdev) { 1330 max = guessMean + FITTED_CLIPPING_NUM * guessStdev; 1331 } 1332 long numBins = PS_MAX (50, PS_MIN (10000, (max - min) / binSize)); 1333 if (CZW) { printf("I've clipped: %f %f => %f %f ; %f %ld\n",guessMean,guessStdev,min,max,binSize,stats->robustN50); } 1490 if (min < guessMean - FITTED_CLIPPING_NUM * guessStdev) 1491 { 1492 min = guessMean - FITTED_CLIPPING_NUM * guessStdev; 1493 } 1494 if (max > guessMean + FITTED_CLIPPING_NUM * guessStdev) 1495 { 1496 max = guessMean + FITTED_CLIPPING_NUM * guessStdev; 1497 } 1498 long numBins = PS_MAX(50, PS_MIN(10000, (max - min) / binSize)); 1499 if (CZW) 1500 { 1501 printf("I've clipped: %f %f => %f %f ; %f %ld\n", guessMean, guessStdev, min, max, binSize, stats->robustN50); 1502 } 1334 1503 psHistogram *histogram = psHistogramAlloc(min, max, numBins); // A new histogram (without outliers) 1335 if (!psVectorHistogram(histogram, myVector, errors, mask, maskVal)) { 1504 if (!psVectorHistogram(histogram, myVector, errors, mask, maskVal)) 1505 { 1336 1506 COUNT_WARNING(10, 100, "Unable to generate histogram for fitted statistics v4.\n"); 1337 1507 psFree(histogram); … … 1339 1509 goto escape; 1340 1510 } 1341 if (psTraceGetLevel("psLib.math") >= 8) { 1511 if (psTraceGetLevel("psLib.math") >= 8) 1512 { 1342 1513 PS_VECTOR_PRINT_F32(histogram->nums); 1343 1514 } … … 1347 1518 // set the full-range upper and lower limits 1348 1519 psF32 maxFitSigma = 2.0; 1349 if (isfinite(stats->clipSigma)) { 1520 if (isfinite(stats->clipSigma)) 1521 { 1350 1522 maxFitSigma = fabs(stats->clipSigma); 1351 1523 } 1352 if (isfinite(stats->max)) { 1524 if (isfinite(stats->max)) 1525 { 1353 1526 maxFitSigma = fabs(stats->max); 1354 1527 } 1355 1528 1356 1529 psF32 minFitSigma = 2.0; 1357 if (isfinite(stats->clipSigma)) { 1530 if (isfinite(stats->clipSigma)) 1531 { 1358 1532 minFitSigma = fabs(stats->clipSigma); 1359 1533 } 1360 if (isfinite(stats->min)) { 1534 if (isfinite(stats->min)) 1535 { 1361 1536 minFitSigma = fabs(stats->min); 1362 1537 } … … 1364 1539 // select the min and max bins, saturating on the lower and upper end-points 1365 1540 long binMin, binMax; 1366 PS_BIN_FOR_VALUE (binMin, histogram->bounds, guessMean - minFitSigma*guessStdev, 0); 1367 PS_BIN_FOR_VALUE (binMax, histogram->bounds, guessMean + maxFitSigma*guessStdev, 0); 1368 1369 if (binMin == binMax) { 1541 PS_BIN_FOR_VALUE(binMin, histogram->bounds, guessMean - minFitSigma * guessStdev, 0); 1542 PS_BIN_FOR_VALUE(binMax, histogram->bounds, guessMean + maxFitSigma * guessStdev, 0); 1543 1544 if (binMin == binMax) 1545 { 1370 1546 COUNT_WARNING(10, 100, "Failed to calculate the min/max of the input vector.\n"); 1371 1547 psFree(statsMinMax); … … 1375 1551 1376 1552 // search for mode (peak of histogram within range mean-2sigma - mean+2sigma 1377 long binPeak = binMin;1553 long binPeak = binMin; 1378 1554 float valPeak = histogram->nums->data.F32[binPeak]; 1379 for (int i = binMin; i < binMax; i++) { 1380 if (histogram->nums->data.F32[i] > valPeak) { 1555 for (int i = binMin; i < binMax; i++) 1556 { 1557 if (histogram->nums->data.F32[i] > valPeak) 1558 { 1381 1559 binPeak = i; 1382 1560 valPeak = histogram->nums->data.F32[binPeak]; 1383 1561 } 1384 psTrace (TRACE, 6, "(%f = %.0f) ", histogram->bounds->data.F32[i], histogram->nums->data.F32[i]); 1385 if (CZW) { printf("CENTERED_HISTOGRAM: %f %f\n", 1386 PS_BIN_MIDPOINT(histogram,i), 1387 histogram->nums->data.F32[i]); } 1388 } 1389 psTrace (TRACE, 6, "\n"); 1390 1391 if (CZW) { printf("Bin selection done: %ld %f %f %ld %f %f %ld %f %f\n", 1392 binMin,PS_BIN_MIDPOINT(histogram,binMin),histogram->nums->data.F32[binMin], 1393 binMax,PS_BIN_MIDPOINT(histogram,binMax),histogram->nums->data.F32[binMax], 1394 binPeak,PS_BIN_MIDPOINT(histogram,binPeak),histogram->nums->data.F32[binPeak]); 1395 } 1396 1562 psTrace(TRACE, 6, "(%f = %.0f) ", histogram->bounds->data.F32[i], histogram->nums->data.F32[i]); 1563 if (CZW) 1564 { 1565 printf("CENTERED_HISTOGRAM: %f %f\n", 1566 PS_BIN_MIDPOINT(histogram, i), 1567 histogram->nums->data.F32[i]); 1568 } 1569 } 1570 psTrace(TRACE, 6, "\n"); 1571 1572 if (CZW) 1573 { 1574 printf("Bin selection done: %ld %f %f %ld %f %f %ld %f %f\n", 1575 binMin, PS_BIN_MIDPOINT(histogram, binMin), histogram->nums->data.F32[binMin], 1576 binMax, PS_BIN_MIDPOINT(histogram, binMax), histogram->nums->data.F32[binMax], 1577 binPeak, PS_BIN_MIDPOINT(histogram, binPeak), histogram->nums->data.F32[binPeak]); 1578 } 1579 1397 1580 // assume a reasonably well-defined gaussian-like population; run from peak out until val < 0.25*peak 1398 1581 psTrace(TRACE, 6, "The clipped numBins is %ld\n", binMax - binMin); … … 1402 1585 psTrace(TRACE, 6, "The clipped peak value is %f\n", histogram->nums->data.F32[binPeak]); 1403 1586 1404 1405 float lowfitMean = NAN; 1406 float lowfitStdev = NAN; 1587 float lowfitMean = NAN; 1588 float lowfitStdev = NAN; 1407 1589 { 1408 1590 // fit the lower half of the distribution … … 1410 1592 // run up until we drop below 0.50*valPeak 1411 1593 long binS = binMin; 1412 long binE = PS_MIN (binPeak + 3, binMax); 1413 for (int i = binPeak - 3; i >= binMin; i--) { 1414 if (histogram->nums->data.F32[i] < 0.25*valPeak) { 1594 long binE = PS_MIN(binPeak + 3, binMax); 1595 for (int i = binPeak - 3; i >= binMin; i--) 1596 { 1597 if (histogram->nums->data.F32[i] < 0.25 * valPeak) 1598 { 1415 1599 binS = i; 1416 1600 break; 1417 1601 } 1418 1602 } 1419 for (int i = binPeak + 3; i < binMax; i++) { 1420 if (histogram->nums->data.F32[i] < 0.50*valPeak) { 1603 for (int i = binPeak + 3; i < binMax; i++) 1604 { 1605 if (histogram->nums->data.F32[i] < 0.50 * valPeak) 1606 { 1421 1607 binE = i; 1422 1608 break; … … 1431 1617 psVector *x = psVectorAllocEmpty(binE - binS, PS_TYPE_F32); // Vector of ordinates 1432 1618 long j = 0; 1433 for (long i = binS; i < binE; i++) { 1619 for (long i = binS; i < binE; i++) 1620 { 1434 1621 if (histogram->nums->data.F32[i] <= 0.0) 1435 1622 continue; … … 1440 1627 } 1441 1628 y->n = x->n = j; 1442 1629 1443 1630 // fit 2nd order polynomial to ln(y) = -(x-xo)^2/2sigma^2 1444 1631 // XXX this fit may fail with an error for an ill-conditioned matrix (bad data) 1445 1632 // we probably should be able to handle the data errors gracefully 1446 1633 psPolynomial1D *poly = psPolynomial1DAlloc(PS_POLYNOMIAL_ORD, 2); 1447 bool status = psVectorFitPolynomial1D (poly, NULL, 0, y, NULL, x);1634 bool status = psVectorFitPolynomial1D(poly, NULL, 0, y, NULL, x); 1448 1635 #if (CZW && 1) 1449 printf("CZW: LowfitPoly: %f %f %f\n",poly->coeff[0],poly->coeff[1],poly->coeff[2]); 1450 for (long i = 0; i < x->n; i++) { 1451 printf("CZW: Lowfit: %d %ld %f %f %f\n", 1452 status,i,x->data.F32[i],y->data.F32[i], 1453 poly->coeff[0] + poly->coeff[1] * x->data.F32[i] + 1454 poly->coeff[2] * pow(x->data.F32[i],2)); 1455 } 1636 printf("CZW: LowfitPoly: %f %f %f\n", poly->coeff[0], poly->coeff[1], poly->coeff[2]); 1637 for (long i = 0; i < x->n; i++) 1638 { 1639 printf("CZW: Lowfit: %d %ld %f %f %f\n", 1640 status, i, x->data.F32[i], y->data.F32[i], 1641 poly->coeff[0] + poly->coeff[1] * x->data.F32[i] + 1642 poly->coeff[2] * pow(x->data.F32[i], 2)); 1643 } 1456 1644 #endif 1457 1645 psFree(x); 1458 1646 psFree(y); 1459 1647 1460 if (!status) { 1648 if (!status) 1649 { 1461 1650 psErrorClear(); 1462 1651 COUNT_WARNING(10, 100, "Failed to fit a gaussian to the robust histogram.\n"); … … 1467 1656 } 1468 1657 1469 if (poly->coeff[2] >= 0.0) { 1658 if (poly->coeff[2] >= 0.0) 1659 { 1470 1660 COUNT_WARNING(10, 100, "Failed parabolic fit: %f + %f x + %f x^2\n", poly->coeff[0], poly->coeff[1], poly->coeff[2]); 1471 1661 … … 1477 1667 // tends to be found in a single bin. make one attempt to recover by dropping the guessStdev 1478 1668 // down by a jump and trying again 1479 if (iteration == 0) { 1480 guessStdev = 0.25*guessStdev; 1669 if (iteration == 0) 1670 { 1671 guessStdev = 0.25 * guessStdev; 1481 1672 psTrace(TRACE, 6, "*** retry, new stdev is %f.\n", guessStdev); 1482 1673 continue; … … 1488 1679 1489 1680 // calculate lower mean & stdev from parabolic fit -- use this as the result 1490 lowfitStdev = sqrt(-0.5 /poly->coeff[2]);1491 lowfitMean = poly->coeff[1]*PS_SQR(lowfitStdev);1681 lowfitStdev = sqrt(-0.5 / poly->coeff[2]); 1682 lowfitMean = poly->coeff[1] * PS_SQR(lowfitStdev); 1492 1683 1493 1684 psTrace(TRACE, 6, "Parabolic Lower fit results: %f + %f x + %f x^2\n", poly->coeff[0], poly->coeff[1], poly->coeff[2]); … … 1498 1689 } 1499 1690 1500 float fullfitMean= NAN;1501 float fullfitStdev = NAN;1502 float minValueSym= NAN;1503 float maxValueSym= NAN;1504 1505 // try the full fit as well:1506 {1691 float fullfitMean = NAN; 1692 float fullfitStdev = NAN; 1693 float minValueSym = NAN; 1694 float maxValueSym = NAN; 1695 1696 // try the full fit as well: 1697 { 1507 1698 // fit a symmetric distribution 1508 1699 // run up until we drop below 0.15*valPeak … … 1510 1701 long binS = binMin; 1511 1702 long binE = binMax; 1512 for (int i = binPeak - 3; i >= binMin; i--) { 1513 if (histogram->nums->data.F32[i] < 0.15*valPeak) { 1703 for (int i = binPeak - 3; i >= binMin; i--) 1704 { 1705 if (histogram->nums->data.F32[i] < 0.15 * valPeak) 1706 { 1514 1707 binS = i; 1515 1708 break; 1516 1709 } 1517 1710 } 1518 for (int i = binPeak + 3; i < binMax; i++) { 1519 if (histogram->nums->data.F32[i] < 0.15*valPeak) { 1711 for (int i = binPeak + 3; i < binMax; i++) 1712 { 1713 if (histogram->nums->data.F32[i] < 0.15 * valPeak) 1714 { 1520 1715 binE = i; 1521 1716 break; … … 1531 1726 psVector *x = psVectorAllocEmpty(binE - binS, PS_TYPE_F32); // Vector of ordinates 1532 1727 long j = 0; 1533 for (long i = binS; i < binE; i++) { 1728 for (long i = binS; i < binE; i++) 1729 { 1534 1730 if (histogram->nums->data.F32[i] <= 0.0) 1535 1731 continue; … … 1543 1739 // fit 2nd order polynomial to ln(y) = -(x-xo)^2/2sigma^2 1544 1740 psPolynomial1D *poly = psPolynomial1DAlloc(PS_POLYNOMIAL_ORD, 2); 1545 bool status = psVectorFitPolynomial1D (poly, NULL, 0, y, NULL, x);1741 bool status = psVectorFitPolynomial1D(poly, NULL, 0, y, NULL, x); 1546 1742 #if (CZW && 1) 1547 printf("CZW: FullfitPoly: %f %f %f\n",poly->coeff[0],poly->coeff[1],poly->coeff[2]); 1548 for (long i = 0; i < x->n; i++) { 1549 printf("CZW: Fullfit: %d %ld %f %f %f\n", 1550 status,i,x->data.F32[i],y->data.F32[i], 1551 poly->coeff[0] + poly->coeff[1] * x->data.F32[i] + 1552 poly->coeff[2] * pow(x->data.F32[i],2)); 1553 } 1743 printf("CZW: FullfitPoly: %f %f %f\n", poly->coeff[0], poly->coeff[1], poly->coeff[2]); 1744 for (long i = 0; i < x->n; i++) 1745 { 1746 printf("CZW: Fullfit: %d %ld %f %f %f\n", 1747 status, i, x->data.F32[i], y->data.F32[i], 1748 poly->coeff[0] + poly->coeff[1] * x->data.F32[i] + 1749 poly->coeff[2] * pow(x->data.F32[i], 2)); 1750 } 1554 1751 #endif 1555 1752 psFree(x); 1556 1753 psFree(y); 1557 1754 1558 if (!status) { 1755 if (!status) 1756 { 1559 1757 psErrorClear(); 1560 1758 COUNT_WARNING(10, 100, "Failed to fit a gaussian to the robust histogram.\n"); … … 1566 1764 1567 1765 // calculate upper mean & stdev from parabolic fit -- ignore this value 1568 fullfitStdev = sqrt(-0.5 /poly->coeff[2]);1569 fullfitMean = poly->coeff[1] *PS_SQR(fullfitStdev);1766 fullfitStdev = sqrt(-0.5 / poly->coeff[2]); 1767 fullfitMean = poly->coeff[1] * PS_SQR(fullfitStdev); 1570 1768 1571 1769 #ifndef PS_NO_TRACE … … 1580 1778 1581 1779 // saturate on min or max value 1582 if (fullfitMean < minValueSym) { 1780 if (fullfitMean < minValueSym) 1781 { 1583 1782 fullfitMean = minValueSym; 1584 1783 psTrace(TRACE, 6, "The symmetric mean is out of bounds, saturating to %f.\n", guessMean); … … 1586 1785 1587 1786 // saturate on min or max value 1588 if (fullfitMean > maxValueSym) { 1787 if (fullfitMean > maxValueSym) 1788 { 1589 1789 fullfitMean = maxValueSym; 1590 1790 psTrace(TRACE, 6, "The symmetric mean is out of bounds, saturating to %f.\n", guessMean); 1591 1791 } 1592 1792 1593 1594 psFree (poly); 1595 } 1596 1597 // we now have the fullfit and the lowfit mean and stdev values 1598 // accept the fullfit unless minValueSym < lowfitMean < fullfitMean 1599 1600 if (isfinite(lowfitMean) && isfinite(lowfitStdev) && (lowfitMean < fullfitMean) && (lowfitMean > minValueSym)) { 1601 guessMean = lowfitMean; 1602 guessStdev = lowfitStdev; 1603 } else { 1604 guessMean = fullfitMean; 1605 guessStdev = fullfitStdev; 1606 } 1607 1608 if (!isfinite(guessMean) || !isfinite(guessStdev)) { 1609 guessMean = stats->robustMedian; 1610 guessStdev = stats->robustStdev; 1611 } 1612 1613 if (guessStdev > 0.75*stats->robustStdev) { 1614 done = true; 1615 } 1616 1617 1793 psFree(poly); 1794 } 1795 1796 // we now have the fullfit and the lowfit mean and stdev values 1797 // accept the fullfit unless minValueSym < lowfitMean < fullfitMean 1798 1799 if (isfinite(lowfitMean) && isfinite(lowfitStdev) && (lowfitMean < fullfitMean) && (lowfitMean > minValueSym)) 1800 { 1801 guessMean = lowfitMean; 1802 guessStdev = lowfitStdev; 1803 } 1804 else 1805 { 1806 guessMean = fullfitMean; 1807 guessStdev = fullfitStdev; 1808 } 1809 1810 if (!isfinite(guessMean) || !isfinite(guessStdev)) 1811 { 1812 guessMean = stats->robustMedian; 1813 guessStdev = stats->robustStdev; 1814 } 1815 1816 if (guessStdev > 0.75 * stats->robustStdev) 1817 { 1818 done = true; 1819 } 1820 1618 1821 #if (CZW && 1) 1619 printf("CZW IN FITTED: iter %d %f \n"1620 " low %f %f \n"1621 " full %f %f \n"1622 " robust %f %f \n"1623 " final %f %f\n",1624 iteration,minValueSym,1625 lowfitMean,lowfitStdev,1626 fullfitMean,fullfitStdev,1627 stats->robustMedian,stats->robustStdev,1628 guessMean,guessStdev);1822 printf("CZW IN FITTED: iter %d %f \n" 1823 " low %f %f \n" 1824 " full %f %f \n" 1825 " robust %f %f \n" 1826 " final %f %f\n", 1827 iteration, minValueSym, 1828 lowfitMean, lowfitStdev, 1829 fullfitMean, fullfitStdev, 1830 stats->robustMedian, stats->robustStdev, 1831 guessMean, guessStdev); 1629 1832 #endif 1630 1833 1631 1834 // Clean up after fitting 1632 psFree (histogram);1633 psFree (statsMinMax);1835 psFree(histogram); 1836 psFree(statsMinMax); 1634 1837 } 1635 1838 … … 1655 1858 return true; 1656 1859 } 1657 1658 1860 1659 1861 /****************************************************************************** … … 1668 1870 { 1669 1871 psTrace(TRACE, 4, "---- %s() begin ----\n", __func__); 1670 psTrace(TRACE, 5, "(histogram->nums->n, sigma) is (%d, %.2f\n", (int) histogram->nums->n, sigma);1872 psTrace(TRACE, 5, "(histogram->nums->n, sigma) is (%d, %.2f\n", (int)histogram->nums->n, sigma); 1671 1873 PS_ASSERT_PTR_NON_NULL(histogram, NULL); 1672 1874 PS_ASSERT_PTR_NON_NULL(histogram->bounds, NULL); 1673 1875 PS_ASSERT_PTR_NON_NULL(histogram->nums, NULL); 1674 if (psTraceGetLevel("psLib.math") >= 8) { 1876 if (psTraceGetLevel("psLib.math") >= 8) 1877 { 1675 1878 PS_VECTOR_PRINT_F32(histogram->nums); 1676 1879 } 1677 1880 1678 long numBins = histogram->nums->n; // Number of histogram bins1881 long numBins = histogram->nums->n; // Number of histogram bins 1679 1882 psVector *smooth = psVectorAlloc(numBins, PS_TYPE_F32); // Smoothed version of histogram bins 1680 const psVector *bounds = histogram->bounds; // The bounds for the histogram bins 1681 1682 if (!histogram->uniform) { 1883 const psVector *bounds = histogram->bounds; // The bounds for the histogram bins 1884 1885 if (!histogram->uniform) 1886 { 1683 1887 // 1684 1888 // We get here if the histogram is non-uniform. This code is not tested. … … 1688 1892 "histograms has not been tested or used.\n"); 1689 1893 1690 for (long i = 0; i < numBins; i++) { 1894 for (long i = 0; i < numBins; i++) 1895 { 1691 1896 // Determine the midpoint of bin i. 1692 1897 float iMid = PS_BIN_MIDPOINT(histogram, i); … … 1708 1913 // 1709 1914 smooth->data.F32[i] = 0.0; 1710 for (long j = jMin ; j <= jMax ; j++) { 1915 for (long j = jMin; j <= jMax; j++) 1916 { 1711 1917 float jMid = PS_BIN_MIDPOINT(histogram, j); 1712 1918 smooth->data.F32[i] += … … 1714 1920 } 1715 1921 } 1716 } else { 1922 } 1923 else 1924 { 1717 1925 // 1718 1926 // We get here if the histogram is uniform. 1719 1927 // 1720 for (long i = 0; i < numBins; i++) { 1928 for (long i = 0; i < numBins; i++) 1929 { 1721 1930 psF32 binSize = bounds->data.F32[1] - bounds->data.F32[0]; 1722 1931 psS32 gaussWidth = ((PS_GAUSS_WIDTH * sigma) / binSize); … … 1745 1954 smooth->data.F32[i] = 0.0; 1746 1955 float iMid = PS_BIN_MIDPOINT(histogram, i); 1747 for (long j = jMin ; j <= jMax ; j++) { 1956 for (long j = jMin; j <= jMax; j++) 1957 { 1748 1958 float jMid = PS_BIN_MIDPOINT(histogram, j); 1749 1959 smooth->data.F32[i] += … … 1753 1963 } 1754 1964 1755 if (psTraceGetLevel("psLib.math") >= 8) { 1965 if (psTraceGetLevel("psLib.math") >= 8) 1966 { 1756 1967 PS_VECTOR_PRINT_F32(smooth); 1757 1968 } 1758 1969 psTrace(TRACE, 4, "---- %s() end ----\n", __func__); 1759 return (smooth);1970 return (smooth); 1760 1971 } 1761 1972 … … 1769 1980 static void statsFree(psStats *stats) 1770 1981 { 1771 if (!stats) return; 1772 psFree (stats->tmpData); 1773 psFree (stats->tmpMask); 1982 if (!stats) 1983 return; 1984 psFree(stats->tmpData); 1985 psFree(stats->tmpMask); 1774 1986 return; 1775 1987 } … … 1778 1990 psStatsAlloc(): This routine must create a new psStats data structure. 1779 1991 *****************************************************************************/ 1780 psStats *p_psStatsAlloc(const char *file, unsigned int lineno, const char *func, psStatsOptions options)1992 psStats *p_psStatsAlloc(const char *file, unsigned int lineno, const char *func, psStatsOptions options) 1781 1993 { 1782 1994 psStats *stats = p_psAlloc(file, lineno, func, sizeof(psStats)); … … 1784 1996 1785 1997 // set initial, default values 1786 psStatsInit (stats);1998 psStatsInit(stats); 1787 1999 1788 2000 // these values are can be set as desired by the user. they are not affected by … … 1818 2030 stats->clippedMean = NAN; 1819 2031 stats->clippedStdev = NAN; 1820 stats->clippedNvalues = -1; // XXX: This is never used2032 stats->clippedNvalues = -1; // XXX: This is never used 1821 2033 stats->min = NAN; 1822 2034 stats->max = NAN; … … 1825 2037 } 1826 2038 1827 1828 2039 bool psMemCheckStats(psPtr ptr) 1829 2040 { 1830 2041 PS_ASSERT_PTR(ptr, false); 1831 return ( psMemGetDeallocator(ptr) == (psFreeFunc)statsFree);2042 return (psMemGetDeallocator(ptr) == (psFreeFunc)statsFree); 1832 2043 } 1833 2044 … … 1847 2058 XXX: Should we free stats if the asserts fail? NO; we don't own it (RHL). 1848 2059 *****************************************************************************/ 1849 bool psVectorStats(psStats *stats,1850 const psVector *in,1851 const psVector *errors,1852 const psVector *mask,2060 bool psVectorStats(psStats *stats, 2061 const psVector *in, 2062 const psVector *errors, 2063 const psVector *mask, 1853 2064 psVectorMaskType maskVal) 1854 2065 { … … 1856 2067 PS_ASSERT_VECTOR_NON_NULL(in, false); 1857 2068 PS_ASSERT_VECTOR_NON_EMPTY(in, false); 1858 if (mask) { 2069 if (mask) 2070 { 1859 2071 PS_ASSERT_VECTORS_SIZE_EQUAL(mask, in, false); 1860 2072 PS_ASSERT_VECTOR_TYPE(mask, PS_TYPE_VECTOR_MASK, false); 1861 2073 } 1862 if (errors) { 2074 if (errors) 2075 { 1863 2076 PS_ASSERT_VECTORS_SIZE_EQUAL(errors, in, false); 1864 2077 PS_ASSERT_VECTOR_TYPE(errors, in->type.type, false); … … 1866 2079 1867 2080 // Convert types, as necessary 1868 psVector *inF32 = NULL; // Input vector of values, F32 version 1869 if (in->type.type == PS_TYPE_F32) { 2081 psVector *inF32 = NULL; // Input vector of values, F32 version 2082 if (in->type.type == PS_TYPE_F32) 2083 { 1870 2084 inF32 = psMemIncrRefCounter((psPtr)in); 1871 } else { 2085 } 2086 else 2087 { 1872 2088 inF32 = psVectorCopy(NULL, in, PS_TYPE_F32); 1873 2089 } 1874 psVector *errorsF32 = NULL; // Input vector of errors, F32 version 1875 if (errors) { 1876 if (errors->type.type == PS_TYPE_F32) { 2090 psVector *errorsF32 = NULL; // Input vector of errors, F32 version 2091 if (errors) 2092 { 2093 if (errors->type.type == PS_TYPE_F32) 2094 { 1877 2095 errorsF32 = psMemIncrRefCounter((psPtr)errors); 1878 } else { 2096 } 2097 else 2098 { 1879 2099 errorsF32 = psVectorCopy(NULL, errors, PS_TYPE_F32); 1880 2100 } 1881 2101 } 1882 psVector *maskVector = NULL; // Input mask vector, U8 version 1883 if (mask) { 1884 if (mask->type.type == PS_TYPE_VECTOR_MASK) { 2102 psVector *maskVector = NULL; // Input mask vector, U8 version 2103 if (mask) 2104 { 2105 if (mask->type.type == PS_TYPE_VECTOR_MASK) 2106 { 1885 2107 maskVector = psMemIncrRefCounter((psPtr)mask); 1886 } else { 2108 } 2109 else 2110 { 1887 2111 maskVector = psVectorCopy(NULL, mask, PS_TYPE_VECTOR_MASK); 1888 2112 } 1889 2113 } 1890 2114 1891 if ((stats->options & PS_STAT_USE_RANGE) && (stats->min >= stats->max)) { 2115 if ((stats->options & PS_STAT_USE_RANGE) && (stats->min >= stats->max)) 2116 { 1892 2117 PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(stats->max, stats->min, false); 1893 2118 } 1894 2119 1895 if ((stats->options & PS_STAT_USE_BINSIZE) && (stats->min >= stats->max)) { 2120 if ((stats->options & PS_STAT_USE_BINSIZE) && (stats->min >= stats->max)) 2121 { 1896 2122 PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(stats->binsize, 0.0, false); 1897 2123 } … … 1903 2129 1904 2130 // ************************************************************************ 1905 if (stats->options & PS_STAT_SAMPLE_MEAN) { 1906 // NOTE: vectorSampleMean cannot return 'false' 1907 if (!vectorSampleMean(inF32, errorsF32, maskVector, maskVal, stats)) { 2131 if (stats->options & PS_STAT_SAMPLE_MEAN) 2132 { 2133 // NOTE: vectorSampleMean cannot return 'false' 2134 if (!vectorSampleMean(inF32, errorsF32, maskVector, maskVal, stats)) 2135 { 1908 2136 psError(PS_ERR_UNKNOWN, false, "Failed to calculate vector sample mean"); 1909 2137 status &= false; … … 1912 2140 1913 2141 // ************************************************************************ 1914 if (stats->options & (PS_STAT_SAMPLE_MEDIAN | PS_STAT_SAMPLE_QUARTILE)) { 1915 // NOTE: vectorSampleMedian only returns 'false' for very bad cases: 1916 // NULL input vector, psVectorCopy failure, invalid vector type (likely programming errors) 1917 if (!vectorSampleMedian(inF32, maskVector, maskVal, stats)) { 1918 psError(PS_ERR_UNKNOWN, false, "Failed to calculate sample median"); 1919 status &= false; 1920 } 2142 if (stats->options & (PS_STAT_SAMPLE_MEDIAN | PS_STAT_SAMPLE_QUARTILE)) 2143 { 2144 // NOTE: vectorSampleMedian only returns 'false' for very bad cases: 2145 // NULL input vector, psVectorCopy failure, invalid vector type (likely programming errors) 2146 if (!vectorSampleMedian(inF32, maskVector, maskVal, stats)) 2147 { 2148 psError(PS_ERR_UNKNOWN, false, "Failed to calculate sample median"); 2149 status &= false; 2150 } 1921 2151 } 1922 2152 1923 2153 // ************************************************************************ 1924 if (stats->options & PS_STAT_SAMPLE_STDEV) { 1925 // NOTE: vectorSampleStdev cannot return 'false' 1926 if (!vectorSampleStdev(inF32, errorsF32, maskVector, maskVal, stats)) { 2154 if (stats->options & PS_STAT_SAMPLE_STDEV) 2155 { 2156 // NOTE: vectorSampleStdev cannot return 'false' 2157 if (!vectorSampleStdev(inF32, errorsF32, maskVector, maskVal, stats)) 2158 { 1927 2159 psError(PS_ERR_UNKNOWN, false, "Failed to calculate sample stdev"); 1928 2160 status &= false; … … 1930 2162 } 1931 2163 1932 if (stats->options & (PS_STAT_SAMPLE_SKEWNESS | PS_STAT_SAMPLE_KURTOSIS)) { 1933 // NOTE: vectorSampleMoments cannot return 'false' 1934 if (!vectorSampleMoments(inF32, maskVector, maskVal, stats)) { 2164 if (stats->options & (PS_STAT_SAMPLE_SKEWNESS | PS_STAT_SAMPLE_KURTOSIS)) 2165 { 2166 // NOTE: vectorSampleMoments cannot return 'false' 2167 if (!vectorSampleMoments(inF32, maskVector, maskVal, stats)) 2168 { 1935 2169 psError(PS_ERR_UNKNOWN, false, "Failed to calculate sample moments"); 1936 2170 status &= false; … … 1939 2173 1940 2174 // ************************************************************************ 1941 if (stats->options & (PS_STAT_MAX | PS_STAT_MIN)) { 1942 // NOTE: vectorMinMax returns 0 if there are no valid values, 1943 // but this is not an error condition. stats.min,max are set to NAN. 1944 // vectorMinMax cannot raise an error 2175 if (stats->options & (PS_STAT_MAX | PS_STAT_MIN)) 2176 { 2177 // NOTE: vectorMinMax returns 0 if there are no valid values, 2178 // but this is not an error condition. stats.min,max are set to NAN. 2179 // vectorMinMax cannot raise an error 1945 2180 vectorMinMax(inF32, maskVector, maskVal, stats); 1946 2181 } 1947 2182 1948 2183 // ************************************************************************ 1949 if (stats->options & (PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV | PS_STAT_ROBUST_QUARTILE)) { 1950 if (!vectorRobustStats(inF32, errorsF32, maskVector, maskVal, stats)) { 2184 if (stats->options & (PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV | PS_STAT_ROBUST_QUARTILE)) 2185 { 2186 if (!vectorRobustStats(inF32, errorsF32, maskVector, maskVal, stats)) 2187 { 1951 2188 psError(PS_ERR_UNKNOWN, false, _("Failed to calculate robust statistics")); 1952 2189 status &= false; … … 1955 2192 1956 2193 // ************************************************************************ 1957 if (stats->options & (PS_STAT_FITTED_MEAN | PS_STAT_FITTED_STDEV)) { 1958 if (!vectorFittedStats(inF32, errorsF32, maskVector, maskVal, stats)) { 2194 if (stats->options & (PS_STAT_FITTED_MEAN | PS_STAT_FITTED_STDEV)) 2195 { 2196 if (!vectorFittedStats(inF32, errorsF32, maskVector, maskVal, stats)) 2197 { 1959 2198 psError(PS_ERR_UNKNOWN, false, _("Failed to calculate fitted statistics")); 1960 2199 status &= false; … … 1963 2202 1964 2203 // ************************************************************************ 1965 if ((stats->options & PS_STAT_CLIPPED_MEAN) || (stats->options & PS_STAT_CLIPPED_STDEV)) { 1966 if (!vectorClippedStats(inF32, errorsF32, maskVector, maskVal, stats)) { 2204 if ((stats->options & PS_STAT_CLIPPED_MEAN) || (stats->options & PS_STAT_CLIPPED_MEDIAN) || (stats->options & PS_STAT_CLIPPED_STDEV)) 2205 { 2206 if (!vectorClippedStats(inF32, errorsF32, maskVector, maskVal, stats)) 2207 { 1967 2208 psError(PS_ERR_UNKNOWN, false, "Failed to calculate clipped statistics\n"); 1968 2209 status &= false; … … 1980 2221 PS_ASSERT_STRING_NON_EMPTY(string, PS_STAT_NONE); 1981 2222 1982 #define READ_STAT(NAME, SYMBOL) \ 1983 if (strcasecmp(string, NAME) == 0) { \ 1984 return SYMBOL; \ 1985 } 1986 1987 READ_STAT("MEAN", PS_STAT_SAMPLE_MEAN); 1988 READ_STAT("STDEV", PS_STAT_SAMPLE_STDEV); 1989 READ_STAT("SKEWNESS", PS_STAT_SAMPLE_SKEWNESS); 1990 READ_STAT("KURTOSIS", PS_STAT_SAMPLE_KURTOSIS); 1991 READ_STAT("MEDIAN", PS_STAT_SAMPLE_MEDIAN); 1992 READ_STAT("QUARTILE", PS_STAT_SAMPLE_QUARTILE); 1993 READ_STAT("SAMPLE_MEAN", PS_STAT_SAMPLE_MEAN); 1994 READ_STAT("SAMPLE_STDEV", PS_STAT_SAMPLE_STDEV); 1995 READ_STAT("SAMPLE_MEDIAN", PS_STAT_SAMPLE_MEDIAN); 2223 #define READ_STAT(NAME, SYMBOL) \ 2224 if (strcasecmp(string, NAME) == 0) \ 2225 { \ 2226 return SYMBOL; \ 2227 } 2228 2229 READ_STAT("MEAN", PS_STAT_SAMPLE_MEAN); 2230 READ_STAT("STDEV", PS_STAT_SAMPLE_STDEV); 2231 READ_STAT("SKEWNESS", PS_STAT_SAMPLE_SKEWNESS); 2232 READ_STAT("KURTOSIS", PS_STAT_SAMPLE_KURTOSIS); 2233 READ_STAT("MEDIAN", PS_STAT_SAMPLE_MEDIAN); 2234 READ_STAT("QUARTILE", PS_STAT_SAMPLE_QUARTILE); 2235 READ_STAT("SAMPLE_MEAN", PS_STAT_SAMPLE_MEAN); 2236 READ_STAT("SAMPLE_STDEV", PS_STAT_SAMPLE_STDEV); 2237 READ_STAT("SAMPLE_MEDIAN", PS_STAT_SAMPLE_MEDIAN); 1996 2238 READ_STAT("SAMPLE_QUARTILE", PS_STAT_SAMPLE_QUARTILE); 1997 2239 READ_STAT("SAMPLE_SKEWNESS", PS_STAT_SAMPLE_SKEWNESS); 1998 2240 READ_STAT("SAMPLE_KURTOSIS", PS_STAT_SAMPLE_KURTOSIS); 1999 READ_STAT("ROBUST", PS_STAT_ROBUST_MEDIAN);2000 READ_STAT("ROBUST_MEDIAN", PS_STAT_ROBUST_MEDIAN);2001 READ_STAT("ROBUST_STDEV", PS_STAT_ROBUST_STDEV);2241 READ_STAT("ROBUST", PS_STAT_ROBUST_MEDIAN); 2242 READ_STAT("ROBUST_MEDIAN", PS_STAT_ROBUST_MEDIAN); 2243 READ_STAT("ROBUST_STDEV", PS_STAT_ROBUST_STDEV); 2002 2244 READ_STAT("ROBUST_QUARTILE", PS_STAT_ROBUST_QUARTILE); 2003 READ_STAT("FITTED", PS_STAT_FITTED_MEAN);2004 READ_STAT("FITTED_MEAN", PS_STAT_FITTED_MEAN);2005 READ_STAT("FITTED_STDEV", PS_STAT_FITTED_STDEV);2006 READ_STAT("FITTED_V2", PS_STAT_FITTED_MEAN);2007 READ_STAT("FITTED_MEAN_V2", PS_STAT_FITTED_MEAN);2245 READ_STAT("FITTED", PS_STAT_FITTED_MEAN); 2246 READ_STAT("FITTED_MEAN", PS_STAT_FITTED_MEAN); 2247 READ_STAT("FITTED_STDEV", PS_STAT_FITTED_STDEV); 2248 READ_STAT("FITTED_V2", PS_STAT_FITTED_MEAN); 2249 READ_STAT("FITTED_MEAN_V2", PS_STAT_FITTED_MEAN); 2008 2250 READ_STAT("FITTED_STDEV_V2", PS_STAT_FITTED_STDEV); 2009 READ_STAT("FITTED_V3", PS_STAT_FITTED_MEAN);2010 READ_STAT("FITTED_MEAN_V3", PS_STAT_FITTED_MEAN);2251 READ_STAT("FITTED_V3", PS_STAT_FITTED_MEAN); 2252 READ_STAT("FITTED_MEAN_V3", PS_STAT_FITTED_MEAN); 2011 2253 READ_STAT("FITTED_STDEV_V3", PS_STAT_FITTED_STDEV); 2012 READ_STAT("FITTED_V4", PS_STAT_FITTED_MEAN);2013 READ_STAT("FITTED_MEAN_V4", PS_STAT_FITTED_MEAN);2254 READ_STAT("FITTED_V4", PS_STAT_FITTED_MEAN); 2255 READ_STAT("FITTED_MEAN_V4", PS_STAT_FITTED_MEAN); 2014 2256 READ_STAT("FITTED_STDEV_V4", PS_STAT_FITTED_STDEV); 2015 READ_STAT("CLIPPED", PS_STAT_CLIPPED_MEAN); 2016 READ_STAT("CLIPPED_MEAN", PS_STAT_CLIPPED_MEAN); 2017 READ_STAT("CLIPPED_STDEV", PS_STAT_CLIPPED_STDEV); 2257 READ_STAT("CLIPPED", PS_STAT_CLIPPED_MEAN); 2258 READ_STAT("CLIPPED_MEAN", PS_STAT_CLIPPED_MEAN); 2259 READ_STAT("CLIPPED_MEDIAN", PS_STAT_CLIPPED_MEDIAN); 2260 READ_STAT("CLIPPED_STDEV", PS_STAT_CLIPPED_STDEV); 2018 2261 2019 2262 psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Unable to parse statistic: %s\n", string); … … 2023 2266 psString psStatsOptionToString(psStatsOptions option) 2024 2267 { 2025 psString string = NULL; // String to return 2026 2027 #define WRITE_STAT(NAME, SYMBOL) \ 2028 if (option & SYMBOL) { \ 2268 psString string = NULL; // String to return 2269 2270 #define WRITE_STAT(NAME, SYMBOL) \ 2271 if (option & SYMBOL) \ 2272 { \ 2029 2273 psStringAppend(&string, "%s ", NAME); \ 2030 2274 } 2031 2275 2032 2276 // Same list as above (for psStatsFromString), but with repeat symbols removed 2033 WRITE_STAT("SAMPLE_MEAN", PS_STAT_SAMPLE_MEAN);2034 WRITE_STAT("SAMPLE_STDEV", PS_STAT_SAMPLE_STDEV);2035 WRITE_STAT("SAMPLE_MEDIAN", PS_STAT_SAMPLE_MEDIAN);2277 WRITE_STAT("SAMPLE_MEAN", PS_STAT_SAMPLE_MEAN); 2278 WRITE_STAT("SAMPLE_STDEV", PS_STAT_SAMPLE_STDEV); 2279 WRITE_STAT("SAMPLE_MEDIAN", PS_STAT_SAMPLE_MEDIAN); 2036 2280 WRITE_STAT("SAMPLE_QUARTILE", PS_STAT_SAMPLE_QUARTILE); 2037 2281 WRITE_STAT("SAMPLE_SKEWNESS", PS_STAT_SAMPLE_SKEWNESS); 2038 2282 WRITE_STAT("SAMPLE_KURTOSIS", PS_STAT_SAMPLE_KURTOSIS); 2039 WRITE_STAT("ROBUST_MEDIAN", PS_STAT_ROBUST_MEDIAN);2040 WRITE_STAT("ROBUST_STDEV", PS_STAT_ROBUST_STDEV);2283 WRITE_STAT("ROBUST_MEDIAN", PS_STAT_ROBUST_MEDIAN); 2284 WRITE_STAT("ROBUST_STDEV", PS_STAT_ROBUST_STDEV); 2041 2285 WRITE_STAT("ROBUST_QUARTILE", PS_STAT_ROBUST_QUARTILE); 2042 WRITE_STAT("FITTED_MEAN", PS_STAT_FITTED_MEAN); 2043 WRITE_STAT("FITTED_STDEV", PS_STAT_FITTED_STDEV); 2044 WRITE_STAT("CLIPPED_MEAN", PS_STAT_CLIPPED_MEAN); 2045 WRITE_STAT("CLIPPED_STDEV", PS_STAT_CLIPPED_STDEV); 2286 WRITE_STAT("FITTED_MEAN", PS_STAT_FITTED_MEAN); 2287 WRITE_STAT("FITTED_STDEV", PS_STAT_FITTED_STDEV); 2288 WRITE_STAT("CLIPPED_MEAN", PS_STAT_CLIPPED_MEAN); 2289 WRITE_STAT("CLIPPED_MEDIAN", PS_STAT_CLIPPED_MEDIAN); 2290 WRITE_STAT("CLIPPED_STDEV", PS_STAT_CLIPPED_STDEV); 2046 2291 2047 2292 return string; … … 2051 2296 { 2052 2297 psList *subStrings = psStringSplit(string, " ,;", false); // List of sub-strings 2053 if (!subStrings || psListLength(subStrings) == 0) { 2298 if (!subStrings || psListLength(subStrings) == 0) 2299 { 2054 2300 // Nothing here 2055 2301 psError(PS_ERR_BAD_PARAMETER_VALUE, false, "No string to parse for statistics: %s\n", string); … … 2057 2303 return NULL; 2058 2304 } 2059 psStats *stats = psStatsAlloc(0); // Generate empty stats structure2305 psStats *stats = psStatsAlloc(0); // Generate empty stats structure 2060 2306 psListIterator *iterator = psListIteratorAlloc(subStrings, PS_LIST_HEAD, false); // Iterator 2061 psString statString; // Statistic string, from iteration 2062 while ((statString = psListGetAndIncrement(iterator))) { 2307 psString statString; // Statistic string, from iteration 2308 while ((statString = psListGetAndIncrement(iterator))) 2309 { 2063 2310 psStatsOptions option = psStatsOptionFromString(statString); 2064 if (option == 0) { 2311 if (option == 0) 2312 { 2065 2313 psWarning("Unable to interpret statistic option: %s --- ignored.\n", statString); 2066 2314 continue; … … 2080 2328 psStatsOptions psStatsSingleOption(psStatsOptions option) 2081 2329 { 2082 switch (option & ~(PS_STAT_USE_RANGE | PS_STAT_USE_BINSIZE)) { 2083 case PS_STAT_SAMPLE_MEAN: 2084 case PS_STAT_SAMPLE_MEDIAN: 2085 case PS_STAT_SAMPLE_STDEV: 2086 case PS_STAT_SAMPLE_QUARTILE: 2087 case PS_STAT_SAMPLE_SKEWNESS: 2088 case PS_STAT_SAMPLE_KURTOSIS: 2089 case PS_STAT_ROBUST_MEDIAN: 2090 case PS_STAT_ROBUST_STDEV: 2091 case PS_STAT_ROBUST_QUARTILE: 2092 case PS_STAT_FITTED_MEAN: 2093 case PS_STAT_FITTED_STDEV: 2094 case PS_STAT_CLIPPED_MEAN: 2095 case PS_STAT_CLIPPED_STDEV: 2096 case PS_STAT_MAX: 2097 case PS_STAT_MIN: 2330 switch (option & ~(PS_STAT_USE_RANGE | PS_STAT_USE_BINSIZE)) 2331 { 2332 case PS_STAT_SAMPLE_MEAN: 2333 case PS_STAT_SAMPLE_MEDIAN: 2334 case PS_STAT_SAMPLE_STDEV: 2335 case PS_STAT_SAMPLE_QUARTILE: 2336 case PS_STAT_SAMPLE_SKEWNESS: 2337 case PS_STAT_SAMPLE_KURTOSIS: 2338 case PS_STAT_ROBUST_MEDIAN: 2339 case PS_STAT_ROBUST_STDEV: 2340 case PS_STAT_ROBUST_QUARTILE: 2341 case PS_STAT_FITTED_MEAN: 2342 case PS_STAT_FITTED_STDEV: 2343 case PS_STAT_CLIPPED_MEAN: 2344 case PS_STAT_CLIPPED_MEDIAN: 2345 case PS_STAT_CLIPPED_STDEV: 2346 case PS_STAT_MAX: 2347 case PS_STAT_MIN: 2098 2348 return option & ~(PS_STAT_USE_RANGE | PS_STAT_USE_BINSIZE); 2099 default:2349 default: 2100 2350 return 0; 2101 2351 } … … 2107 2357 { 2108 2358 return options & (PS_STAT_SAMPLE_MEAN | PS_STAT_SAMPLE_MEDIAN | PS_STAT_ROBUST_MEDIAN | 2109 PS_STAT_CLIPPED_MEAN | PS_STAT_ FITTED_MEAN);2359 PS_STAT_CLIPPED_MEAN | PS_STAT_CLIPPED_MEDIAN | PS_STAT_FITTED_MEAN); 2110 2360 } 2111 2361 … … 2116 2366 } 2117 2367 2118 2119 2368 double psStatsGetValue(const psStats *stats, psStatsOptions option) 2120 2369 { 2121 2370 // We could call psStatsSingle to check, but it would be a waste since we effectively do it anyway 2122 switch (option & ~(PS_STAT_USE_RANGE | PS_STAT_USE_BINSIZE)) { 2123 case PS_STAT_SAMPLE_MEAN: 2371 switch (option & ~(PS_STAT_USE_RANGE | PS_STAT_USE_BINSIZE)) 2372 { 2373 case PS_STAT_SAMPLE_MEAN: 2124 2374 return stats->sampleMean; 2125 case PS_STAT_SAMPLE_MEDIAN:2375 case PS_STAT_SAMPLE_MEDIAN: 2126 2376 return stats->sampleMedian; 2127 case PS_STAT_SAMPLE_STDEV:2377 case PS_STAT_SAMPLE_STDEV: 2128 2378 return stats->sampleStdev; 2129 case PS_STAT_SAMPLE_SKEWNESS:2379 case PS_STAT_SAMPLE_SKEWNESS: 2130 2380 return stats->sampleSkewness; 2131 case PS_STAT_SAMPLE_KURTOSIS:2381 case PS_STAT_SAMPLE_KURTOSIS: 2132 2382 return stats->sampleKurtosis; 2133 case PS_STAT_ROBUST_MEDIAN:2383 case PS_STAT_ROBUST_MEDIAN: 2134 2384 return stats->robustMedian; 2135 case PS_STAT_ROBUST_STDEV:2385 case PS_STAT_ROBUST_STDEV: 2136 2386 return stats->robustStdev; 2137 case PS_STAT_FITTED_MEAN:2387 case PS_STAT_FITTED_MEAN: 2138 2388 return stats->fittedMean; 2139 case PS_STAT_FITTED_STDEV:2389 case PS_STAT_FITTED_STDEV: 2140 2390 return stats->fittedStdev; 2141 case PS_STAT_CLIPPED_MEAN:2391 case PS_STAT_CLIPPED_MEAN: 2142 2392 return stats->clippedMean; 2143 case PS_STAT_CLIPPED_STDEV: 2393 case PS_STAT_CLIPPED_MEDIAN: 2394 return stats->clippedMedian; 2395 case PS_STAT_CLIPPED_STDEV: 2144 2396 return stats->clippedStdev; 2145 case PS_STAT_MAX:2397 case PS_STAT_MAX: 2146 2398 return stats->max; 2147 case PS_STAT_MIN:2399 case PS_STAT_MIN: 2148 2400 return stats->min; 2149 case PS_STAT_SAMPLE_QUARTILE:2150 case PS_STAT_ROBUST_QUARTILE:2401 case PS_STAT_SAMPLE_QUARTILE: 2402 case PS_STAT_ROBUST_QUARTILE: 2151 2403 psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Cannot return a single quartile value; " 2152 "get them yourself.\n");2404 "get them yourself.\n"); 2153 2405 return NAN; 2154 default:2406 default: 2155 2407 return NAN; 2156 2408 } … … 2161 2413 // other private functions used above 2162 2414 2163 # if (0)2415 #if (0) 2164 2416 static psF32 QuadraticInverse(psF32 a, 2165 2417 psF32 b, … … 2167 2419 psF32 y, 2168 2420 psF32 xLo, 2169 psF32 xHi 2170 ) 2421 psF32 xHi) 2171 2422 { 2172 psF64 tmp = sqrt((y - c)/a + (b*b)/(4.0 * a * a)); 2173 2174 psF64 x1 = -b/(2.0*a) + tmp; 2175 psF64 x2 = -b/(2.0*a) - tmp; 2176 2177 if (xLo <= x1 && x1 <= xHi) { 2423 psF64 tmp = sqrt((y - c) / a + (b * b) / (4.0 * a * a)); 2424 2425 psF64 x1 = -b / (2.0 * a) + tmp; 2426 psF64 x2 = -b / (2.0 * a) - tmp; 2427 2428 if (xLo <= x1 && x1 <= xHi) 2429 { 2178 2430 return x1; 2179 2431 } 2180 if (xLo <= x2 && x2 <= xHi) { 2432 if (xLo <= x2 && x2 <= xHi) 2433 { 2181 2434 return x2; 2182 2435 } … … 2185 2438 2186 2439 static psF32 LinearInverse(psF32 a, 2187 psF32 b, 2188 psF32 y, 2189 psF32 xLo, 2190 psF32 xHi 2191 ) 2440 psF32 b, 2441 psF32 y, 2442 psF32 xLo, 2443 psF32 xHi) 2192 2444 { 2193 2445 psF64 x = (y - b) / a; 2194 2446 2195 if (xLo <= x && x <= xHi) { 2447 if (xLo <= x && x <= xHi) 2448 { 2196 2449 return x; 2197 2450 } 2198 2451 return 0.5 * (xLo + xHi); 2199 2452 } 2200 # endif2201 2202 # if (0)2453 #endif 2454 2455 #if (0) 2203 2456 /****************************************************************************** 2204 2457 fitQuadraticSearchForYThenReturnX(*xVec, *yVec, binNum, yVal): A general … … 2214 2467 psVector *yVec, 2215 2468 psS32 binNum, 2216 psF32 yVal 2217 ) 2469 psF32 yVal) 2218 2470 { 2219 2471 psTrace(TRACE, 4, "---- %s() begin ----\n", __func__); 2220 2472 psTrace(TRACE, 5, "binNum, yVal is (%d, %f)\n", binNum, yVal); 2221 if (psTraceGetLevel("psLib.math") >= 8) { 2473 if (psTraceGetLevel("psLib.math") >= 8) 2474 { 2222 2475 PS_VECTOR_PRINT_F32(xVec); 2223 2476 PS_VECTOR_PRINT_F32(yVec); … … 2236 2489 psF32 tmpFloat = 0.0f; 2237 2490 2238 if ((binNum >= 1) && (binNum < (yVec->n - 2)) && (binNum < (xVec->n - 2))) { 2491 if ((binNum >= 1) && (binNum < (yVec->n - 2)) && (binNum < (xVec->n - 2))) 2492 { 2239 2493 // The general case. We have all three points. 2240 x->data.F64[0] = (psF64) (0.5 * (xVec->data.F32[binNum - 1] + xVec->data.F32[binNum]));2241 x->data.F64[1] = (psF64) (0.5 * (xVec->data.F32[binNum] + xVec->data.F32[binNum+1]));2242 x->data.F64[2] = (psF64) (0.5 * (xVec->data.F32[binNum+1] + xVec->data.F32[binNum+2]));2494 x->data.F64[0] = (psF64)(0.5 * (xVec->data.F32[binNum - 1] + xVec->data.F32[binNum])); 2495 x->data.F64[1] = (psF64)(0.5 * (xVec->data.F32[binNum] + xVec->data.F32[binNum + 1])); 2496 x->data.F64[2] = (psF64)(0.5 * (xVec->data.F32[binNum + 1] + xVec->data.F32[binNum + 2])); 2243 2497 y->data.F64[0] = yVec->data.F32[binNum - 1]; 2244 2498 y->data.F64[1] = yVec->data.F32[binNum]; 2245 2499 y->data.F64[2] = yVec->data.F32[binNum + 1]; 2246 2500 psTrace(TRACE, 6, "x vec (orig) is (%f %f %f %f)\n", xVec->data.F32[binNum - 1], 2247 xVec->data.F32[binNum], xVec->data.F32[binNum +1], xVec->data.F32[binNum+2]);2501 xVec->data.F32[binNum], xVec->data.F32[binNum + 1], xVec->data.F32[binNum + 2]); 2248 2502 psTrace(TRACE, 6, "x data is (%f %f %f)\n", x->data.F64[0], x->data.F64[1], x->data.F64[2]); 2249 2503 psTrace(TRACE, 6, "y data is (%f %f %f)\n", y->data.F64[0], y->data.F64[1], y->data.F64[2]); … … 2252 2506 // Ensure that the y value lies within range of the y values. 2253 2507 // 2254 if (! (((y->data.F64[0] <= yVal) && (yVal <= y->data.F64[2])) || 2255 ((y->data.F64[2] <= yVal) && (yVal <= y->data.F64[0]))) ) { 2508 if (!(((y->data.F64[0] <= yVal) && (yVal <= y->data.F64[2])) || 2509 ((y->data.F64[2] <= yVal) && (yVal <= y->data.F64[0])))) 2510 { 2256 2511 psError(PS_ERR_BAD_PARAMETER_VALUE, true, 2257 2512 _("Specified yVal, %g, is not within y-range, %g to %g."), … … 2263 2518 // 2264 2519 if (((y->data.F64[0] < y->data.F64[1]) && !(y->data.F64[1] <= y->data.F64[2])) || 2265 ((y->data.F64[0] > y->data.F64[1]) && !(y->data.F64[1] >= y->data.F64[2]))) { 2520 ((y->data.F64[0] > y->data.F64[1]) && !(y->data.F64[1] >= y->data.F64[2]))) 2521 { 2266 2522 psError(PS_ERR_UNKNOWN, true, 2267 2523 "This routine must be called with monotonically increasing or decreasing data points.\n"); … … 2274 2530 // Determine the coefficients of the polynomial. 2275 2531 psPolynomial1D *myPoly = psPolynomial1DAlloc(PS_POLYNOMIAL_ORD, 2); 2276 if (!psVectorFitPolynomial1D(myPoly, NULL, 0, y, NULL, x)) { 2532 if (!psVectorFitPolynomial1D(myPoly, NULL, 0, y, NULL, x)) 2533 { 2277 2534 psError(PS_ERR_UNEXPECTED_NULL, false, 2278 2535 _("Failed to fit a 1-dimensional polynomial to the three specified data points. " … … 2287 2544 psTrace(TRACE, 6, "myPoly->coeff[2] is %f\n", myPoly->coeff[2]); 2288 2545 psTrace(TRACE, 6, "Fitted y vec is (%f %f %f)\n", 2289 (psF32) psPolynomial1DEval(myPoly, (psF64)x->data.F64[0]),2290 (psF32) psPolynomial1DEval(myPoly, (psF64)x->data.F64[1]),2291 (psF32) psPolynomial1DEval(myPoly, (psF64)x->data.F64[2]));2546 (psF32)psPolynomial1DEval(myPoly, (psF64)x->data.F64[0]), 2547 (psF32)psPolynomial1DEval(myPoly, (psF64)x->data.F64[1]), 2548 (psF32)psPolynomial1DEval(myPoly, (psF64)x->data.F64[2])); 2292 2549 2293 2550 psTrace(TRACE, 6, "We fit the polynomial, now find x such that f(x) equals %f\n", yVal); … … 2296 2553 psFree(myPoly); 2297 2554 2298 if (isnan(tmpFloat)) { 2555 if (isnan(tmpFloat)) 2556 { 2299 2557 psError(PS_ERR_UNEXPECTED_NULL, 2300 2558 false, _("Failed to determine the median of the fitted polynomial. Returning NAN.")); … … 2302 2560 psFree(y); 2303 2561 psTrace(TRACE, 5, "---- %s(NAN) end ----\n", __func__); 2304 return(NAN); 2305 } 2306 } else { 2562 return (NAN); 2563 } 2564 } 2565 else 2566 { 2307 2567 // These are special cases where the bin is at the beginning or end of the vector. 2308 if (binNum == 0) { 2568 if (binNum == 0) 2569 { 2309 2570 // We have two points only at the beginning of the vectors x and y. 2310 2571 tmpFloat = 0.5 * (xVec->data.F32[binNum] + 2311 2572 xVec->data.F32[binNum + 1]); 2312 } else if (binNum == (xVec->n - 1)) { 2573 } 2574 else if (binNum == (xVec->n - 1)) 2575 { 2313 2576 // The special case where we have two points only at the end of 2314 2577 // the vectors x and y. 2315 2578 // XXX: Is this right? 2316 2579 tmpFloat = xVec->data.F32[binNum]; 2317 } else if (binNum == (xVec->n - 2)) { 2580 } 2581 else if (binNum == (xVec->n - 2)) 2582 { 2318 2583 // XXX: Is this right? 2319 2584 tmpFloat = 0.5 * (xVec->data.F32[binNum] + xVec->data.F32[binNum + 1]); … … 2341 2606 psVector *yVec, 2342 2607 psS32 binNum, 2343 psF32 yVal 2344 ) 2608 psF32 yVal) 2345 2609 { 2346 2610 psTrace(TRACE, 4, "---- %s() begin ----\n", __func__); 2347 2611 psTrace(TRACE, 5, "binNum, yVal is (%d, %f)\n", binNum, yVal); 2348 if (psTraceGetLevel("psLib.math") >= 8) { 2612 if (psTraceGetLevel("psLib.math") >= 8) 2613 { 2349 2614 PS_VECTOR_PRINT_F32(xVec); 2350 2615 PS_VECTOR_PRINT_F32(yVec); … … 2362 2627 psF32 tmpFloat = 0.0f; 2363 2628 2364 if ((binNum >= 1) && (binNum < (yVec->n - 2)) && (binNum < (xVec->n - 2))) { 2629 if ((binNum >= 1) && (binNum < (yVec->n - 2)) && (binNum < (xVec->n - 2))) 2630 { 2365 2631 // The general case. We have all three points. 2366 2632 x->data.F64[0] = xVec->data.F32[binNum - 1]; 2367 2633 x->data.F64[1] = xVec->data.F32[binNum]; 2368 x->data.F64[2] = xVec->data.F32[binNum +1];2634 x->data.F64[2] = xVec->data.F32[binNum + 1]; 2369 2635 y->data.F64[0] = yVec->data.F32[binNum - 1]; 2370 2636 y->data.F64[1] = yVec->data.F32[binNum]; 2371 2637 y->data.F64[2] = yVec->data.F32[binNum + 1]; 2372 2638 psTrace(TRACE, 6, "x vec (orig) is (%f %f %f %f)\n", xVec->data.F32[binNum - 1], 2373 xVec->data.F32[binNum], xVec->data.F32[binNum +1], xVec->data.F32[binNum+2]);2639 xVec->data.F32[binNum], xVec->data.F32[binNum + 1], xVec->data.F32[binNum + 2]); 2374 2640 psTrace(TRACE, 6, "x data is (%f %f %f)\n", x->data.F64[0], x->data.F64[1], x->data.F64[2]); 2375 2641 psTrace(TRACE, 6, "y data is (%f %f %f)\n", y->data.F64[0], y->data.F64[1], y->data.F64[2]); … … 2378 2644 // Ensure that the y value lies within range of the y values. 2379 2645 // 2380 if (! (((y->data.F64[0] <= yVal) && (yVal <= y->data.F64[2])) || 2381 ((y->data.F64[2] <= yVal) && (yVal <= y->data.F64[0]))) ) { 2646 if (!(((y->data.F64[0] <= yVal) && (yVal <= y->data.F64[2])) || 2647 ((y->data.F64[2] <= yVal) && (yVal <= y->data.F64[0])))) 2648 { 2382 2649 psError(PS_ERR_BAD_PARAMETER_VALUE, true, 2383 2650 _("Specified yVal, %g, is not within y-range, %g to %g."), … … 2389 2656 // 2390 2657 if (((y->data.F64[0] < y->data.F64[1]) && !(y->data.F64[1] <= y->data.F64[2])) || 2391 ((y->data.F64[0] > y->data.F64[1]) && !(y->data.F64[1] >= y->data.F64[2]))) { 2658 ((y->data.F64[0] > y->data.F64[1]) && !(y->data.F64[1] >= y->data.F64[2]))) 2659 { 2392 2660 psError(PS_ERR_UNKNOWN, true, 2393 2661 "This routine must be called with monotonically increasing or decreasing data points.\n"); … … 2400 2668 // Determine the coefficients of the polynomial. 2401 2669 psPolynomial1D *myPoly = psPolynomial1DAlloc(PS_POLYNOMIAL_ORD, 2); 2402 if (!psVectorFitPolynomial1D(myPoly, NULL, 0, y, NULL, x)) { 2670 if (!psVectorFitPolynomial1D(myPoly, NULL, 0, y, NULL, x)) 2671 { 2403 2672 psError(PS_ERR_UNEXPECTED_NULL, false, 2404 2673 _("Failed to fit a 1-dimensional polynomial to the three specified data points. " … … 2413 2682 psTrace(TRACE, 6, "myPoly->coeff[2] is %f\n", myPoly->coeff[2]); 2414 2683 psTrace(TRACE, 6, "Fitted y vec is (%f %f %f)\n", 2415 (psF32) psPolynomial1DEval(myPoly, (psF64)x->data.F64[0]),2416 (psF32) psPolynomial1DEval(myPoly, (psF64)x->data.F64[1]),2417 (psF32) psPolynomial1DEval(myPoly, (psF64)x->data.F64[2]));2684 (psF32)psPolynomial1DEval(myPoly, (psF64)x->data.F64[0]), 2685 (psF32)psPolynomial1DEval(myPoly, (psF64)x->data.F64[1]), 2686 (psF32)psPolynomial1DEval(myPoly, (psF64)x->data.F64[2])); 2418 2687 2419 2688 psTrace(TRACE, 6, "We fit the polynomial, now find x such that f(x) equals %f\n", yVal); … … 2422 2691 psFree(myPoly); 2423 2692 2424 if (isnan(tmpFloat)) { 2693 if (isnan(tmpFloat)) 2694 { 2425 2695 psError(PS_ERR_UNEXPECTED_NULL, 2426 2696 false, _("Failed to determine the median of the fitted polynomial. Returning NAN.")); … … 2428 2698 psFree(y); 2429 2699 psTrace(TRACE, 5, "---- %s(NAN) end ----\n", __func__); 2430 return(NAN); 2431 } 2432 } else { 2700 return (NAN); 2701 } 2702 } 2703 else 2704 { 2433 2705 // These are special cases where the bin is at the beginning or end of the vector. 2434 if (binNum == 0) { 2706 if (binNum == 0) 2707 { 2435 2708 // We have two points only at the beginning of the vectors x and y. 2436 2709 // XXX this does not seem to be doing the linear interpolation / extrapolation 2437 2710 tmpFloat = 0.5 * (xVec->data.F32[binNum] + 2438 2711 xVec->data.F32[binNum + 1]); 2439 } else if (binNum == (xVec->n - 1)) { 2712 } 2713 else if (binNum == (xVec->n - 1)) 2714 { 2440 2715 // The special case where we have two points only at the end of 2441 2716 // the vectors x and y. 2442 2717 // XXX: Is this right? 2443 2718 tmpFloat = xVec->data.F32[binNum]; 2444 } else if (binNum == (xVec->n - 2)) { 2719 } 2720 else if (binNum == (xVec->n - 2)) 2721 { 2445 2722 // XXX: Is this right? 2446 2723 tmpFloat = 0.5 * (xVec->data.F32[binNum] + xVec->data.F32[binNum + 1]); … … 2472 2749 psVector *yVec, 2473 2750 psS32 binNum, 2474 psF32 yVal 2475 ) 2751 psF32 yVal) 2476 2752 { 2477 2753 psTrace(TRACE, 5, "binNum, yVal is (%d, %f)\n", binNum, yVal); 2478 if (psTraceGetLevel("psLib.math") >= 8) { 2754 if (psTraceGetLevel("psLib.math") >= 8) 2755 { 2479 2756 PS_VECTOR_PRINT_F32(xVec); 2480 2757 PS_VECTOR_PRINT_F32(yVec); … … 2495 2772 2496 2773 // if ((binNum >= 1) && (binNum <= (yVec->n - 2)) && (binNum <= (xVec->n - 2))) { 2497 if ((binNum >= 2) && (binNum <= (yVec->n - 3)) && (binNum <= (xVec->n - 3))) { 2774 if ((binNum >= 2) && (binNum <= (yVec->n - 3)) && (binNum <= (xVec->n - 3))) 2775 { 2498 2776 // The general case. We have all three points. 2499 // x->data.F64[0] = binNum - 1;2500 // x->data.F64[1] = binNum;2501 // x->data.F64[2] = binNum + 1;2502 x->data.F64[0] = xVec->data.F32[binNum - 2];2503 x->data.F64[1] = xVec->data.F32[binNum - 1];2504 x->data.F64[2] = xVec->data.F32[binNum + 0];2505 x->data.F64[3] = xVec->data.F32[binNum + 1];2506 x->data.F64[4] = xVec->data.F32[binNum + 2];2777 // x->data.F64[0] = binNum - 1; 2778 // x->data.F64[1] = binNum; 2779 // x->data.F64[2] = binNum + 1; 2780 x->data.F64[0] = xVec->data.F32[binNum - 2]; 2781 x->data.F64[1] = xVec->data.F32[binNum - 1]; 2782 x->data.F64[2] = xVec->data.F32[binNum + 0]; 2783 x->data.F64[3] = xVec->data.F32[binNum + 1]; 2784 x->data.F64[4] = xVec->data.F32[binNum + 2]; 2507 2785 y->data.F64[0] = yVec->data.F32[binNum - 2]; 2508 2786 y->data.F64[1] = yVec->data.F32[binNum - 1]; 2509 2787 y->data.F64[2] = yVec->data.F32[binNum + 0]; 2510 y->data.F64[3] = yVec->data.F32[binNum + 1];2511 y->data.F64[4] = yVec->data.F32[binNum + 2];2512 psTrace(TRACE, 6, "x vec (orig) is (%f %f %f %f)\n", xVec->data.F32[binNum - 1], xVec->data.F32[binNum], xVec->data.F32[binNum +1], xVec->data.F32[binNum+2]);2788 y->data.F64[3] = yVec->data.F32[binNum + 1]; 2789 y->data.F64[4] = yVec->data.F32[binNum + 2]; 2790 psTrace(TRACE, 6, "x vec (orig) is (%f %f %f %f)\n", xVec->data.F32[binNum - 1], xVec->data.F32[binNum], xVec->data.F32[binNum + 1], xVec->data.F32[binNum + 2]); 2513 2791 psTrace(TRACE, 6, "x data is (%f %f %f)\n", x->data.F64[0], x->data.F64[1], x->data.F64[2]); 2514 2792 psTrace(TRACE, 6, "y data is (%f %f %f)\n", y->data.F64[0], y->data.F64[1], y->data.F64[2]); 2515 2793 2516 2517 2794 // Ensure that the y value lies within range of the y values. 2518 if (! (((y->data.F64[0] <= yVal) && (yVal <= y->data.F64[4])) || 2519 ((y->data.F64[4] <= yVal) && (yVal <= y->data.F64[0]))) ) { 2795 if (!(((y->data.F64[0] <= yVal) && (yVal <= y->data.F64[4])) || 2796 ((y->data.F64[4] <= yVal) && (yVal <= y->data.F64[0])))) 2797 { 2520 2798 psError(PS_ERR_BAD_PARAMETER_VALUE, true, 2521 2799 _("Specified yVal, %g, is not within y-range, %g to %g."), … … 2526 2804 // Ensure that the y values are monotonic. 2527 2805 if (((y->data.F64[0] < y->data.F64[1]) && !(y->data.F64[1] <= y->data.F64[2])) || 2528 ((y->data.F64[0] > y->data.F64[1]) && !(y->data.F64[1] >= y->data.F64[2]))) { 2806 ((y->data.F64[0] > y->data.F64[1]) && !(y->data.F64[1] >= y->data.F64[2]))) 2807 { 2529 2808 psError(PS_ERR_UNKNOWN, true, 2530 2809 "This routine must be called with monotonically increasing or decreasing data points.\n"); … … 2536 2815 // Determine the coefficients of the polynomial. 2537 2816 psPolynomial1D *myPoly = psPolynomial1DAlloc(PS_POLYNOMIAL_ORD, 2); 2538 if (!psVectorFitPolynomial1D(myPoly, NULL, 0, y, NULL, x)) { 2817 if (!psVectorFitPolynomial1D(myPoly, NULL, 0, y, NULL, x)) 2818 { 2539 2819 psError(PS_ERR_UNEXPECTED_NULL, false, 2540 2820 _("Failed to fit a 1-dimensional polynomial to the three specified data points. " … … 2549 2829 psTrace(TRACE, 6, "myPoly->coeff[2] is %f\n", myPoly->coeff[2]); 2550 2830 psTrace(TRACE, 6, "Fitted y vec is (%f %f %f)\n", 2551 (psF32) psPolynomial1DEval(myPoly, (psF64)x->data.F64[0]),2552 (psF32) psPolynomial1DEval(myPoly, (psF64)x->data.F64[1]),2553 (psF32) psPolynomial1DEval(myPoly, (psF64)x->data.F64[2]));2831 (psF32)psPolynomial1DEval(myPoly, (psF64)x->data.F64[0]), 2832 (psF32)psPolynomial1DEval(myPoly, (psF64)x->data.F64[1]), 2833 (psF32)psPolynomial1DEval(myPoly, (psF64)x->data.F64[2])); 2554 2834 2555 2835 psTrace(TRACE, 6, "We fit the polynomial, now find x such that f(x) equals %f\n", yVal); … … 2557 2837 psFree(myPoly); 2558 2838 2559 if (isnan(binValue)) { 2839 if (isnan(binValue)) 2840 { 2560 2841 psError(PS_ERR_UNEXPECTED_NULL, 2561 2842 false, _("Failed to determine the median of the fitted polynomial. Returning NAN.")); 2562 2843 psFree(x); 2563 2844 psFree(y); 2564 return (NAN);2565 } 2566 2845 return (NAN); 2846 } 2847 2567 2848 // I believe that mathematically the fitted bin position must be between binNum - 1 and binNum + 1 2568 // assert (binValue >= binNum - 1); 2569 // assert (binValue <= binNum + 1); 2570 2571 // int fitBin = binValue; 2572 // float dX = xVec->data.F32[fitBin+1] - xVec->data.F32[fitBin]; 2573 // float dY = binValue - fitBin; 2574 // tmpFloat = xVec->data.F32[fitBin] + dY * dX; 2575 tmpFloat = binValue; 2576 2577 } else { 2849 // assert (binValue >= binNum - 1); 2850 // assert (binValue <= binNum + 1); 2851 2852 // int fitBin = binValue; 2853 // float dX = xVec->data.F32[fitBin+1] - xVec->data.F32[fitBin]; 2854 // float dY = binValue - fitBin; 2855 // tmpFloat = xVec->data.F32[fitBin] + dY * dX; 2856 tmpFloat = binValue; 2857 } 2858 else 2859 { 2578 2860 // These are special cases where the bin is at the beginning or end of the vector. 2579 if (binNum == 0) { 2861 if (binNum == 0) 2862 { 2580 2863 // We have two points only at the beginning of the vectors x and y. 2581 2864 // X = (dX/dY)(Y - Yo) + Xo 2582 2865 float dX = xVec->data.F32[1] - xVec->data.F32[0]; 2583 2866 float dY = yVec->data.F32[1] - yVec->data.F32[0]; 2584 if (dY == 0.0) { 2867 if (dY == 0.0) 2868 { 2585 2869 tmpFloat = xVec->data.F32[0]; 2586 } else { 2870 } 2871 else 2872 { 2587 2873 tmpFloat = (yVal - yVec->data.F32[0]) * (dX / dY) + xVec->data.F32[0]; 2588 2874 } 2589 } else if (binNum == (xVec->n - 1)) { 2875 } 2876 else if (binNum == (xVec->n - 1)) 2877 { 2590 2878 // We have two points only at the end of the vectors x and y. 2591 2879 // X = (dX/dY)(Y - Yo) + Xo 2592 float dX = xVec->data.F32[binNum] - xVec->data.F32[binNum-1]; 2593 float dY = yVec->data.F32[binNum] - yVec->data.F32[binNum-1]; 2594 if (dY == 0.0) { 2595 tmpFloat = xVec->data.F32[binNum-1]; 2596 } else { 2597 tmpFloat = (yVal - yVec->data.F32[binNum-1]) * (dX / dY) + xVec->data.F32[binNum-1]; 2880 float dX = xVec->data.F32[binNum] - xVec->data.F32[binNum - 1]; 2881 float dY = yVec->data.F32[binNum] - yVec->data.F32[binNum - 1]; 2882 if (dY == 0.0) 2883 { 2884 tmpFloat = xVec->data.F32[binNum - 1]; 2885 } 2886 else 2887 { 2888 tmpFloat = (yVal - yVec->data.F32[binNum - 1]) * (dX / dY) + xVec->data.F32[binNum - 1]; 2598 2889 } 2599 2890 } … … 2606 2897 return tmpFloat; 2607 2898 } 2608 # endif 2609 2899 #endif 2610 2900 2611 2901 /****************************************************************************** … … 2623 2913 *****************************************************************************/ 2624 2914 static psF32 fitLinearSearchForYThenReturnBin(const psVector *xVec, 2625 psVector *yVec, 2626 psS32 binNum, 2627 psF32 yVal 2628 ) 2915 psVector *yVec, 2916 psS32 binNum, 2917 psF32 yVal) 2629 2918 { 2630 2919 2631 # if (1) 2632 # define HALF_SIZE 2 2633 double Sx = 0.0; 2634 2635 double Sy = 0.0; 2636 double Sxx = 0.0; 2637 double Sxy = 0.0; 2638 double deltaY = 0.0; 2639 int N = 0; 2640 2641 for (int u = binNum - HALF_SIZE; u <= binNum + HALF_SIZE; u++) { 2642 if ((u >= 0)&&(u < yVec->n)) { 2643 if (u+1 < xVec->n) { 2644 Sx += yVec->data.F32[u]; 2645 Sxx += PS_SQR(yVec->data.F32[u]); 2646 2647 deltaY = xVec->data.F32[u]; 2648 //deltaY = 0.5 * (xVec->data.F32[u] + xVec->data.F32[u+1]); 2649 Sy += deltaY; 2650 Sxy += yVec->data.F32[u] * deltaY; 2651 N += 1; 2652 } 2653 } 2654 } 2655 double Det = N * Sxx - Sx * Sx; 2656 if (Det == 0.0) return NAN; 2657 if (N == 0) return NAN; 2658 2659 double C0 = (Sy*Sxx - Sx*Sxy) / Det; 2660 double C1 = (Sxy*N - Sx*Sy) / Det; 2661 2662 double value = C0 + yVal*C1; 2663 return value; 2664 2665 2666 # else 2920 #if (1) 2921 #define HALF_SIZE 2 2922 double Sx = 0.0; 2923 2924 double Sy = 0.0; 2925 double Sxx = 0.0; 2926 double Sxy = 0.0; 2927 double deltaY = 0.0; 2928 int N = 0; 2929 2930 for (int u = binNum - HALF_SIZE; u <= binNum + HALF_SIZE; u++) 2931 { 2932 if ((u >= 0) && (u < yVec->n)) 2933 { 2934 if (u + 1 < xVec->n) 2935 { 2936 Sx += yVec->data.F32[u]; 2937 Sxx += PS_SQR(yVec->data.F32[u]); 2938 2939 deltaY = xVec->data.F32[u]; 2940 // deltaY = 0.5 * (xVec->data.F32[u] + xVec->data.F32[u+1]); 2941 Sy += deltaY; 2942 Sxy += yVec->data.F32[u] * deltaY; 2943 N += 1; 2944 } 2945 } 2946 } 2947 double Det = N * Sxx - Sx * Sx; 2948 if (Det == 0.0) 2949 return NAN; 2950 if (N == 0) 2951 return NAN; 2952 2953 double C0 = (Sy * Sxx - Sx * Sxy) / Det; 2954 double C1 = (Sxy * N - Sx * Sy) / Det; 2955 2956 double value = C0 + yVal * C1; 2957 return value; 2958 2959 #else 2667 2960 psTrace(TRACE, 5, "binNum, yVal is (%d, %f)\n", binNum, yVal); 2668 if (psTraceGetLevel("psLib.math") >= 8) { 2961 if (psTraceGetLevel("psLib.math") >= 8) 2962 { 2669 2963 PS_VECTOR_PRINT_F32(xVec); 2670 2964 PS_VECTOR_PRINT_F32(yVec); … … 2684 2978 psF32 tmpFloat = 0.0f; 2685 2979 2686 if ((binNum >= 2) && (binNum <= (yVec->n - 3)) && (binNum <= (xVec->n - 3))) { 2687 x->data.F64[0] = xVec->data.F32[binNum - 2]; 2688 x->data.F64[1] = xVec->data.F32[binNum - 1]; 2689 x->data.F64[2] = xVec->data.F32[binNum + 0]; 2690 x->data.F64[3] = xVec->data.F32[binNum + 1]; 2691 x->data.F64[4] = xVec->data.F32[binNum + 2]; 2692 2693 y->data.F64[0] = yVec->data.F32[binNum - 2]; 2694 y->data.F64[1] = yVec->data.F32[binNum - 1]; 2695 y->data.F64[2] = yVec->data.F32[binNum + 0]; 2696 y->data.F64[3] = yVec->data.F32[binNum + 1]; 2697 y->data.F64[4] = yVec->data.F32[binNum + 2]; 2698 psTrace(TRACE, 6, "x vec (orig) is (%f %f %f %f)\n", xVec->data.F32[binNum - 1], xVec->data.F32[binNum], xVec->data.F32[binNum+1], xVec->data.F32[binNum+2]); 2699 psTrace(TRACE, 6, "x data is (%f %f %f)\n", x->data.F64[0], x->data.F64[1], x->data.F64[2]); 2700 psTrace(TRACE, 6, "y data is (%f %f %f)\n", y->data.F64[0], y->data.F64[1], y->data.F64[2]); 2701 2702 // Ensure that the y value lies within range of the y values. 2703 if (! (((y->data.F64[0] <= yVal) && (yVal <= y->data.F64[4])) || 2704 ((y->data.F64[4] <= yVal) && (yVal <= y->data.F64[0]))) ) { 2705 psError(PS_ERR_BAD_PARAMETER_VALUE, true, 2706 _("Specified yVal, %g, is not within y-range, %g to %g."), 2980 if ((binNum >= 2) && (binNum <= (yVec->n - 3)) && (binNum <= (xVec->n - 3))) 2981 { 2982 x->data.F64[0] = xVec->data.F32[binNum - 2]; 2983 x->data.F64[1] = xVec->data.F32[binNum - 1]; 2984 x->data.F64[2] = xVec->data.F32[binNum + 0]; 2985 x->data.F64[3] = xVec->data.F32[binNum + 1]; 2986 x->data.F64[4] = xVec->data.F32[binNum + 2]; 2987 2988 y->data.F64[0] = yVec->data.F32[binNum - 2]; 2989 y->data.F64[1] = yVec->data.F32[binNum - 1]; 2990 y->data.F64[2] = yVec->data.F32[binNum + 0]; 2991 y->data.F64[3] = yVec->data.F32[binNum + 1]; 2992 y->data.F64[4] = yVec->data.F32[binNum + 2]; 2993 psTrace(TRACE, 6, "x vec (orig) is (%f %f %f %f)\n", xVec->data.F32[binNum - 1], xVec->data.F32[binNum], xVec->data.F32[binNum + 1], xVec->data.F32[binNum + 2]); 2994 psTrace(TRACE, 6, "x data is (%f %f %f)\n", x->data.F64[0], x->data.F64[1], x->data.F64[2]); 2995 psTrace(TRACE, 6, "y data is (%f %f %f)\n", y->data.F64[0], y->data.F64[1], y->data.F64[2]); 2996 2997 // Ensure that the y value lies within range of the y values. 2998 if (!(((y->data.F64[0] <= yVal) && (yVal <= y->data.F64[4])) || 2999 ((y->data.F64[4] <= yVal) && (yVal <= y->data.F64[0])))) 3000 { 3001 psError(PS_ERR_BAD_PARAMETER_VALUE, true, 3002 _("Specified yVal, %g, is not within y-range, %g to %g."), 2707 3003 (psF64)yVal, y->data.F64[0], y->data.F64[2]); 2708 3004 return NAN; … … 2711 3007 // Ensure that the y values are monotonic. 2712 3008 if (((y->data.F64[0] < y->data.F64[1]) && !(y->data.F64[1] <= y->data.F64[2])) || 2713 ((y->data.F64[0] > y->data.F64[1]) && !(y->data.F64[1] >= y->data.F64[2]))) { 3009 ((y->data.F64[0] > y->data.F64[1]) && !(y->data.F64[1] >= y->data.F64[2]))) 3010 { 2714 3011 psError(PS_ERR_UNKNOWN, true, 2715 3012 "This routine must be called with monotonically increasing or decreasing data points.\n"); … … 2721 3018 // Determine the coefficients of the polynomial. 2722 3019 psPolynomial1D *myPoly = psPolynomial1DAlloc(PS_POLYNOMIAL_ORD, 1); 2723 if (!psVectorFitPolynomial1D(myPoly, NULL, 0, y, NULL, x)) { 3020 if (!psVectorFitPolynomial1D(myPoly, NULL, 0, y, NULL, x)) 3021 { 2724 3022 psError(PS_ERR_UNEXPECTED_NULL, false, 2725 3023 _("Failed to fit a 1-dimensional polynomial to the three specified data points. " … … 2733 3031 psTrace(TRACE, 6, "myPoly->coeff[1] is %f\n", myPoly->coeff[1]); 2734 3032 psTrace(TRACE, 6, "Fitted y vec is (%f %f)\n", 2735 (psF32) psPolynomial1DEval(myPoly, (psF64)x->data.F64[0]),2736 (psF32) psPolynomial1DEval(myPoly, (psF64)x->data.F64[1]));3033 (psF32)psPolynomial1DEval(myPoly, (psF64)x->data.F64[0]), 3034 (psF32)psPolynomial1DEval(myPoly, (psF64)x->data.F64[1])); 2737 3035 2738 3036 psTrace(TRACE, 6, "We fit the polynomial, now find x such that f(x) equals %f\n", yVal); … … 2740 3038 psFree(myPoly); 2741 3039 2742 if (isnan(binValue)) { 3040 if (isnan(binValue)) 3041 { 2743 3042 psError(PS_ERR_UNEXPECTED_NULL, 2744 3043 false, _("Failed to determine the median of the fitted polynomial. Returning NAN.")); 2745 3044 psFree(x); 2746 3045 psFree(y); 2747 return (NAN);2748 } 2749 3046 return (NAN); 3047 } 3048 2750 3049 // I believe that mathematically the fitted bin position must be between binNum - 1 and binNum + 1 2751 // assert (binValue >= binNum - 1);2752 // assert (binValue <= binNum + 1);2753 2754 // int fitBin = binValue;2755 // float dX = xVec->data.F32[fitBin+1] - xVec->data.F32[fitBin];2756 // float dY = binValue - fitBin;2757 // tmpFloat = xVec->data.F32[fitBin] + dY * dX;2758 tmpFloat = binValue;2759 2760 2761 } else{3050 // assert (binValue >= binNum - 1); 3051 // assert (binValue <= binNum + 1); 3052 3053 // int fitBin = binValue; 3054 // float dX = xVec->data.F32[fitBin+1] - xVec->data.F32[fitBin]; 3055 // float dY = binValue - fitBin; 3056 // tmpFloat = xVec->data.F32[fitBin] + dY * dX; 3057 tmpFloat = binValue; 3058 } 3059 else 3060 { 2762 3061 // These are special cases where the bin is at the beginning or end of the vector. 2763 if (binNum == 0) { 3062 if (binNum == 0) 3063 { 2764 3064 // We have two points only at the beginning of the vectors x and y. 2765 3065 // X = (dX/dY)(Y - Yo) + Xo 2766 3066 float dX = xVec->data.F32[1] - xVec->data.F32[0]; 2767 3067 float dY = yVec->data.F32[1] - yVec->data.F32[0]; 2768 if (dY == 0.0) { 3068 if (dY == 0.0) 3069 { 2769 3070 tmpFloat = xVec->data.F32[0]; 2770 } else { 3071 } 3072 else 3073 { 2771 3074 tmpFloat = (yVal - yVec->data.F32[0]) * (dX / dY) + xVec->data.F32[0]; 2772 3075 } 2773 } else if (binNum == (xVec->n - 1)) { 3076 } 3077 else if (binNum == (xVec->n - 1)) 3078 { 2774 3079 // We have two points only at the end of the vectors x and y. 2775 3080 // X = (dX/dY)(Y - Yo) + Xo 2776 float dX = xVec->data.F32[binNum] - xVec->data.F32[binNum-1]; 2777 float dY = yVec->data.F32[binNum] - yVec->data.F32[binNum-1]; 2778 if (dY == 0.0) { 2779 tmpFloat = xVec->data.F32[binNum-1]; 2780 } else { 2781 tmpFloat = (yVal - yVec->data.F32[binNum-1]) * (dX / dY) + xVec->data.F32[binNum-1]; 3081 float dX = xVec->data.F32[binNum] - xVec->data.F32[binNum - 1]; 3082 float dY = yVec->data.F32[binNum] - yVec->data.F32[binNum - 1]; 3083 if (dY == 0.0) 3084 { 3085 tmpFloat = xVec->data.F32[binNum - 1]; 3086 } 3087 else 3088 { 3089 tmpFloat = (yVal - yVec->data.F32[binNum - 1]) * (dX / dY) + xVec->data.F32[binNum - 1]; 2782 3090 } 2783 3091 } … … 2789 3097 2790 3098 return tmpFloat; 2791 # endif3099 #endif 2792 3100 } -
branches/2dbias/psLib/src/math/psStats.h
r31152 r42719 27 27 * @see psStats, psVectorStats, psImageStats 28 28 */ 29 typedef enum { 30 PS_STAT_NONE = 0x000000, ///< Empty set 31 PS_STAT_MIN = 0x000001, ///< Maximum 32 PS_STAT_MAX = 0x000002, ///< Minumum 33 PS_STAT_SAMPLE_MEAN = 0x000004, ///< Sample Mean 34 PS_STAT_SAMPLE_MEDIAN = 0x000008, ///< Sample Median 35 PS_STAT_SAMPLE_STDEV = 0x000010, ///< Sample Standard Deviation 36 PS_STAT_SAMPLE_QUARTILE = 0x000020, ///< Sample Quartile 37 PS_STAT_SAMPLE_SKEWNESS = 0x000040, ///< Sample Skewness (third moment) 38 PS_STAT_SAMPLE_KURTOSIS = 0x000080, ///< Sample Kurtosis (fourth moment) 39 PS_STAT_ROBUST_MEDIAN = 0x000100, ///< Robust Median 40 PS_STAT_ROBUST_STDEV = 0x000200, ///< Robust Standarad Deviation 41 PS_STAT_ROBUST_QUARTILE = 0x000400, ///< Robust Quartile 42 PS_STAT_ROBUST_SPARE1 = 0x000800, ///< Spare 1 43 PS_STAT_FITTED_MEAN = 0x001000, ///< Fitted Mean 44 PS_STAT_FITTED_STDEV = 0x002000, ///< Fitted Standard Deviation 45 PS_STAT_CLIPPED_MEAN = 0x040000, ///< Clipped Mean 46 PS_STAT_CLIPPED_STDEV = 0x080000, ///< Clipped Standard Deviation 47 PS_STAT_USE_RANGE = 0x100000, ///< Range 48 PS_STAT_USE_BINSIZE = 0x200000, ///< Binsize 29 typedef enum 30 { 31 PS_STAT_NONE = 0x000000, ///< Empty set 32 PS_STAT_MIN = 0x000001, ///< Maximum 33 PS_STAT_MAX = 0x000002, ///< Minumum 34 PS_STAT_SAMPLE_MEAN = 0x000004, ///< Sample Mean 35 PS_STAT_SAMPLE_MEDIAN = 0x000008, ///< Sample Median 36 PS_STAT_SAMPLE_STDEV = 0x000010, ///< Sample Standard Deviation 37 PS_STAT_SAMPLE_QUARTILE = 0x000020, ///< Sample Quartile 38 PS_STAT_SAMPLE_SKEWNESS = 0x000040, ///< Sample Skewness (third moment) 39 PS_STAT_SAMPLE_KURTOSIS = 0x000080, ///< Sample Kurtosis (fourth moment) 40 PS_STAT_ROBUST_MEDIAN = 0x000100, ///< Robust Median 41 PS_STAT_ROBUST_STDEV = 0x000200, ///< Robust Standarad Deviation 42 PS_STAT_ROBUST_QUARTILE = 0x000400, ///< Robust Quartile 43 PS_STAT_ROBUST_SPARE1 = 0x000800, ///< Spare 1 44 PS_STAT_FITTED_MEAN = 0x001000, ///< Fitted Mean 45 PS_STAT_FITTED_STDEV = 0x002000, ///< Fitted Standard Deviation 46 PS_STAT_CLIPPED_MEDIAN = 0x020000, ///< Clipped Median 47 PS_STAT_CLIPPED_MEAN = 0x040000, ///< Clipped Mean 48 PS_STAT_CLIPPED_STDEV = 0x080000, ///< Clipped Standard Deviation 49 PS_STAT_USE_RANGE = 0x100000, ///< Range 50 PS_STAT_USE_BINSIZE = 0x200000, ///< Binsize 49 51 } psStatsOptions; 50 52 … … 54 56 typedef struct 55 57 { 56 double sampleMean;///< formal mean of sample57 double sampleMedian;///< formal median of sample58 double sampleStdev;///< standard deviation of sample59 double sampleUQ;///< upper quartile of sample60 double sampleLQ;///< lower quartile of sample61 double sampleSkewness;///< skewness (third moment) of sample62 double sampleKurtosis;///< kurtosis (fourth moment) of sample63 double robustMedian;///< robust median of array64 double robustStdev;///< robust standard deviation of array65 double robustUQ;///< robust upper quartile66 double robustLQ;///< robust lower quartile67 long robustN50;///< Number of points in Gaussian fit; XXX: This is currently unused.68 double fittedMean;///< robust mean of data69 double fittedStdev;///< robust standard deviation of data70 long fittedNfit;///< Number of points in Gaussian fit; XXX: This is currently unused71 double clippedMean;///< Nsigma clipped mean72 double clippedStdev; ///< standard deviation after clipping73 long clippedNvalues; ///< Number of data points used for clipped mean.74 double clipSigma; ///< Nsigma used for clipping; user input75 int clipIter; ///< Number of clipping iterations; user input76 double min; ///< minimum data value in array77 double max; ///< maximum data value in array78 double binsize; ///< binsize for robust fit (input/ouput)79 long nSubsample; ///< maxinum number of measurements (input)80 psStatsOptions options; ///< bitmask of values requested81 psStatsOptions results; ///< bitmask of values calculated82 psVector *tmpData; ///< temporary vector so repeated calls do not have to realloc83 psVector *tmpMask;///< temporary vector so repeated calls do not have to realloc84 } 85 psStats;58 double sampleMean; ///< formal mean of sample 59 double sampleMedian; ///< formal median of sample 60 double sampleStdev; ///< standard deviation of sample 61 double sampleUQ; ///< upper quartile of sample 62 double sampleLQ; ///< lower quartile of sample 63 double sampleSkewness; ///< skewness (third moment) of sample 64 double sampleKurtosis; ///< kurtosis (fourth moment) of sample 65 double robustMedian; ///< robust median of array 66 double robustStdev; ///< robust standard deviation of array 67 double robustUQ; ///< robust upper quartile 68 double robustLQ; ///< robust lower quartile 69 long robustN50; ///< Number of points in Gaussian fit; XXX: This is currently unused. 70 double fittedMean; ///< robust mean of data 71 double fittedStdev; ///< robust standard deviation of data 72 long fittedNfit; ///< Number of points in Gaussian fit; XXX: This is currently unused 73 double clippedMean; ///< Nsigma clipped mean 74 double clippedMedian; ///< Nsigma clipped median 75 double clippedStdev; ///< standard deviation after clipping 76 long clippedNvalues; ///< Number of data points used for clipped mean. 77 double clipSigma; ///< Nsigma used for clipping; user input 78 int clipIter; ///< Number of clipping iterations; user input 79 double min; ///< minimum data value in array 80 double max; ///< maximum data value in array 81 double binsize; ///< binsize for robust fit (input/ouput) 82 long nSubsample; ///< maxinum number of measurements (input) 83 psStatsOptions options; ///< bitmask of values requested 84 psStatsOptions results; ///< bitmask of values calculated 85 psVector *tmpData; ///< temporary vector so repeated calls do not have to realloc 86 psVector *tmpMask; ///< temporary vector so repeated calls do not have to realloc 87 } psStats; 86 88 87 89 /** Performs statistical calculations on a vector. … … 90 92 */ 91 93 bool psVectorStats( 92 psStats * stats,///< stats structure defines stats to be calculated and how93 const psVector * in,///< Vector to be analysed.94 const psVector * errors,///< Errors.95 const psVector * mask,///< Ignore elements where (maskVector & maskVal) != 0: must be INT or NULL94 psStats *stats, ///< stats structure defines stats to be calculated and how 95 const psVector *in, ///< Vector to be analysed. 96 const psVector *errors, ///< Errors. 97 const psVector *mask, ///< Ignore elements where (maskVector & maskVal) != 0: must be INT or NULL 96 98 psVectorMaskType maskVal ///< Only mask elements with one of these bits set in maskVector 97 99 ); … … 103 105 */ 104 106 #ifdef DOXYGEN 105 psStats *psStatsAlloc(106 psStatsOptions options ///< Statistics to calculate107 psStats *psStatsAlloc( 108 psStatsOptions options ///< Statistics to calculate 107 109 ); 108 110 #else // ifdef DOXYGEN 109 psStats *p_psStatsAlloc(110 const char *file, ///< File of caller111 unsigned int lineno, ///< Line number of caller112 const char *func, ///< Function name of caller113 psStatsOptions options ///< Statistics to calculate114 ) PS_ATTR_MALLOC;111 psStats *p_psStatsAlloc( 112 const char *file, ///< File of caller 113 unsigned int lineno, ///< Line number of caller 114 const char *func, ///< Function name of caller 115 psStatsOptions options ///< Statistics to calculate 116 ) PS_ATTR_MALLOC; 115 117 #define psStatsAlloc(options) \ 116 p_psStatsAlloc(__FILE__, __LINE__, __func__, options)118 p_psStatsAlloc(__FILE__, __LINE__, __func__, options) 117 119 #endif // ifdef DOXYGEN 118 120 … … 124 126 */ 125 127 bool psMemCheckStats( 126 psPtr ptr ///< the pointer whose type to check128 psPtr ptr ///< the pointer whose type to check 127 129 ); 128 130 -
branches/2dbias/psLib/src/math/psVectorSmooth.c
r42715 r42719 172 172 if (robust) \ 173 173 { \ 174 statistic = PS_STAT_CLIPPED_ME AN;\174 statistic = PS_STAT_CLIPPED_MEDIAN; \ 175 175 stats = psStatsAlloc(statistic); \ 176 stats->clipSigma = 2.5; \ 176 177 } \ 177 178 else \ -
branches/2dbias/psModules/src/detrend/pmOverscan.c
r42717 r42719 415 415 // Reduce the overscans 416 416 // XXX need to save 2 different chi-square values 417 psVector *yReduced = pmOverscanVector(&chi2, overscanOpts->primary, yscanPixels, false);417 psVector *yReduced = pmOverscanVector(&chi2, overscanOpts->primary, yscanPixels, true); 418 418 psFree(yscanPixels); 419 419 if (!yReduced) … … 453 453 } 454 454 // Now normVector holds the sliced data; then, compute its robust mean 455 psStatsOptions statistic = PS_STAT_ CLIPPED_MEAN;455 psStatsOptions statistic = PS_STAT_ROBUST_MEDIAN; 456 456 psStats *stats = psStatsAlloc(statistic); 457 457 if (!psVectorStats(stats, normVector, NULL, NULL, 0)) 458 458 { 459 psError(PS_ERR_UNKNOWN, false, "failure to measure clipped mean asnormalization of xReduced");459 psError(PS_ERR_UNKNOWN, false, "failure to measure robust median as the normalization of xReduced"); 460 460 psFree(stats); 461 461 psFree(normVector);
Note:
See TracChangeset
for help on using the changeset viewer.
