Changeset 41811 for branches/eam_branches/ipp-dev-20210817/psModules
- Timestamp:
- Sep 16, 2021, 10:26:07 AM (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/eam_branches/ipp-dev-20210817/psModules/src/detrend/pmPattern.c
r41808 r41811 134 134 } 135 135 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 } \ 136 146 } 137 147 … … 313 323 314 324 #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 444 bool 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 315 624 memcpy(corr->data.F64[y], poly->coeff, (order + 1) * PSELEMTYPE_SIZEOF(PS_TYPE_F64)); 316 625 psVector *solution = psPolynomial1DEvalVector(poly, indices); // Solution vector … … 1476 1785 return true; 1477 1786 } 1787
Note:
See TracChangeset
for help on using the changeset viewer.
