IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Sep 11, 2013, 6:12:49 PM (13 years ago)
Author:
eugene
Message:

use linear instead of quadratic fit for UQ and LQ as well (to avoid ill-conditioned matrices)

File:
1 edited

Legend:

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

    r36105 r36114  
    174174*****************************************************************************/
    175175
    176 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);
     177static psF32 fitLinearSearchForYThenReturnBin(const psVector *xVec, psVector *yVec, psS32 binNum, psF32 yVal);
    177178
    178179/******************************************************************************
     
    918919        // There's no reason to do a quadratic fit near the 50% bin, as it's approximately linear there.
    919920        // Instead, do a 5-point linear fit.
     921# if (0)
    920922        { // Quick 5-point linear fit
    921923          double Sx = (cumulative->nums->data.F32[binMedian - 2] + cumulative->nums->data.F32[binMedian - 1] +
     
    937939          stats->robustMedian = linearMedian;
    938940        }
     941# endif
     942        stats->robustMedian = fitLinearSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binMedian, totalDataPoints/2.0);
    939943
    940944        // convert bin to bin value: this is the robust histogram median.
     
    11081112    // ADD step 8: Interpolate to find these two positions exactly: these are the upper and lower quartile
    11091113    // positions.
    1110     psF32 binLo25F32 = fitQuadraticSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binLo25, totalDataPoints * 0.25f);
    1111     psF32 binHi25F32 = fitQuadraticSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binHi25, totalDataPoints * 0.75f);
     1114    psF32 binLo25F32 = fitLinearSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binLo25, totalDataPoints * 0.25f);
     1115    psF32 binHi25F32 = fitLinearSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binHi25, totalDataPoints * 0.75f);
    11121116    if (isnan(binLo25F32) || isnan(binHi25F32)) {
    1113         COUNT_WARNING(10, 100, "could not determine the robustUQ: fitQuadraticSearchForYThenReturnBin() returned a NAN.\n");
     1117        COUNT_WARNING(10, 100, "could not determine the robustUQ or LQ: fitLinearSearchForYThenReturnBin() returned a NAN.\n");
    11141118        goto escape;
    11151119    }
     
    20362040// other private functions used above
    20372041
     2042# if (0)
    20382043static psF32 QuadraticInverse(psF32 a,
    20392044                              psF32 b,
     
    20572062    return 0.5 * (xLo + xHi);
    20582063}
     2064
     2065static psF32 LinearInverse(psF32 a,
     2066                           psF32 b,
     2067                           psF32 y,
     2068                           psF32 xLo,
     2069                           psF32 xHi
     2070    )
     2071{
     2072    psF64 x = (y - b) / a;
     2073
     2074    if (xLo <= x && x <= xHi) {
     2075        return x;
     2076    }
     2077    return 0.5 * (xLo + xHi);
     2078}
     2079# endif
    20592080
    20602081# if (0)
     
    23132334    return tmpFloat;
    23142335}
    2315 # endif
    23162336
    23172337/******************************************************************************
     
    24842504    return tmpFloat;
    24852505}
     2506# endif
     2507
     2508
     2509/******************************************************************************
     2510fitQuadraticSearchForYThenReturnXusingValues(*xVec, *yVec, binNum, yVal): A general routine
     2511which fits a quadratic to three points and returns the x bin value corresponding to the input
     2512y-value.  This routine takes psVectors of x/y pairs as input, and fits a quadratic to the 3
     2513points surrounding element binNum in the vectors.  This version uses the values of x[i] for the
     2514x coordinates (not the midpoints).  This is appropriate for a cumulative histogram.  It then
     2515determines for what value x does that quadratic f(x) = yVal (the input parameter).
     2516
     2517XXX this function is used a fair amount in an inner loop: the polynomial fitting and evaluation
     2518could easily be done with statically allocated doubles, skipping the psLib versions of
     2519polynomial fitting, etc.
     2520
     2521*****************************************************************************/
     2522static psF32 fitLinearSearchForYThenReturnBin(const psVector *xVec,
     2523                                              psVector *yVec,
     2524                                              psS32 binNum,
     2525                                              psF32 yVal
     2526    )
     2527{
     2528# if (1)
     2529    double Sx = (yVec->data.F32[binNum - 2] + yVec->data.F32[binNum - 1] +
     2530                 yVec->data.F32[binNum - 0] +
     2531                 yVec->data.F32[binNum + 1] + yVec->data.F32[binNum + 2]);
     2532    double Sy = (xVec->data.F32[binNum - 2] + xVec->data.F32[binNum - 1] +
     2533                 xVec->data.F32[binNum - 0] +
     2534                 xVec->data.F32[binNum + 1] + xVec->data.F32[binNum + 2]);
     2535    double Sxx = (PS_SQR(yVec->data.F32[binNum - 2]) + PS_SQR(yVec->data.F32[binNum - 1]) +
     2536                  PS_SQR(yVec->data.F32[binNum - 0]) +
     2537                  PS_SQR(yVec->data.F32[binNum + 1]) + PS_SQR(yVec->data.F32[binNum + 2]));
     2538    double Sxy = (xVec->data.F32[binNum - 2] * yVec->data.F32[binNum - 2] +
     2539                  xVec->data.F32[binNum - 1] * yVec->data.F32[binNum - 1] +
     2540                  xVec->data.F32[binNum - 0] * yVec->data.F32[binNum - 0] +
     2541                  xVec->data.F32[binNum + 1] * yVec->data.F32[binNum + 1] +
     2542                  xVec->data.F32[binNum + 2] * yVec->data.F32[binNum + 2]);
     2543    double value = ((Sy * Sxx - Sx * Sxy) + (5 * Sxy - Sx * Sy) * yVal)/(5 * Sxx - Sx * Sx);
     2544
     2545    return value;
     2546# else
     2547    psTrace(TRACE, 5, "binNum, yVal is (%d, %f)\n", binNum, yVal);
     2548    if (psTraceGetLevel("psLib.math") >= 8) {
     2549        PS_VECTOR_PRINT_F32(xVec);
     2550        PS_VECTOR_PRINT_F32(yVec);
     2551    }
     2552
     2553    PS_ASSERT_VECTOR_NON_NULL(xVec, NAN);
     2554    PS_ASSERT_VECTOR_NON_NULL(yVec, NAN);
     2555    PS_ASSERT_VECTOR_TYPE(xVec, PS_TYPE_F32, NAN);
     2556    PS_ASSERT_VECTOR_TYPE(yVec, PS_TYPE_F32, NAN);
     2557    PS_ASSERT_INT_WITHIN_RANGE(binNum, 0, (int)(xVec->n - 1), NAN);
     2558    PS_ASSERT_INT_WITHIN_RANGE(binNum, 0, (int)(yVec->n - 1), NAN);
     2559
     2560    //    psVector *x = psVectorAlloc(3, PS_TYPE_F64);
     2561    //    psVector *y = psVectorAlloc(3, PS_TYPE_F64);
     2562    psVector *x = psVectorAlloc(5, PS_TYPE_F64);
     2563    psVector *y = psVectorAlloc(5, PS_TYPE_F64);
     2564    psF32 tmpFloat = 0.0f;
     2565
     2566    if ((binNum >= 2) && (binNum <= (yVec->n - 3)) && (binNum <= (xVec->n - 3))) {
     2567        x->data.F64[0] = xVec->data.F32[binNum - 2];
     2568        x->data.F64[1] = xVec->data.F32[binNum - 1];
     2569        x->data.F64[2] = xVec->data.F32[binNum + 0];
     2570        x->data.F64[3] = xVec->data.F32[binNum + 1];
     2571        x->data.F64[4] = xVec->data.F32[binNum + 2];
     2572
     2573        y->data.F64[0] = yVec->data.F32[binNum - 2];
     2574        y->data.F64[1] = yVec->data.F32[binNum - 1];
     2575        y->data.F64[2] = yVec->data.F32[binNum + 0];
     2576        y->data.F64[3] = yVec->data.F32[binNum + 1];
     2577        y->data.F64[4] = yVec->data.F32[binNum + 2];
     2578        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]);
     2579        psTrace(TRACE, 6, "x data is (%f %f %f)\n", x->data.F64[0], x->data.F64[1], x->data.F64[2]);
     2580        psTrace(TRACE, 6, "y data is (%f %f %f)\n", y->data.F64[0], y->data.F64[1], y->data.F64[2]);
     2581
     2582        // Ensure that the y value lies within range of the y values.
     2583        if (! (((y->data.F64[0] <= yVal) && (yVal <= y->data.F64[4])) ||
     2584               ((y->data.F64[4] <= yVal) && (yVal <= y->data.F64[0]))) ) {
     2585            psError(PS_ERR_BAD_PARAMETER_VALUE, true,
     2586                    _("Specified yVal, %g, is not within y-range, %g to %g."),
     2587                    (psF64)yVal, y->data.F64[0], y->data.F64[2]);
     2588            return NAN;
     2589        }
     2590
     2591        // Ensure that the y values are monotonic.
     2592        if (((y->data.F64[0] < y->data.F64[1]) && !(y->data.F64[1] <= y->data.F64[2])) ||
     2593            ((y->data.F64[0] > y->data.F64[1]) && !(y->data.F64[1] >= y->data.F64[2]))) {
     2594            psError(PS_ERR_UNKNOWN, true,
     2595                    "This routine must be called with monotonically increasing or decreasing data points.\n");
     2596            psFree(x);
     2597            psFree(y);
     2598            return NAN;
     2599        }
     2600
     2601        // Determine the coefficients of the polynomial.
     2602        psPolynomial1D *myPoly = psPolynomial1DAlloc(PS_POLYNOMIAL_ORD, 1);
     2603        if (!psVectorFitPolynomial1D(myPoly, NULL, 0, y, NULL, x)) {
     2604            psError(PS_ERR_UNEXPECTED_NULL, false,
     2605                    _("Failed to fit a 1-dimensional polynomial to the three specified data points.  "
     2606                      "Returning NAN."));
     2607            psFree(x);
     2608            psFree(y);
     2609            return NAN;
     2610        }
     2611
     2612        psTrace(TRACE, 6, "myPoly->coeff[0] is %f\n", myPoly->coeff[0]);
     2613        psTrace(TRACE, 6, "myPoly->coeff[1] is %f\n", myPoly->coeff[1]);
     2614        psTrace(TRACE, 6, "Fitted y vec is (%f %f)\n",
     2615                (psF32) psPolynomial1DEval(myPoly, (psF64) x->data.F64[0]),
     2616                (psF32) psPolynomial1DEval(myPoly, (psF64) x->data.F64[1]));
     2617
     2618        psTrace(TRACE, 6, "We fit the polynomial, now find x such that f(x) equals %f\n", yVal);
     2619        float binValue = LinearInverse(myPoly->coeff[1], myPoly->coeff[0], yVal, x->data.F64[0], x->data.F64[4]);
     2620        psFree(myPoly);
     2621
     2622        if (isnan(binValue)) {
     2623            psError(PS_ERR_UNEXPECTED_NULL,
     2624                    false, _("Failed to determine the median of the fitted polynomial.  Returning NAN."));
     2625            psFree(x);
     2626            psFree(y);
     2627            return(NAN);
     2628        }
     2629       
     2630        // I believe that mathematically the fitted bin position must be between binNum - 1 and binNum + 1
     2631        //      assert (binValue >= binNum - 1);
     2632        //      assert (binValue <= binNum + 1);
     2633
     2634        //      int fitBin = binValue;
     2635        //        float dX = xVec->data.F32[fitBin+1] - xVec->data.F32[fitBin];
     2636        //        float dY = binValue - fitBin;
     2637        //        tmpFloat = xVec->data.F32[fitBin] + dY * dX;
     2638        tmpFloat = binValue;
     2639               
     2640#if (CZW)
     2641        printf("   internal median: %f %f\n",tmpFloat,binValue);
     2642#endif
     2643       
     2644    } else {
     2645        // These are special cases where the bin is at the beginning or end of the vector.
     2646        if (binNum == 0) {
     2647            // We have two points only at the beginning of the vectors x and y.
     2648            // X = (dX/dY)(Y - Yo) + Xo
     2649            float dX = xVec->data.F32[1] - xVec->data.F32[0];
     2650            float dY = yVec->data.F32[1] - yVec->data.F32[0];
     2651            if (dY == 0.0) {
     2652                tmpFloat = xVec->data.F32[0];
     2653            } else {
     2654                tmpFloat = (yVal - yVec->data.F32[0]) * (dX / dY) + xVec->data.F32[0];
     2655            }
     2656        } else if (binNum == (xVec->n - 1)) {
     2657            // We have two points only at the end of the vectors x and y.
     2658            // X = (dX/dY)(Y - Yo) + Xo
     2659            float dX = xVec->data.F32[binNum] - xVec->data.F32[binNum-1];
     2660            float dY = yVec->data.F32[binNum] - yVec->data.F32[binNum-1];
     2661            if (dY == 0.0) {
     2662                tmpFloat = xVec->data.F32[binNum-1];
     2663            } else {
     2664                tmpFloat = (yVal - yVec->data.F32[binNum-1]) * (dX / dY) + xVec->data.F32[binNum-1];
     2665            }
     2666        }
     2667    }
     2668
     2669    psTrace(TRACE, 6, "FIT: return %f\n", tmpFloat);
     2670    psFree(x);
     2671    psFree(y);
     2672
     2673    return tmpFloat;
     2674# endif
     2675}
Note: See TracChangeset for help on using the changeset viewer.