- Timestamp:
- Oct 28, 2013, 4:42:12 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/eam_branches/ipp-20130904/psLib/src/math/psStats.c
r34703 r36256 140 140 } 141 141 142 // Debug information 143 #define CZW 0 142 144 143 145 /*****************************************************************************/ … … 172 174 *****************************************************************************/ 173 175 174 static psF32 fitQuadraticSearchForYThenReturnBin(const psVector *xVec, psVector *yVec, psS32 binNum, psF32 yVal); 176 // static psF32 fitQuadraticSearchForYThenReturnBin(const psVector *xVec, psVector *yVec, psS32 binNum, psF32 yVal); 177 static psF32 fitLinearSearchForYThenReturnBin(const psVector *xVec, psVector *yVec, psS32 binNum, psF32 yVal); 175 178 176 179 /****************************************************************************** … … 229 232 } 230 233 count++; 234 231 235 } 232 236 if (errors) { … … 793 797 } else { 794 798 // Determine the bin size of the robust histogram, using the pre-defined number of bins 795 binSize = (max - min) / INITIAL_NUM_BINS;799 binSize = (max - min) / INITIAL_NUM_BINS; 796 800 } 797 801 psTrace(TRACE, 6, "Initial robust bin size is %.2f\n", binSize); … … 876 880 cumulative = psHistogramAlloc(min, max, numBins); 877 881 cumulative->nums->data.F32[0] = histogram->nums->data.F32[0]; 878 for (long i = 1; i < histogram->nums->n; i++) { 879 cumulative->nums->data.F32[i] = cumulative->nums->data.F32[i-1] + histogram->nums->data.F32[i]; 880 cumulative->bounds->data.F32[i-1] = histogram->bounds->data.F32[i]; 881 } 882 cumulative->bounds->data.F32[0] = histogram->bounds->data.F32[1]; 883 884 // Correctly fill the cumulative distribution with monotonically increasing values (skip zero valued bins). 885 long Nc = 1; // track the current bin of cumulative 886 // the boundaries for the current cumulative bin are from upper end of the last valid histogram bin to the 887 // upper end of the current histogram bin 888 for (long i = 1; i < histogram->nums->n - 1; i++) { 889 if (histogram->nums->data.F32[i] == 0.0) continue; 890 cumulative->nums->data.F32[Nc] = cumulative->nums->data.F32[Nc - 1] + histogram->nums->data.F32[i]; 891 cumulative->bounds->data.F32[Nc] = histogram->bounds->data.F32[i+1]; 892 Nc ++; 893 } 894 long Nlast = Nc - 1; // last valid cumulative bin 895 for (long i = Nc; i < histogram->nums->n; i++) { // Ensure the unused entries are filled. 896 cumulative->nums->data.F32[i] = cumulative->nums->data.F32[Nlast]; 897 cumulative->bounds->data.F32[i] = cumulative->bounds->data.F32[i-1] + 1.0; 898 } 899 882 900 if (psTraceGetLevel("psLib.math") >= 8) { 883 901 PS_VECTOR_PRINT_F32(cumulative->bounds); … … 895 913 896 914 // ADD step 3: Interpolate to the exact 50% position in bin units 897 stats->robustMedian = fitQuadraticSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binMedian, totalDataPoints/2.0);898 // float robustBin = fitQuadraticSearchForYThenReturnXusingValues(cumulative->bounds, cumulative->nums, binMedian, totalDataPoints/2.0);915 // stats->robustMedian = fitQuadraticSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binMedian, totalDataPoints/2.0); 916 // float robustBin = fitQuadraticSearchForYThenReturnXusingValues(cumulative->bounds, cumulative->nums, binMedian, totalDataPoints/2.0); 899 917 // fprintf (stderr, "robustBin : %f vs %f\n", robustBin, stats->robustMedian); 918 // There's no reason to do a quadratic fit near the 50% bin, as it's approximately linear there. 919 // Instead, do a 5-point linear fit. 920 stats->robustMedian = fitLinearSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binMedian, totalDataPoints/2.0); 900 921 901 922 // convert bin to bin value: this is the robust histogram median. … … 912 933 PS_BIN_FOR_VALUE(binL2, cumulative->nums, totalDataPoints * 0.308538f, 0); 913 934 PS_BIN_FOR_VALUE(binH2, cumulative->nums, totalDataPoints * 0.691462f, 0); 914 PS_BIN_FOR_VALUE(binL4, cumulative->nums, totalDataPoints * 0.022481f, 0); 915 PS_BIN_FOR_VALUE(binH4, cumulative->nums, totalDataPoints * 0.977519f, 0); 916 935 PS_BIN_FOR_VALUE(binL4, cumulative->nums, totalDataPoints * 0.022750f, 0); 936 PS_BIN_FOR_VALUE(binH4, cumulative->nums, totalDataPoints * 0.977250f, 0); 937 938 917 939 psTrace(TRACE, 6, "The 15.8655%% and 84.1345%% data point bins are (%ld, %ld).\n", 918 940 binLo, binHi); … … 926 948 goto escape; 927 949 } 928 950 929 951 // ADD step 4b: Interpolate Sigma (linearly) to find these two positions exactly: these are the 1sigma 930 952 // positions. … … 938 960 // (extrapolation should not be needed and will result in errors) 939 961 float binLoF32, binHiF32, binL2F32, binH2F32, binL4F32, binH4F32; 962 #if (0) 940 963 PS_BIN_INTERPOLATE (binLoF32, cumulative->nums, cumulative->bounds, binLo, 941 964 totalDataPoints * 0.158655f); … … 947 970 totalDataPoints * 0.691462f); 948 971 PS_BIN_INTERPOLATE (binL4F32, cumulative->nums, cumulative->bounds, binL4, 949 totalDataPoints * 0.022 481f);972 totalDataPoints * 0.022750f); 950 973 PS_BIN_INTERPOLATE (binH4F32, cumulative->nums, cumulative->bounds, binH4, 951 totalDataPoints * 0.977519f); 952 974 totalDataPoints * 0.977250f); 975 #else 976 binLoF32 = fitLinearSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binLo, totalDataPoints * 0.158655); 977 binHiF32 = fitLinearSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binHi, totalDataPoints * 0.841345); 978 binL2F32 = fitLinearSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binL2, totalDataPoints * 0.308538); 979 binH2F32 = fitLinearSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binH2, totalDataPoints * 0.691462); 980 binL4F32 = fitLinearSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binL4, totalDataPoints * 0.022750); 981 binH4F32 = fitLinearSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binH4, totalDataPoints * 0.977250); 982 #endif 953 983 // report +/- 1 sigma points 954 984 psTrace(TRACE, 5, … … 959 989 binL2F32, binH2F32); 960 990 psTrace(TRACE, 5, 961 "The exact 02.22 481 and 97.7519percent data point positions are: (%f, %f)\n",991 "The exact 02.2275 and 97.7250 percent data point positions are: (%f, %f)\n", 962 992 binL4F32, binH4F32); 963 993 994 // If some of the fits failed, attempt to fix this 995 if (!isfinite(binLoF32) && isfinite(binHiF32)) { binLoF32 = -1.0 * binHiF32; } 996 if (!isfinite(binHiF32) && isfinite(binLoF32)) { binHiF32 = -1.0 * binLoF32; } 997 if (!isfinite(binL2F32) && isfinite(binH2F32)) { binL2F32 = -1.0 * binH2F32; } 998 if (!isfinite(binH2F32) && isfinite(binL2F32)) { binH2F32 = -1.0 * binL2F32; } 999 if (!isfinite(binL4F32) && isfinite(binH4F32)) { binL4F32 = -1.0 * binH4F32; } 1000 if (!isfinite(binH4F32) && isfinite(binL4F32)) { binH4F32 = -1.0 * binL4F32; } 1001 964 1002 // ADD step 5: Determine SIGMA as the distance between binL2 and binH2 (+/- 0.5 sigma) 1003 1004 965 1005 float sigma1 = (binH2F32 - binL2F32); 966 1006 float sigma2 = (binHiF32 - binLoF32) / 2.0; 967 1007 float sigma4 = (binH4F32 - binL4F32) / 4.0; 968 1008 1009 // Fix again? 1010 if (!isfinite(sigma1) && isfinite(sigma2) && isfinite(sigma4)) { sigma1 = (sigma2 + sigma4) / 2.0; } 1011 if (!isfinite(sigma2) && isfinite(sigma1) && isfinite(sigma4)) { sigma2 = (sigma1 + sigma4) / 2.0; } 1012 if (!isfinite(sigma4) && isfinite(sigma2) && isfinite(sigma1)) { sigma4 = (sigma2 + sigma1) / 2.0; } 1013 969 1014 // take the smallest of the three: if we have a clump with wide outliers, sigma2 and 970 1015 // sigma4 will be biased high; if we have a bi-modal distribution, sigma1 and sigma2 971 1016 // will be biased high. 972 sigma = PS_MIN (sigma1, PS_MIN (sigma2, sigma4)); 1017 // sigma = PS_MIN (sigma1, PS_MIN (sigma2, sigma4)); 1018 // CZW: Instead, take the median. Taking the MIN forces a bias on unbiased data. 1019 // It seems like occasionally getting the wrong answer on a complex distribution 1020 // is more acceptable than always getting the wrong answer for simple ones. 1021 1022 1023 sigma = PS_MAX( PS_MIN(sigma1,sigma2), 1024 PS_MIN( PS_MAX(sigma1,sigma2), 1025 sigma4)); 973 1026 974 1027 psTrace(TRACE, 6, "The 1x sigma is %f.\n", sigma1); … … 977 1030 978 1031 psTrace(TRACE, 6, "The current sigma is %f.\n", sigma); 979 stats->robustStdev = sigma; 1032 // stats->robustStdev = sigma; 1033 stats->robustStdev = sigma; 1034 1035 #if (CZW && 0) 1036 // Skewness check: Find least biased sample for each pair. 1037 sigma1 = 2.0 * PS_MIN(binH2F32 - stats->robustMedian, 1038 stats->robustMedian - binL2F32); 1039 sigma2 = 1.0 * PS_MIN(binHiF32 - stats->robustMedian, 1040 stats->robustMedian - binLoF32); 1041 sigma4 = 0.5 * PS_MIN(binH4F32 - stats->robustMedian, 1042 stats->robustMedian - binL4F32); 1043 // Kurtosis check: Take median sample as the solution. 1044 stats->robustStdev = PS_MAX( PS_MIN(sigma1,sigma2), 1045 PS_MIN( PS_MAX(sigma1,sigma2), 1046 sigma4)); 1047 #endif 1048 1049 1050 #if (CZW) 1051 printf("CZW: bad sigma?: %f %f %f %f %f %f %f %f %f %f\n", 1052 binH2F32,binL2F32,binHiF32,binLoF32,binH4F32,binL4F32, 1053 sigma1,sigma2,sigma4,sigma); 1054 1055 printf("CZW (%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", 1056 iterate, 1057 stats->robustMedian,stats->robustStdev, 1058 fabs(cumulative->bounds->data.F32[binMedian] - cumulative->bounds->data.F32[binMedian + 1]), 1059 1060 cumulative->bounds->data.F32[binMedian-3],cumulative->bounds->data.F32[binMedian-2], 1061 cumulative->bounds->data.F32[binMedian-1], 1062 cumulative->bounds->data.F32[binMedian], 1063 cumulative->bounds->data.F32[binMedian+1], 1064 cumulative->bounds->data.F32[binMedian+2],cumulative->bounds->data.F32[binMedian+3], 1065 1066 cumulative->nums->data.F32[binMedian-3],cumulative->nums->data.F32[binMedian-2], 1067 cumulative->nums->data.F32[binMedian-1], 1068 cumulative->nums->data.F32[binMedian], 1069 cumulative->nums->data.F32[binMedian+1], 1070 cumulative->nums->data.F32[binMedian+2],cumulative->nums->data.F32[binMedian+3]); 1071 // PS_VECTOR_PRINT_F32(histogram->bounds); 1072 // PS_VECTOR_PRINT_F32(histogram->nums); 1073 // PS_VECTOR_PRINT_F32(cumulative->bounds); 1074 // PS_VECTOR_PRINT_F32(cumulative->nums); 1075 #endif 980 1076 981 1077 // ADD step 6: If the measured SIGMA is less than 2 times the bin size, exclude points which are more … … 983 1079 if (sigma < (3.0 * binSize)) { 984 1080 psTrace(TRACE, 6, "*************: Do another iteration (%f %f).\n", sigma, binSize); 985 long maskLo = PS_MAX(0, (binMedian - 25)); // Low index for masking region 986 long maskHi = PS_MIN(histogram->bounds->n - 1, (binMedian + 25)); // High index for masking 987 psF32 medianLo = histogram->bounds->data.F32[maskLo]; // Value at low index 988 psF32 medianHi = histogram->bounds->data.F32[maskHi]; // Value at high index 1081 1082 // these limits are supposed to be 25 x the raw bin size, NOT 25 of the cumulative histogram bins 1083 psF32 medianLo = stats->robustMedian - 25*binSize; 1084 psF32 medianHi = stats->robustMedian + 25*binSize; 1085 1086 // long maskLo = PS_MAX(0, (binMedian - 25)); // Low index for masking region 1087 // long maskHi = PS_MIN(cumulative->bounds->n - 1, (binMedian + 25)); // High index for masking 1088 // psF32 medianLo = cumulative->bounds->data.F32[maskLo]; // Value at low index 1089 // psF32 medianHi = cumulative->bounds->data.F32[maskHi]; // Value at high index 989 1090 psTrace(TRACE, 6, "Masking data more than 25 bins from the median\n"); 990 psTrace(TRACE, 6, 991 "The median is at bin number %ld. We mask bins outside the bin range (%ld:%ld)\n", 992 binMedian, maskLo, maskHi); 1091 // psTrace(TRACE, 6, "The median is at bin number %ld. We mask bins outside the bin range (%ld:%ld)\n", binMedian, maskLo, maskHi); 993 1092 psTrace(TRACE, 6, "Masking data outside (%f %f)\n", medianLo, medianHi); 1093 int Nmasked = 0; 994 1094 for (long i = 0 ; i < myVector->n ; i++) { 995 1095 if ((myVector->data.F32[i] < medianLo) || (myVector->data.F32[i] > medianHi)) { 996 // XXXX is this correct? is MASK_MARK safe?1096 if (mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & MASK_MARK) continue; 997 1097 mask->data.PS_TYPE_VECTOR_MASK_DATA[i] |= MASK_MARK; 998 1098 psTrace(TRACE, 6, "Masking element %ld is %f\n", i, myVector->data.F32[i]); 1099 Nmasked ++; 999 1100 } 1000 1101 } 1102 1103 if (Nmasked == 0) { 1104 // no significant change to the sigma & binsize -- we are done here 1105 iterate = -1; 1106 continue; 1107 } 1001 1108 1002 1109 // Free the histograms; they will be recreated on the next iteration, with new bounds … … 1030 1137 } 1031 1138 } 1032 1139 1033 1140 // XXX test lines while studying algorithm errors 1034 1141 // fprintf (stderr, "robust stats test %7.1f +/- %7.1f : %4ld %4ld %4ld %4ld %4ld : %f %f %f\n", … … 1040 1147 PS_BIN_FOR_VALUE (binLo25, cumulative->nums, totalDataPoints * 0.25f, 0); 1041 1148 PS_BIN_FOR_VALUE (binHi25, cumulative->nums, totalDataPoints * 0.75f, 0); 1042 psTrace(TRACE, 6, "The 25-percent and 75-p recent data point bins are (%ld, %ld).\n", binLo25, binHi25);1149 psTrace(TRACE, 6, "The 25-percent and 75-percent data point bins are (%ld, %ld).\n", binLo25, binHi25); 1043 1150 1044 1151 // ADD step 8: Interpolate to find these two positions exactly: these are the upper and lower quartile 1045 1152 // positions. 1046 psF32 binLo25F32 = fit QuadraticSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binLo25, totalDataPoints * 0.25f);1047 psF32 binHi25F32 = fit QuadraticSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binHi25, totalDataPoints * 0.75f);1153 psF32 binLo25F32 = fitLinearSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binLo25, totalDataPoints * 0.25f); 1154 psF32 binHi25F32 = fitLinearSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binHi25, totalDataPoints * 0.75f); 1048 1155 if (isnan(binLo25F32) || isnan(binHi25F32)) { 1049 COUNT_WARNING(10, 100, "could not determine the robustUQ : fitQuadraticSearchForYThenReturnBin() returned a NAN.\n");1156 COUNT_WARNING(10, 100, "could not determine the robustUQ or LQ: fitLinearSearchForYThenReturnBin() returned a NAN.\n"); 1050 1157 goto escape; 1051 1158 } … … 1100 1207 * "vectorFittedStats_v4" all versions of fitted stats now resolve to this function (only v4 1101 1208 * has really been used) vectorFittedStats requires guess for fittedMean and fittedStdev 1102 * robustN50 should also be set gaussian fit is performed using 2D polynomial to ln(y) this1209 * robustN50 should also be set gaussian fit is performed using 1D polynomial to ln(y) this 1103 1210 * version follows the upper portion of the distribution until it passes 0.5*peak 1104 1211 ********************/ … … 1135 1242 return true; 1136 1243 } 1137 1244 if (myVector->n < 1) { printf("There are no elements in this vector.\n"); abort(); } 1138 1245 float guessStdev = stats->robustStdev; // pass the guess sigma 1139 1246 float guessMean = stats->robustMedian; // pass the guess mean … … 1155 1262 // set roughly so that the lowest bins have about 2 cnts 1156 1263 // Nsmallest ~ N50 / (4*dN)) 1157 psF32 dN = PS_MAX (1, PS_MIN (4, stats->robustN50 / 8)); 1158 binSize = guessStdev / dN;1264 psF32 dN = PS_MAX (1, PS_MIN (4, stats->robustN50 / 8)); 1265 binSize = guessStdev / dN; 1159 1266 } 1160 1267 … … 1182 1289 // XXX can we calculate the binMin, binMax **before** building this histogram? 1183 1290 // if the range is too absurd, adjust numBins & binSize 1291 // We no longer want to reset the binSize here, as it can cause odd things. Better to select 1292 // a number of bins, and then set the min/max values to put those bins sanely around the mean. 1184 1293 long numBins = PS_MAX (50, PS_MIN (10000, (max - min) / binSize)); 1185 binSize = (max - min) / (float) numBins;1294 // binSize = (max - min) / (float) numBins; 1186 1295 psTrace(TRACE, 6, "The new min/max values are (%f, %f).\n", min, max); 1187 1296 psTrace(TRACE, 6, "The new bin size is %f.\n", binSize); 1188 1297 psTrace(TRACE, 6, "The numBins is %ld\n", numBins); 1189 1298 1299 1300 #define FITTED_CLIPPING_NUM 5.0 1301 if (min < guessMean - FITTED_CLIPPING_NUM * guessStdev) { 1302 min = guessMean - FITTED_CLIPPING_NUM * guessStdev; 1303 } 1304 if (max > guessMean + FITTED_CLIPPING_NUM * guessStdev) { 1305 max = guessMean + FITTED_CLIPPING_NUM * guessStdev; 1306 } 1307 1190 1308 psHistogram *histogram = psHistogramAlloc(min, max, numBins); // A new histogram (without outliers) 1191 1309 if (!psVectorHistogram(histogram, myVector, errors, mask, maskVal)) { … … 1222 1340 PS_BIN_FOR_VALUE (binMin, histogram->bounds, guessMean - minFitSigma*guessStdev, 0); 1223 1341 PS_BIN_FOR_VALUE (binMax, histogram->bounds, guessMean + maxFitSigma*guessStdev, 0); 1342 1224 1343 if (binMin == binMax) { 1225 1344 COUNT_WARNING(10, 100, "Failed to calculate the min/max of the input vector.\n"); … … 1248 1367 psTrace(TRACE, 6, "The clipped peak value is %f\n", histogram->nums->data.F32[binPeak]); 1249 1368 1369 1250 1370 float lowfitMean = NAN; 1251 1371 float lowfitStdev = NAN; … … 1285 1405 } 1286 1406 y->n = x->n = j; 1287 1407 1288 1408 // fit 2nd order polynomial to ln(y) = -(x-xo)^2/2sigma^2 1289 1409 // XXX this fit may fail with an error for an ill-conditioned matrix (bad data) … … 1297 1417 psErrorClear(); 1298 1418 COUNT_WARNING(10, 100, "Failed to fit a gaussian to the robust histogram.\n"); 1419 1299 1420 psFree(poly); 1300 1421 psFree(histogram); … … 1378 1499 psPolynomial1D *poly = psPolynomial1DAlloc(PS_POLYNOMIAL_ORD, 2); 1379 1500 bool status = psVectorFitPolynomial1D (poly, NULL, 0, y, NULL, x); 1501 #if (CZW && 0) 1502 for (long i = 0; i < x->n; i++) { 1503 printf("CZW: Dcheck: %ld %f %f %f\n", 1504 i,x->data.F32[i],y->data.F32[i], 1505 poly->coeff[0] + poly->coeff[1] * x->data.F32[i] + 1506 poly->coeff[2] * pow(x->data.F32[i],2)); 1507 } 1508 #endif 1380 1509 psFree(x); 1381 1510 psFree(y); … … 1393 1522 fullfitStdev = sqrt(-0.5/poly->coeff[2]); 1394 1523 fullfitMean = poly->coeff[1]*PS_SQR(fullfitStdev); 1524 1395 1525 #ifndef PS_NO_TRACE 1396 1526 psTrace(TRACE, 6, "Parabolic Symmetric fit results: %f + %f x + %f x^2\n", poly->coeff[0], poly->coeff[1], poly->coeff[2]); … … 1415 1545 } 1416 1546 1547 1417 1548 psFree (poly); 1418 1549 } … … 1437 1568 done = true; 1438 1569 } 1570 1571 1572 #if (CZW && 1) 1573 printf("CZW IN FITTED: iter %d %f \n" 1574 " low %f %f \n" 1575 " full %f %f \n" 1576 " robust %f %f \n" 1577 " final %f %f\n", 1578 iteration,minValueSym, 1579 lowfitMean,lowfitStdev, 1580 fullfitMean,fullfitStdev, 1581 stats->robustMedian,stats->robustStdev, 1582 guessMean,guessStdev); 1583 #endif 1439 1584 1440 1585 // Clean up after fitting … … 1965 2110 // other private functions used above 1966 2111 2112 # if (0) 1967 2113 static psF32 QuadraticInverse(psF32 a, 1968 2114 psF32 b, … … 1986 2132 return 0.5 * (xLo + xHi); 1987 2133 } 2134 2135 static psF32 LinearInverse(psF32 a, 2136 psF32 b, 2137 psF32 y, 2138 psF32 xLo, 2139 psF32 xHi 2140 ) 2141 { 2142 psF64 x = (y - b) / a; 2143 2144 if (xLo <= x && x <= xHi) { 2145 return x; 2146 } 2147 return 0.5 * (xLo + xHi); 2148 } 2149 # endif 1988 2150 1989 2151 # if (0) … … 2242 2404 return tmpFloat; 2243 2405 } 2244 # endif2245 2406 2246 2407 /****************************************************************************** … … 2276 2437 PS_ASSERT_INT_WITHIN_RANGE(binNum, 0, (int)(yVec->n - 1), NAN); 2277 2438 2278 psVector *x = psVectorAlloc(3, PS_TYPE_F64); 2279 psVector *y = psVectorAlloc(3, PS_TYPE_F64); 2439 // psVector *x = psVectorAlloc(3, PS_TYPE_F64); 2440 // psVector *y = psVectorAlloc(3, PS_TYPE_F64); 2441 psVector *x = psVectorAlloc(5, PS_TYPE_F64); 2442 psVector *y = psVectorAlloc(5, PS_TYPE_F64); 2280 2443 psF32 tmpFloat = 0.0f; 2281 2444 2282 if ((binNum >= 1) && (binNum <= (yVec->n - 2)) && (binNum <= (xVec->n - 2))) { 2445 // if ((binNum >= 1) && (binNum <= (yVec->n - 2)) && (binNum <= (xVec->n - 2))) { 2446 if ((binNum >= 2) && (binNum <= (yVec->n - 3)) && (binNum <= (xVec->n - 3))) { 2283 2447 // The general case. We have all three points. 2284 x->data.F64[0] = binNum - 1; 2285 x->data.F64[1] = binNum; 2286 x->data.F64[2] = binNum + 1; 2287 y->data.F64[0] = yVec->data.F32[binNum - 1]; 2288 y->data.F64[1] = yVec->data.F32[binNum]; 2289 y->data.F64[2] = yVec->data.F32[binNum + 1]; 2448 // x->data.F64[0] = binNum - 1; 2449 // x->data.F64[1] = binNum; 2450 // x->data.F64[2] = binNum + 1; 2451 x->data.F64[0] = xVec->data.F32[binNum - 2]; 2452 x->data.F64[1] = xVec->data.F32[binNum - 1]; 2453 x->data.F64[2] = xVec->data.F32[binNum + 0]; 2454 x->data.F64[3] = xVec->data.F32[binNum + 1]; 2455 x->data.F64[4] = xVec->data.F32[binNum + 2]; 2456 y->data.F64[0] = yVec->data.F32[binNum - 2]; 2457 y->data.F64[1] = yVec->data.F32[binNum - 1]; 2458 y->data.F64[2] = yVec->data.F32[binNum + 0]; 2459 y->data.F64[3] = yVec->data.F32[binNum + 1]; 2460 y->data.F64[4] = yVec->data.F32[binNum + 2]; 2290 2461 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]); 2291 2462 psTrace(TRACE, 6, "x data is (%f %f %f)\n", x->data.F64[0], x->data.F64[1], x->data.F64[2]); 2292 2463 psTrace(TRACE, 6, "y data is (%f %f %f)\n", y->data.F64[0], y->data.F64[1], y->data.F64[2]); 2293 2464 2465 2294 2466 // Ensure that the y value lies within range of the y values. 2295 if (! (((y->data.F64[0] <= yVal) && (yVal <= y->data.F64[ 2])) ||2296 ((y->data.F64[ 2] <= yVal) && (yVal <= y->data.F64[0]))) ) {2467 if (! (((y->data.F64[0] <= yVal) && (yVal <= y->data.F64[4])) || 2468 ((y->data.F64[4] <= yVal) && (yVal <= y->data.F64[0]))) ) { 2297 2469 psError(PS_ERR_BAD_PARAMETER_VALUE, true, 2298 2470 _("Specified yVal, %g, is not within y-range, %g to %g."), … … 2331 2503 2332 2504 psTrace(TRACE, 6, "We fit the polynomial, now find x such that f(x) equals %f\n", yVal); 2333 float binValue = QuadraticInverse(myPoly->coeff[2], myPoly->coeff[1], myPoly->coeff[0], yVal, x->data.F64[0], x->data.F64[ 2]);2505 float binValue = QuadraticInverse(myPoly->coeff[2], myPoly->coeff[1], myPoly->coeff[0], yVal, x->data.F64[0], x->data.F64[4]); 2334 2506 psFree(myPoly); 2335 2507 … … 2341 2513 return(NAN); 2342 2514 } 2343 2515 2344 2516 // I believe that mathematically the fitted bin position must be between binNum - 1 and binNum + 1 2345 assert (binValue >= binNum - 1); 2346 assert (binValue <= binNum + 1); 2347 2348 int fitBin = binValue; 2349 float dX = xVec->data.F32[fitBin+1] - xVec->data.F32[fitBin]; 2350 float dY = binValue - fitBin; 2351 tmpFloat = xVec->data.F32[fitBin] + dY * dX; 2517 // assert (binValue >= binNum - 1); 2518 // assert (binValue <= binNum + 1); 2519 2520 // int fitBin = binValue; 2521 // float dX = xVec->data.F32[fitBin+1] - xVec->data.F32[fitBin]; 2522 // float dY = binValue - fitBin; 2523 // tmpFloat = xVec->data.F32[fitBin] + dY * dX; 2524 tmpFloat = binValue; 2525 2352 2526 } else { 2353 2527 // These are special cases where the bin is at the beginning or end of the vector. … … 2381 2555 return tmpFloat; 2382 2556 } 2557 # endif 2558 2559 2560 /****************************************************************************** 2561 fitQuadraticSearchForYThenReturnXusingValues(*xVec, *yVec, binNum, yVal): A general routine 2562 which fits a quadratic to three points and returns the x bin value corresponding to the input 2563 y-value. This routine takes psVectors of x/y pairs as input, and fits a quadratic to the 3 2564 points surrounding element binNum in the vectors. This version uses the values of x[i] for the 2565 x coordinates (not the midpoints). This is appropriate for a cumulative histogram. It then 2566 determines for what value x does that quadratic f(x) = yVal (the input parameter). 2567 2568 XXX this function is used a fair amount in an inner loop: the polynomial fitting and evaluation 2569 could easily be done with statically allocated doubles, skipping the psLib versions of 2570 polynomial fitting, etc. 2571 2572 *****************************************************************************/ 2573 static psF32 fitLinearSearchForYThenReturnBin(const psVector *xVec, 2574 psVector *yVec, 2575 psS32 binNum, 2576 psF32 yVal 2577 ) 2578 { 2579 2580 # if (1) 2581 # define HALF_SIZE 2 2582 double Sx = 0.0; 2583 2584 double Sy = 0.0; 2585 double Sxx = 0.0; 2586 double Sxy = 0.0; 2587 double deltaY = 0.0; 2588 int N = 0; 2589 2590 for (int u = binNum - HALF_SIZE; u <= binNum + HALF_SIZE; u++) { 2591 if ((u >= 0)&&(u < yVec->n)) { 2592 if (u+1 < xVec->n) { 2593 Sx += yVec->data.F32[u]; 2594 Sxx += PS_SQR(yVec->data.F32[u]); 2595 2596 deltaY = xVec->data.F32[u]; 2597 //deltaY = 0.5 * (xVec->data.F32[u] + xVec->data.F32[u+1]); 2598 Sy += deltaY; 2599 Sxy += yVec->data.F32[u] * deltaY; 2600 N += 1; 2601 } 2602 } 2603 } 2604 double Det = N * Sxx - Sx * Sx; 2605 if (Det == 0.0) return NAN; 2606 if (N == 0) return NAN; 2607 2608 double C0 = (Sy*Sxx - Sx*Sxy) / Det; 2609 double C1 = (Sxy*N - Sx*Sy) / Det; 2610 2611 double value = C0 + yVal*C1; 2612 return value; 2613 2614 2615 # else 2616 psTrace(TRACE, 5, "binNum, yVal is (%d, %f)\n", binNum, yVal); 2617 if (psTraceGetLevel("psLib.math") >= 8) { 2618 PS_VECTOR_PRINT_F32(xVec); 2619 PS_VECTOR_PRINT_F32(yVec); 2620 } 2621 2622 PS_ASSERT_VECTOR_NON_NULL(xVec, NAN); 2623 PS_ASSERT_VECTOR_NON_NULL(yVec, NAN); 2624 PS_ASSERT_VECTOR_TYPE(xVec, PS_TYPE_F32, NAN); 2625 PS_ASSERT_VECTOR_TYPE(yVec, PS_TYPE_F32, NAN); 2626 PS_ASSERT_INT_WITHIN_RANGE(binNum, 0, (int)(xVec->n - 1), NAN); 2627 PS_ASSERT_INT_WITHIN_RANGE(binNum, 0, (int)(yVec->n - 1), NAN); 2628 2629 // psVector *x = psVectorAlloc(3, PS_TYPE_F64); 2630 // psVector *y = psVectorAlloc(3, PS_TYPE_F64); 2631 psVector *x = psVectorAlloc(5, PS_TYPE_F64); 2632 psVector *y = psVectorAlloc(5, PS_TYPE_F64); 2633 psF32 tmpFloat = 0.0f; 2634 2635 if ((binNum >= 2) && (binNum <= (yVec->n - 3)) && (binNum <= (xVec->n - 3))) { 2636 x->data.F64[0] = xVec->data.F32[binNum - 2]; 2637 x->data.F64[1] = xVec->data.F32[binNum - 1]; 2638 x->data.F64[2] = xVec->data.F32[binNum + 0]; 2639 x->data.F64[3] = xVec->data.F32[binNum + 1]; 2640 x->data.F64[4] = xVec->data.F32[binNum + 2]; 2641 2642 y->data.F64[0] = yVec->data.F32[binNum - 2]; 2643 y->data.F64[1] = yVec->data.F32[binNum - 1]; 2644 y->data.F64[2] = yVec->data.F32[binNum + 0]; 2645 y->data.F64[3] = yVec->data.F32[binNum + 1]; 2646 y->data.F64[4] = yVec->data.F32[binNum + 2]; 2647 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]); 2648 psTrace(TRACE, 6, "x data is (%f %f %f)\n", x->data.F64[0], x->data.F64[1], x->data.F64[2]); 2649 psTrace(TRACE, 6, "y data is (%f %f %f)\n", y->data.F64[0], y->data.F64[1], y->data.F64[2]); 2650 2651 // Ensure that the y value lies within range of the y values. 2652 if (! (((y->data.F64[0] <= yVal) && (yVal <= y->data.F64[4])) || 2653 ((y->data.F64[4] <= yVal) && (yVal <= y->data.F64[0]))) ) { 2654 psError(PS_ERR_BAD_PARAMETER_VALUE, true, 2655 _("Specified yVal, %g, is not within y-range, %g to %g."), 2656 (psF64)yVal, y->data.F64[0], y->data.F64[2]); 2657 return NAN; 2658 } 2659 2660 // Ensure that the y values are monotonic. 2661 if (((y->data.F64[0] < y->data.F64[1]) && !(y->data.F64[1] <= y->data.F64[2])) || 2662 ((y->data.F64[0] > y->data.F64[1]) && !(y->data.F64[1] >= y->data.F64[2]))) { 2663 psError(PS_ERR_UNKNOWN, true, 2664 "This routine must be called with monotonically increasing or decreasing data points.\n"); 2665 psFree(x); 2666 psFree(y); 2667 return NAN; 2668 } 2669 2670 // Determine the coefficients of the polynomial. 2671 psPolynomial1D *myPoly = psPolynomial1DAlloc(PS_POLYNOMIAL_ORD, 1); 2672 if (!psVectorFitPolynomial1D(myPoly, NULL, 0, y, NULL, x)) { 2673 psError(PS_ERR_UNEXPECTED_NULL, false, 2674 _("Failed to fit a 1-dimensional polynomial to the three specified data points. " 2675 "Returning NAN.")); 2676 psFree(x); 2677 psFree(y); 2678 return NAN; 2679 } 2680 2681 psTrace(TRACE, 6, "myPoly->coeff[0] is %f\n", myPoly->coeff[0]); 2682 psTrace(TRACE, 6, "myPoly->coeff[1] is %f\n", myPoly->coeff[1]); 2683 psTrace(TRACE, 6, "Fitted y vec is (%f %f)\n", 2684 (psF32) psPolynomial1DEval(myPoly, (psF64) x->data.F64[0]), 2685 (psF32) psPolynomial1DEval(myPoly, (psF64) x->data.F64[1])); 2686 2687 psTrace(TRACE, 6, "We fit the polynomial, now find x such that f(x) equals %f\n", yVal); 2688 float binValue = LinearInverse(myPoly->coeff[1], myPoly->coeff[0], yVal, x->data.F64[0], x->data.F64[4]); 2689 psFree(myPoly); 2690 2691 if (isnan(binValue)) { 2692 psError(PS_ERR_UNEXPECTED_NULL, 2693 false, _("Failed to determine the median of the fitted polynomial. Returning NAN.")); 2694 psFree(x); 2695 psFree(y); 2696 return(NAN); 2697 } 2698 2699 // I believe that mathematically the fitted bin position must be between binNum - 1 and binNum + 1 2700 // assert (binValue >= binNum - 1); 2701 // assert (binValue <= binNum + 1); 2702 2703 // int fitBin = binValue; 2704 // float dX = xVec->data.F32[fitBin+1] - xVec->data.F32[fitBin]; 2705 // float dY = binValue - fitBin; 2706 // tmpFloat = xVec->data.F32[fitBin] + dY * dX; 2707 tmpFloat = binValue; 2708 2709 2710 } else { 2711 // These are special cases where the bin is at the beginning or end of the vector. 2712 if (binNum == 0) { 2713 // We have two points only at the beginning of the vectors x and y. 2714 // X = (dX/dY)(Y - Yo) + Xo 2715 float dX = xVec->data.F32[1] - xVec->data.F32[0]; 2716 float dY = yVec->data.F32[1] - yVec->data.F32[0]; 2717 if (dY == 0.0) { 2718 tmpFloat = xVec->data.F32[0]; 2719 } else { 2720 tmpFloat = (yVal - yVec->data.F32[0]) * (dX / dY) + xVec->data.F32[0]; 2721 } 2722 } else if (binNum == (xVec->n - 1)) { 2723 // We have two points only at the end of the vectors x and y. 2724 // X = (dX/dY)(Y - Yo) + Xo 2725 float dX = xVec->data.F32[binNum] - xVec->data.F32[binNum-1]; 2726 float dY = yVec->data.F32[binNum] - yVec->data.F32[binNum-1]; 2727 if (dY == 0.0) { 2728 tmpFloat = xVec->data.F32[binNum-1]; 2729 } else { 2730 tmpFloat = (yVal - yVec->data.F32[binNum-1]) * (dX / dY) + xVec->data.F32[binNum-1]; 2731 } 2732 } 2733 } 2734 2735 psTrace(TRACE, 6, "FIT: return %f\n", tmpFloat); 2736 psFree(x); 2737 psFree(y); 2738 2739 return tmpFloat; 2740 # endif 2741 }
Note:
See TracChangeset
for help on using the changeset viewer.
