Skip to content
Snippets Groups Projects
Commit 54657748 authored by AustinSanders's avatar AustinSanders Committed by GitHub
Browse files

Added initial nadir pointing (#332)


* Added nadir orientation calculation to frame_chain

* Added comments, replaced conditional dict access, replaced hard-coded bool for nadir parameter.

* Updated orientation to be obtained from the frame chain and added tests

* Updated the frame trace returns if nadir is true and propogated those changes to the frame chain from_spice function

* Updated focal2pixel_lines test for the time being

Co-authored-by: default avatarAdam Paquette <acpaquette@usgs.gov>
parent 910a04f2
No related branches found
No related tags found
No related merge requests found
...@@ -392,12 +392,39 @@ class NaifSpice(): ...@@ -392,12 +392,39 @@ class NaifSpice():
@property @property
def frame_chain(self): def frame_chain(self):
if not hasattr(self, '_frame_chain'): if not hasattr(self, '_frame_chain'):
nadir = self._props.get('nadir', False)
self._frame_chain = FrameChain.from_spice(sensor_frame=self.sensor_frame_id, self._frame_chain = FrameChain.from_spice(sensor_frame=self.sensor_frame_id,
target_frame=self.target_frame_id, target_frame=self.target_frame_id,
center_ephemeris_time=self.center_ephemeris_time, center_ephemeris_time=self.center_ephemeris_time,
ephemeris_times=self.ephemeris_time) ephemeris_times=self.ephemeris_time,
nadir=nadir)
if nadir:
# Logic for nadir calculation was taken from ISIS3
# SpiceRotation::setEphemerisTimeNadir
rotation = self._frame_chain.compute_rotation(self.target_frame_id, 1)
p_vec, v_vec, times = self.sensor_position
rotated_positions = rotation.apply_at(p_vec, times)
rotated_velocities = rotation.rotate_velocity_at(p_vec, v_vec, times)
p_vec = rotated_positions
v_vec = rotated_velocities
velocity_axis = 2
trans_x = self.focal2pixel_lines
if (trans_x[0] < trans_x[1]):
velocity_axis = 1
quats = [spice.m2q(spice.twovec(-p_vec[i], 3, v_vec[i], velocity_axis)) for i, time in enumerate(times)]
quats = np.array(quats)[:,[1,2,3,0]]
rotation = TimeDependentRotation(quats, times, 1, self.sensor_frame_id)
self._frame_chain.add_edge(rotation)
return self._frame_chain return self._frame_chain
@property @property
def sensor_orientation(self): def sensor_orientation(self):
""" """
...@@ -405,7 +432,7 @@ class NaifSpice(): ...@@ -405,7 +432,7 @@ class NaifSpice():
to be defined. This must be a floating point number containing the to be defined. This must be a floating point number containing the
ephemeris time. Expects instrument_id to be defined. This must be a string ephemeris time. Expects instrument_id to be defined. This must be a string
containing the short name of the instrument. Expects reference frame to be defined. containing the short name of the instrument. Expects reference frame to be defined.
This must be a sring containing the name of the target reference frame. This must be a string containing the name of the target reference frame.
Returns Returns
------- -------
...@@ -413,18 +440,7 @@ class NaifSpice(): ...@@ -413,18 +440,7 @@ class NaifSpice():
Quaternions describing the orientation of the sensor Quaternions describing the orientation of the sensor
""" """
if not hasattr(self, '_orientation'): if not hasattr(self, '_orientation'):
ephem = self.ephemeris_time self._orientation = self.frame_chain.compute_rotation(self.sensor_frame_id, self.target_frame_id).quats
qua = np.empty((len(ephem), 4))
for i, time in enumerate(ephem):
# Find the rotation matrix
camera2bodyfixed = spice.pxform(self.instrument_id,
self.reference_frame,
time)
q = spice.m2q(camera2bodyfixed)
qua[i,:3] = q[1:]
qua[i,3] = q[0]
self._orientation = qua
return self._orientation.tolist() return self._orientation.tolist()
@property @property
......
...@@ -142,10 +142,7 @@ class LroLrocPds3LabelNaifSpiceDriver(LineScanner, NaifSpice, Pds3Label, Driver) ...@@ -142,10 +142,7 @@ class LroLrocPds3LabelNaifSpiceDriver(LineScanner, NaifSpice, Pds3Label, Driver)
focal plane to detector lines focal plane to detector lines
""" """
focal2pixel_lines = np.array(list(spice.gdpool('INS{}_ITRANSL'.format(self.ikid), 0, 3))) focal2pixel_lines = np.array(list(spice.gdpool('INS{}_ITRANSL'.format(self.ikid), 0, 3)))
if self.spacecraft_direction < 0:
return focal2pixel_lines return focal2pixel_lines
else:
return -focal2pixel_lines
@property @property
def ephemeris_start_time(self): def ephemeris_start_time(self):
...@@ -402,10 +399,7 @@ class LroLrocIsisLabelNaifSpiceDriver(LineScanner, NaifSpice, IsisLabel, Driver) ...@@ -402,10 +399,7 @@ class LroLrocIsisLabelNaifSpiceDriver(LineScanner, NaifSpice, IsisLabel, Driver)
focal plane to detector lines focal plane to detector lines
""" """
focal2pixel_lines = np.array(list(spice.gdpool('INS{}_ITRANSL'.format(self.ikid), 0, 3))) focal2pixel_lines = np.array(list(spice.gdpool('INS{}_ITRANSL'.format(self.ikid), 0, 3)))
if self.spacecraft_direction < 0:
return focal2pixel_lines return focal2pixel_lines
else:
return -focal2pixel_lines
@property @property
def multiplicative_line_error(self): def multiplicative_line_error(self):
......
...@@ -96,12 +96,12 @@ class FrameChain(nx.DiGraph): ...@@ -96,12 +96,12 @@ class FrameChain(nx.DiGraph):
of frame rotations in the frame chain of frame rotations in the frame chain
""" """
@classmethod @classmethod
def from_spice(cls, *args, sensor_frame, target_frame, center_ephemeris_time, ephemeris_times=[], **kwargs): def from_spice(cls, sensor_frame, target_frame, center_ephemeris_time, ephemeris_times=[], nadir=False):
frame_chain = cls() frame_chain = cls()
times = np.array(ephemeris_times) times = np.array(ephemeris_times)
sensor_time_dependent_frames, sensor_constant_frames = cls.frame_trace(sensor_frame, center_ephemeris_time) sensor_time_dependent_frames, sensor_constant_frames = cls.frame_trace(sensor_frame, center_ephemeris_time, nadir)
target_time_dependent_frames, target_constant_frames = cls.frame_trace(target_frame, center_ephemeris_time) target_time_dependent_frames, target_constant_frames = cls.frame_trace(target_frame, center_ephemeris_time)
time_dependent_frames = list(zip(sensor_time_dependent_frames[:-1], sensor_time_dependent_frames[1:])) time_dependent_frames = list(zip(sensor_time_dependent_frames[:-1], sensor_time_dependent_frames[1:]))
...@@ -139,11 +139,14 @@ class FrameChain(nx.DiGraph): ...@@ -139,11 +139,14 @@ class FrameChain(nx.DiGraph):
return frame_chain return frame_chain
@staticmethod @staticmethod
def frame_trace(reference_frame, ephemeris_time): def frame_trace(reference_frame, ephemeris_time, nadir=False):
frame_codes = [reference_frame] frame_codes = [reference_frame]
_, frame_type, _ = spice.frinfo(frame_codes[-1]) _, frame_type, _ = spice.frinfo(frame_codes[-1])
frame_types = [frame_type] frame_types = [frame_type]
if nadir:
return [], []
while(frame_codes[-1] != 1): while(frame_codes[-1] != 1):
try: try:
center, frame_type, frame_type_id = spice.frinfo(frame_codes[-1]) center, frame_type, frame_type_id = spice.frinfo(frame_codes[-1])
......
...@@ -101,6 +101,25 @@ class test_data_naif(unittest.TestCase): ...@@ -101,6 +101,25 @@ class test_data_naif(unittest.TestCase):
assert len(times) == 1 assert len(times) == 1
np.testing.assert_allclose(times[0], 297088762.61698407) np.testing.assert_allclose(times[0], 297088762.61698407)
def test_sensor_orientation(self):
self.driver.ephemeris_time = [297088762.61698407]
self.driver._props = {}
orientation = self.driver.sensor_orientation
np.testing.assert_allclose(orientation[0], [0.08410784798989432, 0.017724689780841133, 0.9945884195952942, 0.058357355025882435])
def test_sensor_position(self):
self.driver.ephemeris_time = [297088762.61698407]
positions, velocities, times = self.driver.sensor_position
np.testing.assert_allclose(positions[0], [-616295.93509894, -97815.27289939, -3573807.40392374])
np.testing.assert_allclose(velocities[0], [-3386.49396159, 411.4392769, 564.95648816])
np.testing.assert_allclose(times[0], 297088762.61698407)
def test_nadir_sensor_orientation(self):
self.driver.ephemeris_time = [297088762.61698407]
self.driver._props = {'nadir': True}
orientation = self.driver.sensor_orientation
np.testing.assert_allclose(orientation[0], [-0.08443224924851939, -0.017974644466439982, -0.9949019866167608, -0.052135827116906064])
def test_light_time_correction_keyword(): def test_light_time_correction_keyword():
with patch('ale.base.data_naif.spice.gcpool', return_value=['NONE']) as gcpool, \ with patch('ale.base.data_naif.spice.gcpool', return_value=['NONE']) as gcpool, \
patch('ale.base.data_naif.NaifSpice.ikid', new_callable=PropertyMock) as ikid: patch('ale.base.data_naif.NaifSpice.ikid', new_callable=PropertyMock) as ikid:
......
...@@ -292,7 +292,7 @@ class test_pds_naif(unittest.TestCase): ...@@ -292,7 +292,7 @@ class test_pds_naif(unittest.TestCase):
spacecraft_direction.return_value = -1 spacecraft_direction.return_value = -1
np.testing.assert_array_equal(self.driver.focal2pixel_lines, [0, 1, 0]) np.testing.assert_array_equal(self.driver.focal2pixel_lines, [0, 1, 0])
spacecraft_direction.return_value = 1 spacecraft_direction.return_value = 1
np.testing.assert_array_equal(self.driver.focal2pixel_lines, [0, -1, 0]) np.testing.assert_array_equal(self.driver.focal2pixel_lines, [0, 1, 0])
# ========= Test isislabel and naifspice driver ========= # ========= Test isislabel and naifspice driver =========
...@@ -383,4 +383,4 @@ class test_isis_naif(unittest.TestCase): ...@@ -383,4 +383,4 @@ class test_isis_naif(unittest.TestCase):
spacecraft_direction.return_value = -1 spacecraft_direction.return_value = -1
np.testing.assert_array_equal(self.driver.focal2pixel_lines, [0, 1, 0]) np.testing.assert_array_equal(self.driver.focal2pixel_lines, [0, 1, 0])
spacecraft_direction.return_value = 1 spacecraft_direction.return_value = 1
np.testing.assert_array_equal(self.driver.focal2pixel_lines, [0, -1, 0]) np.testing.assert_array_equal(self.driver.focal2pixel_lines, [0, 1, 0])
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment