27 max_SPEXone_packet = 298
32 parser = argparse.ArgumentParser(
33 formatter_class=argparse.RawTextHelpFormatter,
34 description=
'Convert S-band housekeeping telemetry to NetCDF4'
36 parser.add_argument(
'ifile', nargs=
'?', type=str,
37 help=
'path to S-band telemetry (HSK file) OR list of input files, one per line, in chronological order')
38 parser.add_argument(
"-o",
"--output", metavar=
"ofile", dest=
"ofile",
39 help=
"output NetCDF4 file; defaults to PACE.yyyymmddThhmmss.HKT.nc")
40 parser.add_argument(
'--verbose',
'-v', action=
'store_true',
41 default=
False, help=
"print status messages")
43 args = parser.parse_args()
45 if args.ifile
is None:
51 infile = os.path.expandvars(args.ifile)
53 with open(infile, mode=
'rt')
as flist:
57 f = os.path.expandvars(ifile.rstrip())
60 except UnicodeDecodeError:
64 filelist.append(infile)
73 HARP2_HKT_packets = []
74 SPEXone_HKT_packets = []
75 oversize_packets = bytearray()
78 for filename
in filelist:
79 print(
'reading: ',filename)
82 ifile = open(filename, mode=
'rb')
84 print(
"Cannot open file \"%s\": exiting." % filename)
88 filehdr = readFileHeader(ifile)
95 desired = (filehdr[
'subtype'] == 101
and
96 filehdr[
'length'] == 64
and
97 filehdr[
'SCID'] == b
'PACE' and
98 filehdr[
'processorid']
in (1,2,30) )
106 header, data, rawhdr = readPacket(ifile)
111 if header[
'length'] > 16378:
112 print(
'Invalid CCSDS packet header:', rawhdr)
116 if (header[
'secondary'] == 1
121 header[
'timestamp'] = ts
127 if header[
'APID']
not in ignored_apids:
131 if header[
'APID'] < 550:
133 if header[
'APID'] == 108:
135 keys = [
'timestamp',
'Est_Time',
'q_EciToBrf_Est',
'w_EciToBrf_Brf_Est',]
137 tmpDict[k] = myDict[k]
138 att_recordlist.append(tmpDict)
140 elif header[
'APID'] == 128:
142 keys = [
'timestamp',
'FSWTime',
'scPosJ2000',
'scVelJ2000',
'DCM_ecef2eci',]
144 tmpDict[k] = myDict[k]
145 orb_recordlist.append(tmpDict)
147 elif header[
'APID'] == 198:
149 keys = [
'timestamp',
'TILT_ENCPOS',]
151 tmpDict[k] = myDict[k]
152 tilt_recordlist.append(tmpDict)
158 if len(packet) > max_SC_packet:
159 oversize_packets += packet
162 SC_HKT_packets.append(packet)
166 elif header[
'APID'] < 750:
167 if len(packet) > max_OCI_packet:
168 oversize_packets += packet
171 OCI_HKT_packets.append(packet)
173 elif header[
'APID'] < 800:
174 if len(packet) > max_HARP2_packet:
175 oversize_packets += packet
178 HARP2_HKT_packets.append(packet)
180 elif header[
'APID'] < 850:
181 if len(packet) > max_SPEXone_packet:
182 oversize_packets += packet
184 packet =
pad_packet(packet, max_SPEXone_packet)
185 SPEXone_HKT_packets.append(packet)
199 if len(orb_recordlist) > 0:
203 if len(alltimes) == 0:
204 print(
'No input packets with valid times')
209 daystart = stime.replace(hour=0, minute=0, second=0, microsecond=0)
212 prod_name = stime.strftime(
'PACE.%Y%m%dT%H%M%S.HKT.nc')
213 if args.ofile
is None:
214 args.ofile = prod_name
218 ofile = netCDF4.Dataset(args.ofile,
'w')
219 except BaseException:
220 print(
"Cannot write file \"%s\": exiting." % args.ofile)
224 ofile.createDimension(
'vector_elements', 3)
225 ofile.createDimension(
'quaternion_elements', 4)
228 group = ofile.createGroup(
'housekeeping_data')
230 if len(SC_HKT_packets) > 0:
231 ofile.createDimension(
'SC_hkt_pkts',
None)
232 ofile.createDimension(
'max_SC_packet', max_SC_packet)
233 var = group.createVariable(
'SC_HKT_packets',
'u1', (
'SC_hkt_pkts',
'max_SC_packet'))
234 var.long_name =
"Spacecraft housekeeping telemetry packets"
235 var[:] = SC_HKT_packets
237 if len(OCI_HKT_packets) > 0:
238 ofile.createDimension(
'OCI_hkt_pkts',
None)
239 ofile.createDimension(
'max_OCI_packet', max_OCI_packet)
240 var = group.createVariable(
'OCI_HKT_packets',
'u1', (
'OCI_hkt_pkts',
'max_OCI_packet'))
241 var.long_name =
"OCI housekeeping telemetry packets"
242 var[:] = OCI_HKT_packets
244 if len(HARP2_HKT_packets) > 0:
245 ofile.createDimension(
'HARP2_hkt_pkts',
None)
246 ofile.createDimension(
'max_HARP2_packet', max_HARP2_packet)
247 var = group.createVariable(
'HARP2_HKT_packets',
'u1', (
'HARP2_hkt_pkts',
'max_HARP2_packet'))
248 var.long_name =
"HARP2 housekeeping telemetry packets"
249 var[:] = HARP2_HKT_packets
251 if len(SPEXone_HKT_packets) > 0:
252 ofile.createDimension(
'SPEXone_hkt_pkts',
None)
253 ofile.createDimension(
'max_SPEXone_packet', max_SPEXone_packet)
254 var = group.createVariable(
'SPEXone_HKT_packets',
'u1', (
'SPEXone_hkt_pkts',
'max_SPEXone_packet'))
255 var.long_name =
"SPEXone housekeeping telemetry packets"
256 var[:] = SPEXone_HKT_packets
258 if len(oversize_packets) > 0:
259 ofile.createDimension(
'os_pkts',
None)
260 var = group.createVariable(
'oversize_packets',
'u1', (
'os_pkts'))
261 var.long_name =
"Buffer for packets exceeding maximum size"
262 var[:] = oversize_packets
265 group = ofile.createGroup(
'navigation_data')
267 if len(att_recordlist) > 0:
268 ofile.createDimension(
'att_records',
None)
270 var = group.createVariable(
271 'att_time',
'f8', (
'att_records'), fill_value=-999.9)
272 var.long_name =
"Attitude sample time (seconds of day)"
274 var.valid_max = 86400.999999
275 var.units =
"seconds"
276 var[:] = [
seconds_since(rec[
'timestamp'], basetime=daystart)
for rec
in att_recordlist]
278 var = group.createVariable(
279 'att_quat',
'f4', (
'att_records',
'quaternion_elements'), fill_value=-999.9)
280 var.long_name =
"Attitude quaternions (J2000 to spacecraft)"
283 var.units =
"seconds"
284 var[:] = [rec[
'q_EciToBrf_Est']
for rec
in att_recordlist]
286 var = group.createVariable(
287 'att_rate',
'f4', (
'att_records',
'vector_elements'), fill_value=-999.9)
288 var.long_name =
"Attitude angular rates in spacecraft frame"
289 var.valid_min = np.array((-0.004),
'f4')
290 var.valid_max = np.array(( 0.004),
'f4')
291 var.units =
"radians/second"
292 var[:] = [rec[
'w_EciToBrf_Brf_Est']
for rec
in att_recordlist]
294 if len(orb_recordlist) > 0:
295 ofile.createDimension(
'orb_records',
None)
297 var = group.createVariable(
298 'orb_time',
'f8', (
'orb_records'), fill_value=-999.9)
299 var.long_name =
"Orbit vector time (seconds of day)"
301 var.valid_max = 86400.999999
302 var.units =
"seconds"
304 for rec
in orb_recordlist]
306 var = group.createVariable(
307 'orb_pos',
'f4', (
'orb_records',
'vector_elements'), fill_value= -9999999)
308 var.long_name =
"Orbit position vectors (ECR)"
309 var.valid_min = -7200000
310 var.valid_max = 7200000
312 var[:] = orbitparams[
'posr']
314 var = group.createVariable(
315 'orb_vel',
'f4', (
'orb_records',
'vector_elements'), fill_value= -9999999)
316 var.long_name =
"Orbit velocity vectors (ECR)"
317 var.valid_min = -7600
319 var.units =
"meters/second"
320 var[:] = orbitparams[
'velr']
322 var = group.createVariable(
323 'orb_lon',
'f8', (
'orb_records'), fill_value=-999.9)
324 var.long_name =
"Orbit longitude (degrees East)"
327 var.units =
"degrees"
328 var[:] = orbitparams[
'lon']
330 var = group.createVariable(
331 'orb_lat',
'f8', (
'orb_records'), fill_value=-999.9)
332 var.long_name =
"Orbit latitude (degrees North)"
335 var.units =
"degrees"
336 var[:] = orbitparams[
'lat']
338 var = group.createVariable(
339 'orb_alt',
'f8', (
'orb_records'), fill_value=-999.9)
340 var.long_name =
"Orbit altitude"
344 var[:] = orbitparams[
'alt']
346 if len(tilt_recordlist) > 0:
347 ofile.createDimension(
'tilt_records',
None)
349 var = group.createVariable(
350 'tilt_time',
'f8', (
'tilt_records'), fill_value=-999.9)
351 var.long_name =
"Tilt sample time (seconds of day)"
353 var.valid_max = 86400.999999
354 var.units =
"seconds"
356 for rec
in tilt_recordlist]
358 var = group.createVariable(
359 'tilt',
'f4', (
'tilt_records'), fill_value=-999.9)
360 var.long_name =
"Tilt angle"
361 var.valid_min = np.array((-20.1),
'f4')
362 var.valid_max = np.array(( 20.1),
'f4')
363 var.units =
"degrees"
364 var[:] = [rec[
'TILT_ENCPOS']
for rec
in tilt_recordlist]
369 ofile.title =
"PACE HKT Data"
370 ofile.instrument =
"Observatory"
371 ofile.processing_version =
"V1.0"
372 ofile.Conventions =
"CF-1.6"
373 ofile.institution =
"NASA Goddard Space Flight Center, Ocean Biology Processing Group"
374 ofile.license =
"http://science.nasa.gov/earth-science/earth-science-data/data-information-policy/"
375 ofile.naming_authority =
"gov.nasa.gsfc.sci.oceancolor"
376 ofile.keywords_vocabulary =
"NASA Global Change Master Directory (GCMD) Science Keywords"
377 ofile.stdname_vocabulary =
"NetCDF Climate and Forecast (CF) Metadata Convention"
378 ofile.creator_name =
"NASA/GSFC"
379 ofile.creator_email =
"data@oceancolor.gsfc.nasa.gov"
380 ofile.creator_url =
"http://oceancolor.gsfc.nasa.gov"
381 ofile.project =
"PACE Project"
382 ofile.publisher_name =
"NASA/GSFC"
383 ofile.publisher_email =
"data@oceancolor.gsfc.nasa.gov"
384 ofile.publisher_url =
"http://oceancolor.gsfc.nasa.gov"
385 ofile.processing_level =
"1"
386 ofile.cdm_data_type =
""
387 ofile.CDL_version_date =
"2022-04-08"
389 ofile.product_name = args.ofile
392 ofile.history =
' '.join([v
for v
in sys.argv])
394 ofile.source =
','.join([os.path.basename(f)
for f
in filelist])
395 ofile.date_created = datetime.datetime.utcnow().strftime(
'%Y-%m-%dT%H:%M:%SZ')
402 if __name__ ==
'__main__':