Changeset 24092
- Timestamp:
- May 6, 2009, 2:23:14 PM (17 years ago)
- File:
-
- 1 edited
-
trunk/psLib/src/math/psStats.c (modified) (5 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psLib/src/math/psStats.c
r23988 r24092 162 162 static psF32 minimizeLMChi2Gauss1D(psVector *deriv, const psVector *params, const psVector *coords); 163 163 // static psF32 fitQuadraticSearchForYThenReturnX(const psVector *xVec, psVector *yVec, psS32 binNum, psF32 yVal); 164 static psF32 fitQuadraticSearchForYThenReturnXusingValues(const psVector *xVec, psVector *yVec, psS32 binNum, psF32 yVal); 164 // static psF32 fitQuadraticSearchForYThenReturnXusingValues(const psVector *xVec, psVector *yVec, psS32 binNum, psF32 yVal); 165 static psF32 fitQuadraticSearchForYThenReturnBin(const psVector *xVec, psVector *yVec, psS32 binNum, psF32 yVal); 165 166 166 167 /****************************************************************************** … … 822 823 PS_BIN_FOR_VALUE(binMedian, cumulative->nums, totalDataPoints/2.0, 0); 823 824 824 psTrace(TRACE, 6, "The median bin is %ld (%.2f to %.2f)\n", binMedian, 825 cumulative->bounds->data.F32[binMedian], cumulative->bounds->data.F32[binMedian+1]); 826 827 // ADD step 3: Interpolate to the exact 50% position: this is the robust histogram median. 828 stats->robustMedian = fitQuadraticSearchForYThenReturnXusingValues(cumulative->bounds, cumulative->nums, binMedian, totalDataPoints/2.0); 825 psTrace(TRACE, 6, "The median bin is %ld (%.2f to %.2f)\n", binMedian, cumulative->bounds->data.F32[binMedian], cumulative->bounds->data.F32[binMedian+1]); 826 827 // ADD step 3: Interpolate to the exact 50% position in bin units 828 stats->robustMedian = fitQuadraticSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binMedian, totalDataPoints/2.0); 829 // float robustBin = fitQuadraticSearchForYThenReturnXusingValues(cumulative->bounds, cumulative->nums, binMedian, totalDataPoints/2.0); 830 // fprintf (stderr, "robustBin : %f vs %f\n", robustBin, stats->robustMedian); 831 832 // convert bin to bin value: this is the robust histogram median. 829 833 if (isnan(stats->robustMedian)) { 830 834 psLogMsg(TRACE, PS_LOG_DETAIL, "Failed to fit a quadratic and calculate the 50-percent position.\n"); … … 971 975 // ADD step 8: Interpolate to find these two positions exactly: these are the upper and lower quartile 972 976 // positions. 973 psF32 binLo25F32 = fitQuadraticSearchForYThenReturn XusingValues(cumulative->bounds, cumulative->nums, binLo25, totalDataPoints * 0.25f);974 psF32 binHi25F32 = fitQuadraticSearchForYThenReturn XusingValues(cumulative->bounds, cumulative->nums, binHi25, totalDataPoints * 0.75f);977 psF32 binLo25F32 = fitQuadraticSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binLo25, totalDataPoints * 0.25f); 978 psF32 binHi25F32 = fitQuadraticSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binHi25, totalDataPoints * 0.75f); 975 979 if (isnan(binLo25F32) || isnan(binHi25F32)) { 976 psLogMsg(TRACE, PS_LOG_DETAIL, "could not determine the robustUQ: fitQuadraticSearchForYThenReturn X() returned a NAN.\n");980 psLogMsg(TRACE, PS_LOG_DETAIL, "could not determine the robustUQ: fitQuadraticSearchForYThenReturnBin() returned a NAN.\n"); 977 981 goto escape; 978 982 } … … 2737 2741 return tmpFloat; 2738 2742 } 2739 # endif2740 2743 2741 2744 /****************************************************************************** … … 2865 2868 return tmpFloat; 2866 2869 } 2870 # endif 2871 2872 /****************************************************************************** 2873 fitQuadraticSearchForYThenReturnXusingValues(*xVec, *yVec, binNum, yVal): A general routine 2874 which fits a quadratic to three points and returns the x bin value corresponding to the input 2875 y-value. This routine takes psVectors of x/y pairs as input, and fits a quadratic to the 3 2876 points surrounding element binNum in the vectors. This version uses the values of x[i] for the 2877 x coordinates (not the midpoints). This is appropriate for a cumulative histogram. It then 2878 determines for what value x does that quadratic f(x) = yVal (the input parameter). 2879 2880 XXX this function is used a fair amount in an inner loop: the polynomial fitting and evaluation 2881 could easily be done with statically allocated doubles, skipping the psLib versions of 2882 polynomial fitting, etc. 2883 2884 *****************************************************************************/ 2885 static psF32 fitQuadraticSearchForYThenReturnBin(const psVector *xVec, 2886 psVector *yVec, 2887 psS32 binNum, 2888 psF32 yVal 2889 ) 2890 { 2891 psTrace(TRACE, 5, "binNum, yVal is (%d, %f)\n", binNum, yVal); 2892 if (psTraceGetLevel("psLib.math") >= 8) { 2893 PS_VECTOR_PRINT_F32(xVec); 2894 PS_VECTOR_PRINT_F32(yVec); 2895 } 2896 2897 PS_ASSERT_VECTOR_NON_NULL(xVec, NAN); 2898 PS_ASSERT_VECTOR_NON_NULL(yVec, NAN); 2899 PS_ASSERT_VECTOR_TYPE(xVec, PS_TYPE_F32, NAN); 2900 PS_ASSERT_VECTOR_TYPE(yVec, PS_TYPE_F32, NAN); 2901 PS_ASSERT_INT_WITHIN_RANGE(binNum, 0, (int)(xVec->n - 1), NAN); 2902 PS_ASSERT_INT_WITHIN_RANGE(binNum, 0, (int)(yVec->n - 1), NAN); 2903 2904 psVector *x = psVectorAlloc(3, PS_TYPE_F64); 2905 psVector *y = psVectorAlloc(3, PS_TYPE_F64); 2906 psF32 tmpFloat = 0.0f; 2907 2908 if ((binNum >= 1) && (binNum <= (yVec->n - 2)) && (binNum <= (xVec->n - 2))) { 2909 // The general case. We have all three points. 2910 x->data.F64[0] = binNum - 1; 2911 x->data.F64[1] = binNum; 2912 x->data.F64[2] = binNum + 1; 2913 y->data.F64[0] = yVec->data.F32[binNum - 1]; 2914 y->data.F64[1] = yVec->data.F32[binNum]; 2915 y->data.F64[2] = yVec->data.F32[binNum + 1]; 2916 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]); 2917 psTrace(TRACE, 6, "x data is (%f %f %f)\n", x->data.F64[0], x->data.F64[1], x->data.F64[2]); 2918 psTrace(TRACE, 6, "y data is (%f %f %f)\n", y->data.F64[0], y->data.F64[1], y->data.F64[2]); 2919 2920 // Ensure that the y value lies within range of the y values. 2921 if (! (((y->data.F64[0] <= yVal) && (yVal <= y->data.F64[2])) || 2922 ((y->data.F64[2] <= yVal) && (yVal <= y->data.F64[0]))) ) { 2923 psError(PS_ERR_BAD_PARAMETER_VALUE, true, 2924 _("Specified yVal, %g, is not within y-range, %g to %g."), 2925 (psF64)yVal, y->data.F64[0], y->data.F64[2]); 2926 return NAN; 2927 } 2928 2929 // Ensure that the y values are monotonic. 2930 if (((y->data.F64[0] < y->data.F64[1]) && !(y->data.F64[1] <= y->data.F64[2])) || 2931 ((y->data.F64[0] > y->data.F64[1]) && !(y->data.F64[1] >= y->data.F64[2]))) { 2932 psError(PS_ERR_UNKNOWN, true, 2933 "This routine must be called with monotonically increasing or decreasing data points.\n"); 2934 psFree(x); 2935 psFree(y); 2936 return NAN; 2937 } 2938 2939 // Determine the coefficients of the polynomial. 2940 psPolynomial1D *myPoly = psPolynomial1DAlloc(PS_POLYNOMIAL_ORD, 2); 2941 if (!psVectorFitPolynomial1D(myPoly, NULL, 0, y, NULL, x)) { 2942 psError(PS_ERR_UNEXPECTED_NULL, false, 2943 _("Failed to fit a 1-dimensional polynomial to the three specified data points. " 2944 "Returning NAN.")); 2945 psFree(x); 2946 psFree(y); 2947 return NAN; 2948 } 2949 2950 psTrace(TRACE, 6, "myPoly->coeff[0] is %f\n", myPoly->coeff[0]); 2951 psTrace(TRACE, 6, "myPoly->coeff[1] is %f\n", myPoly->coeff[1]); 2952 psTrace(TRACE, 6, "myPoly->coeff[2] is %f\n", myPoly->coeff[2]); 2953 psTrace(TRACE, 6, "Fitted y vec is (%f %f %f)\n", 2954 (psF32) psPolynomial1DEval(myPoly, (psF64) x->data.F64[0]), 2955 (psF32) psPolynomial1DEval(myPoly, (psF64) x->data.F64[1]), 2956 (psF32) psPolynomial1DEval(myPoly, (psF64) x->data.F64[2])); 2957 2958 psTrace(TRACE, 6, "We fit the polynomial, now find x such that f(x) equals %f\n", yVal); 2959 float binValue = QuadraticInverse(myPoly->coeff[2], myPoly->coeff[1], myPoly->coeff[0], yVal, x->data.F64[0], x->data.F64[2]); 2960 psFree(myPoly); 2961 2962 if (isnan(binValue)) { 2963 psError(PS_ERR_UNEXPECTED_NULL, 2964 false, _("Failed to determine the median of the fitted polynomial. Returning NAN.")); 2965 psFree(x); 2966 psFree(y); 2967 return(NAN); 2968 } 2969 2970 // I believe that mathematically the fitted bin position must be between binNum - 1 and binNum + 1 2971 assert (binValue >= binNum - 1); 2972 assert (binValue <= binNum + 1); 2973 2974 int fitBin = binValue; 2975 float dX = xVec->data.F32[fitBin+1] - xVec->data.F32[fitBin]; 2976 float dY = binValue - fitBin; 2977 tmpFloat = xVec->data.F32[fitBin] + dY * dX; 2978 } else { 2979 // These are special cases where the bin is at the beginning or end of the vector. 2980 if (binNum == 0) { 2981 // We have two points only at the beginning of the vectors x and y. 2982 // X = (dX/dY)(Y - Yo) + Xo 2983 float dX = xVec->data.F32[1] - xVec->data.F32[0]; 2984 float dY = yVec->data.F32[1] - yVec->data.F32[0]; 2985 tmpFloat = (yVal - yVec->data.F32[0]) * (dX / dY) + xVec->data.F32[0]; 2986 } else if (binNum == (xVec->n - 1)) { 2987 // We have two points only at the end of the vectors x and y. 2988 // X = (dX/dY)(Y - Yo) + Xo 2989 float dX = xVec->data.F32[binNum] - xVec->data.F32[binNum-1]; 2990 float dY = yVec->data.F32[binNum] - yVec->data.F32[binNum-1]; 2991 tmpFloat = (yVal - yVec->data.F32[binNum-1]) * (dX / dY) + xVec->data.F32[binNum-1]; 2992 } 2993 } 2994 2995 psTrace(TRACE, 6, "FIT: return %f\n", tmpFloat); 2996 psFree(x); 2997 psFree(y); 2998 2999 return tmpFloat; 3000 } 2867 3001 2868 3002 /******************************************************************************
Note:
See TracChangeset
for help on using the changeset viewer.
