ocssw  1.0
/disk01/web/ocssw/build/src/libosmi/calibrate_l1a_osmi.c (r8096/r4879)
Go to the documentation of this file.
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 }