IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Sep 16, 2021, 10:26:07 AM (5 years ago)
Author:
eugene
Message:

working on speeding the pattern measurement

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/eam_branches/ipp-dev-20210817/psModules/src/detrend/pmPattern.c

    r41808 r41811  
    134134    }
    135135    return;
     136}
     137
     138// Comparison and swap functions for sorting values directly
     139#define SORT_COMPARE(A,B) (value[A] < value[B])
     140#define SORT_SWAP(A,B) { \
     141    if (A != B) { \
     142        float temp = value[A]; \
     143        value[A] = value[B]; \
     144        value[B] = temp; \
     145    } \
    136146}
    137147
     
    313323       
    314324#endif
     325        memcpy(corr->data.F64[y], poly->coeff, (order + 1) * PSELEMTYPE_SIZEOF(PS_TYPE_F64));
     326        psVector *solution = psPolynomial1DEvalVector(poly, indices); // Solution vector
     327        if (!solution) {
     328            psWarning("Unable to evaluate polynomial for row %d", y);
     329            psErrorClear();
     330            patternMaskRow(ro, y, maskBad);
     331#ifdef PATTERN_ROW_BKG_FIX
     332            yaxisMask->data.PS_TYPE_VECTOR_MASK_DATA[y] = 0xFF;
     333#endif
     334            continue;
     335        }
     336
     337        for (int x = 0; x < numCols; x++) {
     338            image->data.F32[y][x] -= solution->data.F32[x];
     339            psTrace("pattern",5,"A: %d %d %g\n",x,y,solution->data.F32[x]);
     340        }
     341        psFree(solution);
     342    }
     343
     344#ifdef PATTERN_ROW_BKG_FIX
     345    // Put the global trends back that were removed by the PATTERN.ROW correction.
     346    // Set up the indices for the polynomial
     347    psVector *yaxisIndices = psVectorAlloc(numRows, PS_TYPE_F32);
     348    norm = 2.0 / (float)numRows;
     349    for (int y = 0; y < numRows; y++) {
     350      yaxisIndices->data.F32[y] = y * norm - 1.0;
     351      psTrace("psModules.detrend.pattern",10,"%d %f %f\n",y,yaxisIndices->data.F32[y],yaxisData->data.F32[y]);
     352    }
     353
     354    // Fit the trend of the constant term, producing the y-axis global trend
     355    psStatsInit(clip);
     356    psPolynomial1D *yaxisPoly = psPolynomial1DAlloc(PS_POLYNOMIAL_ORD, 1); // Polynomial to fit.
     357    if (!psVectorClipFitPolynomial1D(yaxisPoly,clip,yaxisMask,0xFF,yaxisData, NULL, yaxisIndices)) {
     358      psWarning("Unable to fit polynomial to y-axis trend");
     359      psErrorClear();
     360      // If we've failed, we need to do something, so add back in the background level, and
     361      // expect that the final image will have background mismatches.
     362      for (int y = 0; y < numRows; y++) {
     363        for (int x = 0; x < numCols; x++) {
     364          image->data.F32[y][x] += background;
     365        }
     366        corr->data.F64[y][0]  -= background;
     367      }
     368    }
     369    else {
     370      psVector *solution = psPolynomial1DEvalVector(yaxisPoly,yaxisIndices);
     371      if (!solution) {
     372        psWarning("Unable to evaluate polynomial");
     373        psErrorClear();
     374        // If we've failed, we need to do something, so add back in the background level, and
     375        // expect that the final image will have background mismatches.
     376        for (int y = 0; y < numRows; y++) {
     377          for (int x = 0; x < numCols; x++) {
     378            image->data.F32[y][x] += background;
     379          }
     380          corr->data.F64[y][0]  -= background;
     381        }
     382      }
     383      else {
     384        for (int y = 0; y < numRows; y++) {
     385          for (int x = 0; x < numCols; x++) {
     386            image->data.F32[y][x] += solution->data.F32[y];
     387            psTrace("pattern",5,"B: %d %d %g\n",x,y,solution->data.F32[x]);
     388          }
     389          corr->data.F64[y][0]  -= solution->data.F32[y];
     390        }
     391      }
     392      psFree(solution);
     393    }     
     394
     395    // Fit the trend of the linear term, producing the x-axis global trend
     396    // We can use the same mask vector, as the same rows failed the row-fit earlier.
     397    psStatsInit(clip);
     398    psPolynomial1D *xaxisPoly = psPolynomial1DAlloc(PS_POLYNOMIAL_ORD, 1); // Polynomial to fit.
     399    if (!psVectorClipFitPolynomial1D(xaxisPoly,clip,yaxisMask,0xFF,xaxisData, NULL, yaxisIndices)) {
     400      psWarning("Unable to fit polynomial to x-axis trend");
     401      psErrorClear();
     402    }
     403    else {
     404      psVector *solution = psPolynomial1DEvalVector(xaxisPoly,yaxisIndices);
     405      if (!solution) {
     406        psWarning("Unable to evaluate polynomial");
     407        psErrorClear();
     408      }
     409      else {
     410        for (int y = 0; y < numRows; y++) {
     411          for (int x = 0; x < numCols; x++) {
     412            image->data.F32[y][x] += solution->data.F32[y] * indices->data.F32[x];
     413            psTrace("pattern",5,"C: %d %d %g %g\n",x,y,solution->data.F32[x],indices->data.F32[x]);
     414          }
     415          corr->data.F64[y][1]  -= solution->data.F32[y] ;
     416        }
     417      }
     418      psFree(solution);
     419    }
     420    psFree(yaxisPoly);
     421    psFree(xaxisPoly);
     422    psFree(yaxisIndices);
     423    psFree(yaxisMask);
     424    psFree(yaxisData);
     425    psFree(xaxisData);
     426    // End PATTERN_ROW_BKG_FIX global trend replacement
     427#endif
     428   
     429    psMetadataAddImage(ro->analysis, PS_LIST_TAIL, PM_PATTERN_ROW_CORRECTION, PS_META_REPLACE,
     430                       "Pattern row correction", corr);
     431    psFree(corr);
     432
     433    psFree(indices);
     434    psFree(clip);
     435    psFree(clipMask);
     436    psFree(poly);
     437    psFree(data);
     438
     439    return true;
     440}
     441
     442// bin by Npix in the x-direction to reduce the number of calculations needed to measure
     443// the pattern
     444bool pmPatternRowBinned(pmReadout *ro, int order, int iter, float rej, float thresh,
     445                  psStatsOptions clipMean, psStatsOptions clipStdev,
     446                  psImageMaskType maskVal, psImageMaskType maskBad)
     447{
     448    PM_ASSERT_READOUT_NON_NULL(ro, false);
     449    PM_ASSERT_READOUT_IMAGE(ro, false);
     450    PS_ASSERT_INT_NONNEGATIVE(order, false);
     451    PS_ASSERT_INT_NONNEGATIVE(iter, false);
     452    PS_ASSERT_FLOAT_LARGER_THAN(rej, 0.0, false);
     453    PS_ASSERT_FLOAT_LARGER_THAN(thresh, 0.0, false);
     454
     455    psImage *image = ro->image;         // Image to correct
     456    psImage *mask = ro->mask;           // Mask for image
     457    int numCols = image->numCols, numRows = image->numRows; // Size of image
     458
     459    psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV);
     460    psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS); // Random number generator
     461    if (!psImageBackground(stats, NULL, ro->image, ro->mask, maskVal, rng)) {
     462        psWarning("Unable to calculate statistics on readout; masking entire readout.");
     463        psErrorClear();
     464        psFree(stats);
     465        psFree(rng);
     466        psImageInit(image, NAN);
     467        if (mask) {
     468            psBinaryOp(mask, mask, "|", psScalarAlloc(maskBad, PS_TYPE_IMAGE_MASK));
     469        }
     470        if (ro->variance) {
     471            psImageInit(image, NAN);
     472        }
     473        return true;
     474    }
     475
     476# if (USE_BACKGROUND_STDEV)
     477    float lower = stats->robustMedian - thresh * stats->robustStdev; // Lower bound for data
     478    float upper = stats->robustMedian + thresh * stats->robustStdev; // Upper bound for data
     479    float background = stats->robustMedian;
     480# else
     481    // the signal we are looking for is a small variation on top of the background.  if
     482    // the background is uniform with only read noise + sky noise, then the pixel-to-pixel
     483    // stdev should only be due to known noise sources and predictable.  If the
     484    // pixel-to-pixel variations are from other features, then those variations will
     485    // probably dominate the row-by-row bias variations.
     486
     487    // instead of using the image pixel statistics to measure the stdev, lets assume only
     488    // dark noise plus poisson sky noise.  we are not carrying in the read noise, but it is
     489    // fairly modest for GPC1 (~10 DN)
     490
     491    // if we assume a gain of 1 and the read noise of 10 DN, then a sky of 200 would have
     492    // a noise of N = sqrt (1 * 200 + 10^2) = sqrt (300) ~ 17
     493
     494    // if the gain were as much as 2, then the noise in DN would be N = sqrt(2 * (200 + 100)) / 2 = sqrt(300) / sqrt(2)
     495    // so smaller by a factor of 1.4 than what we predict, which is not very large
     496
     497    # define READNOISE 10
     498    float sigma = sqrt(stats->robustMedian + PS_SQR(READNOISE));
     499    float lower = stats->robustMedian - thresh * sigma; // Lower bound for data
     500    float upper = stats->robustMedian + thresh * sigma; // Upper bound for data
     501    float background = stats->robustMedian;
     502# endif   
     503   
     504    pmCell *cell = ro->parent;
     505    const char *cellName = psMetadataLookupStr(NULL, cell->concepts, "CELL.NAME"); // Name of cell
     506    fprintf (stderr, "pattern row background %s: %f - %f - %f\n", cellName,lower, background, upper);
     507
     508
     509    // XXX add code to skip fit if background stdev is large compared to expected signal
     510    // XXX add a constraint to the fit so the |amplitude| < x (x ~ 20 - 25)
     511
     512    psFree(stats);
     513    psFree(rng);
     514
     515# define NPIX 15   
     516
     517    // Indices are distributed [-1:1] [-1 = 0, +1 = numCols = indices[nSamples]
     518    int nSamples = numCols / NPIX;
     519    psVector *indices = psVectorAlloc(nSamples, PS_TYPE_F32); // Indices for fitting
     520    psVector *fitData = psVectorAlloc(nSAmples, PS_TYPE_F32); // Data to fit
     521
     522    // indices elements run from 0 - nSamples, element 'sample' corresponds to the middle of the bin sample*NPIX + 0.5*NPIX
     523
     524    float norm = 2.0 / (float)numCols;  // Normalisation for indices
     525    for (int sample = 0; sample < nSamples; sample ++) {
     526        int x = (sample + 0.5)*NPIX;
     527        indices->data.F32[sample] = x * norm - 1.0;
     528    }
     529
     530    psStats *clip = psStatsAlloc(clipMean | clipStdev); // Clipping statistics
     531    // XXX clip->clipIter = iter;
     532    clip->clipIter = 1; // XXX skip iteration for a test
     533    clip->clipSigma = rej;
     534    psVector *clipMask = psVectorAlloc(numCols, PS_TYPE_VECTOR_MASK); // Mask for clipping
     535    psPolynomial1D *poly = psPolynomial1DAlloc(PS_POLYNOMIAL_ORD, order); // Polynomial to fit
     536    psVector *data = psVectorAlloc(numCols, PS_TYPE_F32); // Data to fit
     537
     538    psImage *corr = psImageAlloc(order + 1, numRows, PS_TYPE_F64); // Corrections applied
     539    psImageInit(corr, NAN);
     540
     541#ifdef PATTERN_ROW_BKG_FIX
     542    // CZW: 2011-11-30
     543    // Define the vectors to hold the "x" and "y" slope trends.
     544    // Briefly, the slope trend in the y-axis is a due to variations in the 0-th order term
     545    // of the PATTERN.ROW fit between individual rows across the cell.  Similarly, the 1-st
     546    // order term of the PATTERN.ROW fit defines the trend in the x-axis (as that's what we
     547    // are fitting with PATTERN.ROW in the first place).  However, the thing we're trying to
     548    // fix with PATTERN.ROW is the detector level bias wiggles.  These should be overlaid on
     549    // the true sky level.  Therefore, simply applying the PATTERN.ROW correction will
     550    // introduce cell-to-cell sky variations as these two trends are removed.  To avoid this,
     551    // We store the 0th and 1st order values used for each row, and then fit a polynomial to
     552    // these results.  By re-adding these systematic trends back, we can remove the row-to-row
     553    // variations without improperly removing the real sky trend.
     554    psVector *yaxisData = psVectorAlloc(numRows, PS_TYPE_F32); // Data to fit to the constant term
     555    psVector *yaxisMask = psVectorAlloc(numRows, PS_TYPE_VECTOR_MASK); // Mask for rows with no fit
     556    psVector *xaxisData = psVectorAlloc(numRows, PS_TYPE_F32); // Data to fit to the linear term
     557    psVectorInit(yaxisMask, 0);
     558#endif
     559
     560    // we really need more than order + 1 points (= 4).
     561    // this should be tunable, but let's try 5 - 10%
     562    int validNmin = numCols * 0.1;
     563
     564    for (int y = 0; y < numRows; y++) {
     565        psVectorInit(clipMask, 0);
     566        data = psImageRow(data, image, y);
     567        int num = 0;                    // Number of good pixels
     568
     569        // if the unmasked pixels only span a small range in x then we cannot fit the
     570        // 2nd order polynomial variations very well.  Require a minimum fractional range
     571        float validXmin = +1;
     572        float validXmax = -1;
     573
     574        // XXX bookkeeping might be easier if this loop is over elements of 'indices'
     575        // XXX can we do just as well fitting 1/3 of the pixels? (NOT REALLY)
     576        // (x % 3) ||
     577        for (int sample = 0; sample < nSamples; sample ++) {
     578
     579            // store valid samples in the array
     580            float sampleArray[NPIX];
     581            int seq = 0;
     582            for (int j = 0; j < NPIX; j++) {
     583                int pix = sample  * NPIX + j;
     584                if ((mask && mask->data.PS_TYPE_IMAGE_MASK_DATA[y][pix] & maskVal)) continue;
     585                if (data->data.F32[pix] < lower || data->data.F32[pix] > upper) continue;
     586                sampleArray[seq] = data->data.F32[pix];
     587                seq ++;
     588            }
     589            if (seq < 1) {
     590                clipMask->data.PS_TYPE_VECTOR_MASK_DATA[sample] = 0xFF;
     591            } else {
     592                clipMask->data.PS_TYPE_VECTOR_MASK_DATA[sample] = 0;
     593                num++;
     594                validXmin = PS_MIN(indices->data.F32[sample], validXmin);
     595                validXmax = PS_MAX(indices->data.F32[sample], validXmax);
     596            }
     597
     598            PSSORT (seq, sampleArray
     599
     600        }
     601
     602        // XXX how much time is spent in the fitting
     603        if (num < validNmin) {
     604            // Not enough points to fit
     605            patternMaskRow(ro, y, maskBad);
     606            // Ignore this row in our subsequent fits, because the fit failed.
     607            yaxisMask->data.PS_TYPE_VECTOR_MASK_DATA[y] = 0xFF;
     608            continue;
     609        }
     610        // XXX does this need to be a clipped fit if we are clipping based on the median poisson noise?
     611        if (!psVectorClipFitPolynomial1D(poly, clip, clipMask, 0xFF, data, NULL, indices)) {
     612            psWarning("Unable to fit polynomial to row %d", y);
     613            psErrorClear();
     614            patternMaskRow(ro, y, maskBad);
     615            // Ignore this row in our subsequent fits, because the fit failed.
     616            yaxisMask->data.PS_TYPE_VECTOR_MASK_DATA[y] = 0xFF;
     617            continue;
     618        }
     619        // Store the results we found for this row.
     620        yaxisData->data.F32[y] = poly->coeff[0];
     621        xaxisData->data.F32[y] = poly->coeff[1];
     622        psTrace("pattern",1,"%d %g %g\n",y,poly->coeff[0],poly->coeff[1]);
     623
    315624        memcpy(corr->data.F64[y], poly->coeff, (order + 1) * PSELEMTYPE_SIZEOF(PS_TYPE_F64));
    316625        psVector *solution = psPolynomial1DEvalVector(poly, indices); // Solution vector
     
    14761785    return true;
    14771786}
     1787
Note: See TracChangeset for help on using the changeset viewer.