Changeset 27839 for branches/simmosaic_branches/psLib/src/math/psStats.c
- Timestamp:
- May 3, 2010, 8:45:22 AM (16 years ago)
- Location:
- branches/simmosaic_branches
- Files:
-
- 2 edited
-
. (modified) (1 prop)
-
psLib/src/math/psStats.c (modified) (31 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branches/simmosaic_branches
- Property svn:mergeinfo changed
-
branches/simmosaic_branches/psLib/src/math/psStats.c
r24790 r27839 129 129 130 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__); \131 static int nCalls = 1; \ 132 if (nCalls < LIMIT) { \ 133 psWarning(__VA_ARGS__); \ 134 } \ 135 if (!(nCalls % INTERVAL)) { \ 136 psWarning(__VA_ARGS__); \ 137 137 psWarning("(warning raised %d times)", nCalls); \ 138 } \139 nCalls ++; \138 } \ 139 nCalls ++; \ 140 140 } 141 141 142 142 143 143 /*****************************************************************************/ … … 217 217 for (long i = 0; i < numData; i++) { 218 218 // Check if the data is with the specified range 219 if (!isfinite(data[i])) 220 continue;219 if (!isfinite(data[i])) 220 continue; 221 221 if (useRange && (data[i] < stats->min)) 222 222 continue; … … 242 242 243 243 if (!isnan(mean)) { 244 stats->results |= PS_STAT_SAMPLE_MEAN;244 stats->results |= PS_STAT_SAMPLE_MEAN; 245 245 } 246 246 return true; … … 278 278 for (long i = 0; i < num; i++) { 279 279 // Check if the data is with the specified range 280 if (!isfinite(vector[i])) 281 continue;280 if (!isfinite(vector[i])) 281 continue; 282 282 if (useRange && (vector[i] < stats->min)) 283 283 continue; … … 329 329 // into the temporary vectors. 330 330 for (long i = 0; i < inVector->n; i++) { 331 if (!isfinite(input[i])) 332 continue;331 if (!isfinite(input[i])) 332 continue; 333 333 if (useRange && (input[i] < stats->min)) 334 334 continue; … … 353 353 // Sort the temporary vector. 354 354 if (!psVectorSort(outVector, outVector)) { // Sort in-place (since it's a copy, it's OK) 355 // an error in psVectorSort is a serious error355 // an error in psVectorSort is a serious error 356 356 psError(PS_ERR_UNEXPECTED_NULL, false, _("Failed to sort input data.")); 357 357 stats->sampleUQ = NAN; … … 407 407 // If the mean is NAN, then generate a warning and set the stdev to NAN. 408 408 if (isnan(stats->sampleMean)) { 409 COUNT_WARNING(10, 100, "WARNING: vectorSampleStdev(): sample mean is NAN. Setting stats->sampleStdev = NAN.");409 COUNT_WARNING(10, 100, "WARNING: vectorSampleStdev(): sample mean is NAN. Setting stats->sampleStdev = NAN."); 410 410 stats->sampleStdev = NAN; 411 411 return true; … … 425 425 for (long i = 0; i < myVector->n; i++) { 426 426 // Check if the data is with the specified range 427 if (!isfinite(data[i])) 428 continue;427 if (!isfinite(data[i])) 428 continue; 429 429 if (useRange && (data[i] < stats->min)) { 430 430 continue; … … 502 502 for (long i = 0; i < myVector->n; i++) { 503 503 // Check if the data is with the specified range 504 if (!isfinite(data[i])) 505 continue;504 if (!isfinite(data[i])) 505 continue; 506 506 if (useRange && (data[i] < stats->min)) { 507 507 continue; … … 749 749 // Iterate to get the best bin size; an iteration limit is enforced at the bottom of the loop. 750 750 for (int iterate = 1; iterate > 0; iterate++) { 751 psTrace(TRACE, 6, 752 "-------------------- Iterating on Bin size. Iteration number %d --------------------\n", 753 iterate); 751 psTrace(TRACE, 6, "-------------------- Iterating on Bin size. Iteration number %d --------------------\n", iterate); 752 753 if (iterate >= PS_ROBUST_MAX_ITERATIONS) { 754 // This occurs when a large number of the values are identical --- a bin size cannot be found 755 // that will spread out the distribution. Therefore, set what we can, and fall over 756 // gracefully. 757 COUNT_WARNING(10, 100, "Maximum number of iterations (%d) exceeded.", PS_ROBUST_MAX_ITERATIONS); 758 goto escape; 759 } 754 760 755 761 // Get the minimum and maximum values … … 771 777 stats->robustLQ = min; 772 778 stats->robustN50 = numValid; 773 // XXX this is sort of an invalid / out-of-bounds result: to set or not to set these bits:779 // XXX this is sort of an invalid / out-of-bounds result: to set or not to set these bits: 774 780 stats->results |= PS_STAT_ROBUST_MEDIAN; 775 781 stats->results |= PS_STAT_ROBUST_STDEV; … … 791 797 psTrace(TRACE, 6, "Initial robust bin size is %.2f\n", binSize); 792 798 793 // ADD step 0: Construct the histogram with the specified bin size. NOTE: we can not specify the bin 794 // size precisely since the argument to psHistogramAlloc() is the number of bins, not the binSize. If 795 // we get here, we know that binSize != 0.0. 796 long numBins = (max - min) / binSize; // Number of bins 799 // ADD step 0: Construct the histogram with the specified bin size. NOTE: we can 800 // not specify the bin size precisely since the argument to psHistogramAlloc() is 801 // the number of bins, not the binSize. If we get here, we know that binSize != 802 // 0.0. We can also have a floating-point round-off error such that the last bin 803 // of the histogram does not correspond exactly with the value of 'max'. Let's be 804 // a bit generous and extend the histogram by two bins in either direction 805 long numBins = 4 + (max - min) / binSize; // Number of bins 797 806 psTrace(TRACE, 6, "Numbins is %ld\n", numBins); 798 807 psTrace(TRACE, 6, "Creating a robust histogram from data range (%.2f - %.2f)\n", min, max); 799 808 // Generate the histogram 800 histogram = psHistogramAlloc(min , max, numBins);809 histogram = psHistogramAlloc(min - 2.0*binSize, max + 2.0*binSize, numBins); 801 810 // XXXXX we need to consider this step if errors -> variance 802 811 if (!psVectorHistogram(histogram, myVector, errors, mask, maskVal)) { 803 // if psVectorHistogram returns false, we have a programming error812 // if psVectorHistogram returns false, we have a programming error 804 813 psError(PS_ERR_UNKNOWN, false, "Unable to generate histogram for robust statistics.\n"); 805 psFree(histogram); 806 psFree(cumulative); 807 psFree(statsMinMax); 808 psFree(mask); 809 810 return false; 814 psFree(histogram); 815 psFree(cumulative); 816 psFree(statsMinMax); 817 psFree(mask); 818 return false; 811 819 } 812 820 if (psTraceGetLevel("psLib.math") >= 8) { 813 821 PS_VECTOR_PRINT_F32(histogram->bounds); 814 822 PS_VECTOR_PRINT_F32(histogram->nums); 823 } 824 825 // perversity check: if most of the values land in a single bin, then we probably 826 // have a perverse case (eg, small number of points at extremely large / small 827 // values; nearly bi-modal distribution). if so, keep only points within 5? 10? 828 // bins of that excess bin: 829 int nMaxBin = 0; 830 int iMaxBin = 0; 831 for (long i = 1; i < histogram->nums->n; i++) { 832 if (histogram->nums->data.F32[i] > nMaxBin) { 833 nMaxBin = histogram->nums->data.F32[i]; 834 iMaxBin = i; 835 } 836 } 837 if (nMaxBin > numValid / 2) { 838 float minKeep = histogram->bounds->data.F32[iMaxBin] - 10*binSize; 839 float maxKeep = histogram->bounds->data.F32[iMaxBin + 1] + 10*binSize; 840 int nInvalid = 0; 841 for (long i = 0; i < myVector->n; i++) { 842 // skip the already-masked values 843 if (mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & maskVal) continue; 844 bool invalid = false; 845 invalid |= (myVector->data.F32[i] <= minKeep); 846 invalid |= (myVector->data.F32[i] >= maxKeep); 847 invalid |= (!isfinite(myVector->data.F32[i])); 848 if (!invalid) continue; 849 mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = maskVal; 850 nInvalid ++; 851 } 852 853 if (nInvalid) { 854 psTrace(TRACE, 6, "data is concentrated in a single bin, masking %d extreme outliers and retrying\n", nInvalid); 855 psFree(histogram); 856 psFree(cumulative); 857 histogram = NULL; 858 cumulative = NULL; 859 continue; 860 } 861 // if we did not mask anything, give up. 815 862 } 816 863 … … 838 885 839 886 // ADD step 3: Interpolate to the exact 50% position in bin units 840 stats->robustMedian = fitQuadraticSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binMedian, totalDataPoints/2.0);841 // float robustBin = fitQuadraticSearchForYThenReturnXusingValues(cumulative->bounds, cumulative->nums, binMedian, totalDataPoints/2.0);842 // fprintf (stderr, "robustBin : %f vs %f\n", robustBin, stats->robustMedian);843 844 // convert bin to bin value: this is the robust histogram median.887 stats->robustMedian = fitQuadraticSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binMedian, totalDataPoints/2.0); 888 // float robustBin = fitQuadraticSearchForYThenReturnXusingValues(cumulative->bounds, cumulative->nums, binMedian, totalDataPoints/2.0); 889 // fprintf (stderr, "robustBin : %f vs %f\n", robustBin, stats->robustMedian); 890 891 // convert bin to bin value: this is the robust histogram median. 845 892 if (isnan(stats->robustMedian)) { 846 893 COUNT_WARNING(10, 100, "Failed to fit a quadratic and calculate the 50-percent position.\n"); … … 1007 1054 stats->robustN50 = N50; 1008 1055 psTrace(TRACE, 6, "The robustN50 is %ld.\n", N50); 1056 psTrace(TRACE, 6, "The robust median and stdev are %f, %f\n", stats->robustMedian, stats->robustStdev); 1009 1057 1010 1058 // Clean up … … 1054 1102 if (!vectorRobustStats(myVector, errors, mask, maskVal, stats)) { 1055 1103 psError(PS_ERR_UNKNOWN, false, "failure to measure robust stats\n"); 1056 return false;1057 }1104 return false; 1105 } 1058 1106 } 1059 1107 … … 1107 1155 psHistogram *histogram = psHistogramAlloc(min, max, numBins); // A new histogram (without outliers) 1108 1156 if (!psVectorHistogram(histogram, myVector, errors, mask, maskVal)) { 1109 // if psVectorHistogram returns false, we have a programming error1157 // if psVectorHistogram returns false, we have a programming error 1110 1158 psError(PS_ERR_UNKNOWN, false, "Unable to generate histogram for fitted statistics.\n"); 1111 1159 psFree(histogram); … … 1172 1220 PS_VECTOR_PRINT_F32(y); 1173 1221 } 1174 1175 // psMinimizeLMChi2 can return false for bad data as well as for serious failures1222 1223 // psMinimizeLMChi2 can return false for bad data as well as for serious failures 1176 1224 if (!psMinimizeLMChi2(minimizer, NULL, params, NULL, x, y, NULL, minimizeLMChi2Gauss1D)) { 1177 1225 psError(PS_ERR_UNKNOWN, false, "Failed to fit a gaussian to the robust histogram.\n"); … … 1235 1283 if (!vectorRobustStats(myVector, errors, mask, maskVal, stats)) { 1236 1284 psError(PS_ERR_UNKNOWN, false, "failure to measure robust stats\n"); 1237 return false;1238 }1285 return false; 1286 } 1239 1287 } 1240 1288 … … 1355 1403 // psVectorInit (fitMask, 0); 1356 1404 1357 // XXX not sure if these should result in errors or not...1405 // XXX not sure if these should result in errors or not... 1358 1406 if (!psVectorFitPolynomial1D (poly, NULL, 0, y, NULL, x)) { 1359 1407 psError(PS_ERR_UNKNOWN, false, "Failed to fit a gaussian to the robust histogram.\n"); … … 1432 1480 if (!vectorRobustStats(myVector, errors, mask, maskVal, stats)) { 1433 1481 psError(PS_ERR_UNKNOWN, false, "failure to measure robust stats\n"); 1434 return false;1435 }1482 return false; 1483 } 1436 1484 } 1437 1485 … … 1729 1777 if (!vectorRobustStats(myVector, errors, mask, maskVal, stats)) { 1730 1778 psError(PS_ERR_UNKNOWN, false, "failure to measure robust stats\n"); 1731 return false;1732 }1779 return false; 1780 } 1733 1781 } 1734 1782 1735 1783 // If the mean is NAN, then generate a warning and set the stdev to NAN. 1736 if (isnan(stats->robustMedian)) { 1737 stats->fittedStdev = NAN; 1738 stats->fittedStdev = NAN; 1739 return true; 1740 } 1784 if (isnan(stats->robustMedian)) goto escape; 1741 1785 1742 1786 float guessStdev = stats->robustStdev; // pass the guess sigma … … 1770 1814 COUNT_WARNING(10, 100, "Failed to calculate the min/max of the input vector.\n"); 1771 1815 psFree(statsMinMax); 1772 stats->fittedStdev = NAN; 1773 stats->fittedStdev = NAN; 1816 goto escape; 1817 } 1818 1819 // If all data points have the same value, then we set the appropriate members of stats and return. 1820 if (fabs(max - min) <= FLT_EPSILON) { 1821 COUNT_WARNING(10, 100, "All data points have the same value: %f.\n", min); 1822 stats->fittedMean = min; 1823 stats->fittedStdev = 0.0; 1824 stats->results |= PS_STAT_FITTED_MEAN_V4; 1825 stats->results |= PS_STAT_FITTED_STDEV_V4; 1774 1826 return true; 1775 1827 } … … 1789 1841 psFree(histogram); 1790 1842 psFree(statsMinMax); 1791 stats->fittedStdev = NAN; 1792 stats->fittedStdev = NAN; 1793 return true; 1843 goto escape; 1794 1844 } 1795 1845 if (psTraceGetLevel("psLib.math") >= 8) { … … 1823 1873 COUNT_WARNING(10, 100, "Failed to calculate the min/max of the input vector.\n"); 1824 1874 psFree(statsMinMax); 1825 stats->fittedStdev = NAN; 1826 stats->fittedStdev = NAN; 1827 return true; 1875 psFree(histogram); 1876 goto escape; 1828 1877 } 1829 1878 … … 1886 1935 1887 1936 // fit 2nd order polynomial to ln(y) = -(x-xo)^2/2sigma^2 1888 // XXX this fit may fail with an error for an ill-conditioned matrix (bad data)1889 // we probably should be able to handle the data errors gracefully1937 // XXX this fit may fail with an error for an ill-conditioned matrix (bad data) 1938 // we probably should be able to handle the data errors gracefully 1890 1939 psPolynomial1D *poly = psPolynomial1DAlloc(PS_POLYNOMIAL_ORD, 2); 1891 1940 bool status = psVectorFitPolynomial1D (poly, NULL, 0, y, NULL, x); … … 1894 1943 1895 1944 if (!status) { 1945 psErrorClear(); 1896 1946 COUNT_WARNING(10, 100, "Failed to fit a gaussian to the robust histogram.\n"); 1897 1947 psFree(poly); 1898 1948 psFree(histogram); 1899 1949 psFree(statsMinMax); 1900 stats->fittedStdev = NAN; 1901 stats->fittedStdev = NAN; 1902 return true; 1950 goto escape; 1903 1951 } 1904 1952 … … 1919 1967 1920 1968 COUNT_WARNING(10, 100, "fit did not converge\n"); 1921 stats->fittedStdev = NAN; 1922 stats->fittedStdev = NAN; 1923 return true; 1969 goto escape; 1924 1970 } 1925 1971 … … 1987 2033 1988 2034 if (!status) { 2035 psErrorClear(); 1989 2036 COUNT_WARNING(10, 100, "Failed to fit a gaussian to the robust histogram.\n"); 1990 2037 psFree(poly); 1991 2038 psFree(histogram); 1992 2039 psFree(statsMinMax); 1993 stats->fittedStdev = NAN; 1994 stats->fittedStdev = NAN; 1995 return true; 2040 goto escape; 1996 2041 } 1997 2042 … … 2038 2083 psTrace(TRACE, 6, "The fitted stdev is %f.\n", stats->fittedStdev); 2039 2084 2085 stats->results |= PS_STAT_FITTED_MEAN_V4; 2086 stats->results |= PS_STAT_FITTED_STDEV_V4; 2087 2088 return true; 2089 2090 escape: 2091 stats->fittedMean = NAN; 2092 stats->fittedStdev = NAN; 2040 2093 stats->results |= PS_STAT_FITTED_MEAN_V4; 2041 2094 stats->results |= PS_STAT_FITTED_STDEV_V4; … … 2896 2949 *****************************************************************************/ 2897 2950 static psF32 fitQuadraticSearchForYThenReturnBin(const psVector *xVec, 2898 psVector *yVec,2899 psS32 binNum,2900 psF32 yVal2951 psVector *yVec, 2952 psS32 binNum, 2953 psF32 yVal 2901 2954 ) 2902 2955 { … … 2980 3033 } 2981 3034 2982 // I believe that mathematically the fitted bin position must be between binNum - 1 and binNum + 12983 assert (binValue >= binNum - 1);2984 assert (binValue <= binNum + 1);2985 2986 int fitBin = binValue;2987 float dX = xVec->data.F32[fitBin+1] - xVec->data.F32[fitBin];2988 float dY = binValue - fitBin;2989 tmpFloat = xVec->data.F32[fitBin] + dY * dX;3035 // I believe that mathematically the fitted bin position must be between binNum - 1 and binNum + 1 3036 assert (binValue >= binNum - 1); 3037 assert (binValue <= binNum + 1); 3038 3039 int fitBin = binValue; 3040 float dX = xVec->data.F32[fitBin+1] - xVec->data.F32[fitBin]; 3041 float dY = binValue - fitBin; 3042 tmpFloat = xVec->data.F32[fitBin] + dY * dX; 2990 3043 } else { 2991 3044 // These are special cases where the bin is at the beginning or end of the vector. 2992 3045 if (binNum == 0) { 2993 3046 // We have two points only at the beginning of the vectors x and y. 2994 // X = (dX/dY)(Y - Yo) + Xo 2995 float dX = xVec->data.F32[1] - xVec->data.F32[0]; 2996 float dY = yVec->data.F32[1] - yVec->data.F32[0]; 2997 tmpFloat = (yVal - yVec->data.F32[0]) * (dX / dY) + xVec->data.F32[0]; 3047 // X = (dX/dY)(Y - Yo) + Xo 3048 float dX = xVec->data.F32[1] - xVec->data.F32[0]; 3049 float dY = yVec->data.F32[1] - yVec->data.F32[0]; 3050 if (dY == 0.0) { 3051 tmpFloat = xVec->data.F32[0]; 3052 } else { 3053 tmpFloat = (yVal - yVec->data.F32[0]) * (dX / dY) + xVec->data.F32[0]; 3054 } 2998 3055 } else if (binNum == (xVec->n - 1)) { 2999 3056 // We have two points only at the end of the vectors x and y. 3000 // X = (dX/dY)(Y - Yo) + Xo 3001 float dX = xVec->data.F32[binNum] - xVec->data.F32[binNum-1]; 3002 float dY = yVec->data.F32[binNum] - yVec->data.F32[binNum-1]; 3003 tmpFloat = (yVal - yVec->data.F32[binNum-1]) * (dX / dY) + xVec->data.F32[binNum-1]; 3004 } 3057 // X = (dX/dY)(Y - Yo) + Xo 3058 float dX = xVec->data.F32[binNum] - xVec->data.F32[binNum-1]; 3059 float dY = yVec->data.F32[binNum] - yVec->data.F32[binNum-1]; 3060 if (dY == 0.0) { 3061 tmpFloat = xVec->data.F32[binNum-1]; 3062 } else { 3063 tmpFloat = (yVal - yVec->data.F32[binNum-1]) * (dX / dY) + xVec->data.F32[binNum-1]; 3064 } 3065 } 3005 3066 } 3006 3067
Note:
See TracChangeset
for help on using the changeset viewer.
