IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 24092


Ignore:
Timestamp:
May 6, 2009, 2:23:14 PM (17 years ago)
Author:
eugene
Message:

fitting the histogram value can result in ill-conditioned matrices; fit instead the bin index and convert to a value

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/psLib/src/math/psStats.c

    r23988 r24092  
    162162static psF32 minimizeLMChi2Gauss1D(psVector *deriv, const psVector *params, const psVector *coords);
    163163// 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);
     165static psF32 fitQuadraticSearchForYThenReturnBin(const psVector *xVec, psVector *yVec, psS32 binNum, psF32 yVal);
    165166
    166167/******************************************************************************
     
    822823        PS_BIN_FOR_VALUE(binMedian, cumulative->nums, totalDataPoints/2.0, 0);
    823824
    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.
    829833        if (isnan(stats->robustMedian)) {
    830834            psLogMsg(TRACE, PS_LOG_DETAIL, "Failed to fit a quadratic and calculate the 50-percent position.\n");
     
    971975    // ADD step 8: Interpolate to find these two positions exactly: these are the upper and lower quartile
    972976    // positions.
    973     psF32 binLo25F32 = fitQuadraticSearchForYThenReturnXusingValues(cumulative->bounds, cumulative->nums, binLo25, totalDataPoints * 0.25f);
    974     psF32 binHi25F32 = fitQuadraticSearchForYThenReturnXusingValues(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);
    975979    if (isnan(binLo25F32) || isnan(binHi25F32)) {
    976         psLogMsg(TRACE, PS_LOG_DETAIL, "could not determine the robustUQ: fitQuadraticSearchForYThenReturnX() returned a NAN.\n");
     980        psLogMsg(TRACE, PS_LOG_DETAIL, "could not determine the robustUQ: fitQuadraticSearchForYThenReturnBin() returned a NAN.\n");
    977981        goto escape;
    978982    }
     
    27372741    return tmpFloat;
    27382742}
    2739 # endif
    27402743
    27412744/******************************************************************************
     
    28652868    return tmpFloat;
    28662869}
     2870# endif
     2871
     2872/******************************************************************************
     2873fitQuadraticSearchForYThenReturnXusingValues(*xVec, *yVec, binNum, yVal): A general routine
     2874which fits a quadratic to three points and returns the x bin value corresponding to the input
     2875y-value.  This routine takes psVectors of x/y pairs as input, and fits a quadratic to the 3
     2876points surrounding element binNum in the vectors.  This version uses the values of x[i] for the
     2877x coordinates (not the midpoints).  This is appropriate for a cumulative histogram.  It then
     2878determines for what value x does that quadratic f(x) = yVal (the input parameter).
     2879
     2880XXX this function is used a fair amount in an inner loop: the polynomial fitting and evaluation
     2881could easily be done with statically allocated doubles, skipping the psLib versions of
     2882polynomial fitting, etc.
     2883
     2884*****************************************************************************/
     2885static 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}
    28673001
    28683002/******************************************************************************
Note: See TracChangeset for help on using the changeset viewer.