def receive_time(station_id, sc_id, sc_time, max_error=1e-7, **kwargs): t2 = sc_time if type(sc_id) == int: x2 = spice.spkez(sc_id, t2, 'J2000', 'NONE', 399)[0] else: x2 = sc_id x3 = spice.spkez(station_id, t2, 'J2000', 'NONE', 399)[0] t3 = t2 + light_time(x2, x3, **kwargs) dt = max_error * 2 while np.abs(dt) > max_error: x3 = spice.spkez(station_id, t3, 'J2000', 'NONE', 399)[0] df_dt = -1 + np.dot( (x3[0:3] - x2[0:3]) / norm(x3[0:3] - x2[0:3]), x3[3:6]) f = t3 - t2 - light_time(x2, x3, **kwargs) dt = -f / df_dt t3 += dt return t3
def send_time(station_id, sc_id, sc_time, max_error=1e-7, **kwargs): t2 = sc_time if type(sc_id) == int: x2 = spice.spkez(sc_id, t2, 'J2000', 'NONE', 399)[0] else: x2 = sc_id x1 = spice.spkez(station_id, t2, 'J2000', 'NONE', 399)[0] t1 = t2 - light_time(x1, x2, **kwargs) dt = max_error * 2 while np.abs(dt) > max_error: x1 = spice.spkez(station_id, t1, 'J2000', 'NONE', 399)[0] df_dt = -1 + np.dot( (x2[0:3] - x1[0:3]) / norm(x2[0:3] - x1[0:3]), x1[3:6]) f = t2 - t1 - light_time(x1, x2, **kwargs) dt = -f / df_dt t1 += dt return t1
def plot_lvlh_covariance(label, count=0, body_id=399, object_id=-5440, pos_vel_axes=None, snapshot_label=None): if body_id == 'earth': body_id = 399 elif body_id == 'moon': body_id = 301 if pos_vel_axes is None: pos_axes = None vel_axes = None else: pos_axes, vel_axes = pos_vel_axes P, time = LinCov.load_covariance(label, count, snapshot_label) # Get LVLH frame x_inrtl = spice.spkez(object_id, time, 'J2000', 'NONE', body_id)[0] * 1000.0 T_inrtl_to_lvlh = frames.compute_T_inrtl_to_lvlh(x_inrtl) # Transform covariance to LVLH frame P_lvlh = T_inrtl_to_lvlh.dot(P[0:6, 0:6]).dot(T_inrtl_to_lvlh.T) fig1, pos_axes = error_ellipsoid(P_lvlh[0:3, 0:3], dof=3, xlabel='downtrack (m)', ylabel='crosstrack (m)', zlabel='radial (m)', label=label, axes=pos_axes) fig2, vel_axes = error_ellipsoid(P_lvlh[3:6, 3:6], dof=3, xlabel='downtrack (m/s)', ylabel='crosstrack (m/s)', zlabel='radial (m/s)', label=label, axes=vel_axes) if label is not None: pos_axes[0].legend() vel_axes[0].legend() return (fig1, fig2), (pos_axes, vel_axes)
def ltime(t1, id1, dir, x2, gamma=1.0, mu=3.9860043543609598e5): x1 = spice.spkez(id1, t1, 'J2000', 'NONE', 399) r2 = norm(x2[0:3]) if dir == '->': r1 = norm(x1[0:3]) r12 = norm(x2[0:3] - x1[0:3]) tau12 = r12 / C + (1.0 + gamma) * (mu / C**3) * np.log( (r1 + r2 + r12) / (r1 + r2 - r12)) return t1 + tau12, tau12 elif dir == '<-': t3 = t1 r3 = norm(x1[0:3]) r23 = norm(x2[0:3] - x1[0:3]) tau23 = r23 / C + (1.0 + gamma) * (mu / C**3) * np.log( (r2 + r3 + r23) / (r2 + r3 - r23)) return t3 - tau23, tau23 else: raise ValueError("expected '<-' or '->' for dir")
def __init__(self, time, loader=None, params=None): self.loader = loader self.params = params self.mu_earth = loader.mu_earth * 1e9 self.mu_moon = loader.mu_moon * 1e9 # Ensure that ground station locations are loaded if len(State.r_station_ecef) == 0: for station in State.ground_stations: gid = self.ground_stations[station] State.r_station_ecef[station] = spice.spkezr( station, self.loader.start, 'ITRF93', 'NONE', 'earth')[0][0:3] * 1000.0 self.eci = spice.spkez(loader.object_id, time, 'J2000', 'NONE', 399)[0] * 1000.0 self.lci = spice.spkez(loader.object_id, time, 'J2000', 'NONE', 301)[0] * 1000.0 self.T_inrtl_to_body = np.identity( 3) # FIXME: Add attitude, eventually # FIXME: Need measurements here self.a_meas_inrtl = np.zeros(3) self.w_meas_inrtl = np.zeros(3) # Get distance to earth and moon self.d_earth = norm(self.eci[0:3]) self.d_moon = norm(self.lci[0:3]) # Get angular size of each self.earth_angle = 2 * np.arctan( self.loader.r_earth[2] * 1000.0 / self.d_earth) self.moon_angle = 2 * np.arctan( self.loader.r_moon[2] * 1000.0 / self.d_moon) self.earth_phase_angle = sun_spacecraft_angle('earth', time, loader.object_id) self.moon_phase_angle = sun_spacecraft_angle('moon', time, loader.object_id) # We need to be able to clearly see the planet in order to do # horizon detection. planet_occult_code = spice.occult('earth', 'ellipsoid', 'ITRF93', 'moon', 'ellipsoid', 'MOON_ME', 'NONE', str(loader.object_id), time) self.horizon_moon_enabled = False self.horizon_earth_enabled = False if planet_occult_code == 0: if self.earth_angle < self.params.horizon_fov and self.earth_phase_angle < self.params.horizon_max_phase_angle: self.horizon_earth_enabled = True if self.moon_angle < self.params.horizon_fov and self.moon_phase_angle < self.params.horizon_max_phase_angle: self.horizon_moon_enabled = True else: self.earth_angle = 0.0 self.moon_angle = 0.0 self.elevation_from = {} self.visible_from = [] self.r_station_inrtl = {} for ground_name in self.ground_stations: obj_str = str(self.loader.object_id) moon_occult_code = spice.occult( obj_str, 'point', ' ', 'moon', 'ellipsoid', 'MOON_ME', 'NONE', str(self.ground_stations[ground_name]), time) elevation = float('nan') if moon_occult_code >= 0: # get spacecraft elevation x, lt = spice.spkcpo(obj_str, time, ground_name + '_TOPO', 'OBSERVER', 'NONE', self.r_station_ecef[ground_name] / 1000.0, 'earth', 'ITRF93') r, lon, lat = spice.reclat(x[0:3]) if lat >= self.params.radiometric_min_elevation: elevation = lat self.visible_from.append(ground_name) # store elevation of spacecraft for logging purposes self.elevation_from[ground_name] = elevation self.range_earth = norm(self.eci[0:3]) self.range_moon = norm(self.lci[0:3]) self.time = time
def __init__(self, arrival_time): # Start with earth parking orbit leo = Orbit.circular(PatchedConic.mu_earth, 6378136.6 + 185000.0) # Get the state of the moon at arrival so we know how far out # we need to go and how fast. x_moon_arrive = spice.spkez(301, arrival_time, 'J2000', 'NONE', 399)[0] * 1000.0 # Produce patched conic x, pcx = pc.optimize_deltav(np.array( [49.9 * np.pi / 180.0, leo.v + 3200.0]), 1837400.0, leo.r, leo.phi, norm(x_moon_arrive[0:3]), norm(x_moon_arrive[3:6]), conjugate=True) depart_time = arrival_time - pcx.tof free_flight_sweep_angle = pcx.nu1 - pcx.nu0 # Get state of moon at departure so we can figure out the # plane of our trajectory. x_moon_depart = spice.spkez(301, depart_time, 'J2000', 'NONE', 399)[0] * 1000.0 # Get earth--moon frame at SOI arrival time rm0 = x_moon_depart[:3] rm0hat = rm0 / norm(rm0) rm1 = x_moon_arrive[:3] rm1hat = rm1 / norm(rm1) hhat = np.cross(rm0hat, rm1hat) hhat /= norm(hhat) T_eci_to_pqw = spice.twovec(rm1hat, 1, hhat, 3) # Get directions to initial and final vectors r1hat = T_eci_to_pqw.T.dot( rotate_z(pcx.gam1).dot(np.array([1.0, 0, 0]))) r0hat = T_eci_to_pqw.T.dot( rotate_z(pcx.gam1 - free_flight_sweep_angle).dot( np.array([1.0, 0.0, 0.0]))) v0hat = np.cross(hhat, r0hat) # post delta-v state: r0 = r0hat * leo.r v0 = v0hat * x[1] # pre delta-v state: v0m = v0hat * leo.v # arrival state: # r1 = r1hat * pcx.arrive.r # v1 = ? self.free_flight_sweep_angle = free_flight_sweep_angle self.depart_time = depart_time self.arrival_time = arrival_time self.x_depart_post = np.hstack((r0, v0)) self.x_depart_pre = np.hstack((r0, v0m)) self.x_moon_depart = x_moon_depart self.x_moon_arrive = x_moon_arrive self.deltav = v0 - v0m