USGS

Isis 3.0 Application Source Code Reference

Home

DarkCurrent.cpp

Go to the documentation of this file.
00001 /**
00002  * @file
00003  * $Revision: 1.3 $
00004  * $Date: 2009/05/27 21:26:15 $
00005  *
00006  *   Unless noted otherwise, the portions of Isis written by the USGS are public
00007  *   domain. See individual third-party library and package descriptions for
00008  *   intellectual property information,user agreements, and related information.
00009  *
00010  *   Although Isis has been used by the USGS, no warranty, expressed or implied,
00011  *   is made by the USGS as to the accuracy and functioning of such software
00012  *   and related material nor shall the fact of distribution constitute any such
00013  *   warranty, and no responsibility is assumed by the USGS in connection
00014  *   therewith.
00015  *
00016  *   For additional information, launch
00017  *   $ISISROOT/doc//documents/Disclaimers/Disclaimers.html in a browser or see
00018  *   the Privacy & Disclaimers page on the Isis website,
00019  *   http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on
00020  *   http://www.usgs.gov/privacy.html.
00021  */
00022 
00023 #include <cmath>  //use ceiling and floor functions
00024 #include <vector>
00025 #include "Application.h"
00026 #include "Brick.h"
00027 #include "CisscalFile.h"
00028 #include "CissLabels.h"
00029 #include "Cube.h"
00030 #include "DarkCurrent.h"
00031 #include "NumericalApproximation.h"
00032 #include "Message.h"
00033 #include "Preference.h"
00034 #include "Progress.h"
00035 #include "Pvl.h"
00036 #include "SpecialPixel.h"
00037 #include "iException.h"
00038 #include "iString.h"
00039 
00040 using namespace std;
00041 namespace Isis {
00042   /**
00043   * Constructs a DarkCurrent object.  Sets class variables.
00044   *
00045   * @param cissLab <B>CissLabels</B> object from Cassini ISS cube
00046   * @throws Isis::iException::Pvl If the input image has an
00047   *                   invalid InstrumentDataRate or SummingMode.
00048   * @internal
00049   *   @history 2008-11-05 Jeannie Walldren - Original Version
00050   *   @history 2009-05-27 Jeannie Walldren - Updated instrument data rate range
00051   *                          for telemetry rate of 32.
00052   */
00053   DarkCurrent::DarkCurrent(Isis::CissLabels &cissLab) {
00054     p_compType = cissLab.CompressionType();
00055     p_dataConvType = cissLab.DataConversionType();
00056     p_expDur = cissLab.ExposureDuration();
00057     p_flightSoftware = cissLab.FlightSoftwareVersion();
00058     p_gainMode = cissLab.GainModeId();
00059     p_narrow = cissLab.NarrowAngle();
00060     p_sum = cissLab.SummingMode();
00061 
00062     if(cissLab.ReadoutCycleIndex() == "Unknown") {
00063       p_readoutIndex = -999;
00064     }
00065     else {
00066       p_readoutIndex = cissLab.ReadoutCycleIndex().ToInteger();
00067     }
00068 
00069     if(p_compType == "NotCompressed") {
00070       p_compRatio = 1.0;
00071     }
00072     else {
00073       p_compRatio = cissLab.CompressionRatio().ToDouble();
00074     }
00075 
00076     if(cissLab.DelayedReadoutFlag() == "No") {
00077       p_btsm = 0;
00078     }
00079     else if(cissLab.DelayedReadoutFlag() == "Yes") {
00080       p_btsm = 1;
00081     }
00082     else {
00083       p_btsm = -1;
00084     }
00085 
00086     double instDataRate = cissLab.InstrumentDataRate();
00087     if(instDataRate >=  60.0 && instDataRate <=  61.0) p_telemetryRate = 8;
00088     else if(instDataRate >= 121.0 && instDataRate <= 122.0) p_telemetryRate = 16;
00089     else if(instDataRate >= 182.0 && instDataRate <= 183.0) p_telemetryRate = 24;
00090     else if(instDataRate >= 203.0 && instDataRate <= 204.0) p_telemetryRate = 32;
00091     else if(instDataRate >= 304.0 && instDataRate <= 305.0) p_telemetryRate = 40;
00092     else if(instDataRate >= 365.0 && instDataRate <= 366.0) p_telemetryRate = 48;
00093     else throw iException::Message(iException::Pvl,
00094                                      "Input file contains invalid InstrumentDataRate. See Software Interface Specification (SIS), Version 1.1, page 31.",
00095                                      _FILEINFO_);
00096 
00097     p_readoutOrder = cissLab.ReadoutOrder();
00098 
00099     switch(p_sum.ToInteger()) {
00100       case 1:
00101         p_lines   = 1024;
00102         break;
00103       case 2:
00104         p_lines   = 512;
00105         break;
00106       case 4:
00107         p_lines   = 256;
00108         break;
00109       default:
00110         throw iException::Message(iException::Pvl,
00111                                   "Input file contains invalid SummingMode. See Software Interface Specification (SIS), Version 1.1, page 31.",
00112                                   _FILEINFO_);
00113     }
00114     p_samples = p_lines;
00115     p_startTime.resize(p_samples);
00116     p_endTime.resize(p_samples);
00117     p_duration.resize(p_samples);
00118     for(int i = 0; i < p_samples; i++) {
00119       p_startTime[i].resize(p_lines);
00120       p_endTime[i].resize(p_lines);
00121       p_duration[i].resize(p_lines);
00122     }
00123   }//end constructor
00124 
00125 
00126   /**
00127   * @brief Compute dark current values to subtract from image
00128   *
00129   * This method computes the dark current DN values to be
00130   * subtracted from each pixel and returns those values in an
00131   * array of the equal dimension to the image.
00132   *
00133   * @returns <b>vector <vector <double> ></b> Final array of
00134   *         dark current DNs to be subtracted
00135   * @throws Isis::iException::Pvl If the input image has an
00136   *             unknown ReadoutCycleIndex or DelayedReadoutFlag.
00137   * @throws Isis::iException::Pvl If the input image has an
00138   *             invalid GainModeId.
00139   * @throws Isis::iException::Math If MakeDarkArray() returns a
00140   *             vector of zeros.
00141   * @see MakeDarkArray()
00142   *
00143   * @internal
00144   *   @history 2008-11-05 Jeannie Walldren - Original Version
00145   *   @history 2009-01-26 Jeannie Walldren - Changed declarations of 2
00146   *                          dimensional vectors
00147   */
00148   vector <vector <double> > DarkCurrent::ComputeDarkDN() { //get dark_DN
00149     if(p_readoutIndex == -999) {
00150       throw iException::Message(iException::Pvl,
00151                                 "Readout cycle index is unknown.",
00152                                 _FILEINFO_);
00153     }
00154     if(p_btsm == -1) {
00155       throw iException::Message(iException::Pvl,
00156                                 "Delayed readout flag is unknown.",
00157                                 _FILEINFO_);
00158     }
00159     vector <vector <double> > dark_e(p_samples), dark_DN(p_samples);
00160     for(unsigned int i = 0; i < dark_e.size(); i++) {
00161       dark_e[i].resize(p_lines);
00162       dark_DN[i].resize(p_lines);
00163     }
00164 
00165     // create new file
00166     dark_e = DarkCurrent::MakeDarkArray();
00167     int notzero = 0;
00168     for(unsigned int i = 0; i < dark_e.size(); i++) {
00169       for(unsigned int j = 0; j < dark_e[0].size(); j++) {
00170         if(dark_e[i][j] != 0.0) {
00171           notzero++;
00172         }
00173       }
00174     }
00175     if(notzero != 0) {
00176       // correct for gain:
00177       double gain2, gainRatio;
00178       if(p_narrow) {
00179         gain2 = 30.27;
00180         switch(p_gainMode) { // GainState()){
00181           case 215: //gs = 0:
00182             gainRatio = 0.135386;
00183             break;
00184           case 95: //1:
00185             gainRatio = 0.309569;
00186             break;
00187           case 29: //2:
00188             gainRatio = 1.0;
00189             break;
00190           case 12: //3:
00191             gainRatio = 2.357285;
00192             break;
00193           default:
00194             throw iException::Message(iException::Pvl,
00195                                       "Input file contains invalid GainModeId. See Software Interface Specification (SIS), Version 1.1, page 29.",
00196                                       _FILEINFO_);
00197         }
00198       }
00199       else {
00200         gain2 = 27.68;
00201         switch(p_gainMode) { // GainState()){
00202           case 215://0:
00203             gainRatio = 0.125446;
00204             break;
00205           case 95://1:
00206             gainRatio = 0.290637;
00207             break;
00208           case 29://2:
00209             gainRatio = 1.0;
00210             break;
00211           case 12://3:
00212             gainRatio = 2.360374;
00213             break;
00214           default:
00215             throw iException::Message(iException::Pvl,
00216                                       "Input file contains invalid GainModeId. See Software Interface Specification (SIS), Version 1.1, page 29.",
00217                                       _FILEINFO_);
00218         }
00219       }
00220       for(unsigned int i = 0; i < dark_e.size(); i++) {
00221         for(unsigned int j = 0; j < dark_e[0].size(); j++) {
00222           dark_DN[i][j] = (dark_e[i][j] / (gain2 / gainRatio));
00223         }
00224       }
00225       return dark_DN;
00226     }
00227     else {
00228       throw iException::Message(iException::Math,
00229                                 "Error in dark simulation; dark array conatains all zeros.",
00230                                 _FILEINFO_);
00231     }
00232   }//end ComputeDarkDN
00233 
00234 
00235   /**
00236   * @brief Compute time spent on CCD for given line
00237   *
00238   * Compute the line-time from light-flood erase to read out for a
00239   * given image line.  Returns the real seconds that the given
00240   * line spends on the CCD. The parameter <B>lline</B> must be
00241   * between 1 and 1024.
00242   *
00243   * @param lline Current line should range from 1 to 1024
00244   * @returns <b>double</b> Time in seconds spent on CCD for given
00245   *        line
00246   * @throws Isis::iException::Programmer If the input parameter is
00247   *             out of valid range.
00248   * @throws Isis::iException::Pvl If the input image contains an
00249   *             invalid number of lines.
00250   * @throws Isis::iException::Pvl If the input image has an
00251   *             invalid ReadoutCycleIndex.
00252   * @internal
00253   *   @history 2008-11-05 Jeannie Walldren - Original Version
00254   *   @history 2009-05-27 Jeannie Walldren - Updated with new idl cisscal
00255   *                          version, 3.6, linetime code.
00256   */
00257   double DarkCurrent::ComputeLineTime(int lline) { //returns the time for this line, takes the line number
00258     // this method mimics linetime.pro from idl's cisscal program
00259     double fsw;
00260     if(p_flightSoftware == "Unknown") {
00261       fsw = 0.0;
00262     }
00263     else fsw = p_flightSoftware.ToDouble();
00264 
00265     double linetime;
00266     double tlm = p_telemetryRate / 8;
00267     // updated idl code - change t0 initial value:
00268     double t0 = p_expDur / 1000 + 0.020;    //time from erase to first line
00269     t0 = t0 + 0.68 * (p_lines - lline) / ((double) p_lines);
00270     //time due to 680ms erase
00271     int line = lline - 1;       //lline is from 1 to 1024 => line is from 0 to 1023
00272     if(line < 0 || line > 1023) {
00273       iString msg = "DarkCurrent: For ComputeLineTime(lline), lline must be between 1 and 1024." + iString(lline) + " out of range";
00274       throw iException::Message(iException::Programmer, msg.c_str() , _FILEINFO_);
00275     }
00276 
00277     double r1 = 0;
00278     if(p_compType == "Lossy") {
00279       switch(p_lines) {
00280         case 256:
00281           r1 = 89.754;
00282           break;
00283         case 512:
00284           r1 = 110.131;
00285           break;
00286         case 1024:
00287           r1 = 201.734;
00288           break;
00289         default:
00290           throw iException::Message(iException::Pvl,
00291                                     "Input file contains invalid number of lines. See Software Interface Specification (SIS), Version 1.1, page 50.",
00292                                     _FILEINFO_);
00293       }
00294       double linetime = t0 + line / r1;
00295       return linetime;
00296     }
00297     double data;
00298     if(p_dataConvType == "12Bit") {
00299       data = 16.0;
00300     }
00301     else {
00302       data = 8.0;
00303     }
00304 
00305     double correction = 1.0;
00306     // Telemetry rate factors (0,8,16,24,32,40,48 pps)
00307     // The fastest science packet production rate is 48 packets per second.
00308     // When the camera is creating less packets per second, it can have more
00309     // time to service the CCD.  This can lead to a faster readout.  This
00310     // effect is mostly seen in full or non compressed modes.
00311 
00312     double r0;
00313     if(p_compType == "NotCompressed") {
00314       //  Non-compressed modes
00315       //  The following non-compressed rates were measured in ITL tests at 48
00316       //  packets per second.  Rates are specified in lines per second.  The
00317       //  values are for full, sum2 and sum4 modes.  Flight software timing
00318       //  is accurate to 5ms, so rates are specified to 2 decimal places.
00319 
00320       //  Ratio of rate for FSW 1.4 vs 1.3 (EGSE tests at 48 and 24pps)
00321 
00322       double rate_nc = 0;
00323       double telem_nc = 0;
00324       double telem_nc0 = 0;
00325       if(p_dataConvType == "12Bit") { // not converted
00326         switch(p_lines) {
00327           case 1024: {  // full, not converted
00328             rate_nc = 67.49;
00329             if(fsw >= 1.4) {
00330               correction = 1.0027;
00331             }
00332             telem_nc0 = 1.0161;
00333             switch(p_telemetryRate) {
00334               case 8: {
00335                 telem_nc = 1.0128;
00336                 break;
00337               }
00338               case 16: {
00339                 telem_nc = 1.0095;
00340                 break;
00341               }
00342               case 24: {
00343                 telem_nc = 1.0082;
00344                 break;
00345               }
00346               case 32: {
00347                 telem_nc = 1.0031;
00348                 break;
00349               }
00350               case 40: {
00351                 telem_nc = 1.0033;
00352                 break;
00353               }
00354               case 48: {
00355                 telem_nc = 1.0;
00356                 break;
00357               }
00358             }
00359             break;
00360           }
00361           case 512: {  // sum2, not converted
00362             rate_nc = 85.11;
00363             if(fsw >= 1.4) {
00364               correction = 1.0073;
00365             }
00366             telem_nc0 =  1.0297;
00367             switch(p_telemetryRate) {
00368               case 8: {
00369                 telem_nc = 1.0296;
00370                 break;
00371               }
00372               case 16: {
00373                 telem_nc = 1.0252;
00374                 break;
00375               }
00376               case 24: {
00377                 telem_nc = 1.0148;
00378                 break;
00379               }
00380               case 32: {
00381                 telem_nc = 1.0114;
00382                 break;
00383               }
00384               case 40: {
00385                 telem_nc = 1.0071;
00386                 break;
00387               }
00388               case 48: {
00389                 telem_nc = 1.0;
00390                 break;
00391               }
00392             }
00393             break;
00394           }
00395           case 256: {  // sum4, not converted
00396             rate_nc = 142.54;
00397             if(fsw >= 1.4) {
00398               correction = 1.0087;
00399             }
00400             telem_nc0 = 1.0356;
00401             switch(p_telemetryRate) {
00402               case 8: {
00403                 telem_nc = 1.0320;
00404                 break;
00405               }
00406               case 16: {
00407                 telem_nc = 1.0260;
00408                 break;
00409               }
00410               case 24: {
00411                 telem_nc = 1.0201;
00412                 break;
00413               }
00414               case 32: {
00415                 telem_nc = 1.0128;
00416                 break;
00417               }
00418               case 40: {
00419                 telem_nc = 1.0057;
00420                 break;
00421               }
00422               case 48: {
00423                 telem_nc = 1.0;
00424                 break;
00425               }
00426             }
00427             break;
00428           }
00429         }
00430       }
00431       else { // converted
00432         switch(p_lines) {
00433           case 1024: {  // full, converted
00434             rate_nc = 71.96;
00435             if(fsw >= 1.4) {
00436               correction = 1.0016;
00437             }
00438             telem_nc0 = 1.0194;
00439             switch(p_telemetryRate) {
00440               case 8: {
00441                 telem_nc = 1.0148;
00442                 break;
00443               }
00444               case 16: {
00445                 telem_nc = 1.0028;
00446                 break;
00447               }
00448               case 24: {
00449                 telem_nc = 1.0011;
00450                 break;
00451               }
00452               case 32: {
00453                 telem_nc = 1.0014;
00454                 break;
00455               }
00456               case 40: {
00457                 telem_nc = 1.0009;
00458                 break;
00459               }
00460               case 48: {
00461                 telem_nc = 1.0;
00462                 break;
00463               }
00464             }
00465             break;
00466           }
00467           case 512: {  // sum2, converted
00468             rate_nc = 88.99;
00469             if(fsw >= 1.4) {
00470               correction = 1.0042;
00471             }
00472             telem_nc0 = 1.0248;
00473             switch(p_telemetryRate) {
00474               case 8: {
00475                 telem_nc = 1.0219;
00476                 break;
00477               }
00478               case 16: {
00479                 telem_nc = 1.0173;
00480                 break;
00481               }
00482               case 24: {
00483                 telem_nc = 1.0151;
00484                 break;
00485               }
00486               case 32: {
00487                 telem_nc = 1.0097;
00488                 break;
00489               }
00490               case 40: {
00491                 telem_nc = 1.0057;
00492                 break;
00493               }
00494               case 48: {
00495                 telem_nc = 1.0;
00496                 break;
00497               }
00498             }
00499             break;
00500           }
00501           case 256: {  // sum4, converted
00502             rate_nc = 152.12;
00503             if(fsw >= 1.4) {
00504               correction = 0.9946;
00505             }
00506             telem_nc0 = 1.0010;
00507             switch(p_telemetryRate) {
00508               case 8: {
00509                 telem_nc = 1.0000;
00510                 break;
00511               }
00512               case 16: {
00513                 telem_nc = 0.9970;
00514                 break;
00515               }
00516               case 24: {
00517                 telem_nc = 0.9910;
00518                 break;
00519               }
00520               case 32: {
00521                 telem_nc = 0.9821;
00522                 break;
00523               }
00524               case 40: {
00525                 telem_nc = 0.9763;
00526                 break;
00527               }
00528               case 48: {
00529                 telem_nc = 1.0;
00530                 break;
00531               }
00532             }
00533             break;
00534           }
00535         }
00536       }
00537       r1 = rate_nc * telem_nc * correction;
00538       r0 = rate_nc * telem_nc0 * correction;
00539     }
00540     else { // Lossy has already returned linetime, so (p_compType == "Lossless")
00541       // Lossless linear model
00542       // The following are least square fits for Lossless modes at 48pps.  There is
00543       // a fit for each summation mode and converted and not converted (12bit).
00544 
00545       //   RMS of fit  0.255   0.076   0.496    not converted
00546       //   RMS of fit  0.172   0.162   0.429    converted
00547 
00548       //  Ratio of rate for FSW 1.4 vs 1.3 (EGSE tests at 48 and 24pps)
00549 
00550       double rate0 = 0;
00551       double slope = 0;
00552       double telem_L = 0;
00553       double telem_L0 = 0;
00554 
00555       if(p_dataConvType == "12Bit") { // not converted
00556         switch(p_lines) {
00557           case 1024: {  // full, not converted
00558             rate0 = 67.673;
00559             slope = 1.6972; // +/- 0.0102
00560 
00561             if(fsw >= 1.4) {
00562               correction = 0.9999;
00563             }
00564             telem_L0 = 1.0276;
00565             switch(p_telemetryRate) {
00566               case 8: {
00567                 telem_L = 1.0284;
00568                 break;
00569               }
00570               case 16: {
00571                 telem_L = 1.0182;
00572                 break;
00573               }
00574               case 24: {
00575                 telem_L = 1.0122;
00576                 break;
00577               }
00578               case 32: {
00579                 telem_L = 1.0048;
00580                 break;
00581               }
00582               case 40: {
00583                 telem_L = 1.0016;
00584                 break;
00585               }
00586               case 48: {
00587                 telem_L = 1.0;
00588                 break;
00589               }
00590             }
00591             break;
00592           }
00593           case 512: {  // sum2, not converted
00594             rate0 = 90.568;
00595             slope = 0.3671; // +/- 0.0255
00596             
00597             if(fsw >= 1.4) {
00598               correction = 1.0034;
00599             }
00600             telem_L0 = 1.0030;
00601             switch(p_telemetryRate) {
00602               case 8: {
00603                 telem_L = 0.9979;
00604                 break;
00605               }
00606               case 16: {
00607                 telem_L = 0.9933;
00608                 break;
00609               }
00610               case 24: {
00611                 telem_L = 0.9854;
00612                 break;
00613               }
00614               case 32: {
00615                 telem_L = 0.9884;
00616                 break;
00617               }
00618               case 40: {
00619                 telem_L = 1.0023;
00620                 break;
00621               }
00622               case 48: {
00623                 telem_L = 1.0;
00624                 break;
00625               }
00626             }
00627             break;
00628           }
00629           case 256: {  // sum4, not converted
00630             rate0 = 150.593;
00631             slope = 0.4541;  // +/-0.0450
00632 
00633             if(fsw >= 1.4) {
00634               correction = 1.0073;
00635             }
00636             telem_L0 = 1.0011;
00637             switch(p_telemetryRate) {
00638               case 8: {
00639                 telem_L = 0.9976;
00640                 break;
00641               }
00642               case 16: {
00643                 telem_L = 0.9894;
00644                 break;
00645               }
00646               case 24: {
00647                 telem_L = 0.9864;
00648                 break;
00649               }
00650               case 32: {
00651                 telem_L = 1.0000;
00652                 break;
00653               }
00654               case 40: {
00655                 telem_L = 1.0000;
00656                 break;
00657               }
00658               case 48: {
00659                 telem_L = 1.0;
00660                 break;
00661               }
00662             }
00663             break;
00664           }
00665         }
00666       }
00667       else { // converted
00668         switch(p_lines) {
00669           case 1024: {  // full, converted
00670             rate0 = 74.862;
00671             slope = 0.4918; // +/- 0.0069
00672             if(fsw >= 1.4) {
00673               correction = 1.0019;
00674             }
00675             telem_L0 = 1.0013;
00676             switch(p_telemetryRate) {
00677               case 8: {
00678                 telem_L = 1.0004;
00679                 break;
00680               }
00681               case 16: {
00682                 telem_L = 0.9935;
00683                 break;
00684               }
00685               case 24: {
00686                 telem_L = 0.9920;
00687                 break;
00688               }
00689               case 32: {
00690                 telem_L = 1.0002;
00691                 break;
00692               }
00693               case 40: {
00694                 telem_L = 0.9992;
00695                 break;
00696               }
00697               case 48: {
00698                 telem_L = 1.0;
00699                 break;
00700               }
00701             }
00702             break;
00703           }
00704           case 512: {  // sum2, converted
00705             rate0 = 91.429;
00706             slope = 0.4411; // +/- 0.0182
00707             if(fsw >= 1.4) {
00708               correction = 1.0050;
00709             }
00710             telem_L0 = 1.0013;
00711             switch(p_telemetryRate) {
00712               case 8: {
00713                 telem_L = 0.9950;
00714                 break;
00715               }
00716               case 16: {
00717                 telem_L = 1.0000;
00718                 break;
00719               }
00720               case 24: {
00721                 telem_L = 1.0000;
00722                 break;
00723               }
00724               case 32: {
00725                 telem_L = 1.0000;
00726                 break;
00727               }
00728               case 40: {
00729                 telem_L = 1.0001;
00730                 break;
00731               }
00732               case 48: {
00733                 telem_L = 1.0;
00734                 break;
00735               }
00736             }
00737             break;
00738           }
00739           case 256: {  // sum4, converted
00740             rate0 = 152.350;
00741             slope = 0.5417; // +/-  0.0697
00742             if(fsw >= 1.4) {
00743               correction = 1.0080;
00744             }
00745             telem_L0 = 0.9986;
00746             switch(p_telemetryRate) {
00747               case 8: {
00748                 telem_L = 0.9863;
00749                 break;
00750               }
00751               case 16: {
00752                 telem_L = 1.0017;
00753                 break;
00754               }
00755               case 24: {
00756                 telem_L = 1.0021;
00757                 break;
00758               }
00759               case 32: {
00760                 telem_L = 1.0010;
00761                 break;
00762               }
00763               case 40: {
00764                 telem_L = 1.0017;
00765                 break;
00766               }
00767               case 48: {
00768                 telem_L = 1.0;
00769                 break;
00770               }
00771             }
00772             break;
00773           }
00774         }
00775       }
00776       double ro_ratefit = rate0 + slope * p_compRatio;
00777       r1 = ro_ratefit * telem_L * correction;
00778       r0 = ro_ratefit * telem_L0 * correction;
00779     }
00780 
00781     // Calculation of BIU swap line which occurs upon completion of first packet
00782     // If one or more complete lines can fit into the first packet of 440 words,
00783     // they are moved from the Image Buffer allowing more to be read from the CCD
00784     // before the BIU pause.
00785     // Note: must also account for 4-word line header on each line
00786     double tratio = p_compRatio;
00787     if(p_compType == "Lossless" && tratio < 2.0) {
00788       tratio = 2.0;
00789     }
00790     int fpacket = 440 / (4 + ((int)(p_lines * data / 16 / tratio)));
00791     int biu_line = fpacket + 1;
00792 
00793     // if camera is opposite of read_out_order (second)
00794     // Calculate number of lines read in early pad of 0.262 seconds
00795     // BIU swap occurs after these number of lines or when
00796     // first science packet is complete (at biu_line) which
00797     // ever is greater
00798     bool second = false;
00799 
00800     if(p_narrow && p_readoutOrder == 1) {
00801       second = true;
00802     }
00803     else if(!p_narrow && p_readoutOrder == 0) {
00804       second = true;
00805     }
00806 
00807     // First line after biu wait is at 0.289 seconds
00808     double biutime = 0.289;
00809     int early_lines = 1;
00810     if(second && p_btsm == 0) {
00811       early_lines  = ((int)(0.262 * r0)) + 1;
00812       if(early_lines > biu_line) {
00813         biu_line = early_lines;
00814       }
00815       // If there is 0.262 pad before readout window (i.e. second image)
00816       // then biu swap occurs 2 rti later (0.25 sec)
00817       biutime = 0.539;
00818     }
00819 
00820     double rate;
00821     if(p_lines < 1024) {
00822       rate = r1;
00823       if(p_btsm == 1) {
00824         rate = r0;  // No science packet rate
00825       }
00826       if(p_btsm == 0 && line >= biu_line && fsw < 1.4) {
00827         linetime = t0 + biutime + (line - biu_line) / rate;
00828       }
00829       else {
00830         linetime = t0 + line / rate;
00831       }
00832       return linetime;
00833     }
00834     // Only FULL images can fill image buffer and cause r2 rate
00835     double r2 = 3.5989 * tlm; // ITL measured
00836     if(p_dataConvType != "12Bit") {
00837       r2 = 7.1989 * tlm; // ITL measured
00838     }
00839     // For Lossless, r2 depends on compression ratio: but not faster than r1.
00840 
00841     if(p_compType == "Lossless") {
00842       // r2 = cdsr * lines per packet
00843       // lines per packet = data words per packet / data words per line
00844       // data words per packet = (440 * 2% + 467 * 98%) - 4 (line header) = 462.46
00845       // data words per line = 4 (line header) + (1024 or 512)/tratio
00846       r2 = p_telemetryRate * 462.46 / (4.0 + 1024.0 * data / 16.0 / tratio);
00847     }
00848     if(r1 < r2) {
00849       r2 = r1;
00850     }
00851     // Due to bug, FSW < 1.4 did not use 4K words of image buffer
00852     int buffer;
00853     if(fsw < 1.4) {
00854       buffer = 336;
00855     }
00856     else {
00857       buffer = 340;
00858     }
00859     if(p_dataConvType != "12Bit") {
00860       buffer = 2 * buffer;
00861     }
00862     // Stores 2 compressed lines into one
00863     if(p_compType == "Lossless") {
00864       buffer = 2 * buffer;
00865     }
00866     // Due to bug, FSW < 1.4 declared image buffer full with one free line
00867     if(fsw < 1.4) {
00868       buffer = buffer - 1;
00869     }
00870     // Now treat more complicated 1x1 case.
00871     int line_break;
00872     if(p_btsm == 0) {
00873       int inbuffer;
00874       if(fsw >= 1.4) {
00875         // Calculate line break
00876         // Transmit starts at biutime after readout starts
00877         // after early_lines initially read before biutime
00878         // buffer has buffer-inbuffer left to fill
00879         early_lines = ((int)(biutime * r0)) + 1;
00880         if(early_lines > fpacket) {
00881           inbuffer = early_lines - fpacket;
00882         }
00883         else inbuffer = 0;
00884         if(r2 >= r1) {
00885           line_break = 1024;
00886         }
00887         else {
00888           line_break = early_lines + ((int)(r1 * (buffer - inbuffer) / (r1 - r2))) + 1;
00889         }
00890         linetime = t0 + line / r1;
00891         if(line > line_break) {
00892           linetime = t0 + line_break / r1 + (line - line_break) / r2;
00893         }
00894       }
00895       else {
00896         // Calculate line break
00897         // Transmit starts and readout resumes at biutime
00898         // after biu_lines initially read before biutime
00899         // fpacket lines in 1st packet, max(early_lines-fpacket,0) in buffer
00900         if(early_lines > fpacket) {
00901           inbuffer = early_lines - fpacket;
00902         }
00903         else {
00904           inbuffer = 0;
00905         }
00906 
00907         if(r2 >= r1) {
00908           line_break = 1024;
00909         }
00910         else {
00911           line_break = biu_line + ((int)(r1 * (buffer - inbuffer) / (r1 - r2))) + 1;
00912         }
00913         linetime = t0 + line / r1;
00914         if(line >= biu_line && line <= line_break) {
00915           linetime = t0 + biutime + (line - biu_line) / r1;
00916         }
00917         if(line > line_break) {
00918           linetime = t0 + biutime + (line_break - biu_line) / r1 + (line - line_break) / r2;
00919         }
00920       }
00921     }
00922     else { // p_btsm == 1
00923       // t1 is amount of time botsim image waits for first image readout window
00924       // t1 only depends on readout index and telem rate:
00925       // t1 is first camera readout window plus pad plus biu swap
00926       int readout;
00927       switch((int) p_readoutIndex / 4) {
00928         case 0:
00929           readout = 50;
00930           break;
00931         case 1:
00932           readout = 25;
00933           break;
00934         case 2:
00935           readout = 14;
00936           break;
00937         case 3:
00938           readout = 6;
00939           break;
00940         default:
00941           throw iException::Message(iException::Pvl,
00942                                     "Input file contains invalid ReadoutCycleIndex. See Software Interface Specification (SIS), Version 1.1, page 40.",
00943                                     _FILEINFO_);
00944       }
00945       double t1;
00946       if(readout * (6.0 / ((double)(tlm))) - ((int) readout * (6.0 / ((double)(tlm)))) < .5) {
00947         t1 = floor(readout * (6.0 / ((double)(tlm)))) + 0.539;
00948       }
00949       else {
00950         t1 = ceil(readout * (6.0 / ((double)(tlm)))) + 0.539;
00951       }
00952       linetime = t0 + line / r0;
00953       int line_break = buffer  + fpacket + 1; // Full buffer
00954       // NotCompressed 12Bit always stops and waits when buffer filled
00955       if(p_dataConvType == "12Bit" && p_compType == "NotCompressed") {
00956         if(line >= line_break) {
00957           linetime = t0 + t1 + (line - line_break) / r2;
00958         }
00959         return linetime;
00960       }
00961       // Line at which transmission starts
00962       // Reading stops during BIU swap (0.25 sec) for FSW < 1.4
00963       int trans_line;
00964       double biu_swap;
00965       if(fsw < 1.4) {
00966         trans_line = ((int)((t1 - 0.25) * r0)) + 1;
00967         biu_swap = 0.25;
00968       }
00969       else {
00970         trans_line = ((int)(t1 * r0)) + 1;
00971         biu_swap = 0.0;
00972       }
00973       // NOTCOMP TABLE/8LSB may start reading out before buffer is filled
00974       // LOSSLESS 12BIT may start reading out before buffer is filled
00975       // If buffer is filled first, rest is read out at r2
00976       // If t0+t1 occurs first then read continues at r1 until filled, then at r2
00977       if((p_dataConvType != "12Bit" && p_compType == "NotCompressed")
00978           || (p_dataConvType == "12Bit" && p_compType == "Lossless")) {
00979         if(trans_line >= line_break) {
00980           if(line >= line_break) {
00981             linetime = t0 + t1 + (line - line_break) / r2; // waits
00982           }
00983         }
00984         else {
00985           if(r2 >= r1) {
00986             line_break = 1024;
00987           }
00988           else {
00989             line_break = trans_line + ((int)((line_break - trans_line) * r1 / (r1 - r2))) + 1;
00990           }
00991           if(line > trans_line) {
00992             linetime = t0 + trans_line / r0 + (line - trans_line) / r1 + biu_swap;
00993           }
00994           if(line > line_break) {
00995             linetime = t0 + trans_line / r0 + (line_break - trans_line) / r1 + (line - line_break) / r2 + biu_swap;
00996           }
00997         }
00998         return linetime;
00999       }
01000       // LOSSLESS with 8LSB or TABLE fits in image memory
01001       if(p_dataConvType != "12Bit" && p_compType == "LOSSLESS" && line > trans_line) {
01002         linetime = t0 + trans_line / r0 + (line - trans_line) / r1 + biu_swap;
01003       }
01004     }
01005     return linetime;
01006   }// end ComputeLineTime
01007 
01008 
01009 
01010   /**
01011   * @brief Find dark current files for this image.
01012   *
01013   * Determines which dark parameters file and bias distortion
01014   * table, if any, should be used for this image and assigns these
01015   * filenames to p_dparamfile and p_bdpath, respectively. These
01016   * are dependent on the Instrument ID (ISSNA or ISSWA) and
01017   * Instrument Mode ID (Full, Sum2, or Sum4).
01018   *
01019   * @see DarkParameterFile()
01020   * @see BiasDistortionTable()
01021   *
01022   * @internal
01023   *   @history 2008-11-05 Jeannie Walldren - Original Version
01024   */
01025   void DarkCurrent::FindDarkFiles() {
01026     // Get the directory where the CISS darkcurrent directory is
01027     PvlGroup &dataDir = Preference::Preferences().FindGroup("DataDirectory");
01028     iString missionDir = (string) dataDir["Cassini"];
01029     iString darkDir(missionDir + "/calibration/darkcurrent/");
01030 
01031     iString instrumentId("");
01032 
01033     if(p_narrow) {
01034       instrumentId += "nac";
01035       p_bdpath = darkDir + "nac_bias_distortion.tab";
01036     }
01037     else {
01038       instrumentId += "wac";
01039     }
01040     iString instModeId("");
01041     if(p_sum.ToInteger() > 1) {
01042       instModeId = instModeId + "sum" + p_sum;
01043     }
01044     else {
01045       instModeId += "full";
01046     }
01047     p_dparamfile = darkDir + instrumentId + "_median_dark_parameters" + "?????" + "." + instModeId + ".cub";
01048     p_dparamfile.HighestVersion();
01049     return;
01050   }//end FindDarkFiles
01051 
01052 
01053   /**
01054   * Computes begin time, end time, and duration for each pixel of
01055   * the image.
01056   *
01057   * @see ComputeLineTime()
01058   *
01059   * @internal
01060   *   @history 2008-11-05 Jeannie Walldren - Original Version
01061   */
01062   void DarkCurrent::ComputeTimeArrays() {
01063     // this method mimics get_line_times method of cassimg_subtractdark.pro from idl's cisscal program
01064     int numberNegTime = 0;
01065     vector <double> timeToRead(p_lines);
01066     for(int i = 0; i < p_lines; i++) {
01067       timeToRead[i] = ComputeLineTime(i + 1);
01068       if(timeToRead[i] < 0) {
01069         numberNegTime++;
01070       }
01071     }
01072     if(numberNegTime > 0) return;
01073     for(int i = 0; i < p_lines; i++) {
01074       for(int j = 0; j <= i; j++) {
01075         p_endTime[i][j] = timeToRead[i-j];
01076       }
01077       for(int j = 0; j <= i; j++) {
01078         if(j < i) {
01079           p_startTime[i][j] = p_endTime[i][j+1];
01080         }
01081         else {
01082           p_startTime[i][j] = 0.0;
01083         }
01084         p_duration[i][j] = p_endTime[i][j] - p_startTime[i][j];
01085       }
01086     }
01087     for(int i = 0; i < p_lines; i++) {
01088       for(int j = 0; j < p_samples; j++) {
01089         if(p_duration[i][j] <= 0) {
01090           p_duration[i][j] = 0;
01091           //I belive this is equivalent to the IDL code :
01092           //     p_duration(*,*) = p_duration(*,*) > 0.0
01093         }
01094       }
01095     }
01096     for(int i = 0; i < p_lines; i++) {
01097       for(int j = 0; j < p_samples; j++) {
01098         p_endTime[i][j] = p_startTime[i][j] + p_duration[i][j];
01099       }
01100     }
01101     return;
01102   }//end ComputeTimeArrays
01103 
01104 
01105   /**
01106    * @brief Creates dark array
01107    * This method reads in the coefficients from the dark
01108    * parameters file, calls MakeManyLineDark() to create dark_e,
01109    * removes artifacts of this array be taking the median of every
01110    * 5 values, and corrects for the average bias distortion at the
01111    * beginning of each line.
01112    *
01113    * @returns <b>vector <vector <double> ></b> Secondary dark
01114    *         array removed of artifacts and corrected for average
01115    *         bias distortion.
01116    *  @throws Isis::iException::Io If the dark parameter file or
01117    *              bias distortion table is not found.
01118    *  @throws Isis::iException::Io If p_startTime equals p_endTime
01119    *              for all pixels.
01120    *  @see FindDarkFiles()
01121    *  @see ComputeTimeArrays()
01122    *  @see MakeManyLineDark()
01123    *
01124    *  @internal
01125    *   @history 2008-11-05 Jeannie Walldren - Original Version
01126    *   @history 2009-01-26 Jeannie Walldren - Changed declarations of 2
01127    *                          dimensional vectors
01128    */
01129   vector <vector <double> > DarkCurrent::MakeDarkArray() { //return dark_e
01130     // this method mimics makedarkarray method of cassimg_subtractdark.pro from idl's cisscal program
01131     FindDarkFiles();
01132     if(!p_dparamfile.Exists()) {
01133       throw iException::Message(iException::Io,
01134                                 "DarkParameterFile ***"
01135                                 + p_dparamfile.Expanded() + "*** not found.", _FILEINFO_);
01136     }
01137     if(p_narrow && (!p_bdpath.Exists())) {
01138       throw iException::Message(iException::Io,
01139                                 "BiasDistortionFile ***"
01140                                 + p_bdpath.Expanded() + "*** not found.", _FILEINFO_);
01141     }
01142     ComputeTimeArrays();//fill in values for p_startTime, p_endTime, p_duration
01143     int good = 0;
01144     for(int i = 0; i < p_lines; i++) {
01145       for(int j = 0; j < p_samples; j++) {
01146         if(p_startTime[i][j] != p_endTime[i][j]) {
01147           good++;
01148         }
01149       }
01150     }
01151     if(good != 0) {
01152       //read the coefficient cube into a Brick
01153       Brick *darkCoefficients;
01154       Cube dparamCube;
01155       dparamCube.open(p_dparamfile.Expanded());
01156       darkCoefficients = new Brick(p_samples, p_lines, 8, dparamCube.getPixelType());
01157       darkCoefficients->SetBasePosition(1, 1, 1);
01158       dparamCube.read(*darkCoefficients);
01159       dparamCube.close();
01160       // Assume WAC dark current is 0 for 0.005 ms. This is not the case for
01161       // the NAC where there are negative values near the left edge of the frame:
01162       if(!p_narrow) {
01163         for(int i = 0; i < p_lines; i++) {
01164           for(int j = 0; j < p_samples; j++) {
01165             (*darkCoefficients)[darkCoefficients->Index(i+1, j+1, 1)] = 0.0;
01166           }
01167         }
01168       }
01169       // add functionality for summed images:
01170       vector <vector <double> > dark_e(p_samples), di1(p_samples);
01171       for(unsigned int i = 0; i < dark_e.size(); i++) {
01172         dark_e[i].resize(p_lines);
01173         di1[i].resize(p_lines);
01174       }
01175 
01176       dark_e = MakeManyLineDark(*darkCoefficients);
01177 
01178       // Median-ed dark images have some spikes below the fitted curve.
01179       // These are probably artifacts and the next section removes them.
01180       vector <double> neighborhood(5);
01181 
01182       //replace each value of di1 with the median of neighborhood of 5 values
01183       for(int i = 0; i < p_lines; i++) {
01184         for(int j = 0; j < p_samples; j++) {
01185           if(j < 2 || j > (p_samples - 3)) {
01186             di1[i][j] = dark_e[i][j];
01187           }
01188           else {
01189             for(int n = -2; n < 3; n++) {
01190               neighborhood[n+2] = dark_e[i][j+n];
01191             }
01192             //sort these five values
01193             sort(neighborhood.begin(), neighborhood.end());
01194             for(int f = 0; f < 5; f++) {
01195             }
01196             //set equal to median
01197             di1[i][j] = neighborhood[2];
01198           }
01199         }
01200       }
01201       for(int i = 0; i < p_lines; i++) {
01202         for(int j = 0; j < p_samples; j++) {
01203           if(di1[i][j] - dark_e[i][j] > 10) {
01204             dark_e[i][j] = di1[i][j];
01205           }
01206         }
01207       }
01208       // correct for the average bias distortion at the beginning of each line:
01209       if(p_narrow) {
01210         CisscalFile *biasDist = new CisscalFile(p_bdpath.Expanded());
01211         vector<double> samp, bias_distortion;
01212         for(int i = 0; i < biasDist->LineCount(); i++) {
01213           iString line;
01214           biasDist->GetLine(line);  //assigns value to line
01215           line = line.ConvertWhiteSpace();
01216           line = line.Compress();
01217           line = line.TrimHead(" ");
01218           if(line == "") {
01219             break;
01220           }
01221           samp.push_back(line.Token(" ").ToDouble());
01222           bias_distortion.push_back(line.Trim(" ").ToDouble());
01223         }
01224         biasDist->Close();
01225         for(int i = 0; i < 21; i++) {
01226           for(int j = 0; j < p_lines; j++) {
01227             dark_e[i][j] = dark_e[i][j] - bias_distortion[i];
01228           }
01229         }
01230       }
01231       return dark_e;
01232     }
01233     throw iException::Message(iException::Io,
01234                               "StartTime == EndTime for all pixels.",
01235                               _FILEINFO_);
01236   }//end MakeDarkArray
01237 
01238   /**
01239   * @brief Creates preliminary dark array from dark parameters
01240   * file and line-time information
01241   *
01242   * Compute one line of a synthetic dark frame from timing tables
01243   * and dark current parameters for each pixel using a spline
01244   * interpretation method and evaluating at the start and end
01245   * times for that pixel.
01246   *
01247   * @param darkBrick Containing the coefficients found in the dark
01248   *                  parameters file for each pixel.
01249   *
01250   * @returns <b>vector <vector <double> ></b> Preliminary dark
01251   *         array using the darkBrick values
01252   *
01253   * @internal
01254   *   @history 2008-11-05 Jeannie Walldren - Original Version
01255   *   @history 2009-01-26 Jeannie Walldren - Changed declarations of 2
01256   *                          dimensional vectors
01257   */
01258   vector <vector <double> > DarkCurrent::MakeManyLineDark(Brick &darkBrick) { //returns dark_e
01259     // this method mimics make_manyline_dark method of cassimg_subtractdark.pro from idl's cisscal program
01260     int num_params = 8;
01261     vector <vector <double> > dark(p_samples), v1(num_params);
01262     vector <double> temp(p_samples), tgrid(num_params);
01263     vector <double> c(2), timespan(2);
01264 
01265     for(unsigned int i = 0; i < dark.size(); i++) {
01266       dark[i].resize(p_lines);
01267     }
01268     for(int i = 0; i < num_params; i++) {
01269       v1[i].resize(num_params);
01270       switch(i) {
01271         case 0:
01272           tgrid[i] = 0.0;
01273           break;
01274         case 1:
01275           tgrid[i] = 10.0;
01276           break;
01277         case 2:
01278           tgrid[i] = 32.0;
01279           break;
01280         case 3:
01281           tgrid[i] = 100.0;
01282           break;
01283         case 4:
01284           tgrid[i] = 220.0;
01285           break;
01286         case 5:
01287           tgrid[i] = 320.0;
01288           break;
01289         case 6:
01290           tgrid[i] = 460.0;
01291           break;
01292         case 7:
01293           tgrid[i] = 1200.0;
01294           break;
01295         default:
01296           tgrid[i] = Null;
01297       }
01298     }
01299     for(int j = 0; j < num_params; j++) {
01300       v1[j][j] = 1.0;
01301     }
01302     Progress progress;
01303     progress.SetText("Computing dark current array...");
01304     progress.SetMaximumSteps(p_lines);
01305     progress.CheckStatus();
01306     for(int jline = 0; jline < p_lines; jline++) {
01307       for(int i = 0; i < p_samples; i++) {
01308         temp[i] = darkBrick[darkBrick.Index(i+1, jline+1, 1)]; // constant term
01309       }
01310       // sum the contribution from every pixel downstream of jline, including jline
01311       for(int kline = 0; kline <= jline; kline++) {
01312         // derive coefficients so that parameters can be multiplied and added
01313         // rather than interpolated
01314         timespan[0] = p_startTime[jline][kline];
01315         timespan[1] = p_endTime[jline][kline];
01316         //  Interpolate by fitting a cubic spline to the
01317         //    4 point neighborhood (x[i-1], x[i], x[i+1], x[i+2]) surrounding
01318         //    the interval, x[i] <= u < x[i+1].
01319         NumericalApproximation spline(NumericalApproximation::CubicNeighborhood);
01320         for(int j = 0; j < num_params; j++) {
01321           spline.AddData(tgrid, v1[j]);
01322           //spline.Compute();
01323           c = spline.Evaluate(timespan);
01324           spline.Reset();
01325           c[0] =  c[1] - c[0];
01326           if(c[0] != 0.0) {
01327             for(int i = 0; i < p_samples; i++) {
01328               temp[i] = temp[i] + c[0] * darkBrick[darkBrick.Index(i+1, kline+1, j+1)];
01329             }
01330           }
01331         }
01332       }
01333       for(int i = 0; i < p_samples; i++) {
01334         dark[i][jline] = temp[i];
01335       }
01336 
01337       progress.CheckStatus();
01338     }
01339     return dark;
01340   }//end MakeManyLineDark
01341 }//end namespace Isis
01342