|
ocssw
1.0
|
00001 /*----------------------------------------------------------------------------- 00002 File : calibrate_l1a.c 00003 00004 Contents: 00005 calibrate_l1a - takes an array of level-1A raw counts and returns 00006 a corresponding arry of radiance values after 00007 applying the sensor calibration 00008 00009 Other relevant files: 00010 cal_l1a.h - various #defined constants, other include files 00011 (get_cal.h, getcal_proto.h, call1a_proto.h) and 00012 also includes hdf.h 00013 get_cal.c - a higher layer of calibration input functions 00014 get_cal_misc.c - a lower layer of calibration input functions 00015 tcal_l1a.c - a test routine to test calibrate_l1a 00016 00017 Notes: 00018 HDF library used - HDF3.3r3p1 00019 00020 Modification history: 00021 Programmer Organization Date Description of change 00022 -------------- ------------ -------- --------------------- 00023 Lakshmi Kumar Hughes STX 06/07/94 Original development 00024 Lakshmi Kumar Hughes STX 10/30/95 Filtering scan_mod corr. 00025 to data of dtype = SOL & 00026 TDI. 00027 Lakshmi Kumar Hughes STX 11/20/95 Filtering scan_mod corr. 00028 to data of dtype = IGC 00029 Lakshmi Kumar Hughes STX 01/25/96 Modified local variable 00030 "rads" to global var 00031 Gene Eplee GSC 05/24/96 Implemented quadratic 00032 temporal calibration 00033 correction (gain & offset) 00034 Lakshmi Kumar Hughes STX 10/17/96 Removed cal_year, cal_day 00035 output arguments. 00036 Ref. V5.0 I/O specs. 00037 Gene Eplee GSC 01/14/97 Reworked populating of 00038 g_f at the calibration 00039 knees. 00040 Gene Eplee GSC 04/25/97 Modified system gain and 00041 offset corrections to 00042 allow calling routine to 00043 override cal table values. 00044 Gene Eplee GSC 09/09/97 Modified dark restore 00045 subtraction to use 00046 mean values for GAC, LAC, 00047 and HRPT data. 00048 -----------------------------------------------------------------------------*/ 00049 00050 #include "cal_l1a_osmi.h" 00051 #include "call1a_proto_osmi.h" 00052 #include "InstStatData.h" 00053 00054 #define DEBUG 0 /* DEBUG= 0->no debug, 1->logic tracking, 2->data tracking */ 00055 00056 /* function prototype */ 00057 int getCalDay(int year, int jday, int *month, int *day); 00058 00059 00060 /*----------------------------------------------------------------------------- 00061 Function: calibrate_l1a 00062 00063 Returns: int32 (status) 00064 Returns a status code of 0 when successful. Otherwise returns 00065 -1 - to indicate calibration file open/close error 00066 -2 - to indicate read error 00067 -3 - to indicate time error (if the given time cannot be found) 00068 -4 - to indicate insufficient memory error 00069 00070 Description: 00071 The function calibrate_l1a takes an array of level-1A raw counts 00072 and returns a corresponding array of radiance values (level-1B data) 00073 after applying the sensor calibration. 00074 00075 Arguments: (in calling order) 00076 Type Name I/O Description 00077 ---- ---- --- ----------- 00078 char * cal_path I calibration file path 00079 int16 syear I year of data start time 00080 int16 sday I day-of-year for data start time 00081 int32 smsec I milliseconds of the day for data 00082 start tm as returned by get_l1a_open 00083 int16 eday I day-of-year for data end time 00084 int32 msec I millisecs of the day for data start 00085 time as returned by get_l1a_record 00086 char * dtype I data type ("SOL","TDI","IGC","LUN","") 00087 int32 st_samp I start pixel/sample number to process 00088 int32 nsamp I samples per scan line 00089 int16 * dark_rest I dark restore values for all 8 bands 00090 float32 * dark_mean I mean dark restore values for all 8 00091 bands 00092 int16 * gain I gains for all 8 bands; as returned 00093 by get_l1a_record 00094 int16 * tdi I input TDI for all 8 bands 00095 int16 * scan_temp I digitized scan temperatures 00096 int16 * side I mirror side of scan line 00097 int16 * l1a_data I Level-1A data; as returned by 00098 get_l1a_record 00099 float32 * l1b_data O Sensor calibrated radiance values 00100 corresponding to l1a_data 00101 struct cal_mod_struc I Structure for override control of 00102 cal_mod system gain and offset 00103 00104 Notes: 00105 00106 Modification history: 00107 Programmer Organization Date Description of change 00108 -------------- ------------ -------- --------------------- 00109 Lakshmi Kumar Hughes STX 06/07/94 Original development for SeaWiFS 00110 00111 -----------------------------------------------------------------------------*/ 00112 00113 int32 calibrate_l1a_osmi( char *cal_path, 00114 int16 syear, 00115 int16 sday, 00116 int32 smsec, 00117 int16 eday, 00118 int32 msec, 00119 char *dtype, /* "","SOL","TDI","IGC","LUN" */ 00120 int32 st_samp, /* 1 */ 00121 int32 nsamp, /* 1044 */ 00122 int32 fpixel, /* 0-95 */ 00123 int16 gain[4], /* quadrant gain settings from modified ISD */ 00124 int16 offset, /* quadrant offset settings from mod ISD */ 00125 int16 scan_temp, /* sensor temps from mod ISD */ 00126 int16 *l1a_data, 00127 float32 *l1b_data, 00128 cal_mod_struc *cal_mod) 00129 { 00130 00131 static int32 called_get_cal = 0; 00132 static int32 first_call = 1; 00133 static int16 pr_syear = 0; 00134 static int16 pr_sday = 0; 00135 static int32 pr_smsec = 0; 00136 static int16 pr_gain[NBANDS] = {-1,-1,-1,-1,-1,-1,-1,-1}; 00137 00138 /* */ 00139 /* Electronic gains computed from EIDP pp 480-487, BAF */ 00140 /* A,510,- B,510,+ C,865,- D,865,+ */ 00141 static float32 egain[NGAINS][NQUADS] = { 00142 {1.00000, 1.00000, 1.00000, 1.00000}, /* gain setting 0 */ 00143 {1.54269, 1.52875, 1.52107, 1.57918}, /* gain setting 1 */ 00144 {2.08538, 2.05750, 2.04215, 2.15835}, /* gain setting 2 */ 00145 {2.62807, 2.58624, 2.56322, 2.73753}, /* gain setting 3 */ 00146 {3.17076, 3.11499, 3.08430, 3.31671}, /* gain setting 4 */ 00147 {3.71346, 3.64374, 3.60537, 3.89588}, /* gain setting 5 */ 00148 {4.25615, 4.17248, 4.12645, 4.47506}, /* gain setting 6 */ 00149 {4.79884, 4.70123, 4.64752, 5.05424} /* gain setting 7 */ 00150 }; 00151 00152 00153 /* get_cal output parameters */ 00154 00155 static int16 cal_year, cal_day; /* calibrate effective yr,day,msec */ 00156 static int32 cal_msec; 00157 static float32 eoffset; /* electronic offset conv to counts */ 00158 static float32 egain_dummy[NGAINS]; /* electronic gain dummy argument */ 00159 static float32 mirror[NBANDS]; /* mirror corr factors */ 00160 static float32 t_const[NBANDS]; /* time dependent constant term */ 00161 static float32 t_linear[NBANDS]; /* time dependent linear term */ 00162 static float32 t_quadratic[NBANDS]; /* time dependent quadratic term */ 00163 static float32 tempcorr[NBANDS]; /* temp correction coefficients */ 00164 static float32 slopes[NBANDS*96]; /* sensor calibration slopes */ 00165 static float32 dcs[NBANDS*96]; /* sensor calibration offsets */ 00166 static float32 scan_mod[1044]; /* scan modulation corr (sweep dir) */ 00167 00168 /* Add static holders for instrument status data. These data would normally be 00169 passed into this routine (gain,offset,scan_temp). Because this data is only 00170 used here, we will add the routine to look this data up in the instrument 00171 status data file as required. 00172 */ 00173 static int isd_offset[4] = {0,0,0,0}; 00174 static int isd_gain = -1; 00175 static char isd_date[256] = ""; 00176 static int isd_scan_temp = 0; 00177 char scan_date[256]; 00178 int scan_month; 00179 int scan_day; 00180 int hr,min,sec; 00181 int of; 00182 struct inst_stat_data isd; 00183 int records; 00184 00185 /* Local working variables */ 00186 00187 int16 do_scan_mod_correction; /* local flag for calibration-mode */ 00188 int16 band, pixel; /* local band, pixel indices */ 00189 int16 field, quad, gs; /* local field, quad, gain indices */ 00190 int16 status; /* local return status */ 00191 int16 cal_jday, data_jday; /* local julian day counters */ 00192 00193 float32 l1_count; /* local dark-current corrected cnt */ 00194 float32 l1b_rad; /* local radiance output */ 00195 00196 float64 delta_msec, delta_t; /* local calibration model timescale */ 00197 float32 cal_gain, cal_offset; /* local system cal gain & offset */ 00198 float32 slope, dark; /* local combined slope & dc */ 00199 00200 00201 /* === Load calibration file if required === */ 00202 00203 if( first_call || 00204 syear != pr_syear || 00205 sday != pr_sday || 00206 smsec != pr_smsec ) { 00207 00208 first_call = 0; 00209 00210 pr_syear = syear; 00211 pr_sday = sday; 00212 pr_smsec = smsec; 00213 00214 if ((status = get_cal_osmi( cal_path, 00215 syear, sday, eday, msec, 00216 &cal_year, &cal_day, &cal_msec, 00217 &eoffset, 00218 &egain_dummy[0], 00219 &tempcorr[0], 00220 &mirror[0], 00221 &t_const[0], 00222 &t_linear[0], 00223 &t_quadratic[0], 00224 &slopes[0], 00225 &dcs[0], 00226 &scan_mod[0] )) < 0) { 00227 return status; 00228 } 00229 00230 called_get_cal = 1; 00231 00232 } 00233 00234 /* Format the scan date/time for isd look up YYYY/MM/DD HH:MM:SS*/ 00235 hr = (int)(msec/1000.0/3600.0); 00236 min = (int)(((msec/1000.0/3600.0) - hr) * 60.0); 00237 sec = (int)(((((msec/1000.0/3600.0) - hr) * 60.0) - min) * 60.0); 00238 getCalDay(syear,sday,&scan_month,&scan_day); 00239 sprintf(scan_date, "%d/%02d/%02d %02d:%02d:%02d",syear,scan_month,scan_day,hr,min,sec); 00240 00241 00242 /* If the scan date has changed, try and find an ISD record that matches. */ 00243 /* Dong-Han : Error of ISD file, Sep. 2. 2000 00244 if(strcmp(scan_date, isd_date)) { 00245 00246 if(FindISDRecordByGPSTime(scan_date, &isd, &records) != 0) { 00247 printf("Calibrate_l1a failed to find ISD record, using last known values\n"); 00248 printf("%s\n", scan_date); 00249 } 00250 else { 00251 * Get the offsets, gain, and temp from the ISD record. * 00252 isd_offset[0] = isd.isd_osmi.offset1; 00253 isd_offset[1] = isd.isd_osmi.offset2; 00254 isd_offset[2] = isd.isd_osmi.offset3; 00255 isd_offset[3] = isd.isd_osmi.offset4; 00256 isd_gain = isd.isd_osmi.gain; 00257 isd_scan_temp = isd.isd_osmi.temp; 00258 } 00259 strcpy(isd_date, scan_date); 00260 } 00261 */ 00262 strcpy(isd_date, scan_date); 00263 00264 00265 /* Determine the timescale (minutes) for the calibration system gain */ 00266 cal_jday = jul2jday(cal_year,cal_day); 00267 data_jday = jul2jday(syear,sday); 00268 delta_msec = (float64)(data_jday - cal_jday)*86400000L - cal_msec; 00269 delta_t = (delta_msec + (float64)msec)/60000.0; 00270 00271 00272 /* Determine if Scan Modulation corrections are required (not in cal modes) */ 00273 do_scan_mod_correction = (strcmp(dtype, "SOL") != 0) && 00274 (strcmp(dtype, "TDI") != 0) && 00275 (strcmp(dtype, "IGC") != 0); 00276 00277 00278 /* === Loop for each band of data === */ 00279 00280 if (st_samp < 1) st_samp = 1; 00281 00282 fpixel = 95 - fpixel; 00283 00284 for (band = 0; band < NBANDS; band++) { 00285 00286 /* Determine the CCD quadrant (quad) based on band & frame pixel */ 00287 field = fpixel/48; 00288 if (band < 5) 00289 quad = 1 - field; 00290 else 00291 quad = 3 - field; 00292 00293 /* Get gain setting (gs) from input gain argument */ 00294 /* 00295 gs = isd_gain; 00296 of = isd_offset[quad]; 00297 */ 00298 gs = 4; /* Standard operational gain setting is 4 */ 00299 of = 0; 00300 00301 /* Compute the longterm system calibration gain factor for band */ 00302 cal_gain = (float32)( t_const[band]+ 00303 t_linear[band]*(delta_t)+ 00304 t_quadratic[band]*(delta_t*delta_t) ); 00305 00306 /* Compute the calibration offset */ 00307 cal_offset = eoffset*of; 00308 00309 00310 /* Incorporate Longterm, Mirror Reflectance, Temperature Correction, 00311 Sensor Response, and Electronics Gain factors into single 00312 conversion slope and offset for current band and frame-pixel */ 00313 00314 slope = cal_gain* /* longterm or override */ 00315 mirror[band]* /* mirror reflectance */ 00316 (1.0-tempcorr[band]*scan_temp)* /* temperature correction */ 00317 slopes[band*96+fpixel]/ /* sensor responsivity */ 00318 egain[gs][quad]; /* electronics gains */ 00319 00320 dark = dcs[band*96+fpixel] + /* sensor offset */ 00321 cal_offset; /* electronics offset */ 00322 00323 /* 00324 fprintf(stderr, 00325 "pixel= %d band= %d slope= %f gain= %f dark= %f egain[%d][%d]= %f\n", 00326 fpixel,band,slopes[band*96+fpixel],slope,dark,quad,gs,egain[gs][quad]); 00327 */ 00328 00329 00330 /* === Loop for each input pixel -- convert to radiance === */ 00331 for (pixel = st_samp-1; pixel <= st_samp+nsamp-2; pixel++) 00332 { 00333 00334 /* Remove dark-current from input pixel count (trunc to 0..1023) */ 00335 l1_count = (float32)l1a_data[band*nsamp+pixel] - dark; 00336 00337 if (l1_count < 0L) l1_count = 0L; 00338 if (l1_count > 1023L) l1_count = 1023L; 00339 00340 /* Convert counts to radiance */ 00341 l1b_rad = l1_count*slope; 00342 00343 00344 /* Correct for scan modulation if not in a calibration mode */ 00345 /* 00346 if (do_scan_mod_correction) 00347 l1b_rad = l1b_rad*scan_mod[pixel]; 00348 */ 00349 00350 00351 /* Output final L1B radiance value */ 00352 l1b_data[band*nsamp+pixel] = l1b_rad; 00353 00354 } 00355 00356 } 00357 00358 return SUCCEED; 00359 00360 }
1.7.6.1