Skip to content

Commit b966244

Browse files
authored
Bug fix and adding spectrum fits file creation (PADRESat#14)
bug fix to is_consecutive and adding draft spectrum fits file creation
1 parent f294bc4 commit b966244

File tree

4 files changed

+88
-17
lines changed

4 files changed

+88
-17
lines changed

padre_meddea/calibration/calibration.py

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from astropy.io import fits, ascii
1010
from astropy.time import Time
1111
from astropy.table import Table
12+
from astropy.timeseries import TimeSeries
1213

1314
from swxsoc.util.util import record_timeseries
1415

@@ -56,6 +57,9 @@ def process_file(filename: Path, overwrite=False) -> list:
5657
parsed_data = read_raw_file(file_path)
5758
if parsed_data["photons"] is not None: # we have event list data
5859
event_list, pkt_list = parsed_data["photons"]
60+
log.info(
61+
f"Found photon data, {len(event_list)} photons and {len(pkt_list)} packets."
62+
)
5963
primary_hdr = get_primary_header()
6064
primary_hdr = add_process_info_to_header(primary_hdr)
6165
primary_hdr["LEVEL"] = (0, get_std_comment("LEVEL"))
@@ -137,7 +141,7 @@ def process_file(filename: Path, overwrite=False) -> list:
137141
hk_hdu = fits.BinTableHDU(data=hk_table, name="HK")
138142
hk_hdu.add_checksum()
139143

140-
# add command response data if it exists
144+
# add command response data if it exists in the same fits file
141145
if parsed_data["cmd_resp"] is not None:
142146
data_ts = parsed_data["cmd_resp"]
143147
this_header = fits.Header()
@@ -169,6 +173,7 @@ def process_file(filename: Path, overwrite=False) -> list:
169173
hdul = fits.HDUList([empty_primary_hdu, hk_hdu, cmd_hdu])
170174

171175
path = create_science_filename(
176+
"meddea",
172177
time=date_beg,
173178
level="l1",
174179
descriptor="hk",
@@ -178,8 +183,54 @@ def process_file(filename: Path, overwrite=False) -> list:
178183
hdul.writeto(path, overwrite=overwrite)
179184
output_files.append(path)
180185
if parsed_data["spectra"] is not None:
181-
spec_data = parsed_data["spectra"]
186+
timestamps, data, spectra, ids = parsed_data["spectra"]
187+
asic_nums = (ids & 0b11100000) >> 5
188+
channel_nums = ids & 0b00011111
189+
time_s = data["TIME_S"]
190+
time_clk = data["TIME_CLOCKS"]
182191

192+
primary_hdr = get_primary_header()
193+
primary_hdr = add_process_info_to_header(primary_hdr)
194+
primary_hdr["LEVEL"] = (0, get_std_comment("LEVEL"))
195+
primary_hdr["DATATYPE"] = ("spectrum", get_std_comment("DATATYPE"))
196+
primary_hdr["ORIGAPID"] = (
197+
padre_meddea.APID["spectrum"],
198+
get_std_comment("ORIGAPID"),
199+
)
200+
primary_hdr["ORIGFILE"] = (file_path.name, get_std_comment("ORIGFILE"))
201+
dates = {
202+
"DATE-BEG": timestamps[0].fits,
203+
"DATE-END": timestamps[-1].fits,
204+
"DATE-AVG": timestamps[len(timestamps) // 2].fits,
205+
}
206+
primary_hdr["DATEREF"] = (dates["DATE-BEG"], get_std_comment("DATEREF"))
207+
for this_keyword, value in dates.items():
208+
primary_hdr[this_keyword] = (
209+
value,
210+
get_std_comment(this_keyword),
211+
)
212+
spec_hdu = fits.ImageHDU(data=spectra, name="SPEC")
213+
spec_hdu.add_checksum()
214+
data_table = Table()
215+
data_table["pkttimes"] = time_s
216+
data_table["pktclock"] = time_clk
217+
data_table["asic"] = asic_nums
218+
data_table["channel"] = channel_nums
219+
data_table["seqcount"] = data["CCSDS_SEQUENCE_COUNT"]
220+
record_timeseries(TimeSeries(time=timestamps, data=data_table), "spectrum")
221+
pkt_hdu = fits.BinTableHDU(data=data_table, name="PKT")
222+
pkt_hdu.add_checksum()
223+
hdul = fits.HDUList([empty_primary_hdu, spec_hdu, pkt_hdu])
224+
path = create_science_filename(
225+
"meddea",
226+
time=dates["DATE-BEG"],
227+
level="l1",
228+
descriptor="spec",
229+
test=True,
230+
version="0.1.0",
231+
)
232+
hdul.writeto(path, overwrite=overwrite)
233+
output_files.append(path)
183234
# add other tasks below
184235
return output_files
185236

padre_meddea/io/file_tools.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -328,12 +328,12 @@ def parse_spectrum_packets(filename: Path):
328328
packet_definition = packet_definition_hist2()
329329
pkt = ccsdspy.FixedLength(packet_definition)
330330
data = pkt.load(packet_bytes, include_primary_header=True)
331-
timestamps = calc_time(data["TIMESTAMPS"], data["TIMESTAMPCLOCK"])
332-
num_packets = len(timestamps)
331+
timestamps = calc_time(data["TIME_S"], data["TIME_CLOCKS"])
332+
num_packets = len(data["TIME_S"])
333333
h = data["HISTOGRAM_DATA"].reshape((num_packets, 24, 513))
334334
histogram_data = h[:, :, 1:] # remove the id field
335335
ids = h[:, :, 0]
336-
return timestamps, histogram_data, ids
336+
return timestamps, data, histogram_data, ids
337337

338338

339339
def parse_cmd_response_packets(filename: Path):
@@ -374,10 +374,10 @@ def parse_cmd_response_packets(filename: Path):
374374
packet_definition = packet_definition_cmd_response()
375375
pkt = ccsdspy.FixedLength(packet_definition)
376376
data = pkt.load(packet_bytes, include_primary_header=True)
377-
timestamps = calc_time(data["TIMESTAMPS"], data["TIMESTAMPCLOCK"])
377+
timestamps = calc_time(data["TIME_S"], data["TIME_CLOCKS"])
378378
data = {
379-
"time_s": data["TIMESTAMPS"],
380-
"time_clock": data["TIMESTAMPCLOCK"],
379+
"time_s": data["TIME_S"],
380+
"time_clock": data["TIME_CLOCKS"],
381381
"address": data["ADDR"],
382382
"value": data["VALUE"],
383383
"seqcount": data["CCSDS_SEQUENCE_COUNT"],
@@ -438,8 +438,8 @@ def packet_definition_hist2():
438438

439439
# the header
440440
p = [
441-
PacketField(name="TIMESTAMPS", data_type="uint", bit_length=32),
442-
PacketField(name="TIMESTAMPCLOCK", data_type="uint", bit_length=32),
441+
PacketField(name="TIME_S", data_type="uint", bit_length=32),
442+
PacketField(name="TIME_CLOCKS", data_type="uint", bit_length=32),
443443
PacketField(name="INTEGRATION_TIME", data_type="uint", bit_length=32),
444444
PacketField(name="LIVE_TIME", data_type="uint", bit_length=32),
445445
]
@@ -477,8 +477,8 @@ def packet_definition_ph():
477477
def packet_definition_cmd_response():
478478
"""Return the packet definiton for the register read response"""
479479
p = [
480-
PacketField(name="TIMESTAMPS", data_type="uint", bit_length=32),
481-
PacketField(name="TIMESTAMPCLOCK", data_type="uint", bit_length=32),
480+
PacketField(name="TIME_S", data_type="uint", bit_length=32),
481+
PacketField(name="TIME_CLOCKS", data_type="uint", bit_length=32),
482482
PacketField(name="ADDR", data_type="uint", bit_length=16),
483483
PacketField(name="VALUE", data_type="uint", bit_length=16),
484484
PacketField(name="CHECKSUM", data_type="uint", bit_length=16),

padre_meddea/tests/test_util.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,14 @@ def test_is_consecutive():
3636
assert util.is_consecutive(np.arange(10))
3737
assert util.is_consecutive(range(100))
3838
assert util.is_consecutive(np.arange(10, 100, 1))
39+
# test if the array loops over
40+
assert util.is_consecutive(
41+
np.concatenate((np.arange(0, 2**14), np.arange(0, 2000)))
42+
)
3943

4044

4145
def test_is_not_consecutive():
46+
"""Test if not consecutive"""
4247
assert not util.is_consecutive([0, 2, 3, 4, 5])
4348
assert not util.is_consecutive(
4449
np.concatenate((np.arange(1, 10), np.arange(11, 20)))

padre_meddea/util/util.py

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -102,14 +102,29 @@ def has_baseline(filename: Path, packet_count=10) -> bool:
102102
return np.sum(num_hits - np.floor(num_hits)) == 0
103103

104104

105-
def is_consecutive(arr: np.array):
106-
"""Return True if the array is all consecutive integers or has not missing numbers."""
107-
return np.all(np.diff(arr) == 1)
108-
109-
110105
def str_to_fits_keyword(keyword: str) -> str:
111106
"""Given a keyword string, return a fits compatible keyword string
112107
which must not include special characters and have fewer have no more
113108
than 8 characters."""
114109
clean_keyword = "".join(e for e in keyword if e.isalnum()).strip().upper()
115110
return clean_keyword[0:8]
111+
112+
113+
def is_consecutive(arr: np.array) -> bool:
114+
"""Return True if the packet sequence numbers are all consecutive integers, has no missing numbers."""
115+
MAX_SEQCOUNT = 2**14 - 1 # 16383
116+
# check if seqcount has wrapped around
117+
indices = np.where(arr == MAX_SEQCOUNT)
118+
if len(indices[0]) == 0: # no wrap
119+
return np.all(np.diff(arr) == 1)
120+
else:
121+
last_index = 0
122+
result = True
123+
for this_ind in indices[0]:
124+
this_arr = arr[last_index : this_ind + 1]
125+
result = result & np.all(np.diff(this_arr) == 1)
126+
last_index = this_ind + 1
127+
# now do the remaining part of the array
128+
this_arr = arr[last_index + 1 :]
129+
result = result & np.all(np.diff(this_arr) == 1)
130+
return result

0 commit comments

Comments
 (0)