OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
calibrate_l1a.c
Go to the documentation of this file.
1 /*-----------------------------------------------------------------------------
2  File : calibrate_l1a.c
3 
4  Contents:
5  calibrate_l1a - takes an array of level-1A raw counts and returns
6  a corresponding arry of radiance values after
7  applying the sensor calibration
8 
9  Other relevant files:
10  cal_l1a.h - various #defined constants, other include files
11  (get_cal.h, getcal_proto.h, call1a_proto.h) and
12  also includes hdf.h
13  get_cal.c - a higher layer of calibration input functions
14  get_cal_misc.c - a lower layer of calibration input functions
15  tcal_l1a.c - a test routine to test calibrate_l1a
16 
17  Notes:
18  HDF library used - HDF3.3r3p1
19 
20  Modification history:
21  Programmer Organization Date Description of change
22  -------------- ------------ -------- ---------------------
23  Lakshmi Kumar Hughes STX 06/07/94 Original development
24  Lakshmi Kumar Hughes STX 10/30/95 Filtering scan_mod corr.
25  to data of dtype = SOL &
26  TDI.
27  Lakshmi Kumar Hughes STX 11/20/95 Filtering scan_mod corr.
28  to data of dtype = IGC
29  Lakshmi Kumar Hughes STX 01/25/96 Modified local variable
30  "rads" to global var
31  Gene Eplee GSC 05/24/96 Implemented quadratic
32  temporal calibration
33  correction (gain & offset)
34  Lakshmi Kumar Hughes STX 10/17/96 Removed cal_year, cal_day
35  output arguments.
36  Ref. V5.0 I/O specs.
37  Gene Eplee GSC 01/14/97 Reworked populating of
38  g_f at the calibration
39  knees.
40  Gene Eplee GSC 04/25/97 Modified system gain and
41  offset corrections to
42  allow calling routine to
43  override cal table values.
44  Gene Eplee GSC 09/09/97 Modified dark restore
45  subtraction to use
46  mean values for GAC, LAC,
47  and HRPT data.
48  Gene Eplee SAIC GSC 05/08/98 Made calibration model reference
49  times static.
50  Gene Eplee SAIC GSC 05/12/98 Modified cal_mod to multiply
51  cal_gain rather than overwrite it.
52  Gene Eplee SAIC GSC 06/01/98 Fix gain 2 / gain 3 telemetry bit flip.
53  Gene Eplee SAIC GSC 02/08/00 Fix dtype IF-Statement comparison errors
54  for dark_restore and scan modulation.
55  Gene Eplee SAIC GSC 12/12/00 Convert time correction to
56  exponential and add time-dependent
57  mirror side correction.
58  Gene Eplee SAIC 03/08/04 Converted to simultaneous
59  exponentials for time and
60  mirror sides
61  Gene Eplee SAIC 07/26/06 Added focal plane
62  temperatures and
63  instrument electronics
64  temperature corrections
65  Gene Eplee SAIC 06/27/2007 Added focal plane and
66  instrument electronics
67  reference temperatures
68 -----------------------------------------------------------------------------*/
69 
70 #include "cal_l1a.h"
71 #include "call1a_proto.h"
72 #include <mfhdf.h>
73 
74 /*-----------------------------------------------------------------------------
75  Function: calibrate_l1a
76 
77  Returns: int32 (status)
78  Returns a status code of 0 when successful. Otherwise returns
79  -1 - to indicate calibration file open/close error
80  -2 - to indicate read error
81  -3 - to indicate time error (if the given time cannot be found)
82  -4 - to indicate insufficient memory error
83 
84  Description:
85  The function calibrate_l1a takes an array of level-1A raw counts
86  and returns a corresponding array of radiance values (level-1B data)
87  after applying the sensor calibration.
88 
89  Arguments: (in calling order)
90  Type Name I/O Description
91  ---- ---- --- -----------
92  char * cal_path I calibration file path
93  int16 syear I year of data start time
94  int16 sday I day-of-year for data start time
95  int32 smsec I milliseconds of the day for data
96  start tm as returned by get_l1a_open
97  int16 eday I day-of-year for data end time
98  int32 msec I millisecs of the day for data start
99  time as returned by get_l1a_record
100  char * dtype I data type flag
101  int32 nsta I start pixel/sample number to process
102  int32 nsamp I samples per scan line
103  float32 * dark_mean I mean dark restore values for all 8
104  bands
105  int16 * gain I gains for all 8 bands; as returned
106  by get_l1a_record
107  int16 * tdi I input TDI for all 8 bands
108  int16 * scan_temp I digitized scan temperatures
109  int16 * side I mirror side of scan line
110  int16 * l1a_data I Level-1A data; as returned by
111  get_l1a_record
112  float32 * l1b_data O Sensor calibrated radiance values
113  corresponding to l1a_data
114  struct cal_mod_struc I Structure for override control of
115  cal_mod system gain and offset
116 
117  Notes:
118 
119  Modification history:
120  Programmer Organization Date Description of change
121  -------------- ------------ -------- ---------------------
122  Lakshmi Kumar Hughes STX 06/07/94 Original development
123  Lakshmi Kumar Hughes STX 02/07/95 Bug fix--Applied time
124  dependent correction.
125  Added cal_year & cal_day
126  arguments.
127  (ref v4.2 I/O specs.)
128  Lakshmi Kumar Hughes STX 10/30/95 Filtering scan_mod corr.
129  to data of dtype = SOL &
130  TDI.
131  Lakshmi Kumar Hughes STX 11/20/95 Filtering scan_mod corr.
132  to data of dtype = IGC
133  Lakshmi Kumar Hughes STX 01/25/96 Modified loc var "rads"
134  to global var "cal_rads"
135  to make it accessible to
136  l1a_read rtn.
137  Gene Eplee GSC 05/24/96 Implemented quadratic
138  temporal calibration
139  correction (gain & offset)
140  Lakshmi Kumar Hughes STX 10/17/96 Removed cal_year, cal_day
141  output arguments.
142  Ref. V5.0 I/O specs.
143  Gene Eplee GSC 01/14/97 Reworked populating of
144  g_f at the calibration
145  knees.
146  Gene Eplee GSC 04/25/97 Modified system gain and
147  offset corrections to
148  allow calling routine to
149  override cal table values.
150  Lakshmi Kumar Hughes STX 05/02/97 Removed non prototype defns.
151  Gene Eplee GSC 09/09/97 Modified dark restore
152  subtraction to use
153  mean values for GAC, LAC,
154  and HRPT data.
155  Gene Eplee SAIC GSC 05/08/98 Made calibration model reference
156  times static.
157  Gene Eplee SAIC GSC 05/12/98 Modified cal_mod to multiply
158  cal_gain rather than overwrite it.
159  Gene Eplee SAIC GSC 06/01/98 Fix gain 2 / gain 3 telemetry bit flip.
160  Gene Eplee SAIC GSC 02/08/00 Fix dtype IF-Statement comparison errors
161  for dark_restore and scan modulation.
162  Joel Gales Futuretech 10/02/00 Change st_samp to nta
163  Pass nsamp,nsta,&ninc
164  to get_cal
165  Gene Eplee SAIC GSC 12/12/00 Convert time correction to
166  exponential and add time-dependent
167  mirror side correction.
168  B. Franz SAIC 06/02/02 removed dark_rest param
169 -----------------------------------------------------------------------------*/
170 float32 cal_counts[NBANDS][4][5]; /*digital cnts (zero-offs corrected */
171 float32 cal_rads[NBANDS][4][5]; /*radiances corresponding to knees */
172 
173 int32_t calibrate_l1a(char *cal_path, int16_t syear, int16_t sday, int32_t smsec,
174  int16_t eday, int32_t msec, char *dtype, int32_t nsta, int32_t ninc,
175  int32_t nsamp, float *dark_mean, int16_t *gain, int16_t *tdi,
176  int16_t *scan_temp, float *inst_temp, int16_t side,
177  int16_t *l1a_data, float *l1b_data, cal_mod_struc *cal_mod) {
178 
179  static int32 called_get_call = 0, first_call = 1;
180  static int16 pr_syear = 0, pr_sday = 0;
181  static int32 pr_smsec = 0;
182  static int16 pr_gain[NBANDS] = {-1, -1, -1, -1, -1, -1, -1, -1};
183  static int16 pr_tdi[NBANDS] = {-1, -1, -1, -1, -1, -1, -1, -1};
184 
185 
186  int16 cal_year, cal_day; /* calibrate entry year & day */
187  int16 status, n;
188  static int16 ref_year, ref_day, ref_min; /* calibration model reference time */
189  int16 band, knee, count, pixel; /* local indeces */
190  int16 gn[NBANDS]; /* gain buffer */
191  int16 count1, count2, tdi_flag, gain_flag; /* temporary storage fields */
192  int16 l1_data; /*temp space for dark-restore corrected cnt*/
193  static int32 ref_jday; /* julian reference day */
194  int32 data_jday; /* julian data day */
195  float32 slope; /*loc_slope for converting l1a cnt and rad */
196  static float32 g_f[NBANDS][1024]; /*gain factors look up table */
197 
198  static float32 fp_temps[256][NBANDS]; /*focal plane temperatures */
199  static float32 scan_mod[2][1285]; /*scan modulation corr factors */
200 
201  /* Exponential Cal Table Format */
202  float32 mirror[NBANDS]; /* mirror side correction */
203  float32 itemp_corr[NBANDS]; /* instrument temp correction */
204  float32 fptemp_corr[NBANDS]; /* fp temp correction */
205  float64 cal_gain[NBANDS]; /* calibration model system gain */
206  float64 delta_day, delta_t; /* calibration model timescales */
207  static float64 tfactor_const[NBANDS]; /* time dependent constant term */
208  static float64 tfactor_linear_1[NBANDS]; /* time dependent linear term */
209  static float64 tfactor_exponential_1[NBANDS]; /* time dependent exponential term */
210  static float64 tfactor_linear_2[NBANDS]; /* time dependent linear term */
211  static float64 tfactor_exponential_2[NBANDS]; /* time dependent exponential term */
212  static float64 cal_offset[NBANDS]; /* calibration model system offset */
213  static float64 inst_tcorr[NBANDS]; /* instrument temp corrections */
214  static float64 inst_tref[NBANDS]; /* instrument reference temp */
215  static float64 fp_tcorr[NBANDS]; /* fp temp corrections */
216  static float64 fp_tref[NBANDS]; /* fp reference temp */
217  static float64 mside1_const[NBANDS]; /* mirror side1 constant term */
218  static float64 mside1_linear_1[NBANDS]; /* mirror side1 linear term */
219  static float64 mside1_exponential_1[NBANDS]; /* mirror side1 exponential term */
220  static float64 mside1_linear_2[NBANDS]; /* mirror side1 linear term */
221  static float64 mside1_exponential_2[NBANDS]; /* mirror side1 exponential term */
222  static float64 mside2_const[NBANDS]; /* mirror side2 constant term */
223  static float64 mside2_linear_1[NBANDS]; /* mirror side2 linear term */
224  static float64 mside2_exponential_1[NBANDS]; /* mirror side2 exponential term */
225  static float64 mside2_linear_2[NBANDS]; /* mirror side2 linear term */
226  static float64 mside2_exponential_2[NBANDS]; /* mirror side2 exponential term */
227 
228  for (band = 0; band < NBANDS; band++) {
229  if (tdi[band] < 0)
230  tdi[band] = 0;
231  if (tdi[band] > 255)
232  tdi[band] = 255;
233  if (scan_temp[band] < 0)
234  scan_temp[band] = 0;
235  if (scan_temp[band] > 255)
236  scan_temp[band] = 255;
237  /* Fix gain 2 / gain 3 telemetry bit flip */
238  switch (gain[band]) {
239  case 0:
240  gn[band] = 0;
241  break;
242  case 1:
243  gn[band] = 2;
244  break;
245  case 2:
246  gn[band] = 1;
247  break;
248  case 3:
249  gn[band] = 3;
250  break;
251  }
252 
253  }
254 
255  for (band = 0; band < NBANDS && tdi[band] == pr_tdi[band]; band++);
256 
257  if (band < NBANDS)
258  tdi_flag = 1;
259  else
260  tdi_flag = 0;
261 
262  if (first_call || syear != pr_syear || sday != pr_sday || smsec != pr_smsec
263  || tdi_flag) {
264  first_call = 0;
265  pr_syear = syear;
266  pr_sday = sday;
267  pr_smsec = smsec;
268  for (band = 0; band < NBANDS; band++)
269  pr_tdi[band] = tdi[band];
270 
271  if ((status = get_cal(cal_path, syear, sday, eday, msec, nsamp, nsta,
272  ninc, dtype, tdi, &cal_year, &cal_day, &ref_year,
273  &ref_day, &ref_min, fp_temps, scan_mod, tfactor_const,
274  tfactor_linear_1, tfactor_exponential_1, tfactor_linear_2,
275  tfactor_exponential_2, cal_offset, inst_tcorr, inst_tref,
276  fp_tcorr, fp_tref, mside1_const, mside1_linear_1,
277  mside1_exponential_1, mside1_linear_2,
278  mside1_exponential_2, mside2_const, mside2_linear_1,
279  mside2_exponential_1, mside2_linear_2,
280  mside2_exponential_2, cal_counts, cal_rads)) < 0)
281  return status;
282  /* Define the reference timescale for the calibration system gain. */
283  ref_jday = jul2jday(ref_year, ref_day);
284  called_get_call = 1;
285  }
286 
287  for (band = 0; band < NBANDS && gn[band] == pr_gain[band]; band++);
288 
289  if (band < NBANDS)
290  gain_flag = 1;
291  else
292  gain_flag = 0;
293 
294  if (called_get_call || gain_flag) {
295  called_get_call = 0;
296  for (band = 0; band < NBANDS; band++)
297  pr_gain[band] = gn[band];
298  for (band = 0; band < NBANDS; band++) {
299  for (knee = 1; knee <= 4; knee++) {
300  n = 1;
301  while (((int16) cal_counts[band][gn[band]][knee] ==
302  (int16) cal_counts[band][gn[band]][knee - n]) && n <= knee)
303  n++;
304  count1 = (int16) cal_counts[band][gn[band]][knee - n] + 1;
305  count2 = (int16) cal_counts[band][gn[band]][knee];
306  if (knee == 1)
307  count1 = 0;
308  if (knee == 4)
309  count2 = 1023;
310  slope = (cal_rads[band][gn[band]][knee] -
311  cal_rads[band][gn[band]][knee - n]) /
312  (cal_counts[band][gn[band]][knee] -
313  cal_counts[band][gn[band]][knee - n]);
314  for (count = count1; count <= count2; count++)
315  g_f[band][count] =
316  slope * (count - cal_counts[band][gn[band]][knee - n]) +
317  cal_rads[band][gn[band]][knee - n];
318  }
319  }
320  }
321 
322  /* Define the timescale for the calibration system gain. */
323  data_jday = jul2jday(syear, sday);
324  delta_day = (float64) (data_jday - ref_jday) - (float64) ref_min / 1440.0;
325  delta_t = delta_day + (float64) msec / 86400000.0;
326 
327  for (band = 0; band < BANDS; band++) {
328 
329  /* Compute the system gain */
330  cal_gain[band] = 1.0 / (tfactor_const[band] -
331  tfactor_linear_1[band]*(1.0 - exp(-tfactor_exponential_1[band] * delta_t)) -
332  tfactor_linear_2[band]*(1.0 - exp(-tfactor_exponential_2[band] * delta_t)));
333 
334  /* Check for override on system gain and offset */
335  /* and pass back the gain, offset used */
336  if (cal_mod->flag == 1) {
337  cal_gain[band] = cal_mod->gain[band] * cal_gain[band];
338  } else if (cal_mod->flag == 2) {
339  cal_offset[band] = cal_mod->offset[band];
340  } else if (cal_mod->flag == 3) {
341  cal_gain[band] = cal_mod->gain[band] * cal_gain[band];
342  cal_offset[band] = cal_mod->offset[band];
343  } /* return final gain and offset in use only if not externally altered */
344  else {
345  cal_mod->gain[band] = cal_gain[band];
346  cal_mod->offset[band] = cal_offset[band];
347  }
348 
349  /* Compute the mirror side correction */
350  if (side == 0) mirror[band] =
351  (float32) (1.0 / (mside1_const[band] -
352  mside1_linear_1[band]*(1.0 - exp(-mside1_exponential_1[band] * delta_t)) -
353  mside1_linear_2[band]*(1.0 - exp(-mside1_exponential_2[band] * delta_t))));
354  else mirror[band] =
355  (float32) (mside2_const[band] -
356  mside2_linear_1[band]*(1.0 - exp(-mside2_exponential_1[band] * delta_t)) -
357  mside2_linear_2[band]*(1.0 - exp(-mside2_exponential_2[band] * delta_t)));
358 
359  /* Compute the focal plane temperature correction. */
360  fptemp_corr[band] = (float32) (1.0 +
361  fp_tcorr[band]*(fp_temps[scan_temp[band]][band] - fp_tref[band]));
362 
363  /* Compute the instrument electronics temperature correction.
364  The instrument electronics temperature is entry 15 in the
365  inst_ana telemetry array. */
366  itemp_corr[band] = (float32) (1.0 +
367  inst_tcorr[band]*(inst_temp[14] - inst_tref[band]));
368 
369  for (pixel = 0; pixel < nsamp; pixel++) {
370  /* Use mean dark restore values for all data. */
371  l1_data = l1a_data[band * nsamp + pixel] - (int16) (dark_mean[band] + 0.5);
372  if (l1_data < 0)
373  l1_data = 0;
374  if (l1_data > 1023)
375  l1_data = 1023;
376  l1b_data[band * nsamp + pixel] = g_f[band][l1_data];
377  l1b_data[band * nsamp + pixel] =
378  l1b_data[band * nsamp + pixel] * mirror[band];
379  l1b_data[band * nsamp + pixel] =
380  l1b_data[band * nsamp + pixel] * fptemp_corr[band];
381  l1b_data[band * nsamp + pixel] =
382  l1b_data[band * nsamp + pixel] * itemp_corr[band];
383  if ((strcmp(dtype, "SOL") != 0) && (strcmp(dtype, "TDI") != 0) && (strcmp(dtype, "IGC") != 0))
384  l1b_data[band * nsamp + pixel] =
385  l1b_data[band * nsamp + pixel] * scan_mod[band % 2][pixel];
386  l1b_data[band * nsamp + pixel] =
387  (float32) ((float64) l1b_data[band * nsamp + pixel] * cal_gain[band]
388  + cal_offset[band]);
389  }
390  }
391  return SUCCEED;
392 }
393 
394 
395 /*---------------------------------------------------------------------------*/
396 
397 /*------------------------------------------------------------------------------
398 
399  Function: jul2jday
400 
401  Returns type: int
402 
403  Description:
404 
405  Convert year and day-of-year pair to Julian Day. This routine uses
406  the same cal2jday routine by just specifying the month to be 1 and
407  the day-of-month to be day-of-year.
408 
409  Parameters: (in calling order)
410  Type Name I/O Description
411  ---- ---- --- -----------
412  int year I year
413  int yday I day of year [1,366]
414 
415  Modification history:
416  Programmer Date Description of change
417  ---------- ---- ---------------------
418  Frank Chen 30-Jul-1993 Original development
419 
420 ------------------------------------------------------------------------------*/
421 
422 int jul2jday(int year, int yday) {
423  int jday;
424 
425  jday = cal2jday(year, 1, yday);
426  return (jday);
427 }
428 
429 /*------------------------------------------------------------------------------
430 
431  Function: cal2jday
432 
433  Returns type: int
434 
435  Description:
436 
437  This function converts a calendar date to the corresponding Julian
438  day starting at noon on the calendar date. The algorithm used is
439  from Van Flandern and Pulkkinen, Ap. J. Supplement Series 41,
440  November 1979, p.400
441  This will also work when month is 1 and day-of-month is specified
442  as day-of-year.
443 
444  Parameters: (in calling order)
445  Type Name I/O Description
446  ---- ---- --- -----------
447  int year I year
448  int month I month [1,12]
449  int mday I day of month [1,31]
450 
451  Modification history:
452  Programmer Date Description of change
453  ---------- ---- ---------------------
454  Fred Patt 04-Nov-1992 Original written in FORTRAN(jd)
455  Frank Chen 30-Jul-1993 Rewrite in C
456 
457 ------------------------------------------------------------------------------*/
458 
459 int cal2jday(int year, int month, int mday) {
460  int jday;
461 
462  jday = 367 * year
463  - 7 * (year + (month + 9) / 12) / 4
464  + 275 * month / 9
465  + mday
466  + 1721014;
467  /* additional calculation is needed only for dates outside of */
468  /* the period March 1, 1900 to Feburary 28, 2100 */
469  /*
470  jday = jday + 15 - 3 * ((year + (month - 9) / 7) / 100 + 1) / 4;
471  */
472  return (jday);
473 }
474 
475 
integer, parameter int16
Definition: cubeio.f90:3
double fp_tcorr[BANDS_DIMS_1A]
Definition: l1a_seawifs.c:57
int16 eday
Definition: l1_czcs_hdf.c:17
float dark_mean[8]
Definition: l1a_seawifs.c:34
int status
Definition: l1_czcs_hdf.c:32
int cal2jday(int year, int month, int mday)
int16 * gain
Definition: l1_czcs_hdf.c:33
int jul2jday(int year, int yday)
PARAM_TYPE_NONE Default value No parameter is buried in the product name name_prefix is case insensitive string compared to the product name PARAM_TYPE_VIS_WAVE The visible wavelength bands from the sensor are buried in the product name The product name is compared by appending and name_suffix ie aph_412_giop where prod_ix will be set to PARAM_TYPE_IR_WAVE same search method as PARAM_TYPE_VIS_WAVE except only wavelength above are looped through but prod_ix is still based ie aph_2_giop for the second band
int16_t * l1a_data
Definition: l1a_seawifs.c:84
int32 * msec
Definition: l1_czcs_hdf.c:31
double fp_tref[BANDS_DIMS_1A]
Definition: l1a_seawifs.c:58
int syear
Definition: l1_czcs_hdf.c:15
int32_t jday(int16_t i, int16_t j, int16_t k)
Definition: jday.c:4
int32 smsec
Definition: l1_czcs_hdf.c:16
float32 cal_counts[NBANDS][4][5]
int sday
Definition: l1_czcs_hdf.c:15
int32 nsta
Definition: l1_czcs_hdf.c:27
int32 get_cal(char *cal_path, int16 syear, int16 sday, int16 eday, int32 msec, char *dtype, int16 *tdi, int16 *cal_year, int16 *cal_day, int16 *ref_year, int16 *ref_day, int16 *ref_min, float32 temps[256][BANDS], float32 scan_mod[2][1285], float32 mirror[2][BANDS], float64 *t_const, float64 *t_linear, float64 *t_quadratic, float32 *cal_offs, float32 counts[BANDS][4][5], float32 rads[BANDS][4][5])
Definition: calib_get_cal.c:98
float32 slope[]
Definition: l2lists.h:30
int32 ninc
Definition: l1_czcs_hdf.c:28
double inst_tcorr[BANDS_DIMS_1A]
Definition: l1a_seawifs.c:55
int16_t tdi[BANDS_DIMS_1A]
Definition: l1a_seawifs.c:37
float32 cal_rads[NBANDS][4][5]
this program makes no use of any feature of the SDP Toolkit that could generate such a then geolocation is calculated at that and then aggregated up to Resolved feature request Bug by adding three new int8 SDSs for each high resolution pixel
Definition: HISTORY.txt:192
int16_t ref_day
Definition: l1a_seawifs.c:42
float fp_temps[256][BANDS_DIMS_1A]
Definition: l1a_seawifs.c:44
double inst_tref[BANDS_DIMS_1A]
Definition: l1a_seawifs.c:56
dtype
Definition: DDataset.hpp:31
int16_t * side
Definition: l1a_seawifs.c:88
int32_t calibrate_l1a(char *cal_path, int16_t syear, int16_t sday, int32_t smsec, int16_t eday, int32_t msec, char *dtype, int32_t nsta, int32_t ninc, int32_t nsamp, float *dark_mean, int16_t *gain, int16_t *tdi, int16_t *scan_temp, float *inst_temp, int16_t side, int16_t *l1a_data, float *l1b_data, cal_mod_struc *cal_mod)
int16_t ref_year
Definition: l1a_seawifs.c:41
float scan_mod[2][1285]
Definition: l1a_seawifs.c:45
@ NBANDS
Definition: make_L3_v1.1.c:53
#define BANDS
int count
Definition: decode_rs.h:79