Changeset 9298
- Timestamp:
- Oct 5, 2006, 10:48:56 AM (20 years ago)
- Location:
- trunk/psModules/src/detrend
- Files:
-
- 2 edited
-
pmShutterCorrection.c (modified) (6 diffs)
-
pmShutterCorrection.h (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psModules/src/detrend/pmShutterCorrection.c
r8926 r9298 63 63 #include "psVectorBracket.h" 64 64 65 static void pmShutterCorrParsFree (pmShutterCorrPars *pars) 66 { 67 if (pars == NULL) 68 return; 65 static void pmShutterCorrectionFree(pmShutterCorrection *pars) 66 { 67 // Nothing to free 69 68 return; 70 69 } 71 70 72 pmShutterCorrPars *pmShutterCorrParsAlloc () 73 { 74 75 pmShutterCorrPars *pars = (pmShutterCorrPars *) psAlloc(sizeof(pmShutterCorrPars)); 76 psMemSetDeallocator(pars, (psFreeFunc) pmShutterCorrParsFree); 77 pars->scale = 0.0; 78 pars->offset = 0.0; 79 pars->offref = 0.0; 80 return (pars); 81 } 82 83 // use interpolation to guess shutter correction parameters given a set of exposures times and normalized 84 // counts (divided by the reference counts for each image) 85 pmShutterCorrPars *pmShutterCorrectionGuess (psVector *exptime, psVector *counts) 86 { 87 88 psVector *tmpX = NULL; 89 psVector *tmpY = NULL; 90 91 pmShutterCorrPars *pars = pmShutterCorrParsAlloc (); 92 psPolynomial1D *line = psPolynomial1DAlloc (PS_POLYNOMIAL_ORD, 1); 93 94 int N = exptime->n; 95 // ASSERT (N >> 5) 96 71 pmShutterCorrection *pmShutterCorrectionAlloc() 72 { 73 pmShutterCorrection *corr = (pmShutterCorrection*)psAlloc(sizeof(pmShutterCorrection)); 74 psMemSetDeallocator(corr, (psFreeFunc)pmShutterCorrectionFree); 75 76 corr->scale = 0.0; 77 corr->offset = 0.0; 78 corr->offref = 0.0; 79 80 return corr; 81 } 82 83 pmShutterCorrection *pmShutterCorrectionGuess(const psVector *exptime, const psVector *counts) 84 { 97 85 // NOTE: vectors must be sorted on input. It is expensive to sort or check this here, but 98 86 // it is easy to arrange by sorting the images before generating these vectors. 87 88 PS_ASSERT_VECTOR_NON_NULL(exptime, NULL); 89 PS_ASSERT_VECTOR_NON_NULL(counts, NULL); 90 PS_ASSERT_VECTOR_TYPE(exptime, PS_TYPE_F32, NULL); 91 PS_ASSERT_VECTOR_TYPE(counts, PS_TYPE_F32, NULL); 92 PS_ASSERT_VECTORS_SIZE_EQUAL(exptime, counts, NULL); 93 if (exptime->n <= 2) { 94 psError(PS_ERR_BAD_PARAMETER_SIZE, true, 95 "Require more than 2 exposures to guess shutter correction.\n"); 96 return NULL; 97 } 98 99 long N = exptime->n; // Number of exposures 100 101 // use interpolation to guess shutter correction parameters given a set of exposures times and normalized 102 // counts (divided by the reference counts for each image) 103 104 pmShutterCorrection *corr = pmShutterCorrectionAlloc(); // Shutter correction, to be returned 105 psPolynomial1D *line = psPolynomial1DAlloc(PS_POLYNOMIAL_ORD, 1); // Straight line, for extrapolation 99 106 100 107 // choose the highest exptime point as the guess for the scale: 101 108 // XXX we could examine the top 2 or 3 values and decide if we 102 109 // extended exptime enough or median clip. 103 pars->scale = counts->data.F32[N-1];110 corr->scale = counts->data.F32[N-1]; 104 111 105 112 // fit a line to the lowest three points and extrapolate to 0.0 106 tmpX = psVectorAlloc(2, PS_TYPE_F32);107 tmpY = psVectorAlloc(2, PS_TYPE_F32);113 psVector *tmpX = psVectorAlloc(2, PS_TYPE_F32); 114 psVector *tmpY = psVectorAlloc(2, PS_TYPE_F32); 108 115 tmpX->n = tmpY->n = 2; 109 116 110 tmpX->data.F32[0] = exptime->data.F32[0]; 111 tmpX->data.F32[1] = exptime->data.F32[1]; 112 tmpY->data.F32[0] = counts->data.F32[0]; 113 tmpY->data.F32[1] = counts->data.F32[1]; 117 long index; 118 for (index = 0; !isfinite(exptime->data.F32[index]) && index < N - 1; index++) 119 ; // Iterate only 120 if (index == N - 1) { 121 psError(PS_ERR_BAD_PARAMETER_VALUE, true, 122 "Not enough good values to guess shutter correction.\n"); 123 goto ERROR; 124 } 125 tmpX->data.F32[0] = exptime->data.F32[index]; 126 tmpY->data.F32[0] = counts->data.F32[index]; 127 128 for (index++; 129 (!isfinite(exptime->data.F32[index]) || exptime->data.F32[index] == exptime->data.F32[0]) && 130 index < N; index++) 131 ; // Iterate only 132 if (index == N) { 133 psError(PS_ERR_BAD_PARAMETER_VALUE, true, 134 "Exposure times are all identical --- cannot guess shutter correction.\n"); 135 goto ERROR; 136 } 137 tmpY->data.F32[1] = counts->data.F32[index]; 138 tmpX->data.F32[1] = exptime->data.F32[index]; 114 139 115 140 // fit a line and extrapolate the fit to 0.0 116 psVectorFitPolynomial1D (line, NULL, 0, tmpY, NULL, tmpX); 117 float ratio = psPolynomial1DEval (line, 0.0) / pars->scale; 141 if (!psVectorFitPolynomial1D(line, NULL, 0, tmpY, NULL, tmpX)) { 142 psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to fit for the time offset.\n"); 143 goto ERROR; 144 } 145 float ratio = psPolynomial1DEval(line, 0.0) / corr->scale; 118 146 119 147 // XXX we need a sanity check: 120 // if the mean value of the three points is higher than pars->scale,148 // if the mean value of the three points is higher than corr->scale, 121 149 // then the slope should be negative. 122 // if the mean value of the three points is lower than pars->scale,150 // if the mean value of the three points is lower than corr->scale, 123 151 // then the slope should be positive. 124 152 125 // find two points bracketing the value counts = A (1 + dTk/dTo) / 2 = pars->scale (1 + ratio) / 2126 float value = pars->scale * (1 + ratio) / 2.0;127 128 int Np; 153 // find two points bracketing the value counts = A (1 + dTk/dTo) / 2 = corr->scale (1 + ratio) / 2 154 float value = corr->scale * (1 + ratio) / 2.0; 155 156 int Np; // Index of the value above (positive side) 129 157 if (ratio < 1.0) { 130 Np = psVectorBracket (counts, value, true);158 Np = psVectorBracket(counts, value, true); 131 159 } else { 132 Np = psVectorBracketDescend (counts, value, true);133 } 134 int Nm = (Np == 0) ? 1 : Np - 1; 160 Np = psVectorBracketDescend(counts, value, true); 161 } 162 int Nm = (Np == 0) ? 1 : Np - 1; // Index of the value below (negative side) 135 163 136 164 tmpX->data.F32[0] = counts->data.F32[Nm]; … … 140 168 141 169 // fit a line and extrapolate the fit to counts = A (1 + dTk/dTo) : exptime = dTo 142 line = psVectorFitPolynomial1D (line, NULL, 0, tmpY, NULL, tmpX); 143 pars->offref = psPolynomial1DEval (line, value); 144 pars->offset = ratio * pars->offref; 145 146 psFree (line); 147 psFree (tmpX); 148 psFree (tmpY); 149 150 return (pars); 170 if (!psVectorFitPolynomial1D (line, NULL, 0, tmpY, NULL, tmpX)) { 171 psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to fit for the reference offset.\n"); 172 goto ERROR; 173 } 174 corr->offref = psPolynomial1DEval(line, value); 175 corr->offset = ratio * corr->offref; 176 177 psFree(line); 178 psFree(tmpX); 179 psFree(tmpY); 180 181 return corr; 182 183 ERROR: 184 psFree(tmpX); 185 psFree(tmpY); 186 psFree(line); 187 psFree(corr); 188 return NULL; 151 189 } 152 190 153 191 // linear fit to the counts and exptime, given a value for offref 154 pmShutterCorrPars *pmShutterCorrectionLinFit (psVector *exptime, psVector *counts, psVector *cntError, float offref) 155 { 192 pmShutterCorrection *pmShutterCorrectionLinFit(const psVector *exptime, 193 const psVector *counts, 194 const psVector *cntError, 195 float offref 196 ) 197 { 198 PS_ASSERT_VECTOR_NON_NULL(exptime, NULL); 199 PS_ASSERT_VECTOR_NON_NULL(counts, NULL); 200 PS_ASSERT_VECTOR_TYPE(exptime, PS_TYPE_F32, NULL); 201 PS_ASSERT_VECTOR_TYPE(counts, PS_TYPE_F32, NULL); 202 PS_ASSERT_VECTORS_SIZE_EQUAL(exptime, counts, NULL); 203 if (exptime->n <= 2) { 204 psError(PS_ERR_BAD_PARAMETER_SIZE, true, 205 "Require more than 2 exposures to guess shutter correction.\n"); 206 return NULL; 207 } 208 if (cntError) { 209 PS_ASSERT_VECTOR_TYPE(cntError, PS_TYPE_F32, NULL); 210 PS_ASSERT_VECTORS_SIZE_EQUAL(counts, cntError, NULL); 211 } 212 PS_ASSERT_FLOAT_LARGER_THAN(offref, 0.0, NULL); 156 213 157 214 // this step is identical for all pixels: do it once and save? 158 psVector *x = psVectorAlloc (exptime->n, PS_TYPE_F32);159 psVector *y = psVectorAlloc (exptime->n, PS_TYPE_F32);215 psVector *x = psVectorAlloc(exptime->n, PS_TYPE_F32); 216 psVector *y = psVectorAlloc(exptime->n, PS_TYPE_F32); 160 217 x->n = y->n = exptime->n; 161 218 162 for (int i = 0; i < exptime->n; i++) { 219 for (long i = 0; i < exptime->n; i++) { 220 // Should be safe (if expensive) to stick NaNs in --- the fitter deals with them 163 221 float value = 1.0 / (exptime->data.F32[i] + offref); 164 222 x->data.F32[i] = exptime->data.F32[i] * value; … … 174 232 line->coeff[1][1] = 0; 175 233 176 psVectorFitPolynomial2D (line, NULL, 0, counts, cntError, x, y); 177 178 pmShutterCorrPars *pars = pmShutterCorrParsAlloc (); 179 180 pars->offref = offref; 181 pars->scale = line->coeff[1][0]; 182 pars->offset = line->coeff[0][1] / line->coeff[1][0]; 183 184 psFree (x); 185 psFree (y); 186 psFree (line); 187 188 return (pars); 234 if (!psVectorFitPolynomial2D(line, NULL, 0, counts, cntError, x, y)) { 235 psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to fit shutter correction.\n"); 236 psFree(x); 237 psFree(y); 238 psFree(line); 239 return NULL; 240 } 241 242 pmShutterCorrection *corr = pmShutterCorrectionAlloc(); 243 corr->offref = offref; 244 corr->scale = line->coeff[1][0]; 245 corr->offset = line->coeff[0][1] / line->coeff[1][0]; 246 247 psFree(x); 248 psFree(y); 249 psFree(line); 250 251 return corr; 189 252 } 190 253 … … 193 256 const psVector *x) 194 257 { 195 psF32 A = params->data.F32[0]; 196 psF32 p = x->data.F32[0] + params->data.F32[1]; 197 psF32 q = 1.0 / (x->data.F32[0] + params->data.F32[2]); 198 psF32 f = A*p*q; 199 200 if (deriv != NULL) { 201 deriv->data.F32[0] = p*q; 202 deriv->data.F32[1] = A*q; 203 deriv->data.F32[2] = -A*p*q*q; 204 } 205 return(f); 258 // This is in a tight loop, so we won't assert here. 259 260 psF32 A = params->data.F32[0]; 261 psF32 p = x->data.F32[0] + params->data.F32[1]; 262 psF32 q = 1.0 / (x->data.F32[0] + params->data.F32[2]); 263 psF32 f = A * p * q; 264 265 if (deriv) { 266 deriv->data.F32[0] = p * q; 267 deriv->data.F32[1] = A * q; 268 deriv->data.F32[2] = - f * q; 269 } 270 return f; 206 271 } 207 272 208 273 // non-linear fit to the counts and exptime, given a guess for the three parameters 209 pmShutterCorrPars *pmShutterCorrectionFullFit (psVector *exptime, psVector *counts, psVector *cntError, pmShutterCorrPars *guess) 210 { 211 212 psMinimization *myMin = psMinimizationAlloc(15, 0.1); 213 214 psVector *params = psVectorAlloc (3, PS_TYPE_F32); 274 pmShutterCorrection *pmShutterCorrectionFullFit(const psVector *exptime, 275 const psVector *counts, 276 const psVector *cntError, 277 const pmShutterCorrection *guess 278 ) 279 { 280 PS_ASSERT_VECTOR_NON_NULL(exptime, NULL); 281 PS_ASSERT_VECTOR_NON_NULL(counts, NULL); 282 PS_ASSERT_VECTOR_TYPE(exptime, PS_TYPE_F32, NULL); 283 PS_ASSERT_VECTOR_TYPE(counts, PS_TYPE_F32, NULL); 284 PS_ASSERT_VECTORS_SIZE_EQUAL(exptime, counts, NULL); 285 if (exptime->n <= 2) { 286 psError(PS_ERR_BAD_PARAMETER_SIZE, true, 287 "Require more than 2 exposures to guess shutter correction.\n"); 288 return NULL; 289 } 290 if (cntError) { 291 PS_ASSERT_VECTOR_TYPE(cntError, PS_TYPE_F32, NULL); 292 PS_ASSERT_VECTORS_SIZE_EQUAL(counts, cntError, NULL); 293 } 294 PS_ASSERT_PTR_NON_NULL(guess, NULL); 295 296 psMinimization *minInfo = psMinimizationAlloc(15, 0.1); // Minimization information 297 298 psVector *params = psVectorAlloc (3, PS_TYPE_F32); // Fitting parameters 215 299 params->data.F32[0] = guess->scale; 216 300 params->data.F32[1] = guess->offset; … … 224 308 // constrain->paramMax = psVectorAlloc (3, PS_TYPE_F32); 225 309 // constrain->paramMask = NULL; 226 psMinConstrain *constrain = NULL; 310 psMinConstrain *constrain = NULL; // Constraints on the minimization 227 311 228 312 // XXX ignore covariance matrix for the moment 229 313 // psImage *covar = psImageAlloc (params->n, params->n, PS_TYPE_F64); 230 psImage *covar = NULL; 314 psImage *covar = NULL; // Covariance matrix 231 315 232 316 // construct the coordinate and value entries (y is counts) 233 psArray *x = psArrayAlloc(exptime->n); 317 psArray *x = psArrayAlloc(exptime->n); // Coordinates 234 318 x->n = exptime->n; 235 319 236 for ( inti = 0; i < exptime->n; i++) {320 for (long i = 0; i < exptime->n; i++) { 237 321 psVector *coord = psVectorAlloc(1, PS_TYPE_F32); 238 322 coord->n = 1; … … 241 325 } 242 326 243 psMinimizeLMChi2(myMin, covar, params, constrain, x, counts, cntError, pmShutterCorrectionModel); 244 245 pmShutterCorrPars *pars = pmShutterCorrParsAlloc (); 246 247 pars->scale = params->data.F32[0]; 248 pars->offset = params->data.F32[1]; 249 pars->offref = params->data.F32[2]; 250 251 psFree (myMin); 252 psFree (params); 253 psFree (x); 254 255 return (pars); 256 } 327 if (!psMinimizeLMChi2(minInfo, covar, params, constrain, x, counts, cntError, pmShutterCorrectionModel)) { 328 psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to fit for shutter correction.\n"); 329 psFree(x); 330 psFree(minInfo); 331 psFree(params); 332 return NULL; 333 } 334 335 pmShutterCorrection *corr = pmShutterCorrectionAlloc(); // Shutter correction 336 corr->scale = params->data.F32[0]; 337 corr->offset = params->data.F32[1]; 338 corr->offref = params->data.F32[2]; 339 340 psFree(minInfo); 341 psFree(params); 342 psFree(x); 343 344 return corr; 345 } -
trunk/psModules/src/detrend/pmShutterCorrection.h
r8926 r9298 31 31 * First, as T_o goes to a large value, s() approaches the value of f'(x,y). 32 32 * Next, as T_o goes to a very small value, s() approaches the value of 33 * f'(x,y)*dT(x,y)/dT(0,0). Finally, when s() has the value of 33 * f'(x,y)*dT(x,y)/dT(0,0). Finally, when s() has the value of 34 34 * f'(x,y)*(1 + dT(x,y)/dT(0,0))/2, T_o has the value of dT(0,0). with data 35 35 * points covering a reasonable dynamic range, we can solve for these three 36 * values by interpolation and/or extrapolation. 36 * values by interpolation and/or extrapolation. 37 37 38 38 * To take the strategy one step further, we could use the above recipe to … … 48 48 * @author Eugene Magnier, IfA 49 49 * 50 * @version $Revision: 1. 4$ $Name: not supported by cvs2svn $51 * @date $Date: 2006- 09-25 01:06:28$50 * @version $Revision: 1.5 $ $Name: not supported by cvs2svn $ 51 * @date $Date: 2006-10-05 20:48:56 $ 52 52 * 53 53 * Copyright 2004 Maui High Performance Computing Center, University of Hawaii … … 56 56 #include "pslib.h" 57 57 58 // Shutter correction parameters, applicable for a single pixel 58 59 typedef struct 59 60 { 60 double scale; //A(k)61 double offset; //dTk62 double offref; //dTo61 double scale; // The normalisation for an exposure, A(k) 62 double offset; // The time offset, dTk 63 double offref; // The reference time offset, dTo 63 64 } 64 pmShutterCorr Pars;65 pmShutterCorrection; 65 66 66 pmShutterCorrPars *pmShutterCorrParsAlloc (); 67 pmShutterCorrPars *pmShutterCorrectionGuess (psVector *exptime, psVector *counts); 68 pmShutterCorrPars *pmShutterCorrectionLinFit (psVector *exptime, psVector *counts, psVector *cntError, float offref); 69 pmShutterCorrPars *pmShutterCorrectionFullFit (psVector *exptime, psVector *counts, psVector *cntError, pmShutterCorrPars *guess); 67 // Allocator 68 pmShutterCorrection *pmShutterCorrectionAlloc(); 69 70 // Guess a shutter correction, based on plot of counts vs exposure time. 71 // Used before doing the full non-linear fit, to get parameters close to the true. 72 // Assumes exptime vector is sorted (ascending order; longest is last) prior to input. 73 pmShutterCorrection *pmShutterCorrectionGuess(const psVector *exptime, // Exposure times for each exposure 74 const psVector *counts // Counts for each exposure 75 ); 76 77 // Generate shutter correction based on a linear fit 78 pmShutterCorrection *pmShutterCorrectionLinFit(const psVector *exptime, // Exposure times for each exposure 79 const psVector *counts, // Counts for each exposure 80 const psVector *cntError, // Error in the counts, for each exp. 81 float offref // Reference time offset 82 ); 83 84 // Generate shutter correction based on a full non-linear fit 85 pmShutterCorrection *pmShutterCorrectionFullFit(const psVector *exptime, // Exposure times for each exposure 86 const psVector *counts, // Counts for each exposure 87 const psVector *cntError, // Error in the counts, for each exp 88 const pmShutterCorrection *guess // Initial guess 89 );
Note:
See TracChangeset
for help on using the changeset viewer.
