def test_radec_eci_multidim(shape): """Test radec_to_eci and eci_to_radec for multidimensional inputs""" ras = np.linspace(0., 359., 24) decs = np.linspace(-90., 90., 24) ras_nd = ras.reshape(shape) decs_nd = decs.reshape(shape) # First do everything as scalars ecis_list = [ radec_to_eci(ra, dec) for ra, dec in zip(ras.tolist(), decs.tolist()) ] ecis_nd_from_list = np.array(ecis_list).reshape(shape + (3, )) ecis = radec_to_eci(ras_nd, decs_nd) assert ecis.shape == shape + (3, ) assert np.allclose(ecis, ecis_nd_from_list) ras_rt, decs_rt = eci_to_radec(ecis) assert ras_rt.shape == shape assert decs_rt.shape == shape assert np.allclose(ras_rt, ras_nd) assert np.allclose(decs_rt, decs_nd)
def _deltas_vs_obc_quat(vals, times, catalog): # Misalign is the identity matrix because this is the OBC quaternion aca_misalign = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) q_att = Quat(q=np.array([ vals['AOATTQT1'], vals['AOATTQT2'], vals['AOATTQT3'], vals['AOATTQT4'] ]).transpose()) Ts = q_att.transform acqs = catalog R2A = 206264.81 dy = {} dz = {} yag = {} zag = {} star_info = {} for slot in range(0, 8): if slot not in acqs['slot']: continue agasc_id = acqs[acqs['slot'] == slot][0]['id'] if agasc_id is None: logger.info("No agasc id for slot {}, skipping".format(slot)) continue try: # This is not perfect for star catalogs for agasc 1.4 and 1.5 star = agasc.get_star(agasc_id, date=times[0], use_supplement=False) except: logger.info("agasc error on slot {}:{}".format( slot, sys.exc_info()[0])) continue ra = star['RA_PMCORR'] dec = star['DEC_PMCORR'] star_pos_eci = radec_to_eci(ra, dec) d_aca = np.dot(np.dot(aca_misalign, Ts.transpose(0, 2, 1)), star_pos_eci).transpose() yag[slot] = np.arctan2(d_aca[:, 1], d_aca[:, 0]) * R2A zag[slot] = np.arctan2(d_aca[:, 2], d_aca[:, 0]) * R2A dy[slot] = vals['AOACYAN{}'.format(slot)] - yag[slot] dz[slot] = vals['AOACZAN{}'.format(slot)] - zag[slot] star_info[slot] = star return dy, dz, star_info, yag, zag
def calc_residuals(self): """ Calculate residuals based on attitude and ra/dec of star. Note that the sampling and times of yags may be different from zags so these should be done independently. Residuals are available in self.dyags and self.dzags. Predicted values from attitude and star position in self.pred_yags and self.pred_zags """ # If time offsets weren't applied because centroids were initialized before atts, try again if self.centroid_dt is None: self.set_offsets() # If still not set, warn if self.centroid_dt is None: warnings.warn( "Residuals calculated on centroids without time offsets applied" ) if len(self.att_times) < 2: raise ValueError( "Cannot attempt to calculate residuals with fewer than 2 attitude samples" ) eci = transform.radec_to_eci(self.ra, self.dec) # Transform the 3x3 to get the axes to align to have the dot product make sense d_aca = np.dot(Quat(q=self.atts).transform.transpose(0, 2, 1), eci) p_yags = np.arctan2(d_aca[:, 1], d_aca[:, 0]) * R2A p_zags = np.arctan2(d_aca[:, 2], d_aca[:, 0]) * R2A self.pred_yags = interpolate(p_yags, self.att_times, self.yag_times, sorted=True) self.pred_zags = interpolate(p_zags, self.att_times, self.zag_times, sorted=True) self.dyags = self.yags - self.pred_yags self.dzags = self.zags - self.pred_zags
def test_radec_to_eci(): eci = radec_to_eci(10, 20) assert np.allclose(eci[0], 0.92541658) assert np.allclose(eci[1], 0.16317591) assert np.allclose(eci[2], 0.34202014) assert isinstance(eci, np.ndarray)