Changeset 36114 for trunk/psLib/src/math/psStats.c
- Timestamp:
- Sep 11, 2013, 6:12:49 PM (13 years ago)
- File:
-
- 1 edited
-
trunk/psLib/src/math/psStats.c (modified) (8 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psLib/src/math/psStats.c
r36105 r36114 174 174 *****************************************************************************/ 175 175 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); 177 static psF32 fitLinearSearchForYThenReturnBin(const psVector *xVec, psVector *yVec, psS32 binNum, psF32 yVal); 177 178 178 179 /****************************************************************************** … … 918 919 // There's no reason to do a quadratic fit near the 50% bin, as it's approximately linear there. 919 920 // Instead, do a 5-point linear fit. 921 # if (0) 920 922 { // Quick 5-point linear fit 921 923 double Sx = (cumulative->nums->data.F32[binMedian - 2] + cumulative->nums->data.F32[binMedian - 1] + … … 937 939 stats->robustMedian = linearMedian; 938 940 } 941 # endif 942 stats->robustMedian = fitLinearSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binMedian, totalDataPoints/2.0); 939 943 940 944 // convert bin to bin value: this is the robust histogram median. … … 1108 1112 // ADD step 8: Interpolate to find these two positions exactly: these are the upper and lower quartile 1109 1113 // positions. 1110 psF32 binLo25F32 = fit QuadraticSearchForYThenReturnBin(cumulative->bounds, cumulative->nums, binLo25, totalDataPoints * 0.25f);1111 psF32 binHi25F32 = fit QuadraticSearchForYThenReturnBin(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); 1112 1116 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"); 1114 1118 goto escape; 1115 1119 } … … 2036 2040 // other private functions used above 2037 2041 2042 # if (0) 2038 2043 static psF32 QuadraticInverse(psF32 a, 2039 2044 psF32 b, … … 2057 2062 return 0.5 * (xLo + xHi); 2058 2063 } 2064 2065 static 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 2059 2080 2060 2081 # if (0) … … 2313 2334 return tmpFloat; 2314 2335 } 2315 # endif2316 2336 2317 2337 /****************************************************************************** … … 2484 2504 return tmpFloat; 2485 2505 } 2506 # endif 2507 2508 2509 /****************************************************************************** 2510 fitQuadraticSearchForYThenReturnXusingValues(*xVec, *yVec, binNum, yVal): A general routine 2511 which fits a quadratic to three points and returns the x bin value corresponding to the input 2512 y-value. This routine takes psVectors of x/y pairs as input, and fits a quadratic to the 3 2513 points surrounding element binNum in the vectors. This version uses the values of x[i] for the 2514 x coordinates (not the midpoints). This is appropriate for a cumulative histogram. It then 2515 determines for what value x does that quadratic f(x) = yVal (the input parameter). 2516 2517 XXX this function is used a fair amount in an inner loop: the polynomial fitting and evaluation 2518 could easily be done with statically allocated doubles, skipping the psLib versions of 2519 polynomial fitting, etc. 2520 2521 *****************************************************************************/ 2522 static 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.
