Changeset 10173 for trunk/psLib/src/math/psStats.c
- Timestamp:
- Nov 22, 2006, 7:33:28 PM (20 years ago)
- File:
-
- 1 edited
-
trunk/psLib/src/math/psStats.c (modified) (18 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psLib/src/math/psStats.c
r9982 r10173 16 16 * use ->min and ->max (PS_STAT_USE_RANGE) 17 17 * 18 * @version $Revision: 1.1 89$ $Name: not supported by cvs2svn $19 * @date $Date: 2006-11- 15 00:36:14$18 * @version $Revision: 1.190 $ $Name: not supported by cvs2svn $ 19 * @date $Date: 2006-11-23 05:33:28 $ 20 20 * 21 21 * Copyright 2004 Maui High Performance Computing Center, University of Hawaii … … 55 55 /*****************************************************************************/ 56 56 #define PS_GAUSS_WIDTH 3 // The width of the Gaussian smoothing. 57 // This corresponds to N in the ADD. 58 #define PS_CLIPPED_NUM_ITER_LB 1 57 #define PS_CLIPPED_NUM_ITER_LB 1 // This corresponds to N in the ADD. 59 58 #define PS_CLIPPED_NUM_ITER_UB 10 60 59 #define PS_CLIPPED_SIGMA_LB 1.0 61 60 #define PS_CLIPPED_SIGMA_UB 10.0 62 61 #define PS_POLY_MEDIAN_MAX_ITERATIONS 30 62 #define MASK_MARK 0x80 // bit to use internally to mark data as bad 63 63 64 64 #define PS_BIN_MIDPOINT(HISTOGRAM, BIN_NUM) \ … … 104 104 this routine sets stats->sampleMean to NAN. 105 105 *****************************************************************************/ 106 static bool vectorSampleMean(const psVector* myVector, 107 const psVector* errors, 108 const psVector* maskVector, 109 psMaskType maskVal, 110 psStats* stats) 106 # if (0) 107 static bool vectorSampleMean(const psVector* myVector, 108 const psVector* errors, 109 const psVector* maskVector, 110 psMaskType maskVal, 111 psStats* stats) 111 112 { 112 113 psTrace("psLib.math", 4, "---- %s() begin ----\n", __func__); … … 228 229 return true; 229 230 } 231 #endif 232 233 /****************************************************************************** 234 vectorSampleMean(myVector, maskVector, maskVal, stats): calculates the 235 mean of the input vector. If there was a problem with the mean calculation, 236 this routine sets stats->sampleMean to NAN. 237 238 XXX : using the method below, with a single loop for various options 239 costs only a small amount and is much easier to debug. running 10000 tests 240 of 1000 point vectors for the two methods gives: 241 separate single 242 (mask: 0, range: 0): 0.067 sec 0.073 sec 243 (mask: 1, range: 0): 0.098 sec 0.102 sec 244 (mask: 0, range: 0): 0.136 sec 0.162 sec 245 (mask: 1, range: 0): 0.177 sec 0.181 sec 246 *****************************************************************************/ 247 static bool vectorSampleMean(const psVector* myVector, 248 const psVector* errors, 249 const psVector* maskVector, 250 psMaskType maskVal, 251 psStats* stats) 252 { 253 psTrace("psLib.math", 4, "---- %s() begin ----\n", __func__); 254 255 psF32 mean = 0.0; // The mean 256 long count = 0; // Number of points contributing to this mean 257 258 psF32 *data = myVector->data.F32; // Dereference 259 int numData = myVector->n; // Number of data points 260 261 psU8 *maskData = (maskVector == NULL) ? NULL : maskVector->data.U8; 262 bool useRange = stats->options & PS_STAT_USE_RANGE; 263 264 // If errors exist, we enter a slightly different loop. 265 // XXX collapse to a single loop? 266 if (!errors) { 267 for (long i = 0; i < numData; i++) { 268 // Check if the data is with the specified range 269 if (useRange && (data[i] < stats->min)) 270 continue; 271 if (useRange && (data[i] > stats->max)) 272 continue; 273 if (maskData && (maskData[i] & maskVal)) 274 continue; 275 mean += data[i]; 276 count++; 277 } 278 mean = (count > 0) ? mean / (psF32) count : NAN; 279 } else { 280 psF32 sumWeights = 0.0; // The sum of the weights 281 psF32 *errorsData = errors->data.F32; 282 for (long i = 0; i < numData; i++) { 283 // Check if the data is with the specified range 284 if (useRange && (data[i] < stats->min)) 285 continue; 286 if (useRange && (data[i] > stats->max)) 287 continue; 288 if (maskData && (maskData[i] & maskVal)) 289 continue; 290 291 float weight = 1.0 / PS_SQR(errorsData[i]); 292 mean += data[i] * weight; 293 sumWeights += weight; 294 count++; 295 } 296 mean = (count > 0) ? mean / sumWeights : NAN; 297 } 298 299 stats->sampleMean = mean; 300 if (isnan(mean)) { 301 psTrace("psLib.math", 4, "---- %s(false) end ----\n", __func__); 302 return false; 303 } 304 305 psTrace("psLib.math", 4, "---- %s(true) end ----\n", __func__); 306 return true; 307 } 230 308 231 309 /****************************************************************************** … … 233 311 If there was a problem with the calculation, this routine sets stats->max and stats->min to NAN. Return the 234 312 number of valid values in the vector (those not masked or outside the specified range. 313 XXX : using the method below, with a single loop for various options 314 costs only a small amount and is much easier to debug. running 10000 tests 315 of 1000 point vectors for the two methods gives: 316 separate single 317 (mask: 0, range: 0): 0.101 sec 0.149 sec 318 (mask: 1, range: 0): 0.125 sec 0.160 sec 319 (mask: 0, range: 0): 0.179 sec 0.208 sec 320 (mask: 1, range: 0): 0.200 sec 0.244 sec 235 321 *****************************************************************************/ 236 322 static long vectorMinMax(const psVector* myVector, … … 244 330 psF32 min = PS_MAX_F32; // The calculated minimum 245 331 psF32 *vector = myVector->data.F32; // Dereference the vector 246 psU8 *mask = NULL; // Dereference the mask 247 if (maskVector) { 248 mask = maskVector->data.U8; 249 } 332 250 333 int num = myVector->n; // Number of values 251 334 int numValid = 0; // Number of valid values 252 335 253 // If PS_STAT_USE_RANGE is requested, then we enter a different loop. 254 if (stats->options & PS_STAT_USE_RANGE) { 255 if (mask) { 256 // Need to check range and mask 257 for (long i = 0; i < num; i++) { 258 if (!(maskVal & mask[i]) && vector[i] >= stats->min && vector[i] <= stats->max) { 259 numValid++; 260 if (vector[i] > max) { 261 max = vector[i]; 262 } 263 if (vector[i] < min) { 264 min = vector[i]; 265 } 266 } 267 } 268 } else { 269 // Need to check range 270 for (long i = 0; i < num; i++) { 271 if (vector[i] >= stats->min && vector[i] <= stats->max) { 272 numValid++; 273 if (vector[i] > max) { 274 max = vector[i]; 275 } 276 if (vector[i] < min) { 277 min = vector[i]; 278 } 279 } 280 } 281 } 282 } else { 283 if (mask) { 284 // Need to check mask 285 for (long i = 0; i < num; i++) { 286 if (!(maskVal & mask[i])) { 287 numValid++; 288 if (vector[i] > max) { 289 max = vector[i]; 290 } 291 if (vector[i] < min) { 292 min = vector[i]; 293 } 294 } 295 } 296 } else { 297 // No checks 298 for (long i = 0; i < num; i++) { 299 if (vector[i] > max) { 300 max = vector[i]; 301 } 302 if (vector[i] < min) { 303 min = vector[i]; 304 } 305 } 306 numValid = num; 307 } 308 } 309 336 psU8 *maskData = (maskVector == NULL) ? NULL : maskVector->data.U8; 337 bool useRange = stats->options & PS_STAT_USE_RANGE; 338 339 for (long i = 0; i < num; i++) { 340 // Check if the data is with the specified range 341 if (useRange && (vector[i] < stats->min)) 342 continue; 343 if (useRange && (vector[i] > stats->max)) 344 continue; 345 if (maskData && (maskData[i] & maskVal)) 346 continue; 347 numValid++; 348 max = PS_MAX (vector[i], max); 349 min = PS_MIN (vector[i], min); 350 } 310 351 311 352 if (numValid == 0) { … … 685 726 686 727 /****************************************************************************** 687 vectorClippedStats(myVector, errors, mask Vector, maskVal, stats): calculates the728 vectorClippedStats(myVector, errors, maskInput, maskValInput, stats): calculates the 688 729 clipped stats (mean or stdev) of the input vector. 689 730 690 731 Inputs 691 732 myVector 692 mask Vector693 maskVal 733 maskInput 734 maskValInput 694 735 stats 695 736 Returns … … 698 739 static bool vectorClippedStats(const psVector* myVector, 699 740 const psVector* errors, 700 psVector* mask Vector,701 psMaskType maskVal ,741 psVector* maskInput, 742 psMaskType maskValInput, 702 743 psStats* stats 703 744 ) … … 721 762 722 763 // We copy the mask vector, to preserve the original 764 psMaskType maskVal = MASK_MARK | maskValInput; 723 765 psVector *tmpMask = psVectorAlloc(myVector->n, PS_TYPE_U8); 724 766 psVectorInit(tmpMask, 0); 725 if (mask Vector) {767 if (maskInput) { 726 768 for (long i = 0; i < myVector->n; i++) { 727 if (mask Vector->data.U8[i] & maskVal) {728 tmpMask->data.U8[i] = 0xff;769 if (maskInput->data.U8[i] & maskValInput) { 770 tmpMask->data.U8[i] = maskVal; 729 771 } 730 772 } … … 1012 1054 psF32 x = coords->data.F32[0]; 1013 1055 psF32 mean = params->data.F32[0]; 1014 psF32 stdev = params->data.F32[1]; 1015 1016 psF32 gauss = psGaussian(x, mean, stdev, false); 1056 psF32 var = params->data.F32[1]; 1057 psF32 dx = (x - mean); 1058 1059 psF32 gauss = exp (-0.5*PS_SQR(dx)/var); 1017 1060 if (deriv) { 1018 1061 PS_ASSERT_VECTOR_SIZE(deriv, (long)2, NAN); 1019 1062 PS_ASSERT_VECTOR_TYPE(deriv, PS_TYPE_F32, NAN); 1020 psF32 tmp = (x - mean)* gauss;1021 deriv->data.F32[0] = tmp / (stdev * stdev);1022 deriv->data.F32[1] = (x - mean) * tmp / (stdev * stdev * stdev);1063 psF32 tmp = dx * gauss; 1064 deriv->data.F32[0] = tmp / var; 1065 deriv->data.F32[1] = tmp * dx / (var * var); 1023 1066 } 1024 1067 … … 1028 1071 } 1029 1072 1073 /* 1074 * vectorFittedStats requires guess for fittedMean and fittedStdev 1075 * robustN50 should also be set 1076 */ 1077 static bool vectorFittedStats (const psVector* myVector, 1078 const psVector* errors, 1079 psVector* mask, 1080 psMaskType maskVal, 1081 psStats* stats) 1082 { 1083 1084 psTrace("psLib.math", 6, "The guess mean is %f.\n", stats->fittedMean); 1085 psTrace("psLib.math", 6, "The guess stdev is %f.\n", stats->fittedStdev); 1086 1087 psStats *statsMinMax = psStatsAlloc(PS_STAT_MIN | PS_STAT_MAX); // Statistics for min and max 1088 1089 psScalar tmpScalar; // Temporary scalar variable, for p_psVectorBinDisect 1090 tmpScalar.type.type = PS_TYPE_F32; 1091 1092 // construct a histogram with (sigma/10 < binsize < sigma) 1093 // set roughly so that the lowest bins have about 2 cnts 1094 // Nsmallest ~ N50 / (4*dN)) 1095 psF32 dN = PS_MAX (1, PS_MIN (10, stats->robustN50 / 8)); 1096 psF32 newBinSize = stats->fittedStdev / dN; 1097 1098 // Determine the min/max of the vector (which prior outliers masked out) 1099 int numValid = vectorMinMax(myVector, mask, maskVal, statsMinMax); // Number of values 1100 float min = statsMinMax->min; 1101 float max = statsMinMax->max; 1102 if (numValid == 0 || isnan(min) || isnan(max)) { 1103 psError(PS_ERR_UNKNOWN, false, "Failed to calculate the min/max of the input vector.\n"); 1104 psFree(statsMinMax); 1105 psFree(mask); 1106 psTrace("psLib.math", 4, "---- %s(false) end ----\n", __func__); 1107 return false; 1108 } 1109 1110 // Calculate the number of bins. 1111 long numBins = (max - min) / newBinSize; 1112 psTrace("psLib.math", 6, "The new min/max values are (%f, %f).\n", min, max); 1113 psTrace("psLib.math", 6, "The new bin size is %f.\n", newBinSize); 1114 psTrace("psLib.math", 6, "The numBins is %ld\n", numBins); 1115 1116 psHistogram *histogram = psHistogramAlloc(min, max, numBins); // A new histogram (without outliers) 1117 histogram = psVectorHistogram(histogram, myVector, errors, mask, maskVal); 1118 if (psTraceGetLevel("psLib.math") >= 8) { 1119 PS_VECTOR_PRINT_F32(histogram->nums); 1120 } 1121 1122 long binMin = 0; // Low bin to check 1123 long binMax = 0; // High bin to check 1124 1125 // Fit a Gaussian to the bins in the requested range about the guess mean 1126 // min,max overrides clipSigma 1127 psF32 maxFitSigma = 2.0; 1128 if (isfinite(stats->clipSigma)) { 1129 maxFitSigma = fabs(stats->clipSigma); 1130 } 1131 if (isfinite(stats->max)) { 1132 maxFitSigma = fabs(stats->max); 1133 } 1134 1135 psF32 minFitSigma = 2.0; 1136 if (isfinite(stats->clipSigma)) { 1137 minFitSigma = fabs(stats->clipSigma); 1138 } 1139 if (isfinite(stats->min)) { 1140 minFitSigma = fabs(stats->min); 1141 } 1142 1143 tmpScalar.data.F32 = stats->fittedMean - minFitSigma*stats->fittedStdev; 1144 if (tmpScalar.data.F32 < min) { 1145 binMin = 0; 1146 } else { 1147 binMin = p_psVectorBinDisect(histogram->bounds, &tmpScalar); 1148 } 1149 tmpScalar.data.F32 = stats->fittedMean + maxFitSigma*stats->fittedStdev; 1150 if (tmpScalar.data.F32 > max) { 1151 binMax = histogram->bounds->n - 1; 1152 } else { 1153 binMax = p_psVectorBinDisect(histogram->bounds, &tmpScalar); 1154 } 1155 if (binMin < 0 || binMax < 0) { 1156 psError(PS_ERR_UNKNOWN, false, "Failed to calculate the -%f sigma : +%f sigma bins\n", minFitSigma, maxFitSigma); 1157 psFree(statsMinMax); 1158 psFree(histogram); 1159 psFree(mask); 1160 psTrace("psLib.math", 4, "---- %s(false) end ----\n", __func__); 1161 return false; 1162 } 1163 1164 // Generate the variables that will be used in the Gaussian fitting 1165 // XXX EAM : we should test / guarantee that there are at least 3 (right?) bins 1166 psVector *y = psVectorAlloc((1 + (binMax - binMin)), PS_TYPE_F32); // Vector of coordinates 1167 psArray *x = psArrayAlloc((1 + (binMax - binMin))); // Array of ordinates 1168 for (long i = binMin, j = 0; i <= binMax ; i++, j++) { 1169 y->data.F32[j] = histogram->nums->data.F32[i]; 1170 psVector *ordinate = psVectorAlloc(1, PS_TYPE_F32); // The ordinate value 1171 ordinate->data.F32[0] = PS_BIN_MIDPOINT(histogram, i); 1172 x->data[j] = ordinate; 1173 } 1174 if (psTraceGetLevel("psLib.math") >= 8) { 1175 // XXX: Print the x array somehow. 1176 PS_VECTOR_PRINT_F32(y); 1177 } 1178 psTrace("psLib.math", 6, "The clipped numBins is %ld\n", y->n); 1179 1180 // Normalize y to [0.0:1.0] (since the psMinimizeLMChi2Gauss1D() functions is [0.0:1.0]) 1181 // XXX EAM : why not just fit the normalization as well?? 1182 p_psNormalizeVectorRange(y, 0.0, 1.0); 1183 1184 // Fit a Gaussian to the data. 1185 psMinimization *minimizer = psMinimizationAlloc(100, 0.01); // The minimizer information 1186 psVector *params = psVectorAlloc(2, PS_TYPE_F32); // Parameters for the Gaussian 1187 // Initial guess for the mean (index 0) and var (index 1). 1188 params->data.F32[0] = stats->fittedMean; 1189 params->data.F32[1] = PS_SQR(stats->fittedStdev); 1190 if (psTraceGetLevel("psLib.math") >= 8) { 1191 PS_VECTOR_PRINT_F32(params); 1192 PS_VECTOR_PRINT_F32(y); 1193 } 1194 if (!psMinimizeLMChi2(minimizer, NULL, params, NULL, x, y, NULL, minimizeLMChi2Gauss1D)) { 1195 psError(PS_ERR_UNKNOWN, false, "Failed to fit a gaussian to the robust histogram.\n"); 1196 psFree(statsMinMax); 1197 psFree(x); 1198 psFree(y); 1199 psFree(minimizer); 1200 psFree(params); 1201 psFree(mask); 1202 psTrace("psLib.math", 4, "---- %s(false) end ----\n", __func__); 1203 return false; 1204 } 1205 if (psTraceGetLevel("psLib.math") >= 8) { 1206 PS_VECTOR_PRINT_F32(params); 1207 } 1208 1209 // The fitted mean is the Gaussian mean. 1210 stats->fittedMean = params->data.F32[0]; 1211 psTrace("psLib.math", 6, "The fitted mean is %f.\n", stats->fittedMean); 1212 1213 // The fitted standard deviation 1214 stats->fittedStdev = sqrt(params->data.F32[1]); 1215 psTrace("psLib.math", 6, "The fitted stdev is %f.\n", stats->fittedStdev); 1216 1217 // Clean up after fitting 1218 psFree (histogram); 1219 psFree (x); 1220 psFree (y); 1221 psFree (minimizer); 1222 psFree (params); 1223 psFree (statsMinMax); 1224 return true; 1225 } 1226 1227 1030 1228 /****************************************************************************** 1031 vectorRobustStats(myVector, mask Vector, maskVal, stats): This is the new1229 vectorRobustStats(myVector, maskInput, maskValInput, stats): This is the new 1032 1230 version of the robust stats routine. 1033 1231 … … 1049 1247 static bool vectorRobustStats(const psVector* myVector, 1050 1248 const psVector* errors, 1051 psVector* mask Vector,1052 psMaskType maskVal ,1249 psVector* maskInput, 1250 psMaskType maskValInput, 1053 1251 psStats* stats) 1054 1252 { … … 1061 1259 tmpScalar.type.type = PS_TYPE_F32; 1062 1260 1261 // we need to generate an internal mask and maskVal which ensures a bit is set 1262 // and tested even if there is no supplied mask (and/or the maskVal is 0) 1263 // XXX this would be better if we had globally defined mask values 1264 psMaskType maskVal = MASK_MARK | maskValInput; 1063 1265 psVector *mask = psVectorAlloc(myVector->n, PS_TYPE_MASK); // The actual mask we will use 1064 1266 psVectorInit(mask, 0); 1065 if (mask Vector) {1267 if (maskInput) { 1066 1268 for (long i = 0; i < myVector->n; i++) { 1067 if (mask Vector->data.U8[i] & maskVal) {1068 mask->data.U8[i] = 0xff;1269 if (maskInput->data.U8[i] & maskValInput) { 1270 mask->data.U8[i] = maskVal; 1069 1271 } 1070 1272 } … … 1098 1300 psTrace("psLib.math", 6, "Data min/max is (%.2f, %.2f)\n", min, max); 1099 1301 1100 // If all data points have the same value, then we set the approp iate members of stats and return.1302 // If all data points have the same value, then we set the appropriate members of stats and return. 1101 1303 if (fabs(max - min) <= FLT_EPSILON) { 1102 1304 psTrace("psLib.math", 5, "All data points have the same value: %f.\n", min); … … 1226 1428 return false; 1227 1429 } 1228 1430 // XXXX we can probably just use the bin values to get sigma without interpolating... 1229 1431 // ADD step 4b: Interpolate Sigma to find these two positions exactly: these are the 1sigma positions. 1230 1432 #if 0 … … 1304 1506 for (long i = 0 ; i < myVector->n ; i++) { 1305 1507 if ((myVector->data.F32[i] < medianLo) || (myVector->data.F32[i] > medianHi)) { 1306 mask->data.U8[i] = 0xff;1508 mask->data.U8[i] |= MASK_MARK; 1307 1509 psTrace("psLib.math", 6, "Masking element %ld is %f\n", i, myVector->data.F32[i]); 1308 1510 } … … 1378 1580 psTrace("psLib.math", 6, "The robustN50 is %ld.\n", N50); 1379 1581 1380 1381 1582 // Fitted statistics 1382 1583 if (stats->options & PS_STAT_FITTED_MEAN || stats->options & PS_STAT_FITTED_STDEV) { 1383 // New algorithm for calculated mean and stdev. 1384 1385 // XXX: Where is this documented? 1386 psF32 dN = 0.17 * N50; 1387 if (dN < 1.0) { 1388 dN = 1.0; 1389 } else if (dN > 4.0) { 1390 dN = 4.0; 1391 } 1392 psF32 newBinSize = sigma / dN; 1393 1394 // Determine the min/max of the vector (which prior outliers masked out) 1395 int numValid = vectorMinMax(myVector, mask, maskVal, statsMinMax); // Number of values 1396 min = statsMinMax->min; 1397 max = statsMinMax->max; 1398 if (numValid == 0 || isnan(min) || isnan(max)) { 1399 psError(PS_ERR_UNKNOWN, false, "Failed to calculate the min/max of the input vector.\n"); 1400 psFree(statsMinMax); 1401 psFree(mask); 1402 psTrace("psLib.math", 4, "---- %s(false) end ----\n", __func__); 1403 return false; 1404 } 1405 1406 // Calculate the number of bins. 1407 long numBins = (max - min) / newBinSize; 1408 psTrace("psLib.math", 6, "The new min/max values are (%f, %f).\n", min, max); 1409 psTrace("psLib.math", 6, "The new bin size is %f.\n", newBinSize); 1410 psTrace("psLib.math", 6, "The numBins is %ld\n", numBins); 1411 1412 psHistogram *histogram = psHistogramAlloc(min, max, numBins); // A new histogram (without outliers) 1413 histogram = psVectorHistogram(histogram, myVector, errors, mask, maskVal); 1414 if (psTraceGetLevel("psLib.math") >= 8) { 1415 PS_VECTOR_PRINT_F32(histogram->nums); 1416 } 1417 1418 // Smooth the resulting histogram with a Gaussian with sigma_s = 1 bin. 1419 psVector *smoothed = vectorSmoothHistGaussian(histogram, newBinSize); // Smoothed histogram 1420 if (psTraceGetLevel("psLib.math") >= 8) { 1421 PS_VECTOR_PRINT_F32(smoothed); 1422 } 1423 1424 // Find the bin with the peak value in the range 2 sigma of the robust histogram median. 1425 long binMin = 0; // Low bin to check 1426 long binMax = 0; // High bin to check 1427 tmpScalar.data.F32 = stats->robustMedian - (2.0 * sigma); 1428 if (tmpScalar.data.F32 <= histogram->bounds->data.F32[0]) { 1429 binMin = 0; 1430 } else { 1431 binMin = p_psVectorBinDisect(histogram->bounds, &tmpScalar); 1432 } 1433 1434 tmpScalar.data.F32 = stats->robustMedian + (2.0 + sigma); 1435 if (tmpScalar.data.F32 >= histogram->bounds->data.F32[histogram->bounds->n-1]) { 1436 binMax = histogram->bounds->n-1; 1437 } else { 1438 binMax = p_psVectorBinDisect(histogram->bounds, &tmpScalar); 1439 } 1440 if ((binMin < 0) || (binMax < 0)) { 1441 psError(PS_ERR_UNKNOWN, false, "Failed to calculate the +/- 2.0 * sigma bins\n"); 1442 psFree(statsMinMax); 1443 psFree(histogram); 1444 psFree(mask); 1445 psTrace("psLib.math", 4, "---- %s(false) end ----\n", __func__); 1446 return false; 1447 } 1448 1449 long binNum = binMin; // Bin number containing the peak 1450 psF32 binMaxNums = smoothed->data.F32[binNum]; // The peak value 1451 for (psS32 i = binMin+1 ; i <= binMax ; i++) { 1452 if (smoothed->data.F32[i] > binMaxNums) { 1453 binNum = i; 1454 binMaxNums = smoothed->data.F32[i]; 1455 } 1456 } 1457 psTrace("psLib.math", 6, "The peak bin is %ld, with %f data.n", binNum, binMaxNums); 1458 1459 // Fit a Gaussian to the bins in the range 20 sigma of the robust histogram median. 1460 tmpScalar.data.F32 = stats->robustMedian - (20.0 * sigma); 1461 if (tmpScalar.data.F32 < min) { 1462 binMin = 0; 1463 } else { 1464 binMin = p_psVectorBinDisect(histogram->bounds, &tmpScalar); 1465 } 1466 tmpScalar.data.F32 = stats->robustMedian + (20.0 * sigma); 1467 if (tmpScalar.data.F32 > max) { 1468 binMax = smoothed->n - 1; 1469 } else { 1470 binMax = p_psVectorBinDisect(histogram->bounds, &tmpScalar); 1471 } 1472 if (binMin < 0 || binMax < 0) { 1473 psError(PS_ERR_UNKNOWN, false, "Failed to calculate the +/- 20.0 * sigma bins\n"); 1474 psFree(statsMinMax); 1475 psFree(histogram); 1476 psFree(mask); 1477 psTrace("psLib.math", 4, "---- %s(false) end ----\n", __func__); 1478 return false; 1479 } 1480 1481 // Generate the variables that will be used in the Gaussian fitting 1482 psVector *y = psVectorAlloc((1 + (binMax - binMin)), PS_TYPE_F32); // Vector of coordinates 1483 psArray *x = psArrayAlloc((1 + (binMax - binMin))); // Array of ordinates 1484 for (long i = binMin, j = 0; i <= binMax ; i++, j++) { 1485 y->data.F32[j] = smoothed->data.F32[i]; 1486 psVector *ordinate = psVectorAlloc(1, PS_TYPE_F32); // The ordinate value 1487 ordinate->data.F32[0] = PS_BIN_MIDPOINT(histogram, i); 1488 x->data[j] = ordinate; 1489 } 1490 if (psTraceGetLevel("psLib.math") >= 8) { 1491 // XXX: Print the x array somehow. 1492 PS_VECTOR_PRINT_F32(y); 1493 } 1494 psFree(smoothed); 1495 psFree(histogram); 1496 1497 numValid = vectorMinMax(y, NULL, 0, statsMinMax); // Number of valid values 1498 min = statsMinMax->min; 1499 max = statsMinMax->max; 1500 if (numValid == 0 || isnan(min) || isnan(max)) { 1501 psError(PS_ERR_UNKNOWN, false, "Failed to calculate the min/max of the input vector.\n"); 1502 psFree(mask); 1503 psFree(histogram); 1504 psFree(statsMinMax); 1505 psTrace("psLib.math", 4, "---- %s(false) end ----\n", __func__); 1506 return false; 1507 } 1508 1509 // Normalize y to [0.0:1.0] (since the psMinimizeLMChi2Gauss1D() functions is [0.0:1.0]) 1510 p_psNormalizeVectorRange(y, 0.0, 1.0); 1511 1512 // Fit a Gaussian to the data. 1513 psMinimization *minimizer = psMinimizationAlloc(100, 0.01); // The minimizer information 1514 psVector *params = psVectorAlloc(2, PS_TYPE_F32); // Parameters for the Gaussian 1515 // Initial guess for the mean (index 0) and standard dev (index 1). 1516 params->data.F32[0] = stats->robustMedian; 1517 params->data.F32[1] = sigma; 1518 if (psTraceGetLevel("psLib.math") >= 8) { 1519 PS_VECTOR_PRINT_F32(params); 1520 PS_VECTOR_PRINT_F32(y); 1521 } 1522 if (!psMinimizeLMChi2(minimizer, NULL, params, NULL, x, y, NULL, minimizeLMChi2Gauss1D)) { 1523 psError(PS_ERR_UNKNOWN, false, "Failed to fit a gaussian to the robust histogram.\n"); 1524 psFree(statsMinMax); 1525 psFree(x); 1526 psFree(y); 1527 psFree(minimizer); 1528 psFree(params); 1529 psFree(mask); 1530 psTrace("psLib.math", 4, "---- %s(false) end ----\n", __func__); 1531 return false; 1532 } 1533 if (psTraceGetLevel("psLib.math") >= 8) { 1534 PS_VECTOR_PRINT_F32(params); 1535 } 1536 1537 // The fitted mean is the Gaussian mean. 1538 stats->fittedMean = params->data.F32[0]; 1539 psTrace("psLib.math", 6, "The fitted mean is %f.\n", params->data.F32[0]); 1540 1541 // The fitted standard deviation, SIGMA_r is determined by subtracting the smoothing scale in 1542 // quadrature: SIGMA_r^2 = SIGMA^2 - sigma_s^2 1543 stats->fittedStdev = sqrt(PS_SQR(params->data.F32[1]) - PS_SQR(newBinSize)); 1544 psTrace("psLib.math", 6, "The fitted stdev is %f.\n", stats->fittedStdev); 1545 1546 // Clean up after fitting 1547 psFree(x); 1548 psFree(y); 1549 psFree(minimizer); 1550 psFree(params); 1584 stats->fittedStdev = stats->robustStdev; // pass the guess sigma 1585 stats->fittedMean = stats->robustMedian; // pass the guess mean 1586 vectorFittedStats (myVector, errors, mask, maskVal, stats); 1587 // if there is a large swing in sigma, try a second time 1588 if ((stats->fittedStdev/stats->robustStdev) < 0.75) { 1589 vectorFittedStats (myVector, errors, mask, maskVal, stats); 1590 } 1551 1591 } 1552 1592 … … 1914 1954 1915 1955 /****************************************************************************** 1916 psVectorStats( myVector, maskVector, maskVal, stats): this is the public API1956 psVectorStats(in, mask, maskVal, stats): this is the public API 1917 1957 function which calls the above private stats functions based on what bits 1918 1958 were set in stats->options. 1919 1959 1920 1960 Inputs 1921 myVector1922 mask Vector1961 in 1962 mask 1923 1963 maskVal 1924 1964 stats
Note:
See TracChangeset
for help on using the changeset viewer.
