|
2 | 2 | #include <stdlib.h>
|
3 | 3 | #include <string.h>
|
4 | 4 | #include <stdio.h>
|
| 5 | +#include <stdarg.h> /* Supports the variable number of parameters for bias_shift_corr() */ |
| 6 | +#include <ctype.h> |
5 | 7 |
|
| 8 | +#include "hstcal_memory.h" |
6 | 9 | #include "hstcal.h"
|
7 | 10 | #include "hstio.h"
|
8 | 11 |
|
@@ -36,152 +39,218 @@ static int make_amp_array(const int arr_rows, const int arr_cols, SingleGroup *
|
36 | 39 | static int unmake_amp_array(const int arr_rows, const int arr_cols, SingleGroup * im,
|
37 | 40 | int amp, double * array);
|
38 | 41 |
|
| 42 | +/* Remove the signal dependent bias shift from post-SM4 full frame WFC data |
| 43 | + * (based on ISR http://www.stsci.edu/hst/acs/documents/isrs/isr1202.pdf), |
| 44 | + * as well as from supported subarray data (~post-mid-2016) as identified by |
| 45 | + * specific aperture names |
| 46 | + * (based on ISR http://www.stsci.edu/hst/acs/documents/isrs/isr1703.pdf). |
| 47 | + * |
| 48 | + * chip2 consists of amps C & D, chip1 consists of amps A & B. |
| 49 | + * |
| 50 | + * Because full frame data uses both chips, but supported subarray data |
| 51 | + * is only from a single amp (therefore, a portion of a single chip), this |
| 52 | + * routine has a variable number of input SingleGroups. |
| 53 | + * |
| 54 | + * 16-May-2018 M.D. De La Pena: Generalized bias_shift_corr() to handle subarray data. |
| 55 | + */ |
| 56 | +int bias_shift_corr(ACSInfo *acs, int nGroups, ...) { |
| 57 | + |
| 58 | + /* Code to handle variable number of input parameters. The number of SingleGroup is 2 when |
| 59 | + processing a full frame (2 chips - all 4 amps) and only 1 when processing a supported subarray |
| 60 | + (1 chip from a single amp). |
| 61 | + */ |
| 62 | + SingleGroup *sg[nGroups]; |
| 63 | + va_list arguments; |
| 64 | + |
| 65 | + /* Initializing arguments to store all the values being passed to this routine via "..." */ |
| 66 | + va_start (arguments, nGroups); |
| 67 | + { |
| 68 | + /* sg[0] is chip2 and sg[1] is chip 1 for a full frame image */ |
| 69 | + {unsigned int i; |
| 70 | + for (i = 0; i < nGroups; i++) { |
| 71 | + sg[i]= va_arg (arguments, SingleGroup *); |
| 72 | + }} |
| 73 | + } |
| 74 | + va_end (arguments); |
39 | 75 |
|
40 |
| -/* remove signal dependent bias shift from post-SM4 full frame WFC data. |
41 |
| - * based on ISR http://www.stsci.edu/hst/acs/documents/isrs/isr1202.pdf |
42 |
| - * chip2 is amps C & D, chip1 is amps A & B. */ |
43 |
| -int bias_shift_corr(ACSInfo *acs, SingleGroup *chip2, SingleGroup *chip1) { |
44 | 76 | extern int status;
|
45 |
| - |
46 |
| - int i, j, k; /* iteration variables */ |
47 |
| - |
48 |
| - /* array for amp data and amp data + gap pixels */ |
49 |
| - double * ampdata, * ampdata_gap; |
50 |
| - |
| 77 | + |
51 | 78 | const double serial_freq = 1000./22.; /* serial pixel frequency */
|
52 | 79 | const double parallel_shift = 3.212; /* parallel shift time */
|
53 | 80 |
|
54 | 81 | /* number of virtual pixels at end of each row */
|
55 | 82 | const int ngap_pix = (int) (serial_freq * parallel_shift + 0.5);
|
56 | 83 |
|
57 |
| - const int arr_rows = chip2->sci.data.ny; |
58 |
| - const int arr_cols = chip2->sci.data.nx/2; |
| 84 | + /* There is always at least one SingleGroup - use sg[0] to get the image size of a single amp. |
| 85 | + * If this is a full frame image, then "nx" represents all the columns across both amps plus |
| 86 | + * the physical overscan and must be divided by 2. If this is a subarray, then "nx" represents |
| 87 | + * just the columns for a single amp plus physical overscan. |
| 88 | + */ |
| 89 | + const int arr_rows = sg[0]->sci.data.ny; |
| 90 | + const int arr_cols = (acs->subarray == NO) ? sg[0]->sci.data.nx/2 : sg[0]->sci.data.nx; |
59 | 91 |
|
60 | 92 | /* total number of real and gap pixels per quadrant */
|
61 | 93 | const int nquad_pix = (arr_cols + ngap_pix) * arr_rows;
|
62 | 94 |
|
63 |
| - /* array of true DC bias levels */ |
64 |
| - double * dc_bias_levels; |
65 |
| - |
66 | 95 | /* arrays below are in order of amp A, B, C, D */
|
67 | 96 |
|
68 |
| - /* time constant of AC high pass filter in external pre-amp. */ |
| 97 | + /* time constant of AC high pass filter in external pre-amp in microseconds */ |
69 | 98 | const double time_const[NAMPS] = {37.290251, 36.180001, 37.867770, 42.461249};
|
70 | 99 |
|
71 | 100 | /* ratio of DC offset shift and pixel signal */
|
72 | 101 | const double dc_ratio[NAMPS] = {0.3, 0.3, 0.3, 0.3};
|
73 | 102 |
|
74 | 103 | /* DSI sensitivity */
|
75 | 104 | const double dsi_sens[NAMPS] = {2.9188919e-3, 10.805754e-3, 12.432145e-3, 3.8596253e-3};
|
76 |
| - |
77 |
| - /* factor combining time constant and clocking frequency */ |
78 |
| - double factor; |
79 |
| - |
80 |
| - /* summation variables */ |
81 |
| - double sum; |
82 |
| - int num; |
83 |
| - double magic_square_mean; |
84 |
| - |
85 |
| - /* allocate space for data arrays */ |
86 |
| - ampdata = malloc(arr_rows * arr_cols * sizeof(double)); |
87 |
| - ampdata_gap = malloc(nquad_pix * sizeof(double)); |
88 |
| - |
89 |
| - /* allocate space for true DC bias levels array */ |
| 105 | + |
| 106 | + PtrRegister ptrReg; |
| 107 | + initPtrRegister(&ptrReg); |
| 108 | + |
| 109 | + /* array of true DC bias levels */ |
| 110 | + double * dc_bias_levels = NULL; |
90 | 111 | dc_bias_levels = malloc((nquad_pix + 1) * sizeof(double));
|
91 |
| - |
92 |
| - for (i = 0; i < NAMPS; i++) { |
93 |
| - /* put a single amp's data into ampdata */ |
94 |
| - if (i < 2) { |
95 |
| - make_amp_array(arr_rows, arr_cols, chip1, i, ampdata); |
96 |
| - } else { |
97 |
| - make_amp_array(arr_rows, arr_cols, chip2, i, ampdata); |
98 |
| - } |
99 |
| - |
100 |
| - /* calculate "magic square mean" */ |
101 |
| - sum = 0.0; |
102 |
| - num = 0; |
| 112 | + addPtr(&ptrReg, dc_bias_levels, &free); |
103 | 113 |
|
104 |
| - for (j = 2057; j <= 2066; j++) { |
105 |
| - for (k = 13; k <= 22; k++) { |
106 |
| - sum += ampdata[arr_cols*j + k]; |
107 |
| - num++; |
| 114 | + /* array for amp data and amp data + gap pixels */ |
| 115 | + double *ampdata = malloc(arr_rows * arr_cols * sizeof(double)); |
| 116 | + addPtr(&ptrReg, ampdata, &free); |
| 117 | + double *ampdata_gap = malloc(nquad_pix * sizeof(double)); |
| 118 | + addPtr(&ptrReg, ampdata_gap, &free); |
| 119 | + |
| 120 | + /* For full frame data, there are four amps in use. For supported subarray |
| 121 | + * data, there is only one amp in use. The actual amp in use must be determined. |
| 122 | + */ |
| 123 | + int numAmpsInUse = (acs->subarray == YES) ? 1 : NAMPS; |
| 124 | + |
| 125 | + /* Loop over all the amps for full frame data (total of 4 amps, 0 to 3) or just use |
| 126 | + * the single amp value corresponding to the supported subarray (1 amp, value defined in acs.h). |
| 127 | + */ |
| 128 | + int ampInUse = 0; |
| 129 | + {unsigned int i; |
| 130 | + for (i = 0; i < numAmpsInUse; i++) { |
| 131 | + ampInUse = i; |
| 132 | + if ((i == 0) && (acs->subarray == YES)) { |
| 133 | + if (strcmp (acs->ccdamp, "A") == 0) |
| 134 | + ampInUse = AMP_A; |
| 135 | + else if (strcmp (acs->ccdamp, "B") == 0) |
| 136 | + ampInUse = AMP_B; |
| 137 | + else if (strcmp (acs->ccdamp, "C") == 0) |
| 138 | + ampInUse = AMP_C; |
| 139 | + else if (strcmp (acs->ccdamp, "D") == 0) |
| 140 | + ampInUse = AMP_D; |
| 141 | + } |
| 142 | + |
| 143 | + /* put a single amp's data into ampdata */ |
| 144 | + if (acs->subarray == YES) { |
| 145 | + make_amp_array(arr_rows, arr_cols, sg[0], ampInUse, ampdata); |
| 146 | + } else { |
| 147 | + if (i < 2) { |
| 148 | + make_amp_array(arr_rows, arr_cols, sg[1], ampInUse, ampdata); |
| 149 | + } else { |
| 150 | + make_amp_array(arr_rows, arr_cols, sg[0], ampInUse, ampdata); |
| 151 | + } |
108 | 152 | }
|
109 |
| - } |
| 153 | + |
| 154 | + /* calculate "magic square mean" - this works for any single amp */ |
| 155 | + double sum = 0.0; |
| 156 | + int num = 0; |
| 157 | + double magic_square_mean = 0.0; |
110 | 158 |
|
111 |
| - magic_square_mean = sum / (double) num; |
| 159 | + {unsigned int j, k; |
| 160 | + for (j = 2057; j <= 2066; j++) { |
| 161 | + for (k = 13; k <= 22; k++) { |
| 162 | + sum += ampdata[arr_cols*j + k]; |
| 163 | + num++; |
| 164 | + } |
| 165 | + }} |
112 | 166 |
|
113 |
| - /* make amp + gap array */ |
114 |
| - for (j = 0; j < arr_rows; j++) { |
115 |
| - for (k = 0; k < (arr_cols + ngap_pix); k++) { |
116 |
| - if (k < arr_cols) { |
117 |
| - ampdata_gap[(arr_cols + ngap_pix)*j + k] = ampdata[arr_cols*j + k]; |
118 |
| - } else { |
119 |
| - ampdata_gap[(arr_cols + ngap_pix)*j + k] = magic_square_mean; |
| 167 | + magic_square_mean = sum / (double) num; |
| 168 | + |
| 169 | + /* make amp + gap array */ |
| 170 | + {unsigned int j, k; |
| 171 | + for (j = 0; j < arr_rows; j++) { |
| 172 | + for (k = 0; k < (arr_cols + ngap_pix); k++) { |
| 173 | + if (k < arr_cols) { |
| 174 | + ampdata_gap[(arr_cols + ngap_pix)*j + k] = ampdata[arr_cols*j + k]; |
| 175 | + } else { |
| 176 | + ampdata_gap[(arr_cols + ngap_pix)*j + k] = magic_square_mean; |
| 177 | + } |
120 | 178 | }
|
121 |
| - } |
122 |
| - } |
| 179 | + }} |
123 | 180 |
|
124 |
| - /* calculate true DC bias levels */ |
125 |
| - factor = 1.0 - exp(-1.0 / (time_const[i] * serial_freq)); |
| 181 | + /* factor combining time constant and clocking frequency */ |
| 182 | + double factor = 1.0 - exp(-1.0 / (time_const[ampInUse] * serial_freq)); |
126 | 183 |
|
127 |
| - dc_bias_levels[0] = magic_square_mean * dc_ratio[i]; |
| 184 | + /* calculate true DC bias levels */ |
| 185 | + dc_bias_levels[0] = magic_square_mean * dc_ratio[ampInUse]; |
128 | 186 |
|
129 |
| - for (j = 1; j < nquad_pix + 1; j++) { |
130 |
| - dc_bias_levels[j] = ampdata_gap[j-1] * factor * dc_ratio[i] + |
| 187 | + {unsigned int j; |
| 188 | + for (j = 1; j < nquad_pix + 1; j++) { |
| 189 | + dc_bias_levels[j] = ampdata_gap[j-1] * factor * dc_ratio[ampInUse] + |
131 | 190 | (1.0 - factor) * dc_bias_levels[j-1];
|
132 |
| - } |
| 191 | + }} |
133 | 192 |
|
134 |
| - /* calculate correction to data */ |
135 |
| - for (j = 0; j < nquad_pix; j++) { |
136 |
| - ampdata_gap[j] = (ampdata_gap[j] - dsi_sens[i] * dc_bias_levels[j+1]) - |
| 193 | + /* calculate correction to data */ |
| 194 | + {unsigned int j; |
| 195 | + for (j = 0; j < nquad_pix; j++) { |
| 196 | + ampdata_gap[j] = (ampdata_gap[j] - dsi_sens[ampInUse] * dc_bias_levels[j+1]) - |
137 | 197 | (10./22.) * (dc_bias_levels[j+1] - dc_bias_levels[j]);
|
138 |
| - } |
| 198 | + }} |
139 | 199 |
|
140 |
| - /* copy corrected data back to ampdata */ |
141 |
| - for (j = 0; j < arr_rows; j++) { |
142 |
| - for (k = 0; k < arr_cols; k++) { |
143 |
| - ampdata[arr_cols*j + k] = ampdata_gap[(arr_cols + ngap_pix)*j + k]; |
144 |
| - } |
145 |
| - } |
| 200 | + /* copy corrected data back to ampdata */ |
| 201 | + {unsigned int j, k; |
| 202 | + for (j = 0; j < arr_rows; j++) { |
| 203 | + for (k = 0; k < arr_cols; k++) { |
| 204 | + ampdata[arr_cols*j + k] = ampdata_gap[(arr_cols + ngap_pix)*j + k]; |
| 205 | + } |
| 206 | + }} |
146 | 207 |
|
147 |
| - /* re-calculate "magic square mean" */ |
148 |
| - sum = 0.0; |
149 |
| - num = 0; |
| 208 | + /* re-calculate "magic square mean" */ |
| 209 | + sum = 0.0; |
| 210 | + num = 0; |
| 211 | + magic_square_mean = 0.0; |
150 | 212 |
|
151 |
| - for (j = 2057; j <= 2066; j++) { |
152 |
| - for (k = 13; k <= 22; k++) { |
153 |
| - sum += ampdata[arr_cols*j + k]; |
154 |
| - num++; |
155 |
| - } |
156 |
| - } |
| 213 | + {unsigned int j, k; |
| 214 | + for (j = 2057; j <= 2066; j++) { |
| 215 | + for (k = 13; k <= 22; k++) { |
| 216 | + sum += ampdata[arr_cols*j + k]; |
| 217 | + num++; |
| 218 | + } |
| 219 | + }} |
157 | 220 |
|
158 |
| - magic_square_mean = sum / (double) num; |
159 |
| - /* Keep track of the total bias correction applied to each AMP region */ |
160 |
| - acs->blev[i] += magic_square_mean; |
161 |
| - /* Report to the user the contribution to the bias level correction |
162 |
| - made by this processing step. |
163 |
| - */ |
164 |
| - sprintf(MsgText, "Bias shift correcting for bias level in Amp %c of %0.4f electrons.",AMPSORDER[i], magic_square_mean); |
165 |
| - trlmessage(MsgText); |
| 221 | + magic_square_mean = sum / (double) num; |
| 222 | + |
| 223 | + /* Keep track of the total bias correction applied to each AMP region */ |
| 224 | + acs->blev[ampInUse] += magic_square_mean; |
| 225 | + |
| 226 | + /* Report to the user the contribution to the bias level correction |
| 227 | + made by this processing step. |
| 228 | + */ |
| 229 | + sprintf(MsgText, "Bias shift correcting for bias level in Amp %c of %0.4f electrons.",AMPSORDER[ampInUse], magic_square_mean); |
| 230 | + trlmessage(MsgText); |
166 | 231 |
|
167 |
| - /* subtract "magic square mean" from data*/ |
168 |
| - for (j = 0; j < arr_rows; j++) { |
169 |
| - for (k = 0; k < arr_cols; k++) { |
170 |
| - ampdata[arr_cols*j + k] -= magic_square_mean; |
171 |
| - } |
172 |
| - } |
| 232 | + /* subtract "magic square mean" from data*/ |
| 233 | + {unsigned int j, k; |
| 234 | + for (j = 0; j < arr_rows; j++) { |
| 235 | + for (k = 0; k < arr_cols; k++) { |
| 236 | + ampdata[arr_cols*j + k] -= magic_square_mean; |
| 237 | + } |
| 238 | + }} |
173 | 239 |
|
174 |
| - /* copy modified data back to SingleGroup structs */ |
175 |
| - if (i < 2) { |
176 |
| - unmake_amp_array(arr_rows, arr_cols, chip1, i, ampdata); |
177 |
| - } else { |
178 |
| - unmake_amp_array(arr_rows, arr_cols, chip2, i, ampdata); |
179 |
| - } |
180 |
| - } |
| 240 | + /* copy modified data back to SingleGroup structs */ |
| 241 | + |
| 242 | + if (acs->subarray == YES) { |
| 243 | + unmake_amp_array(arr_rows, arr_cols, sg[0], ampInUse, ampdata); |
| 244 | + } else { |
| 245 | + if (i < 2) { |
| 246 | + unmake_amp_array(arr_rows, arr_cols, sg[1], ampInUse, ampdata); |
| 247 | + } else { |
| 248 | + unmake_amp_array(arr_rows, arr_cols, sg[0], ampInUse, ampdata); |
| 249 | + } |
| 250 | + } |
| 251 | + }} |
181 | 252 |
|
182 |
| - free(ampdata); |
183 |
| - free(ampdata_gap); |
184 |
| - free(dc_bias_levels); |
| 253 | + freeOnExit(&ptrReg); |
185 | 254 |
|
186 | 255 | return status;
|
187 | 256 | }
|
@@ -894,6 +963,7 @@ static int make_amp_array(const int arr_rows, const int arr_cols, SingleGroup *i
|
894 | 963 | array[i*arr_cols + j] = Pix(im->sci.data, c, r);
|
895 | 964 | }
|
896 | 965 | }
|
| 966 | +trlmessage (MsgText); |
897 | 967 |
|
898 | 968 | return status;
|
899 | 969 | }
|
|
0 commit comments