Deep Impact/EPOXI Spacecraft Clock: Data Processing Anomalies ============================================================== By B.Carcich, DI/EPOXI Science Data Center, 2011-04-25 Revisions: 2013-02-04, DI/EPOXI:McLaughlin, Fixed several minor typos; removed DIF-M-HRII-3/4-EPOXI-MARS-V1.0 because that dataset was reprocessed and archived after SCLK corrections were implemented in 2011. Table of Contents ================= Overview and scope Terminology and filenames Quick start Supplemental materials Tables Sample code Conversions to the SPICE virtual SCLK model S/C hardware clock timestamp, full resolution HRI, ITS or MRI timestamps from image file data from SDC or PDS S/C ApID 33 low-rate attitude quaternion timestamps Pseudo-code notes Background Spacecraft clock: flight hardware Spacecraft clock: NAIF/SPICE virtual SCLK model Spacecraft clock: timestamps in data files Spacecraft clock: ApID 33 timestamps Spacecraft clock: ApID 17 timestamps Spacecraft clock: time correlation packet timestamps Appendix 1: Conversion table Appendix 2: Python code to generate conversion table in Appendix 1 Appendix 3: FORTRAN code to generate conversion table in Appendix 1 Appendix 4: C code to generate conversion table in Appendix 1 Appendix 5: Terminology Summary Details: seconds Details: bits and bit positions Appendix 6: Abbreviations Appendix 7: Glossary Overview and scope ================== Timestamp data from the Deep Impact flyby (DIF) and impactor (DII) spacecraft clocks occur in several places in the telemetry for the Deep Impact (DI) and EPOXI (EPOCh + DIXI) mission. Examples are time correlation packets, imaging data headers, and attitude quaternions. The clock comprises a one-microsecond counter cascading into a one-second counter. Data from the microsecond counter have been interpreted both correctly and incorrectly by ground-based data processing pipelines. The maximum errors in interpretation are ~40ms and have been propagated into the PDS datasets listed below. For comparison, the uncertainty in the time correlation of the spacecraft clock with UTC has a minimum of ~10ms and the error has been as high as several seconds during the DI Impact and EPOXI missions. It is unlikely that the errors will impact analysis for any data beyond the closest approach images and spectra taken during DI flyby encounters at comets 9P/Tempel 1 and 103P/Hartley 2. Additionally there is an error in the earlier processing for High Resolution Instrument InfraRed (HRIIR) data taken in alternating modes (ALTFF, DIAG). The base timestamp was used as the end of the integration when it is actually for the beginning of the integration. The affected datasets are listed below. This document describes the spacecraft hardware clock, describes how to covert from various timestamps used during the mission to the SPICE S/C clock model, describes each timestamps along the source of any errors, and directs the reader to resources for correcting the error. All archived Deep Impact and EPOXI/EPOCh and early cruise calibration data acquired and archived before 01 September 2010 are affected: DI raw cruise calibrations: DIF-CAL-HRII-2-9P-CRUISE-V1.0 DIF-CAL-HRIV-2-9P-CRUISE-V1.0 DIF-CAL-MRI-2-9P-CRUISE-V1.0 DII-CAL-ITS-2-9P-CRUISE-V1.0 DIF-CAL-HRIV-2-NAV-9P-CRUISE-V1.0 DIF-CAL-MRI-2-NAV-9P-CRUISE-V1.1 DII-CAL-ITS-2-NAV-9P-CRUISE-V1.1 DI raw Tempel1 encounter data and calibrations: DIF-C-HRII-2-9P-ENCOUNTER-V1.0 DIF-C-HRIV-2-9P-ENCOUNTER-V1.0 DIF-C-MRI-2-9P-ENCOUNTER-V1.0 DII-C-ITS-2-9P-ENCOUNTER-V1.0 DIF-C-HRIV-2-NAV-9P-ENCOUNTER-V1.0 DIF-C-MRI-2-NAV-9P-ENCOUNTER-V1.1 DII-C-ITS-2-NAV-9P-ENCOUNTER-V1.1 DI calibrated and derived Tempel1 encounter data: DIF-C-HRII-3/4-9P-ENCOUNTER-V2.0 DIF-C-HRIV-3/4-9P-ENCOUNTER-V2.0 DIF-C-MRI-3/4-9P-ENCOUNTER-V2.0 DII-C-ITS-3/4-9P-ENCOUNTER-V2.0 DIF-C-HRIV-3-NAV-9P-ENCOUNTER-V1.0 DIF-C-MRI-3-NAV-9P-ENCOUNTER-V1.1 DII-C-ITS-3-NAV-9P-ENCOUNTER-V1.0 DIF-C-MRI-5-TEMPEL1-PHOTOMETRY-V1.0 EPOXI raw calibrations acquired *before* 01 September 2010 in these datasets: DIF-CAL-HRII-2-EPOXI-CALIBRATIONS-V2.0 DIF-CAL-HRIV-2-EPOXI-CALIBRATIONS-V2.0 DIF-CAL-MRI-2-EPOXI-CALIBRATIONS-V2.0 EPOXI/EPOCh raw exoplanet, Earth, and Mars data: DIF-X-HRIV-2-EPOXI-EXOPLANETS-V1.0 DIF-E-HRII-2-EPOXI-EARTH-V1.0 DIF-E-HRIV-2-EPOXI-EARTH-V1.0 DIF-E-MRI-2-EPOXI-EARTH-V1.0 DIF-M-HRII-2-EPOXI-MARS-V1.0 DIF-M-HRIV-2-EPOXI-MARS-V1.0 DIF-M-MRI-2-EPOXI-MARS-V1.0 EPOXI/EPOCh calibrated and derived exoplanet, Earth, and Mars data: DIF-X-HRIV-3-EPOXI-EXOPLANETS-V1.0 DIF-X-HRIV-5-EPOXI-EXOPLANETS-PHOT-V1.0 DIF-E-HRII-3/4-EPOXI-EARTH-V1.0 DIF-E-HRIV-3/4-EPOXI-EARTH-V1.0 DIF-E-MRI-3/4-EPOXI-EARTH-V1.0 DIF-M-HRIV-3/4-EPOXI-MARS-V1.0 DIF-M-MRI-3/4-EPOXI-MARS-V1.0 Terminology and filenames ========================= Refer to the appendices below for details of terminology (spacecraft seconds and bit position), abbreviations and glossary of words used in this document. Filenames of files referred to in this document are given in uppercase, but the filenames may be in lowercase on the media on which this data set is distributed. Quick start =========== This section contains a brief summary of the steps required to find and correct errors in the times stored by the Science Data Center (SDC) in DI imaging and spectral products. Although the reader should become familiar with the rest of the material in this document, especially the terminology, this section may be used as a quick start when assessing the error for an observation and making the correction. For DI prime mission imaging and spectral data within one hour either side of the flyby encounter with comet 9P/Tempel 1 on 04 July 2005, a companion table distributed with this document, SCLK_FIX_DI.TAB, contains corrected SCLK information. Refer to the PDS label file SCLK_FIX_DI.LBL for a description of the data in the table. ######################################################################## N.B. The correction only applies to the base SCLK timestamp for each observation; once the correction offset for the base timestamp has been determined, it can be applied as an offset to all other times. The only exception is HRIIR data taken in alternating modes (ALTFF and DIAG), where the base timestamp was assumed to indicate the end of the integration but it actually indicates the start. Refer to the HRIIR ALTFF section below for additional corrections. ######################################################################## For other DI data (other instrument observations and raw attitude data), the table in the appendices contains the correlation from the various resolutions of SCLK subtick representations (8-bit, 16-bit, and 20-bit) that are used in the raw data to the SPICE virtual SCLK. Refer to the comments in the appendix for a description of the data in the table and how to use them. Supplemental materials ====================== There are supplemental materials either in the appendices below or delivered with this file. Tables ------ - Conversion between SCLK bit subfields and SPICE virtual SCLK model - 32-bit tick and 16-bit subtick values from archived data (separate table delivered with this document) Sample code ----------- Several versions, in multiple programming languages, of the code used to generate the tables referred to above have been included. Conversions to the SPICE virtual SCLK model =========================================== This section describes, using pseudo-code, how to convert from the various SCLK timestamp forms used by the DI mission into the SPICE virtual SCLK model. Each SCLK form is described in detail in the Background section below. See Pseudo-code notes below for variables, syntax, &c. S/C hardware clock timestamp, full resolution --------------------------------------------- // Inputs: // TICKS: s, 32-bits, modulo 2^32 // sub: us, modulo 1,000,000, 0 to 999,999 // // Output: // sclk: SPICE SCLK string sub = round( 256.0 * (sub + 0.5) / 1000000.0) if ( sub > 255 ) { sub = 0 TICK = TICK + 1 } sclk = string(TICK) + ':' + string(sub) HRI, ITS or MRI timestamps from image file data from SDC or PDS --------------------------------------------------------------- // Inputs: // TICKS: s, 32-bits, modulo 2^32 // iHi: bits [19:12] from 20-bit SCLK subticks, 0 to 244 // iLo: bits [11:4] from 20-bit SCLK subticks, 0 to 255 // // Output: // sclk: SPICE SCLK string sub = (iHi * 256) + iLo sub = round( 256.0 * (sub + 0.5) / 62500.0) if ( sub > 255 ) { sub = 0 TICK = TICK + 1 } sclk = string(TICK) + ':' + string(sub) S/C ApID 33 low-rate attitude quaternion timestamps --------------------------------------------------- // Inputs: // TICKS: s, 32-bits, modulo 2^32 // sub: bits [19:12] from 20-bit SCLK subticks; 0 to 244 // // Output: // sclk: SPICE SCLK string sub = round( 256.0 * (sub + 0.5) / (62500.0/256.0) ) if ( sub > 255 ) { sub = 0 TICK = TICK + 1 } sclk = string(TICK) + ':' + string(sub) Pseudo-code notes ----------------- Variables --------- sub - input integer containing SCLK subtick (8, 16 or 20 bits) TICK - input integer containing SCLK ticks (seconds) sclk - output string containing SPICE SCLK ':' - constant string containing SPICE SCLK separator Functions --------- round() - rounds range [N.5 to {N+1}.5) to {N+1} string() - converts integer to string with no whitespace Misc ---- Refer to SPICE documentation (http://naif.jpl.nasa.gov/)for a description of SPICE SCLK strings, partitions, &c. For the purposes of this document, the SPICE SCLK for DI is a string of form TICK:sub where TICK and sub run from 0 to (2^32-1) and from 000 to 255, respectively e.g. 4294967295:255 (maximum value in any partition) 0000000000:000 (0:0 is valid and equivalent) This ignores ignores SCLK partition to keep things simple. Background ========== Spacecraft clock: flight hardware (20-bit, modulo 1,000,000) ------------------------------------------------------------- The DI spacecraft clock (SCLK) hardware comprises two cascading counters: a 20-bit sub-second (subtick) counter incrementing every microsecond (1us); a 32-bit one-second (tick) counter incrementing every 1,000,000 increments of the subtick counter i.e. when the subtick counter rolls over from 999,999 to zero, or every one second. ######################################################################## N.B. A 20-bit counter can in principle count from zero to 1,048,575, a few percent higher than the 999,999 at which the DI subtick counter rolls over. This difference is the genesis of the misinterpretation of the DI SCLK timestamps. ######################################################################## Spacecraft clock: NAIF/SPICE virtual SCLK model (8-bit, modulo 256) -------------------------------------------------------------------- The universal representation of time for DI science data is per the mission NAIF/SPICE SCLK-kernel [see SCLK and TIME required reading documentation at http://naif.jpl.nasa.gov/]. SCLK-Kernels, along with the NAIF/SPICE toolkit, provide convenient methods to convert between spacecraft time and other time standards (e.g. TDB or TDT or UTC), including allowing for the non-constant rate or even discontinuous operation of the actual spacecraft clock. This DI mission SCLK-Kernel models the spacecraft clock as two cascading counters: an 8-bit subtick counter (0 to 255); a 32-bit one-second tick counter incrementing every 256 increments of the subtick counter. The modeled 32-bit tick counter in the SCLK-kernel was intended to be identical to the actual SCLK 32-bit tick counter. ######################################################################## N.B. The 256 increments per second of of the 8-bit subtick counter in the SPICE model does not divide evenly into the 1,000,000 increments per second of the subtick counter in the actual spacecraft clock, or into any bit sub-field of the 20-bit counters described below. This means that in converting timestamps from actual to model, there is no way to simply copy any bit sub-field of actual SCLK timestamps as is typical for SCLK-Kernels on other missions. Because of this difference the SCLK-Kernel clock will be referred to as a virtual SCLK. N.B. Also, DI is an ongoing mission with a significant quantity of mission-critical flight- and ground-based software, much of which interacts with the SCLK-Kernel. So it is not an option to change the SCLK-Kernel to implement a different model. ######################################################################## Spacecraft clock: timestamps in data files (16-bit, modulo 62,500) ------------------------------------------------------------------- The base timestamp for each observation is stored in six consecutive bytes at byte offsets 94 through 99 of the 100-byte header; that header is written over the image data at the start of the raw S/C data file. The first four bytes (offsets 94 to 97) are identical to the hardware 32-bit tick counter value which increments every second; the last two bytes (offsets 98 and 99) are the high sixteen bits of the 20-bit hardware subtick counter. Because these two bytes from the 100-byte header are only the high sixteen bits of the 20-bit counter (i.e. bits [19:4] - see Terminology appendix), they compose a subtick pseudo-counter which increments every 16us and rolls over once per second after reaching a count of 62,499. The Science Data Center (SDC) pipeline interprets the 100-byte header from the raw S/C data file and stores the results in the FITS header of products created by the SDC. The pipeline further converts the six-byte timestamp into a SPICE virtual SCLK model which forms the base timestamp for further time processing, e.g. converting SPICE virtual SCLK to UTC, calculating start-, mid- and end-observation times at known offsets from the base timestamp. One misinterpretation came from the SDC code assuming the S/C subtick counter rolled over at the full range accessible to its 20-bits i.e. after 1,048,575 instead of 999,999, and that the high 16-bit subtick pseudo-counter in these data files rolled over after 65,535 instead of 62,499. Spacecraft clock: ApID 33 timestamps (8-bit, modulo 244.14) ------------------------------------------------------------ Another type of telemetry, called ApID 33 packets, contained S/C attitude as raw quaternions. These data are known as low-rate attitude. They are processed by NAIF to produce C-Kernels (S/C attitude data in SPICE format). The raw quaternions do not have a timestamp in the packet data so the packet timestamp is used. The packet timestamp uses the same 32-bit counter for seconds, but for subticks uses the high eight bits of the 20-bit hardware subtick counter (bits [19:12]). This subtick counter rolls over after 244, but the rollover occurs earlier than the full one full subtick that one would normally expect; it happens at subtick 62,499/256 = 244 35/256 = ~244.14 As in the case with the SDC and the 16-bit modulo 62,500 counter, the misinterpretation NAIF made was to take the eight bits from the subtick counter and copy them to the subtick value of the SPICE virtual SCLK without scaling between the clocks' moduli (~244.14 vs. 256). At the end of the EPOXI mission in the spring of 2011, NAIF plans to re-process all of the attitude data and archive PDS data sets with corrected C-Kernels. ######################################################################## N.B. That ends the list of SCLKs that need to corrected because of past misinterpretations. The following SCLK descriptions have been added for completeness. ######################################################################## Spacecraft clock: ApID 17 timestamps (20-bit, modulo 1,000,000) ---------------------------------------------------------------- Hi-rate attitude telemetry, called ApID 17 packets, contains S/C attitude as quaternions, similar to the ApID 33 packets, but at a higher sampling frequency. In this case, however, the timestamp is provided as part of the packet data in seconds using a floating point representation which preserved the full modulo 1,000,000 subticks of the S/C hardware SCLK. NAIF scales these timestamps to the modulo 256 virtual SCLK model and no corrections need to be made. Spacecraft clock: time correlation packet timestamps (8-bit, modulo ?) ----------------------------------------------------------------------- Time correlation packets are used to track the S/C hardware SCLK drift over time. The details are beyond the scope of this document, but this is another packet with a SCLK timestamp. The same 32-bit tick counter is used as with the other timestamps, but in this case a typo in the flight software resulted in bits [16:9] being used as the subtick counter. Early in the mission this caused SCLK time correlation uncertainties to be about one-second, but subsequent analysis of the subtick bits have driven those uncertainties down by two orders of magnitude. Appendix 1: Conversion table ============================= This table summarizes all possible conversions from the hardware SCLK to the SPICE model subtick. This table is generated by the source code of any of the following appendices. The columns are separated by whitespace. The first column is the SPICE SCLK model subtick to which an actual value from the SCLK is converted. Each succeeding pair of columns is the range of hardware SCLK bit subfields that convert to the SPICE SCLK model subtick in the first column. Column 1: the SPICE SCLK model subtick (0 to 256) Columns 2 & 3: the 20-bit low and high values (0 to 999,999) Columns 4 & 5: the high 8-bit low and high values (0 to 244) Columns 6 & 7: the high 16-bit low and high values (0 to 62,499) Columns 8 & 9: the high 16-bit low and high values, as 8-bit pairs (000:000 to 244:035) ======================================================================== N.B. In the 8-bit columns (4 & 5), some rows have pairs of -1s. This means that the SPICE SCLK model subtick in column 1 on that row cannot be the result of a conversion from any of the high 8-bits of the possible actual SCLK subtick values. ======================================================================== ======================================================================== N.B. If the conversion returns 256 as the SPICE SCLK model subtick, then the 32-bit tick counter should be incremented by one and a subtick of zero should be used. See the pseudo-code examples above. ======================================================================== SPICE <====20-bit===> < 8-bit> <==16-bit==> <===8+8-bit====> subtk Low High Low High Low High Low High ===== ====== ====== === === ===== ===== ======= ======= 0 0 1952 -1 -1 0 121 000:000 000:121 1 1953 5858 0 0 122 365 000:122 001:109 2 5859 9765 1 1 366 609 001:110 002:097 3 9766 13671 2 2 610 853 002:098 003:085 4 13672 17577 3 3 854 1098 003:086 004:074 5 17578 21483 4 4 1099 1342 004:075 005:062 6 21484 25390 5 5 1343 1586 005:063 006:050 7 25391 29296 6 6 1587 1830 006:051 007:038 8 29297 33202 7 7 1831 2074 007:039 008:026 9 33203 37108 8 8 2075 2318 008:027 009:014 10 37109 41015 9 9 2319 2562 009:015 010:002 11 41016 44921 10 10 2563 2807 010:003 010:247 12 44922 48827 11 11 2808 3051 010:248 011:235 13 48828 52733 12 12 3052 3295 011:236 012:223 14 52734 56640 13 13 3296 3539 012:224 013:211 15 56641 60546 14 14 3540 3783 013:212 014:199 16 60547 64452 15 15 3784 4027 014:200 015:187 17 64453 68358 16 16 4028 4271 015:188 016:175 18 68359 72265 17 17 4272 4516 016:176 017:164 19 72266 76171 18 18 4517 4760 017:165 018:152 20 76172 80077 19 19 4761 5004 018:153 019:140 21 80078 83983 20 20 5005 5248 019:141 020:128 22 83984 87890 -1 -1 5249 5492 020:129 021:116 23 87891 91796 21 21 5493 5736 021:117 022:104 24 91797 95702 22 22 5737 5980 022:105 023:092 25 95703 99608 23 23 5981 6225 023:093 024:081 26 99609 103515 24 24 6226 6469 024:082 025:069 27 103516 107421 25 25 6470 6713 025:070 026:057 28 107422 111327 26 26 6714 6957 026:058 027:045 29 111328 115233 27 27 6958 7201 027:046 028:033 30 115234 119140 28 28 7202 7445 028:034 029:021 31 119141 123046 29 29 7446 7689 029:022 030:009 32 123047 126952 30 30 7690 7934 030:010 030:254 33 126953 130858 31 31 7935 8178 030:255 031:242 34 130859 134765 32 32 8179 8422 031:243 032:230 35 134766 138671 33 33 8423 8666 032:231 033:218 36 138672 142577 34 34 8667 8910 033:219 034:206 37 142578 146483 35 35 8911 9154 034:207 035:194 38 146484 150390 36 36 9155 9398 035:195 036:182 39 150391 154296 37 37 9399 9643 036:183 037:171 40 154297 158202 38 38 9644 9887 037:172 038:159 41 158203 162108 39 39 9888 10131 038:160 039:147 42 162109 166015 40 40 10132 10375 039:148 040:135 43 166016 169921 -1 -1 10376 10619 040:136 041:123 44 169922 173827 41 41 10620 10863 041:124 042:111 45 173828 177733 42 42 10864 11107 042:112 043:099 46 177734 181640 43 43 11108 11352 043:100 044:088 47 181641 185546 44 44 11353 11596 044:089 045:076 48 185547 189452 45 45 11597 11840 045:077 046:064 49 189453 193358 46 46 11841 12084 046:065 047:052 50 193359 197265 47 47 12085 12328 047:053 048:040 51 197266 201171 48 48 12329 12572 048:041 049:028 52 201172 205077 49 49 12573 12816 049:029 050:016 53 205078 208983 50 50 12817 13061 050:017 051:005 54 208984 212890 51 51 13062 13305 051:006 051:249 55 212891 216796 52 52 13306 13549 051:250 052:237 56 216797 220702 53 53 13550 13793 052:238 053:225 57 220703 224608 54 54 13794 14037 053:226 054:213 58 224609 228515 55 55 14038 14281 054:214 055:201 59 228516 232421 56 56 14282 14525 055:202 056:189 60 232422 236327 57 57 14526 14770 056:190 057:178 61 236328 240233 58 58 14771 15014 057:179 058:166 62 240234 244140 59 59 15015 15258 058:167 059:154 63 244141 248046 60 60 15259 15502 059:155 060:142 64 248047 251952 61 61 15503 15746 060:143 061:130 65 251953 255858 -1 -1 15747 15990 061:131 062:118 66 255859 259765 62 62 15991 16234 062:119 063:106 67 259766 263671 63 63 16235 16478 063:107 064:094 68 263672 267577 64 64 16479 16723 064:095 065:083 69 267578 271483 65 65 16724 16967 065:084 066:071 70 271484 275390 66 66 16968 17211 066:072 067:059 71 275391 279296 67 67 17212 17455 067:060 068:047 72 279297 283202 68 68 17456 17699 068:048 069:035 73 283203 287108 69 69 17700 17943 069:036 070:023 74 287109 291015 70 70 17944 18187 070:024 071:011 75 291016 294921 71 71 18188 18432 071:012 072:000 76 294922 298827 72 72 18433 18676 072:001 072:244 77 298828 302733 73 73 18677 18920 072:245 073:232 78 302734 306640 74 74 18921 19164 073:233 074:220 79 306641 310546 75 75 19165 19408 074:221 075:208 80 310547 314452 76 76 19409 19652 075:209 076:196 81 314453 318358 77 77 19653 19896 076:197 077:184 82 318359 322265 78 78 19897 20141 077:185 078:173 83 322266 326171 79 79 20142 20385 078:174 079:161 84 326172 330077 80 80 20386 20629 079:162 080:149 85 330078 333983 81 81 20630 20873 080:150 081:137 86 333984 337890 -1 -1 20874 21117 081:138 082:125 87 337891 341796 82 82 21118 21361 082:126 083:113 88 341797 345702 83 83 21362 21605 083:114 084:101 89 345703 349608 84 84 21606 21850 084:102 085:090 90 349609 353515 85 85 21851 22094 085:091 086:078 91 353516 357421 86 86 22095 22338 086:079 087:066 92 357422 361327 87 87 22339 22582 087:067 088:054 93 361328 365233 88 88 22583 22826 088:055 089:042 94 365234 369140 89 89 22827 23070 089:043 090:030 95 369141 373046 90 90 23071 23314 090:031 091:018 96 373047 376952 91 91 23315 23559 091:019 092:007 97 376953 380858 92 92 23560 23803 092:008 092:251 98 380859 384765 93 93 23804 24047 092:252 093:239 99 384766 388671 94 94 24048 24291 093:240 094:227 100 388672 392577 95 95 24292 24535 094:228 095:215 101 392578 396483 96 96 24536 24779 095:216 096:203 102 396484 400390 97 97 24780 25023 096:204 097:191 103 400391 404296 98 98 25024 25268 097:192 098:180 104 404297 408202 99 99 25269 25512 098:181 099:168 105 408203 412108 100 100 25513 25756 099:169 100:156 106 412109 416015 101 101 25757 26000 100:157 101:144 107 416016 419921 102 102 26001 26244 101:145 102:132 108 419922 423827 -1 -1 26245 26488 102:133 103:120 109 423828 427733 103 103 26489 26732 103:121 104:108 110 427734 431640 104 104 26733 26977 104:109 105:097 111 431641 435546 105 105 26978 27221 105:098 106:085 112 435547 439452 106 106 27222 27465 106:086 107:073 113 439453 443358 107 107 27466 27709 107:074 108:061 114 443359 447265 108 108 27710 27953 108:062 109:049 115 447266 451171 109 109 27954 28197 109:050 110:037 116 451172 455077 110 110 28198 28441 110:038 111:025 117 455078 458983 111 111 28442 28686 111:026 112:014 118 458984 462890 112 112 28687 28930 112:015 113:002 119 462891 466796 113 113 28931 29174 113:003 113:246 120 466797 470702 114 114 29175 29418 113:247 114:234 121 470703 474608 115 115 29419 29662 114:235 115:222 122 474609 478515 116 116 29663 29906 115:223 116:210 123 478516 482421 117 117 29907 30150 116:211 117:198 124 482422 486327 118 118 30151 30395 117:199 118:187 125 486328 490233 119 119 30396 30639 118:188 119:175 126 490234 494140 120 120 30640 30883 119:176 120:163 127 494141 498046 121 121 30884 31127 120:164 121:151 128 498047 501952 122 122 31128 31371 121:152 122:139 129 501953 505858 123 123 31372 31615 122:140 123:127 130 505859 509765 -1 -1 31616 31859 123:128 124:115 131 509766 513671 124 124 31860 32103 124:116 125:103 132 513672 517577 125 125 32104 32348 125:104 126:092 133 517578 521483 126 126 32349 32592 126:093 127:080 134 521484 525390 127 127 32593 32836 127:081 128:068 135 525391 529296 128 128 32837 33080 128:069 129:056 136 529297 533202 129 129 33081 33324 129:057 130:044 137 533203 537108 130 130 33325 33568 130:045 131:032 138 537109 541015 131 131 33569 33812 131:033 132:020 139 541016 544921 132 132 33813 34057 132:021 133:009 140 544922 548827 133 133 34058 34301 133:010 133:253 141 548828 552733 134 134 34302 34545 133:254 134:241 142 552734 556640 135 135 34546 34789 134:242 135:229 143 556641 560546 136 136 34790 35033 135:230 136:217 144 560547 564452 137 137 35034 35277 136:218 137:205 145 564453 568358 138 138 35278 35521 137:206 138:193 146 568359 572265 139 139 35522 35766 138:194 139:182 147 572266 576171 140 140 35767 36010 139:183 140:170 148 576172 580077 141 141 36011 36254 140:171 141:158 149 580078 583983 142 142 36255 36498 141:159 142:146 150 583984 587890 143 143 36499 36742 142:147 143:134 151 587891 591796 -1 -1 36743 36986 143:135 144:122 152 591797 595702 144 144 36987 37230 144:123 145:110 153 595703 599608 145 145 37231 37475 145:111 146:099 154 599609 603515 146 146 37476 37719 146:100 147:087 155 603516 607421 147 147 37720 37963 147:088 148:075 156 607422 611327 148 148 37964 38207 148:076 149:063 157 611328 615233 149 149 38208 38451 149:064 150:051 158 615234 619140 150 150 38452 38695 150:052 151:039 159 619141 623046 151 151 38696 38939 151:040 152:027 160 623047 626952 152 152 38940 39184 152:028 153:016 161 626953 630858 153 153 39185 39428 153:017 154:004 162 630859 634765 154 154 39429 39672 154:005 154:248 163 634766 638671 155 155 39673 39916 154:249 155:236 164 638672 642577 156 156 39917 40160 155:237 156:224 165 642578 646483 157 157 40161 40404 156:225 157:212 166 646484 650390 158 158 40405 40648 157:213 158:200 167 650391 654296 159 159 40649 40893 158:201 159:189 168 654297 658202 160 160 40894 41137 159:190 160:177 169 658203 662108 161 161 41138 41381 160:178 161:165 170 662109 666015 162 162 41382 41625 161:166 162:153 171 666016 669921 163 163 41626 41869 162:154 163:141 172 669922 673827 164 164 41870 42113 163:142 164:129 173 673828 677733 -1 -1 42114 42357 164:130 165:117 174 677734 681640 165 165 42358 42602 165:118 166:106 175 681641 685546 166 166 42603 42846 166:107 167:094 176 685547 689452 167 167 42847 43090 167:095 168:082 177 689453 693358 168 168 43091 43334 168:083 169:070 178 693359 697265 169 169 43335 43578 169:071 170:058 179 697266 701171 170 170 43579 43822 170:059 171:046 180 701172 705077 171 171 43823 44066 171:047 172:034 181 705078 708983 172 172 44067 44311 172:035 173:023 182 708984 712890 173 173 44312 44555 173:024 174:011 183 712891 716796 174 174 44556 44799 174:012 174:255 184 716797 720702 175 175 44800 45043 175:000 175:243 185 720703 724608 176 176 45044 45287 175:244 176:231 186 724609 728515 177 177 45288 45531 176:232 177:219 187 728516 732421 178 178 45532 45775 177:220 178:207 188 732422 736327 179 179 45776 46020 178:208 179:196 189 736328 740233 180 180 46021 46264 179:197 180:184 190 740234 744140 181 181 46265 46508 180:185 181:172 191 744141 748046 182 182 46509 46752 181:173 182:160 192 748047 751952 183 183 46753 46996 182:161 183:148 193 751953 755858 184 184 46997 47240 183:149 184:136 194 755859 759765 -1 -1 47241 47484 184:137 185:124 195 759766 763671 185 185 47485 47728 185:125 186:112 196 763672 767577 186 186 47729 47973 186:113 187:101 197 767578 771483 187 187 47974 48217 187:102 188:089 198 771484 775390 188 188 48218 48461 188:090 189:077 199 775391 779296 189 189 48462 48705 189:078 190:065 200 779297 783202 190 190 48706 48949 190:066 191:053 201 783203 787108 191 191 48950 49193 191:054 192:041 202 787109 791015 192 192 49194 49437 192:042 193:029 203 791016 794921 193 193 49438 49682 193:030 194:018 204 794922 798827 194 194 49683 49926 194:019 195:006 205 798828 802733 195 195 49927 50170 195:007 195:250 206 802734 806640 196 196 50171 50414 195:251 196:238 207 806641 810546 197 197 50415 50658 196:239 197:226 208 810547 814452 198 198 50659 50902 197:227 198:214 209 814453 818358 199 199 50903 51146 198:215 199:202 210 818359 822265 200 200 51147 51391 199:203 200:191 211 822266 826171 201 201 51392 51635 200:192 201:179 212 826172 830077 202 202 51636 51879 201:180 202:167 213 830078 833983 203 203 51880 52123 202:168 203:155 214 833984 837890 204 204 52124 52367 203:156 204:143 215 837891 841796 205 205 52368 52611 204:144 205:131 216 841797 845702 -1 -1 52612 52855 205:132 206:119 217 845703 849608 206 206 52856 53100 206:120 207:108 218 849609 853515 207 207 53101 53344 207:109 208:096 219 853516 857421 208 208 53345 53588 208:097 209:084 220 857422 861327 209 209 53589 53832 209:085 210:072 221 861328 865233 210 210 53833 54076 210:073 211:060 222 865234 869140 211 211 54077 54320 211:061 212:048 223 869141 873046 212 212 54321 54564 212:049 213:036 224 873047 876952 213 213 54565 54809 213:037 214:025 225 876953 880858 214 214 54810 55053 214:026 215:013 226 880859 884765 215 215 55054 55297 215:014 216:001 227 884766 888671 216 216 55298 55541 216:002 216:245 228 888672 892577 217 217 55542 55785 216:246 217:233 229 892578 896483 218 218 55786 56029 217:234 218:221 230 896484 900390 219 219 56030 56273 218:222 219:209 231 900391 904296 220 220 56274 56518 219:210 220:198 232 904297 908202 221 221 56519 56762 220:199 221:186 233 908203 912108 222 222 56763 57006 221:187 222:174 234 912109 916015 223 223 57007 57250 222:175 223:162 235 916016 919921 224 224 57251 57494 223:163 224:150 236 919922 923827 225 225 57495 57738 224:151 225:138 237 923828 927733 -1 -1 57739 57982 225:139 226:126 238 927734 931640 226 226 57983 58227 226:127 227:115 239 931641 935546 227 227 58228 58471 227:116 228:103 240 935547 939452 228 228 58472 58715 228:104 229:091 241 939453 943358 229 229 58716 58959 229:092 230:079 242 943359 947265 230 230 58960 59203 230:080 231:067 243 947266 951171 231 231 59204 59447 231:068 232:055 244 951172 955077 232 232 59448 59691 232:056 233:043 245 955078 958983 233 233 59692 59936 233:044 234:032 246 958984 962890 234 234 59937 60180 234:033 235:020 247 962891 966796 235 235 60181 60424 235:021 236:008 248 966797 970702 236 236 60425 60668 236:009 236:252 249 970703 974608 237 237 60669 60912 236:253 237:240 250 974609 978515 238 238 60913 61156 237:241 238:228 251 978516 982421 239 239 61157 61400 238:229 239:216 252 982422 986327 240 240 61401 61645 239:217 240:205 253 986328 990233 241 241 61646 61889 240:206 241:193 254 990234 994140 242 242 61890 62133 241:194 242:181 255 994141 998046 243 243 62134 62377 242:182 243:169 256 998047 999999 244 244 62378 62499 243:170 244:035 Appendix 2: Python code to generate conversion table in Appendix 1 =================================================================== ######################################## ### START of source code file sclk140.py ######################################## class sclk140: """ Class to implement conversion from various representations of Deep Impact Spacecraft Clock to NAIF/with 1us sub-second (subtick) resolution to NAIF/SPICE virtual 8-bit subticks @ 1/256-second in SCLK-Kernel """ def __init__(self, doPrint=False, doTest=False): ### full 20 bits, or 16 or 8 high bits of subtick self.top20 = 1000000L self.top16 = 62500L self.top8 = 245L #################################################################### ### for 20- and 16-bits: x256 = [0.5, 1.5, ..., 255.5] array will ### be used to find splits in subticks between subticks of virtual ### 8-bit SCLK subticks arr20=[0] arr16=[0] arr8=[] m1=[-1L] for iBit8 in range(256): x256 = iBit8 + 0.5 arr20.append( long( round(x256*self.top20/256.0) ) ) arr16.append( long( round(x256*self.top16/256.0) ) ) if iBit8=top: ### undo any subtick overflow subticks -= top ticks += 1 while subticks<0: ### undo any subtick underflow subticks += top ticks -= 1 ### get subtick lookup table, or convert 20-bit value if nBits== 8: lut=self.lut8 elif nBits==16: lut=self.lut16 elif nBits==20: lut = None subticks = int( round(256.0*(subticks+0.5)/self.top20) ) if not (lut is None): ### perform lookup subticks = lut[subticks] if subticks==256: ### Deal with overflow subticks = 0 ticks += 1 sclk = "%10.10d.%3.3d" % (ticks,subticks,) if sclkOnly: return sclk ### Return SCLK only, return ( sclk, ticks, subticks, ) ### or with ticks & subticks ###################################################################### def printLOHI(self): """ Test code to print out contents of sclk140 class self.lohi array Format is identical to outputs from sclk140.f and sclk140.c programs """ for i in range(257): row=[i] for j in range(self.ilo20,self.ihi16+1): row.append( self.lohi[j][i] ) lo16 = self.lohi[self.ilo16][i] hi16 = self.lohi[self.ihi16][i] row.extend( [lo16>>8, lo16 & 0x0ffL ] ) row.extend( [hi16>>8, hi16 & 0x0ffL ] ) print( "%5d%9d%9d%5d%5d%7d%7d %03d:%03d %03d:%03d\r" % tuple(row) ) def testLOHI(self): return def correctFlatfile(self, flatfileName): for lin in open(flatfileName,"r").readlines(): for c in ('\n','\r',): if lin[-1:]==c: lin=lin[:-1] toks = lin.split('\t') prodId = toks[0][:24] ### 1st 24 chars of HI0173717021_9000025_001... instr = toks[1] ### Instrument oldSlk0 = toks[2] ### Old timestamp expdur = float(toks[4])*1000.0 ### Exposure duration, ms => us modenm = toks[5] ### Mode name ### SCLK bytes IMGH094 - IMGH099 tick0 = (long(toks[6])<<24) \ + (long(toks[7])<<16) \ + (long(toks[8])<< 8) \ + long(toks[9]) subtk0 = (long(toks[10])<<8) \ + long(toks[11]) oldMidSclk = toks[12] ### Get Base sclk baseSclk, \ baseTick0, \ baseSubtk0 = s140.toSclk( tick0, subtk0, 16, sclkOnly=False) ### Calculate Start, Mid, End SCLKs ### - For HRIIR/Alternating, base is start time, subtract expdur if instr=='HRIIR' and ( modenm=='ALTFF' or modenm=='DIAG' ): midSubtk = int( round((baseSubtk0/256e-6)+0.5-(expdur/2)) ) endSubtk = int( round((baseSubtk0/256e-6)+0.5-(expdur )) ) startSclk = baseSclk endSclk = s140.toSclk( baseTick0, endSubtk, 20) ### - For non-HRIIR/Alternating, base time is end time time else: midSubtk = int( round((baseSubtk0/256e-6)+0.5-(expdur/2)) ) startSubtk = int( round((baseSubtk0/256e-6)+0.5-(expdur )) ) startSclk = s140.toSclk( baseTick0, startSubtk, 20) endSclk = baseSclk midSclk = s140.toSclk( baseTick0, midSubtk, 20) ### Determine if start SCLK changed which would change the filename ### if the pipeline re-ran the file if prodId[2:12]==midSclk[:10]: nameChange="NO " else: nameChange="YES" ### Calculate delta time ### - Parse tick (seconds) and subtick portions of mid-obs SCLKs ### - divide by 256 subtick/s to scale subtick difference to seconds oldToks = oldMidSclk.split('/')[-1:][0].split('.') newToks = midSclk.split('/')[-1:][0].split('.') deltaT = ( long(newToks[0]) - long(oldToks[0]) ) \ + ( (float(newToks[1]) - float(oldToks[1])) / 256.0 ) ### Pad mode name to five characters and print out results modenmPad = modenm + ' ' print ( '"%24s",%8.3f,"%s","%s","%s","%s","%s","%s","%s","%s"\r' % (prodId , round(deltaT,3) , modenmPad[:5] , startSclk , midSclk , endSclk , baseSclk , oldSlk0 , oldMidSclk , nameChange ,) ) if __name__=='__main__': import sys hasNoArgv=len(sys.argv)==1 s140 = sclk140(doPrint=hasNoArgv, doTest=hasNoArgv) if hasNoArgv: exit(0) s140.correctFlatfile(sys.argv[1]) ###################################### ### END of source code file sclk140.py ###################################### Appendix 3: FORTRAN code to generate conversion table in Appendix 1 ==================================================================== CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC CCCCC START of source code file sclk140.f CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC CCCCC Generate table which implement Deep Impact SCLK sub-second CCCCC (subtick) rounding from 1M actual subticks to 256 virtual subticks CCCCC at different resolutions of the actual subticks CCCCC CCCCC To compile: CCCCC CCCCC gfortran sclk140.f -o sclk140_f CCCCC CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC CCCCC SUBROUTINE LOHISUB(): build virtual MOD-256 subtick table for one CCCCC actual subtick resolution CCCCC Arguments CCCCC - lohi CCCCC - output CCCCC - integer(0:256,0:1) CCCCC - 257-element output table, contains limits of actual clock values CCCCC corresponding to each virtual mod-256 subtick value CCCCC - this is the inverse of the 8-bit and 16-bit actual-to-virtual CCCCC lookup tables, but is built as a first step to developing CCCCC those tables. CCCCC - first index is virtual mod-256 subtick value, 0 to 256 CCCCC - index value of 256 implies subtick value rolls over to zero CCCCC and seconds field of clock should increment by one CCCCC - second index indicates low (0) and high (1) limits of actual CCCCC subtick values CCCCC - nBits CCCCC - input CCCCC - integer CCCCC - actual subtick resolution, # of high bits of 20-bit CCCCC subtick counter CCCCC CCCCC Algorithm description CCCCC Loop from 0 to 1,000,000 (actual subtick values at full resolution) CCCCC - val8 = virtual subtick (8-bit resolution) scaled from actual subtick CCCCC - loopChop = high nBits bits of each 20-bit actual subtick CCCCC - val8Avg = average of all virtual subticks for each loopChop value CCCCC - Put low and high loopChops (actual high nBits subticks) for each CCCCC val8Avg (virtual subtick average) in lohi(val8Avg,ILO) and CCCCC lohi(val8Avg,IHI), respectively CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC subroutine lohisub( lohi, nBits) implicit none CCCCC Parameters integer ILO ! lohi(0:256,0) are low values integer IHI ! lohi(0:256,1) are high values parameter (ILO=0,IHI=ILO+1) integer TOP parameter (TOP=1000000) ! SCLK sub-second range = 0:999,999 subticks integer TOPBITS parameter (TOPBITS=20) ! # of bits in SCLK CCCCC Subroutine Arguments integer lohi(0:256,ILO:IHI) integer nBits ! # of bits to which to compress 0:1M range CCCCC Local variables integer iLoop ! Loop counter 0:1,000,000 integer iLoopChop ! High nBits bits of iLoop integer iLastLoopChop ! Previous iLoopchop doubleprecision val8 ! iLoop+.5 scaled to 8-bits integer val8Count ! Number of iLoop values w/same iLoopChop doubleprecision val8Sum ! Sum of val8Count val8 values doubleprecision val8Avg ! Average of val8 values in val8Sum integer iVal8 ! Rounded integer of val8Avg CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC CCCCC Initialize table high and low values to -1 do iLoop=0,256 lohi(iLoop,ILO)=-1 lohi(iLoop,IHI)=-1 enddo CCCCC Initialize "last" and cumulative values iLastLoopChop=0 val8Sum = 0d0 val8Count = 0 CCCCC Loop through all values do iLoop=0,TOP ! Loop from 0 to 1,000,000 iLoopChop = ishft(iLoop,nBits-TOPBITS) ! Top nBits bits of iLoop val8 = (iLoop+0.50) * 256d0 / TOP ! iLoop scaled to 8-bit value CCCCC If iLoopChop has not changed since last loop iter, sum its 8-bit value if ( iLoopChop .eq. iLastLoopChop .and. iLoop .lt. TOP ) then val8Sum = val8Sum + val8 val8Count = val8Count + 1 CCCCC Else store last iLoopChop at table index = [val8's average] else val8Avg = val8Sum / val8Count ! Summed val8's average iVal8 = int( 0.5d0 + val8Avg ) ! ", converted to index if ( lohi(iVal8,ILO) .eq. -1 ) then lohi(iVal8,ILO) = iLastLoopChop ! Store low value endif lohi(iVal8,IHI) = iLastLoopChop ! Store high value CCCCC Re-initialize "last" and cumulative values iLastLoopChop = iLoopChop val8Sum = val8 val8Count = 1 endif enddo return end CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC CCCCC Main routine: generate multiple tables, or print them out, or CCCCC convert actual clock inputs of 8- 16- or 20-bit CCCCC resolution to virtual MOD-256 clock value CCCCC nBits must be 8, 16 or 20 to convert iSeconds CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC subroutine sclk140( iSeconds, iSubticks, nBits) implicitnone integer iSeconds integer iSubticks integer nBits integer ILO20 integer ILO8 integer ILO16 integer IHI20 integer IHI8 integer IHI16 parameter (ILO20=0,ILO8=ILO20+2,ILO16=ILO8+2) parameter (IHI20=ILO20+1,IHI8=ILO8+1,IHI16=ILO16+1) integer lohi(0:256,ILO20:IHI16) integer lut8(0:244) integer lut16(0:62499) integer i integer j integer iLo integer iMid integer iHi integer iRow integer iCol logical first / .true. / save CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC CCCCC Initialization: call subroutine LOHISUB to build tables for CCCCC nBits = 20, 8 and 16, then build 8-bit and 16-bit LookUp Tables CCCCC - Print out table if nBits is -1 if ( first .or. nBits .eq. -1 ) then first = .false. call lohisub( lohi(0,ILO20), 20) ! 20-bit table call lohisub( lohi(0, ILO8), 8) ! 8-bit table call lohisub( lohi(0,ILO16), 16) ! 16-bit table do i=0,256 do j=lohi(i,ILO8),lohi(i,IHI8) ! 8-bit lookup table if ( j .gt. -1 ) lut8(j) = i enddo do j=lohi(i,ILO16),lohi(i,IHI16) ! 20-bit lookup table lut16(j) = i enddo enddo CCCCC Print out table if requested (nBits is -1) and return if ( nBits .eq. -1 ) then do iRow=0,256 write(*,'(i5,2i9,2i5,2i7,2(2x,i3.3,1h:,i3.3),a1)') iRow & , ( lohi(iRow,iCol),iCol=0,5 ) & , ishft(lohi(iRow,4),-8), iand(lohi(iRow,4),255) & , ishft(lohi(iRow,5),-8), iand(lohi(iRow,5),255) & , char(13) enddo return endif endif CCCCC For 8- (0:244) and 16-bit (0:62499) subtick, use lookup tables; CCCCC for all others, assume 20-bit (0:999,999) subtick, use math. CCCCC Special case: for nBits = -20, use binary search if ( nBits .eq. 8 ) then iSeconds = iSeconds + (iSubticks/245) iSubticks = lut8(MOD( iSubticks, 245)) elseif ( nBits .eq. 16 ) then iSeconds = iSeconds + (iSubticks/62500) iSubticks = lut16(MOD( iSubticks, 62500)) else iSeconds = iSeconds + (iSubticks/1000000) iSubticks = MOD( iSubticks, 1000000) if ( nBits .ne. -20 ) then iSubticks = int( 0.5d0 + ((iSubticks + .5d0) * 256d0 / 1d6) ) CCCCC nBits.eq.-20 => Binary search else iLo = 0 iHi = 256 do while ( lohi(iLo,IHI20) .lt. iSubticks & .and. lohi(iHi,ILO20) .gt. iSubticks ) iMid = (iLo + iHi) / 2 CCCCC Maintain low limit of iHi above iSubticks if ( lohi(iMid,ILO20) .gt. iSubticks ) then iHi = iMid else iLo = iMid endif enddo if ( lohi(iLo,IHI20) .lt. iSubticks ) then iSubticks = iHi else iSubticks = iLo endif endif endif CCCCC Final check: roll over subticks and round up seconds as needed if ( iSubticks .eq. 256 ) then iSubticks = 0 iSeconds = iSeconds + 1 endif return end CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC CCCCC Main program: exercise virtual clock routines above CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC program sclk140_f implicit none CCCCC Test variables: integer i integer isub integer iSec0 integer iSec1 integer iSub0 integer iSub1 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC CCCCC Build tables and LUTs and print out call sclk140( -1, -1, -1) CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC CCCCC Test code CCCCC - loop i from 0 to 1,000,000 CCCCC - set isub to high 20-, 16- or 8-bits of i CCCCC - set iSec0 & iSec1 to zero CCCCC - set iSub0 & iSub1 to iSub CCCCC - perform independent conversions on iSec0:Sub0 & iSec1:iSub1 CCCCC to 8-bit virtual clock CCCCC - compare results of independent conversions 80000 format( a8, i8,i8,a1,i8,a5, i4,a1,i3.3, a6, i4,a1,i3.3, a2 ) do i=0,1000000 CCCCC 20-bit, compare math vs. binary search iSub=i iSec0=0 iSub0=iSub iSec1=iSec0 iSub1=iSub0 call sclk140( iSec0, iSub0, 20) call sclk140( iSec1, iSub1, -20) if ( iSec0 .ne. iSec1 .or. iSub0 .ne. iSub1 ) then print80000 & ,'ERROR: ',-20,i,'[',iSub,']: [' & ,iSec0,':',iSub0 & ,'].ne.[' & ,iSec1,':',iSub1 & ,']'//char(13) endif CCCCC 16-bit, compare lookup tables in sclk140 with local math iSub=ishft(i,-4) iSec0=0 iSub0=iSub iSec1=iSec0 iSub1=iSub0 iSub0=int( .5d0 + (((iSub0*256d0) + 128d0) / 62500d0) ) if ( iSub0 .eq. 256 ) then iSub0=0 iSec0=iSec0 + 1 endif call sclk140( iSec1, iSub1, 16) if ( iSec0 .ne. iSec1 .or. iSub0 .ne. iSub1 ) then print80000 & ,'ERROR: ',16,i,'[',iSub,']: [' & ,iSec0,':',iSub0 & ,'].ne.[' & ,iSec1,':',iSub1 & ,']' endif CCCCC 8-bit, compare lookup tables in sclk140 with local math iSub=ishft(i,-12) iSec0=0 iSub0=iSub iSec1=iSec0 iSub1=iSub0 if ( iSub0 .ne. 244 ) then iSub0=int( .5d0 + (((iSub0*256d0) + 128d0) / (1d6/4096d0)) ) else iSub0=int( .5d0 + (((iSub0*256d0) + 18d0) / (1d6/4096d0)) ) endif if ( iSub0 .eq. 256 ) then iSub0=0 iSec0=iSec0 + 1 endif call sclk140( iSec1, iSub1, 8) if ( iSec0 .ne. iSec1 .or. iSub0 .ne. iSub1 ) then print80000 & ,'ERROR: ',8,i,'[',iSub,']: [' & ,iSec0,':',iSub0 & ,'].ne.[' & ,iSec1,':',iSub1 & ,']' endif enddo end CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC72345678 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC CCCCC END of source code file sclk140.f CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC Appendix 4: C code to generate conversion table in Appendix 1 ==================================================================== /* *********************************** */ /* START of source code file sclk140.c */ /* *********************************** */ // CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC // Generate tables which implement Deep Impact SCLK sub-second // (subtick) rounding from 1M actual subticks to 256 virtual subticks // at different resolutions of the actual subticks // // To compile: // // cc sclk140.c -o sclk140_c -lm // // CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC #include #include #include #include // CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC // routine lohisub(): build virtual MOD-256 subtick table for one // actual subtick resolution // Arguments // - lohi // - output // - int[2][257] // - 257-element output table, contains limits of actual clock values // corresponding to each virtual mod-256 subtick value // - this is the inverse of the 8-bit and 16-bit actual-to-virtual // lookup tables, but is built as a first step to developing // those tables. // - first index is virtual mod-256 subtick value, 0 to 256 // - index value of 256 implies subtick value rolls over to zero // and seconds field of clock should increment by one // - second index indicates low (0) and high (1) limits of actual // subtick values // - nBits // - input // - int // - actual subtick resolution, # of high bits of 20-bit // subtick counter // // Algorithm description // Loop from 0 to 1,000,000 (actual subtick values at full resolution) // - val8 = virtual subtick (8-bit resolution) scaled from actual subtick // - loopChop = high nBits bits of each 20-bit actual subtick // - val8Avg = average of all virtual subticks for each loopChop value // - Put low and high loopChops (actual high nBits subticks) for each // val8Avg (virtual subtick average) in lohi[ILO][val8Avg] and // lohi[IHI][val8Avg], respectively // CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC void lohisub( int lohi[][257], int nBits) { // Parameters #define TOP 1000000L // SCLK sub-second range = 0:999,999 subticks #define TOPBITS 20L // # of bits to which to compress 0:1M range enum { ILO=0 , IHI }; // Local variables int iLoop; // Loop counter 0:1,000,000 int iLoopChop; // High nBits bits of iLoop int iLastLoopChop; // Previous iLoopChop double val8; // iLoop+.5 scaled to 8-bits int val8Count; // Number of iLoop values w/same iLoopChop double val8Sum; // Sum of val8Count val8 values double val8Avg; // Average of val8 values in val8Sum int iVal8; // Rounded integer of val8Avg // CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC // Initialize table high and low values to -1 for ( iLoop=0; iLoop<257; ++iLoop) { lohi[ILO][iLoop]=-1; lohi[IHI][iLoop]=-1; } // Initialize "last" and cumulative values iLastLoopChop=0; val8Sum = 0.0; val8Count = 0; // Loop through all values for ( iLoop=0; iLoop<=TOP; iLoop++) { // Loop from 0 to 1,000,000 iLoopChop = iLoop >> (TOPBITS-nBits); // Top nBits bits of iLoop val8 = (iLoop+0.50) * 256.0 / TOP; // iLoop scaled to 8-bit value // If iLoopChop has not changed since last loop iter, sum its 8-bit value if ( iLoopChop == iLastLoopChop && iLoop < TOP ) { val8Sum += val8; ++val8Count; // Else store last iLoopChop at table index = [val8's average] } else { val8Avg = val8Sum / val8Count; // Summed val8's average iVal8 = round( val8Avg ); // ", converted to index if ( lohi[ILO][iVal8] == -1 ) { lohi[ILO][iVal8] = iLastLoopChop; // Store low value } lohi[IHI][iVal8] = iLastLoopChop; // Store high value // Re-initialize "last" and cumulative values iLastLoopChop = iLoopChop; val8Sum = val8; val8Count = 1; } } return; } // CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC // Main routine: generate multiple tables, or print them out, or // convert actual clock inputs of 8- 16- or 20-bit // resolution to virtual MOD-256 clock value // nBits must be 8, 16 or 20 to convert iSeconds // CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC void sclk140( int *iSeconds, int *iSubticks, int nBits) { enum { ILO20 = 0 , IHI20 , ILO8 , IHI8 , ILO16 , IHI16 , ILOHICOUNT }; static int lohi[ILOHICOUNT][257]; static int lut8[245]; static int lut16[62500]; static int first = 1; int i; int j; int iLo; int iMid; int iHi; int iRow; int iCol; // CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC // Initialization: call subroutine LOHISUB to build tables for // nBits = 20, 8 and 16, then build 8-bit and 16-bit LookUp Tables // - Print out table if nBits is -1 if ( first || nBits == -1 ) { first = 0; lohisub( lohi+ILO20, 20); // 20-bit table lohisub( lohi+ILO8, 8); // 8-bit table lohisub( lohi+ILO16, 16); // 16-bit table for ( i=0; i<257; ++i) { for ( j=lohi[ILO8][i]; j<=lohi[IHI8][i]; ++j) { // 8-bit lookup table if ( j > -1 ) lut8[j] = i; } for ( j=lohi[ILO16][i]; j<=lohi[IHI16][i]; ++j) { // 20-bit lookup table lut16[j] = i; } } // Print out table if requested (nBits is -1) and return if ( nBits == -1 ) { for ( iRow=0; iRow<257; ++iRow) { printf( "%5d%9d%9d%5d%5d%7d%7d %03d:%03d %03d:%03d\r\n" , iRow , lohi[0][iRow] , lohi[1][iRow] , lohi[2][iRow] , lohi[3][iRow] , lohi[4][iRow] , lohi[5][iRow] , lohi[4][iRow] >> 8, lohi[4][iRow] & 255 , lohi[5][iRow] >> 8, lohi[5][iRow] & 255 ); } return; } } // For 8- (0:244) and 16-bit (0:62499) subtick, use lookup tables; // for all others, assume 20-bit (0:999,999) subtick, use math. // Special case: for nBits = -20, use binary search if ( nBits == 8 ) { *iSeconds += (*iSubticks/245); *iSubticks = lut8[ *iSubticks % 245 ]; } else if ( nBits == 16 ) { *iSeconds += (*iSubticks/62500); *iSubticks = lut16[ *iSubticks % 62500]; } else { *iSeconds += (*iSubticks/1000000); *iSubticks %= 1000000; if ( nBits != -20 ) { *iSubticks = round( (*iSubticks + 0.5) * 256.0 / 1e6 ); // nBits==-20 => Binary search } else { iLo = 0; iHi = 256; while ( lohi[IHI20][iLo] < *iSubticks && lohi[ILO20][iHi] > *iSubticks ) { iMid = (iLo + iHi) / 2; // Maintain low limit of iHi above iSubticks if ( lohi[ILO20][iMid] > *iSubticks ) { iHi = iMid; } else { iLo = iMid; } } if ( lohi[IHI20][iLo] < *iSubticks ) { *iSubticks = iHi; } else { *iSubticks = iLo; } } } // Final check: roll over subticks and round up seconds as needed if ( *iSubticks == 256 ) { *iSubticks = 0; ++*iSeconds; } return; } // CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC // Main program: exercise virtual clock routines above // CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC int main( int ac, char** av) { // Test variables: int i; int iSub; int iSec0; int iSec1; int iSub0; int iSub1; char fmt[] = { "ERROR: %8d%8d[%8d]: [%4d:%03d]!=[%4d:%03d]\r\n" }; // CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC // Build tables and LUTs and print out sclk140( &i, &i, -1); // CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC // Test code // - loop i from 0 to 1,000,000 // - set iSub to high 20-, 16- or 8-bits of i // - set iSec0 & iSec1 to zero // - set iSub0 & iSub1 to iSub // - perform independent conversions on iSec0:Sub0 & iSec1:iSub1 // to 8-bit virtual clock // - compare results of independent conversions for ( i=0; i<=1000000; ++i) { // 20-bit, compare math vs. binary search iSub = i; iSec0 = 0; iSub0 = iSub; iSec1 = iSec0; iSub1 = iSub0; sclk140( &iSec0, &iSub0, 20); sclk140( &iSec1, &iSub1, -20); if ( iSec0 != iSec1 || iSub0 != iSub1 ) { printf( fmt,-20,i,iSub,iSec0,iSub0,iSec1,iSub1); } // 16-bit, compare lookup tables in sclk140 with local math iSub = i >> 4; iSec0 = 0; iSub0 = iSub; iSec1 = iSec0; iSub1 = iSub0; iSub0=round( ((iSub0*256.0) + 128.0) / 62500.0 ); if ( iSub0 == 256 ) { iSub0=0; ++iSec0; } sclk140( &iSec1, &iSub1, 16); if ( iSec0 != iSec1 || iSub0 != iSub1 ) { printf( fmt,16,i,iSub,iSec0,iSub0,iSec1,iSub1); } // 8-bit, compare lookup tables in sclk140 with local math iSub = i >> 12; iSec0 = 0; iSub0 = iSub; iSec1 = iSec0; iSub1 = iSub0; if ( iSub0 != 244 ) { iSub0 = round( ((iSub0*256.0) + 128.0) / (1e6/4096.0) ); } else { iSub0 = round( ((iSub0*256.0) + 18.0) / (1e6/4096.0) ); } if ( iSub0 == 256 ) { iSub0=0; ++iSec0; } sclk140( &iSec1, &iSub1, 8); if ( iSec0 != iSec1 || iSub0 != iSub1 ) { printf( fmt,8,i,iSub,iSec0,iSub0,iSec1,iSub1); } } return 0; } // CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC7234567890 /* ********************************* */ /* END of source code file sclk140.c */ /* ********************************* */ Appendix 5: Terminology ======================== Summary ------- The word 'seconds' may refer to either non-constant rate spacecraft clock seconds or constant rate seconds (e.g. TDT). Where context may not make the intent clear, this document will refer to 'S/C [or spacecraft] seconds' or 'TDT seconds.' Contiguous bit positions (i.e. subsets of bits) in binary numbers are described using the notation [MSB:LSB] where MSB and LSB are decimal numbers referring to the offsets of the most significant bit and least significant bits, respectively, in the bit subset from the least significant bit of the full binary number. For example, all the bits in the 20-bit DI SCLK are bits [19:0], the highest eight bits of the DI SCLK are bits [19:12], &c. Details: seconds ----------------- The unit of time, seconds, is used loosely here to refer both to constant-rate TDT seconds (a.k.a. TDB or ephemeris) and to variable-rate DI spacecraft clock seconds. Context will usually be adequate to distinguish the meaning; the phrases 'TDT seconds' and 'S/C seconds' will be used when deemed necessary. Details: bits and bit positions -------------------------------- There is an extensive discussion of bits and bit positions in this document, but this is not the appropriate place for a treatise on binary number representation; instead, here is a brief description: The word bit is a compression of the phrase Binary digIT. The binary digits (0 and 1) are the building blocks of the binary counting system, and are analogous to the decimal digits (0 through 9) of the familiar decimal counting system. Bits have places and meanings in binary numbers the same way decimal digits have places in decimal numbers: 952 is a three-digit decimal number using three of the ten available decimal digits, and 101 is a three-digit binary number using both of the two available binary digits (bits). In the decimal number 952, we say the rightmost digit (2 in this case) is the ones digit, the middle digit (5) is the tens digit, and the leftmost digit (9) is the hundreds digit, meaning the number 952 represents the quantity that is the sum of 2 ones, 5 tens and 9 one-hundreds. An alternate notation for ones, tens and one-hundreds is the exponential form where ^ is the exponentiation operator: one = 10^0; ten = 10^1; one-hundred = 10^2. So we can say 952 = (9 x 10^2) + (5 x 10^1) + (1 x 10^0) and, because the value of each place increases to the left (ones, tens, one-hundreds, &c), we can also say the least significant decimal digit is on the right and the most significant decimal digit is on the left. From there it can be seen that the exponent (power of ten) is also the leftward positional (place) offset from the rightmost decimal digit i.e. the decimal digit 2 is offset 0 places from the right, and the decimal digit 9 (representing 9 x 10^2 or 900) is offset 2 places leftward from the rightmost digit. Binary numbers work in the same fashion, only instead of describing bit places with names (ones, tens, hundreds), we use the offset from the rightmost place, which is also the exponent or power of two for that place. So in the binary number 101, the rightmost bit (1) is in bit position 0, the middle bit (0) is in bit position 1, and the leftmost bit (another 1) is in bit position 2. To describe contiguous groups of bit positions, we use the form [MSB:LSB], where MSB and LSB are decimal numbers giving the positional offsets from the rightmost bit. So bits [2:1] of the binary number 101 refer to the two leftmost bits i.e. the leading 1 and 0. The abbreviations MSB and LSB refer to Most Significant Bit and Least Significant Bit, respectively, analogous to the most and least significant decimal digits in the decimal digit example above. Appendix 6: Abbreviations ========================== ALTFF ALTernating Full-Frame operating mode for HRIR DI Deep Impact mission and/or spacecraft DIAG DIAGnostic operating mode for HRIR DSN Deep Space Network ERT Earth-Received Time ITS Impactor Targeting Instrument (DI imager) HRI High Resolution Instrument (DI imager and imaging spectrograph) HRIIR High Resolution Instrument, Infra Red spectral imaging detector MRI Medium Resolution Instrument (DI imager) NAIF Navigation and Ancillary Information Facility (naif.jpl.nasa.gov) JPL Jet Propulsion Laboratory, Pasadena, California PDS Planetary Data System S/C SpaceCraft SCLK Spacecraft CLocK; also sometimes NAIF/SPICE SCLK-Kernel SDC Science Data Center; converts raw S/C data to products for PDS SPICE S/C navigation toolkit and data kernels from NAIF TDB Barycentric Dynamical Time; constant rate TDT Terrestrial Dynamical Time; constant rate us microsecond (7-bit ASCII u posing as Greek mu SI prefix for 1E-6) UTC Universal Time Coordinated; constant rate with discontinuities Appendix 7: Glossary ===================== second Context-dependent word indicating exactly or very near one SI second. In this document this word most often refers to the rollover period of the SCLK subtick counter. virtual Term used in this document to refer to NAIF/SPICE SCLK model of actual SCLK, due to difference in number of sub-second counter increments per second