Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HIT housekeeping data class #342

Merged
merged 14 commits into from
Feb 19, 2024

Conversation

sdhoyt
Copy link
Contributor

@sdhoyt sdhoyt commented Feb 15, 2024

Change Summary

Overview

Added a housekeeping data class for decommutation to L1A.

New Dependencies

None

New Files

  • housekeeping.py
    • new data class for HIT housekeeping L1A data
  • hit_base.py
    • base data class for all of the HIT L1A data classes.

Deleted Files

None

Updated Files

  • hit.rst
    • added new files to docs
  • Updated the XTCE files based on new Telem definitions

Testing

Added test_houskeeping.py to unit test the housekeeping data. This unit test includes validation for CCSDS decommutation.

@sdhoyt sdhoyt requested a review from a team February 15, 2024 18:14
@sdhoyt sdhoyt self-assigned this Feb 15, 2024
@sdhoyt sdhoyt requested review from bourque, greglucas, tech3371, bryan-harter, laspsandoval, bmcclellan-cu and maxinelasp and removed request for a team February 15, 2024 18:14
Comment on lines 208 to 219
leak_list = list()
leak_bits = bitstring.Bits(bin=self.LEAK_I_RAW)
# Each Leak field is 10 bits long
leak_bit_length = 10
# There are 64 leak fields
num_leak_fields = 64
# The leak fields appear in the packet in ascending order, so to append
# the leak fields in the correct order, the binary will be parsed
# from right to left.
for leak_idx in range(leak_bit_length * num_leak_fields, 0, -leak_bit_length):
leak_list.append(leak_bits[leak_idx - leak_bit_length:leak_idx].uint)
self.LEAK_I = np.array(leak_list)
Copy link
Collaborator

@greglucas greglucas Feb 15, 2024

Choose a reason for hiding this comment

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

You can initialize the shape of the array right away and then fill in the values and avoid bitstring as well I think.

Suggested change
leak_list = list()
leak_bits = bitstring.Bits(bin=self.LEAK_I_RAW)
# Each Leak field is 10 bits long
leak_bit_length = 10
# There are 64 leak fields
num_leak_fields = 64
# The leak fields appear in the packet in ascending order, so to append
# the leak fields in the correct order, the binary will be parsed
# from right to left.
for leak_idx in range(leak_bit_length * num_leak_fields, 0, -leak_bit_length):
leak_list.append(leak_bits[leak_idx - leak_bit_length:leak_idx].uint)
self.LEAK_I = np.array(leak_list)
# Each Leak field is 10 bits long
leak_bit_length = 10
# There are 64 leak fields
num_leak_fields = 64
self.LEAK_I = np.empty(num_leak_fields, dtype=np.uint16)
# The leak fields appear in the packet in ascending order, so to append
# the leak fields in the correct order, the binary will be parsed
# from right to left.
for i, leak_idx in enumerate(range(leak_bit_length * num_leak_fields, 0, -leak_bit_length)):
self.LEAK_I[i] = int(self.LEAK_I_RAW[leak_idx - leak_bit_length:leak_idx], 2)
# or something like this to iterate through and then just fill backwards:
# self.LEAK_I[-i] = int(self.LEAK_I_RAW[i * leak_bit_length:(i + 1) * leak_bit_length], 2)

Also, are the bits supposed to be read in reverse as well (little-endian vs big-endian matter). Or are they just stored in reverse?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

They're just stored in reverse. There's 64 leak fields in the packet and they're ordered as leak_64, leak_63, .... so I just need to reverse the field order when I make the array

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Are we trying to move away from the bitstring library entirely?

Copy link
Collaborator

Choose a reason for hiding this comment

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

IMO we should. Let bitstring be a detail for space_packet_parser, but not bring it into imap_processing if we can avoid it. I found it to be really slow. If we need to do complicated bit manipulations then I don't see much of an issue, but everything I've seen so far is not too bad to handle ourselves. Note that bitstring has already made this a string for you, so you're sort of going back to bitstring then rather than using the original bits.

Comment on lines +46 to +47
if "SPARE" in key:
continue
Copy link
Collaborator

Choose a reason for hiding this comment

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

I wonder if there is a way to get XTCE / space packet parser to ignore a field like this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good question. I'll check the docs

)
if "SPARE" in key:
continue
if key not in attributes and "SPARE" not in key:
Copy link
Collaborator

Choose a reason for hiding this comment

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

You already checked for it above I think

Suggested change
if key not in attributes and "SPARE" not in key:
if key not in attributes:

Copy link
Contributor Author

Choose a reason for hiding this comment

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

forgot to remove that part. thanks!

Comment on lines +15 to +16
# this test. These issues were discovered / confirmed with the HIT Ops
# engineer who delivered the data.
Copy link
Collaborator

Choose a reason for hiding this comment

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

What joy :) Thanks for your patience in finding these! And especially documenting this.

Comment on lines 28 to 29
packets = decom.decom_packets(test_file.resolve(), xtce_file.resolve())
del packets[-1]
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
packets = decom.decom_packets(test_file.resolve(), xtce_file.resolve())
del packets[-1]
packets = decom.decom_packets(test_file.resolve(), xtce_file.resolve())[:-1]

del packets[-1]
pkt_idx = 0

for packet in packets:
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'd remove the pkt_idx tracking yourself and let enumerate capture it.

Suggested change
for packet in packets:
for pkt_idx, packet in enumerate(packets):

