def from_spice(cls, *args, sensor_frame, target_frame, center_ephemeris_time, ephemeris_times=[], **kwargs): frame_chain = cls() times = np.array(ephemeris_times) sensor_time_dependent_frames, sensor_constant_frames = cls.frame_trace( sensor_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:])) constant_frames = list( zip(sensor_constant_frames[:-1], sensor_constant_frames[1:])) target_time_dependent_frames = list( zip(target_time_dependent_frames[:-1], target_time_dependent_frames[1:])) target_constant_frames = list( zip(target_constant_frames[:-1], target_constant_frames[1:])) time_dependent_frames.extend(target_time_dependent_frames) constant_frames.extend(target_constant_frames) for s, d in time_dependent_frames: quats = np.zeros((len(times), 4)) avs = np.zeros((len(times), 3)) for j, time in enumerate(times): state_matrix = spice.sxform(spice.frmnam(s), spice.frmnam(d), time) rotation_matrix, avs[j] = spice.xf2rav(state_matrix) quat_from_rotation = spice.m2q(rotation_matrix) quats[j, :3] = quat_from_rotation[1:] quats[j, 3] = quat_from_rotation[0] rotation = TimeDependentRotation(quats, times, s, d, av=avs) frame_chain.add_edge(rotation=rotation) for s, d in constant_frames: quats = np.zeros(4) rotation_matrix = spice.pxform(spice.frmnam(s), spice.frmnam(d), times[0]) quat_from_rotation = spice.m2q(rotation_matrix) quats[:3] = quat_from_rotation[1:] quats[3] = quat_from_rotation[0] rotation = ConstantRotation(quats, s, d) frame_chain.add_edge(rotation=rotation) return frame_chain
def frame_chain(self): """ Return the root node of the rotation frame tree/chain. The root node is the J2000 reference frame. The other nodes in the tree can be accessed via the methods in the FrameNode class. This property expects the ephemeris_time property/attribute to be defined. It should be a list of the ephemeris seconds past the J2000 epoch for each exposure in the image. Returns ------- FrameNode The root node of the frame tree. This will always be the J2000 reference frame. """ if not hasattr(self, '_root_frame'): j2000_id = 1 #J2000 is our root reference frame self._root_frame = FrameNode(j2000_id) sensor_quats = np.zeros((len(self.ephemeris_time), 4)) sensor_times = np.array(self.ephemeris_time) body_quats = np.zeros((len(self.ephemeris_time), 4)) body_times = np.array(self.ephemeris_time) for i, time in enumerate(self.ephemeris_time): sensor2j2000 = spice.pxform(spice.frmnam(self.sensor_frame_id), spice.frmnam(j2000_id), time) q_sensor = spice.m2q(sensor2j2000) sensor_quats[i, :3] = q_sensor[1:] sensor_quats[i, 3] = q_sensor[0] body2j2000 = spice.pxform(spice.frmnam(self.target_frame_id), spice.frmnam(j2000_id), time) q_body = spice.m2q(body2j2000) body_quats[i, :3] = q_body[1:] body_quats[i, 3] = q_body[0] sensor2j2000_rot = TimeDependentRotation(sensor_quats, sensor_times, self.sensor_frame_id, j2000_id) sensor_node = FrameNode(self.sensor_frame_id, parent=self._root_frame, rotation=sensor2j2000_rot) body2j2000_rot = TimeDependentRotation(body_quats, body_times, self.target_frame_id, j2000_id) body_node = FrameNode(self.target_frame_id, parent=self._root_frame, rotation=body2j2000_rot) return self._root_frame
def info(self): """Read and Output info about the loaded kernels """ spice.kclear() spice.furnsh(self.metakernel) self.spkList = [ self.SpkPlanet, self.SpkEros, self.SpkEros2, self.SpkMath, self.SpkNearLanded, self.SpkNearOrbit, self.SpkStations ] self.ckList = [self.Ck] self.pckList = [self.PckEros1, self.PckEros2] # check SPK coverage self.bodies = {} self.bodies_coverage = {} for spk in self.spkList: idcell = spice.spkobj(spk) for code in idcell: cover = spice.stypes.SPICEDOUBLE_CELL(1000) spice.spkcov(spk, code, cover) self.bodies[str(code)] = spice.bodc2n(code) self.bodies[spice.bodc2n(code)] = code self.bodies_coverage[str(code)] = [x for x in cover] self.bodies_coverage[spice.bodc2n(code)] = [x for x in cover] # check CK coverage self.ckframes = {} self.ckframes_coverage = {} for ck in self.ckList: idcell = spice.ckobj(ck) for code in idcell: cover = spice.ckcov(ck, code, True, 'SEGMENT', 0.0, 'TDB') self.ckframes[str(code)] = spice.frmnam(code) self.ckframes[spice.frmnam(code)] = code self.ckframes_coverage[str(code)] = [x for x in cover] self.ckframes_coverage[spice.frmnam(code)] = [x for x in cover] # check pck coverage self.pckframes = {} for pck in self.pckList: ids = spice.stypes.SPICEINT_CELL(1000) spice.pckfrm(pck, ids) for code in ids: self.pckframes[str(code)] = spice.frmnam(code) self.pckframes[spice.frmnam(code)] = code spice.kclear()
def target2frame(target): if target == '67P/C-G': target_frame = '67P/C-G_CK' elif target == '21 LUTETIA': target_frame = 'LUTETIA_FIXED' elif target == 'DIDYMOS' or target == 'DIDYMOON': target_frame = '{}_FIXED'.format(target) else: try: target_frame = 'IAU_' + target.upper() target_frame_id = spiceypy.namfrm(target_frame) if target_frame_id == 0: raise Exception except: try: target_id = str(spiceypy.bodn2c(target)) target_frame = spiceypy.frmnam(int(target_id)) except: target_id += '000' target_frame = spiceypy.frmnam(int(target_id)) return target_frame
def cov_int(object_cov, object_id, kernel, time_format='TDB', global_boundary=False, report=False): """ Generates a list of time windows out of a SPICE cell for which either the SPICE API spkcov_c or ckcov_c have been run. :param object_cov: SPICE :type object_cov: :param object_id: Object ID or Name for which we provide the coverage :type object_id: Union[str, int] :param kernel: Kernel name for which the coverage is being checked :type kernel: str :param time_format: Desired output format; 'UTC' or 'CAL' :type time_format: str :param global_boundary: Boolean to indicate whether if we want all the coverage windows or only the absolute start and finish coverage times :type global_boundary: bool :param report: If True prints the resulting coverage on the screen :type report: bool :return: Time Windows in the shape of a list :rtype: list """ boundaries = False if '/' in kernel: kernel = kernel.split('/')[-1] # # Reporting should only be activated if we are not asking for global # boundaries. # if report and not global_boundary: try: body_name = spiceypy.bodc2n(object_id) except: body_name = spiceypy.frmnam(object_id, 60) print("Coverage for {} in {} [{}]:".format(body_name, kernel, time_format)) number_of_intervals = list(range(spiceypy.wncard(object_cov))) interval_start_list = [] interval_finish_list = [] coverage = [] for element in number_of_intervals: et_boundaries = spiceypy.wnfetd(object_cov, element) if time_format == 'CAL' or time_format == 'UTC': boundaries = et2cal(et_boundaries, format=time_format) else: boundaries = et_boundaries interval_start = boundaries[0] interval_finish = boundaries[1] if report and not global_boundary: print("Interval {}: {} - {}\n".format(element, boundaries[0], boundaries[1])) coverage.append(interval_start) coverage.append(interval_finish) interval_start_list.append(interval_start) interval_finish_list.append(interval_finish) # # If the global_boundary parameter is set the only output is the global # coverage start and finish # if global_boundary: start_time = min(interval_start) finish_time = max(interval_finish) coverage = et2cal([start_time, finish_time], format=time_format) return coverage