Changeset 36345
- Timestamp:
- Dec 4, 2013, 2:11:09 PM (13 years ago)
- Location:
- branches/eam_branches/ipp-20130904/psLib/src/math
- Files:
-
- 2 edited
-
psMinimizePolyFit.c (modified) (4 diffs, 1 prop)
-
psStats.c (modified) (37 diffs, 1 prop)
Legend:
- Unmodified
- Added
- Removed
-
branches/eam_branches/ipp-20130904/psLib/src/math/psMinimizePolyFit.c
- Property svn:mergeinfo set to
r36291 r36345 715 715 sigma = (sorted->data.F64[3 * sorted->n / 4] - sorted->data.F64[sorted->n / 4]); 716 716 psFree(sorted); 717 718 if ((!isfinite(median))|| 719 (!isfinite(sigma))) { 720 median = 0.0; 721 sigma = 1.0; 722 } 723 if ((median == 0.0)&&(sigma == 1.0)) { 724 scale = false; 725 } 717 726 // I can't see a way to not clobber x if it's already F64, so make a copy.x 718 727 z64 = psVectorCopy(NULL,x64,PS_TYPE_F64); … … 726 735 727 736 result = VectorFitPolynomial1DOrd(poly, mask, maskValue, f64, fErr64, z64); 737 psFree(z64); // Done with this. 728 738 } 729 739 else { … … 736 746 737 747 if (scale) { 738 psFree(z64); // Done with this.739 740 748 // Undo scaling in the polynomial values. 741 749 psF64 *Zcoeff = psAlloc((1 + poly->nX) * sizeof(psF64)); … … 757 765 #if (CZW) 758 766 printf(" %d %d %f %f %f %f => %f\n", 759 i,j,Zcoeff[j],pow(1.0 / sigma,j) * pow(-1,j - i),pow(median,j - i),1.0 * psBinomialCoeff(j,i), 767 i,j,Zcoeff[j], 768 pow(1.0 / sigma,j) * pow(-1,j - i), 769 pow(median,j - i), 770 1.0 * psBinomialCoeff(j,i), 760 771 Zcoeff[j] * pow(1.0 / sigma,j) * pow(-1,j -i) * pow(median,j - i) * 1.0 * psBinomialCoeff(j,i) 761 772 ); -
branches/eam_branches/ipp-20130904/psLib/src/math/psStats.c
- Property svn:mergeinfo set to
r36262 r36345 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 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", 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 1266 // CZW 2013-11-20: We know that the histogram is going to be basically Gaussian. 1267 // Furthermore, we only use the inner +/- 2 sigma parts. Therefore, define the 1268 // binsize such that the bin at 2 sigma contains ~50 points (S/N ~ 7). robustN50 1269 // contains half the total points, so 2 * robustN50 / 50 is the fraction of all 1270 // points in the 2 sigma bin. Dance the erf() relations around, and it looks like 1271 // there's a factor of about 1/20 to include. Keep the PS_MAX to ensure we never bin 1272 // wider than 1 sigma when the number of points is small. 1273 psF32 dN = PS_MAX(1, (stats->robustN50 / 500.0)); 1274 binSize = guessStdev / dN; 1159 1275 } 1160 1276 … … 1182 1298 // XXX can we calculate the binMin, binMax **before** building this histogram? 1183 1299 // if the range is too absurd, adjust numBins & binSize 1184 long numBins = PS_MAX (50, PS_MIN (10000, (max - min) / binSize)); 1185 binSize = (max - min) / (float) numBins; 1300 // We no longer want to reset the binSize here, as it can cause odd things. Better to select 1301 // a number of bins, and then set the min/max values to put those bins sanely around the mean. 1302 // long numBins = PS_MAX (50, PS_MIN (10000, (max - min) / binSize)); 1303 // binSize = (max - min) / (float) numBins; 1186 1304 psTrace(TRACE, 6, "The new min/max values are (%f, %f).\n", min, max); 1187 1305 psTrace(TRACE, 6, "The new bin size is %f.\n", binSize); 1188 psTrace(TRACE, 6, "The numBins is %ld\n", numBins); 1189 1306 // psTrace(TRACE, 6, "The numBins is %ld\n", numBins); 1307 1308 1309 #define FITTED_CLIPPING_NUM 5.0 1310 if (min < guessMean - FITTED_CLIPPING_NUM * guessStdev) { 1311 min = guessMean - FITTED_CLIPPING_NUM * guessStdev; 1312 } 1313 if (max > guessMean + FITTED_CLIPPING_NUM * guessStdev) { 1314 max = guessMean + FITTED_CLIPPING_NUM * guessStdev; 1315 } 1316 long numBins = PS_MAX (50, PS_MIN (10000, (max - min) / binSize)); 1317 if (CZW) { printf("I've clipped: %f %f => %f %f ; %f %ld\n",guessMean,guessStdev,min,max,binSize,stats->robustN50); } 1190 1318 psHistogram *histogram = psHistogramAlloc(min, max, numBins); // A new histogram (without outliers) 1191 1319 if (!psVectorHistogram(histogram, myVector, errors, mask, maskVal)) { … … 1222 1350 PS_BIN_FOR_VALUE (binMin, histogram->bounds, guessMean - minFitSigma*guessStdev, 0); 1223 1351 PS_BIN_FOR_VALUE (binMax, histogram->bounds, guessMean + maxFitSigma*guessStdev, 0); 1352 1224 1353 if (binMin == binMax) { 1225 1354 COUNT_WARNING(10, 100, "Failed to calculate the min/max of the input vector.\n"); … … 1238 1367 } 1239 1368 psTrace (TRACE, 6, "(%f = %.0f) ", histogram->bounds->data.F32[i], histogram->nums->data.F32[i]); 1369 if (CZW) { printf("CENTERED_HISTOGRAM: %f %f\n", 1370 PS_BIN_MIDPOINT(histogram,i), 1371 histogram->nums->data.F32[i]); } 1240 1372 } 1241 1373 psTrace (TRACE, 6, "\n"); 1242 1374 1375 if (CZW) { printf("Bin selection done: %ld %f %f %ld %f %f %ld %f %f\n", 1376 binMin,PS_BIN_MIDPOINT(histogram,binMin),histogram->nums->data.F32[binMin], 1377 binMax,PS_BIN_MIDPOINT(histogram,binMax),histogram->nums->data.F32[binMax], 1378 binPeak,PS_BIN_MIDPOINT(histogram,binPeak),histogram->nums->data.F32[binPeak]); 1379 } 1380 1243 1381 // assume a reasonably well-defined gaussian-like population; run from peak out until val < 0.25*peak 1244 1382 psTrace(TRACE, 6, "The clipped numBins is %ld\n", binMax - binMin); … … 1248 1386 psTrace(TRACE, 6, "The clipped peak value is %f\n", histogram->nums->data.F32[binPeak]); 1249 1387 1388 1250 1389 float lowfitMean = NAN; 1251 1390 float lowfitStdev = NAN; … … 1285 1424 } 1286 1425 y->n = x->n = j; 1287 1426 1288 1427 // fit 2nd order polynomial to ln(y) = -(x-xo)^2/2sigma^2 1289 1428 // XXX this fit may fail with an error for an ill-conditioned matrix (bad data) … … 1291 1430 psPolynomial1D *poly = psPolynomial1DAlloc(PS_POLYNOMIAL_ORD, 2); 1292 1431 bool status = psVectorFitPolynomial1D (poly, NULL, 0, y, NULL, x); 1432 #if (CZW && 1) 1433 printf("CZW: LowfitPoly: %f %f %f\n",poly->coeff[0],poly->coeff[1],poly->coeff[2]); 1434 for (long i = 0; i < x->n; i++) { 1435 printf("CZW: Lowfit: %d %ld %f %f %f\n", 1436 status,i,x->data.F32[i],y->data.F32[i], 1437 poly->coeff[0] + poly->coeff[1] * x->data.F32[i] + 1438 poly->coeff[2] * pow(x->data.F32[i],2)); 1439 } 1440 #endif 1293 1441 psFree(x); 1294 1442 psFree(y); … … 1305 1453 if (poly->coeff[2] >= 0.0) { 1306 1454 COUNT_WARNING(10, 100, "Failed parabolic fit: %f + %f x + %f x^2\n", poly->coeff[0], poly->coeff[1], poly->coeff[2]); 1455 1307 1456 psFree(poly); 1308 1457 psFree(histogram); … … 1357 1506 } 1358 1507 } 1508 1359 1509 psTrace(TRACE, 6, "Lower bound for symmetric range: %f (%ld)\n", 1360 1510 PS_BIN_MIDPOINT(histogram, binS), binS); … … 1378 1528 psPolynomial1D *poly = psPolynomial1DAlloc(PS_POLYNOMIAL_ORD, 2); 1379 1529 bool status = psVectorFitPolynomial1D (poly, NULL, 0, y, NULL, x); 1530 #if (CZW && 1) 1531 printf("CZW: FullfitPoly: %f %f %f\n",poly->coeff[0],poly->coeff[1],poly->coeff[2]); 1532 for (long i = 0; i < x->n; i++) { 1533 printf("CZW: Fullfit: %d %ld %f %f %f\n", 1534 status,i,x->data.F32[i],y->data.F32[i], 1535 poly->coeff[0] + poly->coeff[1] * x->data.F32[i] + 1536 poly->coeff[2] * pow(x->data.F32[i],2)); 1537 } 1538 #endif 1380 1539 psFree(x); 1381 1540 psFree(y); … … 1393 1552 fullfitStdev = sqrt(-0.5/poly->coeff[2]); 1394 1553 fullfitMean = poly->coeff[1]*PS_SQR(fullfitStdev); 1554 1395 1555 #ifndef PS_NO_TRACE 1396 1556 psTrace(TRACE, 6, "Parabolic Symmetric fit results: %f + %f x + %f x^2\n", poly->coeff[0], poly->coeff[1], poly->coeff[2]); … … 1415 1575 } 1416 1576 1577 1417 1578 psFree (poly); 1418 1579 } … … 1437 1598 done = true; 1438 1599 } 1600 1601 1602 #if (CZW && 1) 1603 printf("CZW IN FITTED: iter %d %f \n" 1604 " low %f %f \n" 1605 " full %f %f \n" 1606 " robust %f %f \n" 1607 " final %f %f\n", 1608 iteration,minValueSym, 1609 lowfitMean,lowfitStdev, 1610 fullfitMean,fullfitStdev, 1611 stats->robustMedian,stats->robustStdev, 1612 guessMean,guessStdev); 1613 #endif 1439 1614 1440 1615 // Clean up after fitting … … 1965 2140 // other private functions used above 1966 2141 2142 # if (0) 1967 2143 static psF32 QuadraticInverse(psF32 a, 1968 2144 psF32 b, … … 1986 2162 return 0.5 * (xLo + xHi); 1987 2163 } 2164 2165 static psF32 LinearInverse(psF32 a, 2166 psF32 b, 2167 psF32 y, 2168 psF32 xLo, 2169 psF32 xHi 2170 ) 2171 { 2172 psF64 x = (y - b) / a; 2173 2174 if (xLo <= x && x <= xHi) { 2175 return x; 2176 } 2177 return 0.5 * (xLo + xHi); 2178 } 2179 # endif 1988 2180 1989 2181 # if (0) … … 2242 2434 return tmpFloat; 2243 2435 } 2244 # endif2245 2436 2246 2437 /****************************************************************************** … … 2276 2467 PS_ASSERT_INT_WITHIN_RANGE(binNum, 0, (int)(yVec->n - 1), NAN); 2277 2468 2278 psVector *x = psVectorAlloc(3, PS_TYPE_F64); 2279 psVector *y = psVectorAlloc(3, PS_TYPE_F64); 2469 // psVector *x = psVectorAlloc(3, PS_TYPE_F64); 2470 // psVector *y = psVectorAlloc(3, PS_TYPE_F64); 2471 psVector *x = psVectorAlloc(5, PS_TYPE_F64); 2472 psVector *y = psVectorAlloc(5, PS_TYPE_F64); 2280 2473 psF32 tmpFloat = 0.0f; 2281 2474 2282 if ((binNum >= 1) && (binNum <= (yVec->n - 2)) && (binNum <= (xVec->n - 2))) { 2475 // if ((binNum >= 1) && (binNum <= (yVec->n - 2)) && (binNum <= (xVec->n - 2))) { 2476 if ((binNum >= 2) && (binNum <= (yVec->n - 3)) && (binNum <= (xVec->n - 3))) { 2283 2477 // 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]; 2478 // x->data.F64[0] = binNum - 1; 2479 // x->data.F64[1] = binNum; 2480 // x->data.F64[2] = binNum + 1; 2481 x->data.F64[0] = xVec->data.F32[binNum - 2]; 2482 x->data.F64[1] = xVec->data.F32[binNum - 1]; 2483 x->data.F64[2] = xVec->data.F32[binNum + 0]; 2484 x->data.F64[3] = xVec->data.F32[binNum + 1]; 2485 x->data.F64[4] = xVec->data.F32[binNum + 2]; 2486 y->data.F64[0] = yVec->data.F32[binNum - 2]; 2487 y->data.F64[1] = yVec->data.F32[binNum - 1]; 2488 y->data.F64[2] = yVec->data.F32[binNum + 0]; 2489 y->data.F64[3] = yVec->data.F32[binNum + 1]; 2490 y->data.F64[4] = yVec->data.F32[binNum + 2]; 2290 2491 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 2492 psTrace(TRACE, 6, "x data is (%f %f %f)\n", x->data.F64[0], x->data.F64[1], x->data.F64[2]); 2292 2493 psTrace(TRACE, 6, "y data is (%f %f %f)\n", y->data.F64[0], y->data.F64[1], y->data.F64[2]); 2293 2494 2495 2294 2496 // 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]))) ) {2497 if (! (((y->data.F64[0] <= yVal) && (yVal <= y->data.F64[4])) || 2498 ((y->data.F64[4] <= yVal) && (yVal <= y->data.F64[0]))) ) { 2297 2499 psError(PS_ERR_BAD_PARAMETER_VALUE, true, 2298 2500 _("Specified yVal, %g, is not within y-range, %g to %g."), … … 2331 2533 2332 2534 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]);2535 float binValue = QuadraticInverse(myPoly->coeff[2], myPoly->coeff[1], myPoly->coeff[0], yVal, x->data.F64[0], x->data.F64[4]); 2334 2536 psFree(myPoly); 2335 2537 … … 2341 2543 return(NAN); 2342 2544 } 2343 2545 2344 2546 // 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; 2547 // assert (binValue >= binNum - 1); 2548 // assert (binValue <= binNum + 1); 2549 2550 // int fitBin = binValue; 2551 // float dX = xVec->data.F32[fitBin+1] - xVec->data.F32[fitBin]; 2552 // float dY = binValue - fitBin; 2553 // tmpFloat = xVec->data.F32[fitBin] + dY * dX; 2554 tmpFloat = binValue; 2555 2352 2556 } else { 2353 2557 // These are special cases where the bin is at the beginning or end of the vector. … … 2381 2585 return tmpFloat; 2382 2586 } 2587 # endif 2588 2589 2590 /****************************************************************************** 2591 fitQuadraticSearchForYThenReturnXusingValues(*xVec, *yVec, binNum, yVal): A general routine 2592 which fits a quadratic to three points and returns the x bin value corresponding to the input 2593 y-value. This routine takes psVectors of x/y pairs as input, and fits a quadratic to the 3 2594 points surrounding element binNum in the vectors. This version uses the values of x[i] for the 2595 x coordinates (not the midpoints). This is appropriate for a cumulative histogram. It then 2596 determines for what value x does that quadratic f(x) = yVal (the input parameter). 2597 2598 XXX this function is used a fair amount in an inner loop: the polynomial fitting and evaluation 2599 could easily be done with statically allocated doubles, skipping the psLib versions of 2600 polynomial fitting, etc. 2601 2602 *****************************************************************************/ 2603 static psF32 fitLinearSearchForYThenReturnBin(const psVector *xVec, 2604 psVector *yVec, 2605 psS32 binNum, 2606 psF32 yVal 2607 ) 2608 { 2609 2610 # if (1) 2611 # define HALF_SIZE 2 2612 double Sx = 0.0; 2613 2614 double Sy = 0.0; 2615 double Sxx = 0.0; 2616 double Sxy = 0.0; 2617 double deltaY = 0.0; 2618 int N = 0; 2619 2620 for (int u = binNum - HALF_SIZE; u <= binNum + HALF_SIZE; u++) { 2621 if ((u >= 0)&&(u < yVec->n)) { 2622 if (u+1 < xVec->n) { 2623 Sx += yVec->data.F32[u]; 2624 Sxx += PS_SQR(yVec->data.F32[u]); 2625 2626 deltaY = xVec->data.F32[u]; 2627 //deltaY = 0.5 * (xVec->data.F32[u] + xVec->data.F32[u+1]); 2628 Sy += deltaY; 2629 Sxy += yVec->data.F32[u] * deltaY; 2630 N += 1; 2631 } 2632 } 2633 } 2634 double Det = N * Sxx - Sx * Sx; 2635 if (Det == 0.0) return NAN; 2636 if (N == 0) return NAN; 2637 2638 double C0 = (Sy*Sxx - Sx*Sxy) / Det; 2639 double C1 = (Sxy*N - Sx*Sy) / Det; 2640 2641 double value = C0 + yVal*C1; 2642 return value; 2643 2644 2645 # else 2646 psTrace(TRACE, 5, "binNum, yVal is (%d, %f)\n", binNum, yVal); 2647 if (psTraceGetLevel("psLib.math") >= 8) { 2648 PS_VECTOR_PRINT_F32(xVec); 2649 PS_VECTOR_PRINT_F32(yVec); 2650 } 2651 2652 PS_ASSERT_VECTOR_NON_NULL(xVec, NAN); 2653 PS_ASSERT_VECTOR_NON_NULL(yVec, NAN); 2654 PS_ASSERT_VECTOR_TYPE(xVec, PS_TYPE_F32, NAN); 2655 PS_ASSERT_VECTOR_TYPE(yVec, PS_TYPE_F32, NAN); 2656 PS_ASSERT_INT_WITHIN_RANGE(binNum, 0, (int)(xVec->n - 1), NAN); 2657 PS_ASSERT_INT_WITHIN_RANGE(binNum, 0, (int)(yVec->n - 1), NAN); 2658 2659 // psVector *x = psVectorAlloc(3, PS_TYPE_F64); 2660 // psVector *y = psVectorAlloc(3, PS_TYPE_F64); 2661 psVector *x = psVectorAlloc(5, PS_TYPE_F64); 2662 psVector *y = psVectorAlloc(5, PS_TYPE_F64); 2663 psF32 tmpFloat = 0.0f; 2664 2665 if ((binNum >= 2) && (binNum <= (yVec->n - 3)) && (binNum <= (xVec->n - 3))) { 2666 x->data.F64[0] = xVec->data.F32[binNum - 2]; 2667 x->data.F64[1] = xVec->data.F32[binNum - 1]; 2668 x->data.F64[2] = xVec->data.F32[binNum + 0]; 2669 x->data.F64[3] = xVec->data.F32[binNum + 1]; 2670 x->data.F64[4] = xVec->data.F32[binNum + 2]; 2671 2672 y->data.F64[0] = yVec->data.F32[binNum - 2]; 2673 y->data.F64[1] = yVec->data.F32[binNum - 1]; 2674 y->data.F64[2] = yVec->data.F32[binNum + 0]; 2675 y->data.F64[3] = yVec->data.F32[binNum + 1]; 2676 y->data.F64[4] = yVec->data.F32[binNum + 2]; 2677 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]); 2678 psTrace(TRACE, 6, "x data is (%f %f %f)\n", x->data.F64[0], x->data.F64[1], x->data.F64[2]); 2679 psTrace(TRACE, 6, "y data is (%f %f %f)\n", y->data.F64[0], y->data.F64[1], y->data.F64[2]); 2680 2681 // Ensure that the y value lies within range of the y values. 2682 if (! (((y->data.F64[0] <= yVal) && (yVal <= y->data.F64[4])) || 2683 ((y->data.F64[4] <= yVal) && (yVal <= y->data.F64[0]))) ) { 2684 psError(PS_ERR_BAD_PARAMETER_VALUE, true, 2685 _("Specified yVal, %g, is not within y-range, %g to %g."), 2686 (psF64)yVal, y->data.F64[0], y->data.F64[2]); 2687 return NAN; 2688 } 2689 2690 // Ensure that the y values are monotonic. 2691 if (((y->data.F64[0] < y->data.F64[1]) && !(y->data.F64[1] <= y->data.F64[2])) || 2692 ((y->data.F64[0] > y->data.F64[1]) && !(y->data.F64[1] >= y->data.F64[2]))) { 2693 psError(PS_ERR_UNKNOWN, true, 2694 "This routine must be called with monotonically increasing or decreasing data points.\n"); 2695 psFree(x); 2696 psFree(y); 2697 return NAN; 2698 } 2699 2700 // Determine the coefficients of the polynomial. 2701 psPolynomial1D *myPoly = psPolynomial1DAlloc(PS_POLYNOMIAL_ORD, 1); 2702 if (!psVectorFitPolynomial1D(myPoly, NULL, 0, y, NULL, x)) { 2703 psError(PS_ERR_UNEXPECTED_NULL, false, 2704 _("Failed to fit a 1-dimensional polynomial to the three specified data points. " 2705 "Returning NAN.")); 2706 psFree(x); 2707 psFree(y); 2708 return NAN; 2709 } 2710 2711 psTrace(TRACE, 6, "myPoly->coeff[0] is %f\n", myPoly->coeff[0]); 2712 psTrace(TRACE, 6, "myPoly->coeff[1] is %f\n", myPoly->coeff[1]); 2713 psTrace(TRACE, 6, "Fitted y vec is (%f %f)\n", 2714 (psF32) psPolynomial1DEval(myPoly, (psF64) x->data.F64[0]), 2715 (psF32) psPolynomial1DEval(myPoly, (psF64) x->data.F64[1])); 2716 2717 psTrace(TRACE, 6, "We fit the polynomial, now find x such that f(x) equals %f\n", yVal); 2718 float binValue = LinearInverse(myPoly->coeff[1], myPoly->coeff[0], yVal, x->data.F64[0], x->data.F64[4]); 2719 psFree(myPoly); 2720 2721 if (isnan(binValue)) { 2722 psError(PS_ERR_UNEXPECTED_NULL, 2723 false, _("Failed to determine the median of the fitted polynomial. Returning NAN.")); 2724 psFree(x); 2725 psFree(y); 2726 return(NAN); 2727 } 2728 2729 // I believe that mathematically the fitted bin position must be between binNum - 1 and binNum + 1 2730 // assert (binValue >= binNum - 1); 2731 // assert (binValue <= binNum + 1); 2732 2733 // int fitBin = binValue; 2734 // float dX = xVec->data.F32[fitBin+1] - xVec->data.F32[fitBin]; 2735 // float dY = binValue - fitBin; 2736 // tmpFloat = xVec->data.F32[fitBin] + dY * dX; 2737 tmpFloat = binValue; 2738 2739 2740 } else { 2741 // These are special cases where the bin is at the beginning or end of the vector. 2742 if (binNum == 0) { 2743 // We have two points only at the beginning of the vectors x and y. 2744 // X = (dX/dY)(Y - Yo) + Xo 2745 float dX = xVec->data.F32[1] - xVec->data.F32[0]; 2746 float dY = yVec->data.F32[1] - yVec->data.F32[0]; 2747 if (dY == 0.0) { 2748 tmpFloat = xVec->data.F32[0]; 2749 } else { 2750 tmpFloat = (yVal - yVec->data.F32[0]) * (dX / dY) + xVec->data.F32[0]; 2751 } 2752 } else if (binNum == (xVec->n - 1)) { 2753 // We have two points only at the end of the vectors x and y. 2754 // X = (dX/dY)(Y - Yo) + Xo 2755 float dX = xVec->data.F32[binNum] - xVec->data.F32[binNum-1]; 2756 float dY = yVec->data.F32[binNum] - yVec->data.F32[binNum-1]; 2757 if (dY == 0.0) { 2758 tmpFloat = xVec->data.F32[binNum-1]; 2759 } else { 2760 tmpFloat = (yVal - yVec->data.F32[binNum-1]) * (dX / dY) + xVec->data.F32[binNum-1]; 2761 } 2762 } 2763 } 2764 2765 psTrace(TRACE, 6, "FIT: return %f\n", tmpFloat); 2766 psFree(x); 2767 psFree(y); 2768 2769 return tmpFloat; 2770 # endif 2771 }
Note:
See TracChangeset
for help on using the changeset viewer.