"""HIT XTCE generator"""
instrument_name = "hit"
current_directory = Path(__file__).parent
module_path = f"{current_directory}/../../imap_processing"
Copy link
Collaborator

Choose a reason for hiding this comment

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

import imap_module_path from the main package?

@sdhoyt
Copy link
Contributor Author

sdhoyt commented Feb 15, 2024

I'm getting a "Too many statements" ruff error (PLR0915) because of the length of my test_houskeeping.py unit test function. Is this something we think can be ignored or should I break this test up? It seems weird to spread testing class attributes across multiple functions.

@greglucas
Copy link
Collaborator

greglucas commented Feb 15, 2024

I'm getting a "Too many statements" ruff error (PLR0915) because of the length of my test_houskeeping.py unit test function. Is this something we think can be ignored or should I break this test up? It seems weird to spread testing class attributes across multiple functions.

Yes, you can ignore it IMO. But, if you're looking to reduce boilerplate you have to write you could do something like this for many of those assertions:

# Turn this
assert hk.LAST_BAD_CMD == validation_data["LAST_BAD_CMD"][pkt_idx]
# into:
keys = ["LAST_BAD_CMD", ...]
for key in keys:
    assert getattr(hk, key) == validation_data[key][pkt_idx]

l0.hit_l1a_decom
l0.data_classes
l0.utils
l0.hit_l1a_decom.py
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think the extra .py might be causing the doc build failure.

Suggested change
l0.hit_l1a_decom.py
l0.hit_l1a_decom

Comment on lines 89 to 94
# Need to create an array out of the separate leak columns in the
# validation data
assert (
hk.LEAK_I
== np.array(validation_data.loc[pkt_idx, leak_columns].tolist())
).all()
Copy link
Collaborator

Choose a reason for hiding this comment

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

Definitely a nit, so feel free to ignore, but I would pull this out and test it individually before the loop since this is only one odd-ball. Also, numpy has nice array testing utilities, which will also print out which entries are failing if you want to start using those for the array tests too.

Suggested change
# Need to create an array out of the separate leak columns in the
# validation data
assert (
hk.LEAK_I
== np.array(validation_data.loc[pkt_idx, leak_columns].tolist())
).all()
# Need to create an array out of the separate leak columns in the
# validation data
np.testing.assert_array_equal(hk.LEAK_I, validation_data.loc[pkt_idx, leak_columns])

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's cool, I didn't realize numpy had the testing module

Copy link
Collaborator

Choose a reason for hiding this comment

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

Do you want to keep the I-ALiRT definition in the repo? @laspsandoval might want to reference it and keep it in, although I think she is creating a new one manually from these as reference so this might not be explicitly needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I can remove the packet definition. I forgot to ignore it when I did one of the xtce generations.

Copy link
Collaborator

@greglucas greglucas left a comment

Choose a reason for hiding this comment

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

Looks good to me. Just need to fix the doc build.

Copy link
Contributor

@maxinelasp maxinelasp left a comment

Choose a reason for hiding this comment

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

Looks good!



@dataclass
class HITBase:
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice, I like this

@@ -50,11 +47,11 @@
<xtce:Parameter name="PKT_LEN" parameterTypeRef="UINT16">
<xtce:LongDescription>CCSDS Packet Length (number of bytes after Packet length minus 1)</xtce:LongDescription>
</xtce:Parameter>
<xtce:Parameter name="SHCOARSE" parameterTypeRef="UINT32">
<xtce:ShortDescription>CCSDS Packet Sec Header</xtce:ShortDescription>
<xtce:Parameter name="SC_TICK" parameterTypeRef="UINT32">
Copy link
Contributor

Choose a reason for hiding this comment

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

I thought SHCOARSE or MET was required - is it missing here because it's a housekeeping packet?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No you're correct. HIT is calling it SC_TICK in their Telem definition and I guess I forgot to change it back to SHCOARSE when I got an updated definition sheet and re-generated the XTCE. I'm going to remove all the HIT XTCE that isn't housekeeping.

@@ -63,7 +71,7 @@
<xtce:LongDescription>CCSDS Packet Length (number of bytes after Packet length minus 1)</xtce:LongDescription>
</xtce:Parameter>
<xtce:Parameter name="SHCOARSE" parameterTypeRef="UINT32">
Copy link
Contributor

Choose a reason for hiding this comment

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

But here, it's still named SHCOARSE? Why?

Copy link
Contributor Author

@sdhoyt sdhoyt Feb 19, 2024

Choose a reason for hiding this comment

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

Yeah, I did remember to change the updated sheet to SHCOARSE for housekeeping since this is the one I was working on for this PR. Going to remove all non-hk xtce for this PR

)
xtce_file = imap_module_directory / "hit/packet_definitions/P_HIT_HSKP.xml"

validation_data = pd.read_csv(validation_file)
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice, I like this method of validation

@sdhoyt sdhoyt merged commit 4195b8f into IMAP-Science-Operations-Center:dev Feb 19, 2024
17 checks passed
@sdhoyt sdhoyt deleted the hit-housekeeping branch February 19, 2024 22:41
laspsandoval pushed a commit to laspsandoval/imap_processing that referenced this pull request Apr 2, 2024
* added housekeeping data class

* added docstrings

* removed unneeded import

* updated variable names

* fixed line lengths

* fixed line lengths

* comment updates

* doc fix attempt

* updated hk unit test

* comment fixes

* comment fix

* removed all hit non-hk xtce
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants