IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
May 3, 2010, 8:45:22 AM (16 years ago)
Author:
eugene
Message:

updates from trunk

Location:
branches/simmosaic_branches
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • branches/simmosaic_branches

  • branches/simmosaic_branches/psLib/src/math/psStats.c

    r24790 r27839  
    129129
    130130# 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__); \
    137137            psWarning("(warning raised %d times)", nCalls); \
    138         } \
    139         nCalls ++; \
     138        } \
     139        nCalls ++; \
    140140}
    141  
     141
    142142
    143143/*****************************************************************************/
     
    217217    for (long i = 0; i < numData; i++) {
    218218        // Check if the data is with the specified range
    219         if (!isfinite(data[i]))
    220             continue;
     219        if (!isfinite(data[i]))
     220            continue;
    221221        if (useRange && (data[i] < stats->min))
    222222            continue;
     
    242242
    243243    if (!isnan(mean)) {
    244         stats->results |= PS_STAT_SAMPLE_MEAN;
     244        stats->results |= PS_STAT_SAMPLE_MEAN;
    245245    }
    246246    return true;
     
    278278    for (long i = 0; i < num; i++) {
    279279        // Check if the data is with the specified range
    280         if (!isfinite(vector[i]))
    281             continue;
     280        if (!isfinite(vector[i]))
     281            continue;
    282282        if (useRange && (vector[i] < stats->min))
    283283            continue;
     
    329329    // into the temporary vectors.
    330330    for (long i = 0; i < inVector->n; i++) {
    331         if (!isfinite(input[i]))
    332             continue;
     331        if (!isfinite(input[i]))
     332            continue;
    333333        if (useRange && (input[i] < stats->min))
    334334            continue;
     
    353353    // Sort the temporary vector.
    354354    if (!psVectorSort(outVector, outVector)) { // Sort in-place (since it's a copy, it's OK)
    355         // an error in psVectorSort is a serious error
     355        // an error in psVectorSort is a serious error
    356356        psError(PS_ERR_UNEXPECTED_NULL, false, _("Failed to sort input data."));
    357357        stats->sampleUQ = NAN;
     
    407407    // If the mean is NAN, then generate a warning and set the stdev to NAN.
    408408    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.");
    410410        stats->sampleStdev = NAN;
    411411        return true;
     
    425425    for (long i = 0; i < myVector->n; i++) {
    426426        // Check if the data is with the specified range
    427         if (!isfinite(data[i]))
    428             continue;
     427        if (!isfinite(data[i]))
     428            continue;
    429429        if (useRange && (data[i] < stats->min)) {
    430430            continue;
     
    502502    for (long i = 0; i < myVector->n; i++) {
    503503        // Check if the data is with the specified range
    504         if (!isfinite(data[i]))
    505             continue;
     504        if (!isfinite(data[i]))
     505            continue;
    506506        if (useRange && (data[i] < stats->min)) {
    507507            continue;
     
    749749    // Iterate to get the best bin size; an iteration limit is enforced at the bottom of the loop.
    750750    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        }
    754760
    755761        // Get the minimum and maximum values
     
    771777            stats->robustLQ = min;
    772778            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:
    774780            stats->results |= PS_STAT_ROBUST_MEDIAN;
    775781            stats->results |= PS_STAT_ROBUST_STDEV;
     
    791797        psTrace(TRACE, 6, "Initial robust bin size is %.2f\n", binSize);
    792798
    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
    797806        psTrace(TRACE, 6, "Numbins is %ld\n", numBins);
    798807        psTrace(TRACE, 6, "Creating a robust histogram from data range (%.2f - %.2f)\n", min, max);
    799808        // Generate the histogram
    800         histogram = psHistogramAlloc(min, max, numBins);
     809        histogram = psHistogramAlloc(min - 2.0*binSize, max + 2.0*binSize, numBins);
    801810        // XXXXX we need to consider this step if errors -> variance
    802811        if (!psVectorHistogram(histogram, myVector, errors, mask, maskVal)) {
    803             // if psVectorHistogram returns false, we have a programming error
     812            // if psVectorHistogram returns false, we have a programming error
    804813            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;
    811819        }
    812820        if (psTraceGetLevel("psLib.math") >= 8) {
    813821            PS_VECTOR_PRINT_F32(histogram->bounds);
    814822            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.
    815862        }
    816863
     
    838885
    839886        // 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.
    845892        if (isnan(stats->robustMedian)) {
    846893            COUNT_WARNING(10, 100, "Failed to fit a quadratic and calculate the 50-percent position.\n");
     
    10071054    stats->robustN50 = N50;
    10081055    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);
    10091057
    10101058    // Clean up
     
    10541102        if (!vectorRobustStats(myVector, errors, mask, maskVal, stats)) {
    10551103            psError(PS_ERR_UNKNOWN, false, "failure to measure robust stats\n");
    1056             return false;
    1057         }
     1104            return false;
     1105        }
    10581106    }
    10591107
     
    11071155        psHistogram *histogram = psHistogramAlloc(min, max, numBins); // A new histogram (without outliers)
    11081156        if (!psVectorHistogram(histogram, myVector, errors, mask, maskVal)) {
    1109             // if psVectorHistogram returns false, we have a programming error
     1157            // if psVectorHistogram returns false, we have a programming error
    11101158            psError(PS_ERR_UNKNOWN, false, "Unable to generate histogram for fitted statistics.\n");
    11111159            psFree(histogram);
     
    11721220            PS_VECTOR_PRINT_F32(y);
    11731221        }
    1174        
    1175         // psMinimizeLMChi2 can return false for bad data as well as for serious failures
     1222
     1223        // psMinimizeLMChi2 can return false for bad data as well as for serious failures
    11761224        if (!psMinimizeLMChi2(minimizer, NULL, params, NULL, x, y, NULL, minimizeLMChi2Gauss1D)) {
    11771225            psError(PS_ERR_UNKNOWN, false, "Failed to fit a gaussian to the robust histogram.\n");
     
    12351283        if (!vectorRobustStats(myVector, errors, mask, maskVal, stats)) {
    12361284            psError(PS_ERR_UNKNOWN, false, "failure to measure robust stats\n");
    1237             return false;
    1238         }
     1285            return false;
     1286        }
    12391287    }
    12401288
     
    13551403        // psVectorInit (fitMask, 0);
    13561404
    1357         // XXX not sure if these should result in errors or not...
     1405        // XXX not sure if these should result in errors or not...
    13581406        if (!psVectorFitPolynomial1D (poly, NULL, 0, y, NULL, x)) {
    13591407            psError(PS_ERR_UNKNOWN, false, "Failed to fit a gaussian to the robust histogram.\n");
     
    14321480        if (!vectorRobustStats(myVector, errors, mask, maskVal, stats)) {
    14331481            psError(PS_ERR_UNKNOWN, false, "failure to measure robust stats\n");
    1434             return false;
    1435         }
     1482            return false;
     1483        }
    14361484    }
    14371485
     
    17291777        if (!vectorRobustStats(myVector, errors, mask, maskVal, stats)) {
    17301778            psError(PS_ERR_UNKNOWN, false, "failure to measure robust stats\n");
    1731             return false;
    1732         }
     1779            return false;
     1780        }
    17331781    }
    17341782
    17351783    // 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;
    17411785
    17421786    float guessStdev = stats->robustStdev;  // pass the guess sigma
     
    17701814            COUNT_WARNING(10, 100, "Failed to calculate the min/max of the input vector.\n");
    17711815            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;
    17741826            return true;
    17751827        }
     
    17891841            psFree(histogram);
    17901842            psFree(statsMinMax);
    1791             stats->fittedStdev = NAN;
    1792             stats->fittedStdev = NAN;
    1793             return true;
     1843            goto escape;
    17941844        }
    17951845        if (psTraceGetLevel("psLib.math") >= 8) {
     
    18231873            COUNT_WARNING(10, 100, "Failed to calculate the min/max of the input vector.\n");
    18241874            psFree(statsMinMax);
    1825             stats->fittedStdev = NAN;
    1826             stats->fittedStdev = NAN;
    1827             return true;
     1875            psFree(histogram);
     1876            goto escape;
    18281877        }
    18291878
     
    18861935
    18871936            // 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 gracefully
     1937            // 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
    18901939            psPolynomial1D *poly = psPolynomial1DAlloc(PS_POLYNOMIAL_ORD, 2);
    18911940            bool status = psVectorFitPolynomial1D (poly, NULL, 0, y, NULL, x);
     
    18941943
    18951944            if (!status) {
     1945                psErrorClear();
    18961946                COUNT_WARNING(10, 100, "Failed to fit a gaussian to the robust histogram.\n");
    18971947                psFree(poly);
    18981948                psFree(histogram);
    18991949                psFree(statsMinMax);
    1900                 stats->fittedStdev = NAN;
    1901                 stats->fittedStdev = NAN;
    1902                 return true;
     1950                goto escape;
    19031951            }
    19041952
     
    19191967
    19201968                COUNT_WARNING(10, 100, "fit did not converge\n");
    1921                 stats->fittedStdev = NAN;
    1922                 stats->fittedStdev = NAN;
    1923                 return true;
     1969                goto escape;
    19241970            }
    19251971
     
    19872033
    19882034            if (!status) {
     2035                psErrorClear();
    19892036                COUNT_WARNING(10, 100, "Failed to fit a gaussian to the robust histogram.\n");
    19902037                psFree(poly);
    19912038                psFree(histogram);
    19922039                psFree(statsMinMax);
    1993                 stats->fittedStdev = NAN;
    1994                 stats->fittedStdev = NAN;
    1995                 return true;
     2040                goto escape;
    19962041            }
    19972042
     
    20382083    psTrace(TRACE, 6, "The fitted stdev is %f.\n", stats->fittedStdev);
    20392084
     2085    stats->results |= PS_STAT_FITTED_MEAN_V4;
     2086    stats->results |= PS_STAT_FITTED_STDEV_V4;
     2087
     2088    return true;
     2089
     2090escape:
     2091    stats->fittedMean = NAN;
     2092    stats->fittedStdev = NAN;
    20402093    stats->results |= PS_STAT_FITTED_MEAN_V4;
    20412094    stats->results |= PS_STAT_FITTED_STDEV_V4;
     
    28962949*****************************************************************************/
    28972950static psF32 fitQuadraticSearchForYThenReturnBin(const psVector *xVec,
    2898                                                 psVector *yVec,
    2899                                                 psS32 binNum,
    2900                                                 psF32 yVal
     2951                                                psVector *yVec,
     2952                                                psS32 binNum,
     2953                                                psF32 yVal
    29012954    )
    29022955{
     
    29803033        }
    29813034
    2982         // I believe that mathematically the fitted bin position must be between binNum - 1 and binNum + 1
    2983         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;
    29903043    } else {
    29913044        // These are special cases where the bin is at the beginning or end of the vector.
    29923045        if (binNum == 0) {
    29933046            // 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            }
    29983055        } else if (binNum == (xVec->n - 1)) {
    29993056            // 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        }
    30053066    }
    30063067
Note: See TracChangeset for help on using the changeset viewer.