Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 43 additions & 21 deletions imap_processing/idex/idex_l1a.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ def __init__(self, packet_file: str | Path) -> None:
data.attrs = self.idex_attrs.get_global_attributes(
f"imap_idex_{level}_evt"
)
data["epoch"] = calculate_idex_epoch_time(
data["shcoarse"], data["shfine"]
data["epoch"] = calculate_idex_event_time(
data["shfine"].data, data["shcoarse"].data
)
data["epoch"].attrs = epoch_attrs
self.data.append(data)
Expand All @@ -107,8 +107,8 @@ def __init__(self, packet_file: str | Path) -> None:
data.attrs = self.idex_attrs.get_global_attributes(
f"imap_idex_{level}_catlst"
)
data["epoch"] = calculate_idex_epoch_time(
data["shcoarse"], data["shfine"]
data["epoch"] = calculate_idex_event_time(
data["shfine"].data, data["shcoarse"].data
)
data["epoch"].attrs = epoch_attrs
self.data.append(data)
Expand Down Expand Up @@ -248,35 +248,55 @@ def _read_waveform_bits(waveform_raw: str, high_sample: bool = True) -> list[int
return ints


def calculate_idex_epoch_time(
shcoarse_time: float | np.ndarray, shfine_time: float | np.ndarray
def calculate_idex_event_time(
fine_time_subs: np.ndarray,
coarse_time_sec1: np.ndarray,
coarse_time_sec2: np.ndarray | None = None,
) -> npt.NDArray[np.int64]:
"""
Calculate the epoch time from the FPGA header time variables.

We are given the MET seconds, we need to convert it to nanoseconds in j2000. IDEX
epoch is calculated with shcoarse and shfine time values. The shcoarse time counts
the number of whole seconds elapsed since the epoch (Jan 1st 2010), while shfine
time counts the number of additional 20-microsecond intervals beyond the whole
seconds. Together, these time measurements establish when a dust event took place.
For science packets, we are given the MET seconds, we need to convert it to
nanoseconds in j2000. The idx__txhdrtimesec1 and idx__txhdrtimesec2 variables count
the number of whole seconds elapsed since the epoch (Jan 1st 2010), while
idx__txhdrtimesubs time counts the number of additional 20-microsecond intervals
beyond the whole seconds. Together, these time measurements establish when a dust
event took place.

The elapsed seconds are stored as a 32-bit unsigned integer that is split across
two 16-bit words for packetization. As a result, idx__txhdrtimesec1 represents
multiples of 2^16 seconds, while idx_txhdrtimesec2 represents the remaining seconds
within that range. This necessitates scaling the upper word by 2^16 = 65,536 when
reconstructing the full seconds counter.

For housekeeping packets, use the shcoarse and shfine variables instead.

Parameters
----------
shcoarse_time : float, numpy.ndarray
The coarse time value from the FPGA header. Number of seconds since epoch.
shfine_time : float, numpy.ndarray
The fine time value from the FPGA header. Number of 20 microsecond "ticks" since
the last second.
fine_time_subs : numpy.ndarray, optional
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't optional anymore since it is the first argument, the final coarse_time_sec2 is optional now though.

The lower 16 bits of the coarse event time.
coarse_time_sec1 : numpy.ndarray
The fine event time in 20-microsecond intervals.
coarse_time_sec2 : numpy.ndarray
The upper 16 bits of the coarse event time.

Returns
-------
numpy.ndarray[numpy.int64]
The mission elapsed time converted to nanoseconds since the J2000 epoch
in the terrestrial time (TT) timescale.
"""
# Get met time in seconds including shfine (number of 20 microsecond ticks)
met = shcoarse_time + shfine_time * 20e-6
return met_to_ttj2000ns(met)
if coarse_time_sec2 is not None:
# Reconstruct the total seconds from the two 16-bit words
coarse_event_time = 65536 * coarse_time_sec1 + coarse_time_sec2
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am little curious why they want to multiply coarse second time with 65536. I have seen this number is CoDICE and they are doing this:

    center_times_seconds = (
        acq_start_seconds + acq_start_subseconds / 65536 + (delta_times / 1e9)
    )

Can you check with them if 65536 should be applied to fine_time_subs instead?

else:
# Use coarse_time_sec1 as the full coarse time (e.g., for housekeeping)
coarse_event_time = coarse_time_sec1

# Calculate the fine event time in seconds
fine_event_time = fine_time_subs * 20e-6

return met_to_ttj2000ns(coarse_event_time + fine_event_time)


class RawDustEvent:
Expand Down Expand Up @@ -357,8 +377,10 @@ def __init__(self, header_packet: space_packet_parser.SpacePacket) -> None:
"""
# Calculate the impact time in seconds since epoch
self.impact_time = 0
self.impact_time = calculate_idex_epoch_time(
header_packet["SHCOARSE"], header_packet["SHFINE"]
self.impact_time = calculate_idex_event_time(
header_packet["IDX__TXHDRTIMESUBS"],
header_packet["IDX__TXHDRTIMESEC1"],
header_packet["IDX__TXHDRTIMESEC2"],
Comment on lines +380 to +383
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a comment here about what these times are, but I think this might be clearer what is going on (to me at least). You are left-shifting the first timer to the first 16 bits to make a 32-bit integer, so I'd use the bitwise operators (you might need to do this on .data of the packets I'm not sure)

Suggested change
self.impact_time = calculate_idex_event_time(
header_packet["IDX__TXHDRTIMESUBS"],
header_packet["IDX__TXHDRTIMESEC1"],
header_packet["IDX__TXHDRTIMESEC2"],
self.impact_time = calculate_idex_event_time(
(header_packet["IDX__TXHDRTIMESEC1"] << 16) + header_packet["IDX__TXHDRTIMESEC2"],
header_packet["IDX__TXHDRTIMESUBS"],

)
self.event_number = header_packet["IDX__SCI0EVTNUM"]

Expand Down
Loading