def from_state_vectors(cls, pos: TypeVar_NumPy3DArray, vel: TypeVar_NumPy3DArray, epoch: TypeVar_DateTime, name="UNNAMED SATELLITE") -> object: """ Creates an instance of Orbit object, using both position and velocity vectors at given epoch :param pos: vector of position, in GCRS rect frame, at given epoch. units: ([m], [m], [m]) :param vel: vector of velocity, in GCRS rect frame, at given epoch. units: ([m/s], [m/s], [m/s]) :param epoch: corresponding epoch :type pos: NumPy 3D array :type vel: NumPy 3D array :type epoch: Arrow object :returns: Orbit object """ x = np.array([1, 0, 0]) z = np.array([0, 0, 1]) kinetic = np.cross(pos, vel) kinetic_sq = kinetic.dot(kinetic) pos_dir = Maths.normalize_vect(pos) ecc_vec = np.cross(vel, kinetic) / Orbit.MU_EARTH - pos_dir minusy_ellipse = np.cross(kinetic, ecc_vec) * (-1) e = np.linalg.norm(ecc_vec) # [1] ee = e * e eee = ee * e eeee = eee * e i = Maths.angle_vects(z, kinetic) # [rad] nu = Maths.angle_vects(pos_dir, ecc_vec) raan = Maths.angle_vects(x, minusy_ellipse) # [rad] argp = Maths.angle_vects(minusy_ellipse, ecc_vec) # [rad] a = kinetic_sq / Orbit.MU_EARTH / (1 - e * e) aaa = a * a * a n = np.sqrt(Orbit.MU_EARTH / aaa) # [rad/s] M = (nu - 2 * e * np.sin(nu) + (3 / 4 * ee + 1 / 8 * eeee) * np.sin(2 * nu) - 1 / 3 * eee * np.sin(3 * nu) + 5 / 32 * eeee * np.sin(4 * nu)) return cls(epoch, e, np.rad2deg(i), np.rad2deg(raan), np.rad2deg(argp), n * 86400 / Maths.TWOPI, np.rad2deg(M), "idk")
def push_target_limbs_vel(self, epoch: TypeVar_DateTime): """ Pushes a target at given epoch. Direction is: LIMBS and colinear to velocity. :param epoch: Epoch when the satellite has to be pointing to target :type epoch: Arrow object """ ts = self.simulation.get_closest_timestamp(epoch) target = ts["sat_vel_gcrs"] target_quat = Maths.get_orientation_quat(target) return self.push_target(epoch, target_quat)
def push_target_nadir(self, epoch: TypeVar_DateTime): """ Pushes a target at given epoch. Direction is: NADIR. :param epoch: Epoch when the satellite has to be pointing to target :type epoch: Arrow object """ ts = self.simulation.get_closest_timestamp(epoch) target = -1 * ts["sat_pos_gcrs"] target_quat = Maths.get_orientation_quat(target) return self.push_target(epoch, target_quat)
def rot_qsw(self, start_quat: TypeVar_NumPy3DArray, target_quat: TypeVar_NumPy3DArray, unix_target: int): """ From a direction and a target, returns the quaternion corresponding in QSW frame of satellite :param start_quat: Orientation quaternion corresponding to start direction :type start_quat: pyquaternion object :param target_quat: Orientation quaternion corresponding to target direction :type target_quat: pyquaternion object :param unix_target: Unixepoch when the satellite has to be pointing to target [s] :type unix_target: int :return: Dictionary containing the infos for rotation, and quaternion in QSW frame """ rot_in_gcrs = target_quat * start_quat.inverse # to get the rotation to make from start to target, we rotate to x axis AND apply orientation quaternion of target x = np.array([1, 0, 0]) start_dir = start_quat.rotate(x) target_dir = target_quat.rotate(x) angle_torot = Maths.angle_vects(start_dir, target_dir) time_torot = angle_torot / self.average_rotation_speed unix_start = round(unix_target - time_torot) ts_start = self.simulation.get_closest_timestamp(arrow.get(unix_start)) x_qsw = ts_start["sat_pos_gcrs"] rot_quat_sat = Maths.get_orientation_quat(x_qsw) rot_quat = rot_in_gcrs * rot_quat_sat.inverse # to get the rotation quaternion in QSW frame, we rotate to x axis AND apply orientation of target return { "qsw_quat": rot_quat, "gcrs_start_dir": start_dir, "gcrs_target_dir": target_dir, "unix_start": unix_start, "unix_stop": unix_target, "duration": time_torot }
def gps2itrs(gps_coords: TypeVar_NumPy3DArray) -> TypeVar_NumPy3DArray: """ Converts GPS coordinates, from ITRS spherical frame to ITRS rectangular frame :param gps_coords: coordinates in ITRS spherical frame to be converted (units: [m], [°], [°]) :type cartesian_coord: NumPy 3D vector :return: coordinates converted to ITRS rectangular frame :rtype: NumPy 3D array """ alt = gps_coords[0] lon = np.deg2rad(gps_coords[1]) lat = np.deg2rad(gps_coords[2]) return Maths.spherical2rectangular(np.array([alt, lon, lat]))
def bbq_check(self, rot_list: list, safe_angle: float): """ check for bbq :param rot_list: list of rotations generated with 'rot_qsw' :param safe_angle: safe angle for bbq [rad] """ bbq_alert = [] for rot in rot_list: x = rot["gcrs_start_dir"] y = rot["gcrs_target_dir"] z = np.cross(x, y) t = arrow.get(rot["unix_start"]) ts = self.simulation.get_closest_timestamp(t) s = ts["sun_pos_gcrs"] s = Maths.normalize_vect(s) alert = False angle_norm_plane = Maths.angle_vects(z, s) if angle_norm_plane > Maths.HALFPI - safe_angle: if Maths.angle_vects(x, s) < safe_angle or Maths.angle_vects( y, s) < safe_angle: alert = True else: a = np.cross(z, x) b = np.cross(y, z) if np.dot(s, a) > 0 and np.dot(s, b) > 0: alert = True if alert: bbq_alert.append(rot) return bbq_alert if len(bbq_alert) != 0 else True
def push_target_gs(self, epoch: TypeVar_DateTime, gs_name: str): """ Pushes a target at given epoch. Direction is: Given groundstation. :param epoch: Epoch when the satellite has to be pointing to target :type epoch: Arrow object :param gs_name: Name of groundstation :type gs_name: str """ ts = self.simulation.get_closest_timestamp(epoch) gs_pos_gcrs = ts["gs_pos_gcrs"][gs_name] sat_pos_gcrs = ts["sat_pos_gcrs"] target = gs_pos_gcrs - sat_pos_gcrs target_quat = Maths.get_orientation_quat(target) return self.push_target(epoch, target_quat)
def push_target_limbs_ortho(self, epoch: TypeVar_DateTime): """ Pushes a target at given epoch. Direction is: LIMBS and orthogonal to velocity. :param epoch: Epoch when the satellite has to be pointing to target :type epoch: Arrow object """ ts = self.simulation.get_closest_timestamp(epoch) sat_pos_gcrs = ts["sat_pos_gcrs"] x = sat_pos_gcrs / np.linalg.norm(sat_pos_gcrs) sat_vel_gcrs = ts["sat_vel_gcrs"] y = sat_vel_gcrs / np.linalg.norm(sat_vel_gcrs) target = np.cross(x, y) target_quat = Maths.get_orientation_quat(target) return self.push_target(epoch, target_quat)
def pos_gps(self, epoch: TypeVar_DateTime) -> TypeVar_NumPy3DArray: """ Compute position (in ITRS spherical frame, aka. GPS coordinates) corresponding at given epoch :param epoch: corresponding epoch :type epoch: Arrow object :return: NumPy 3D vector of position in GPS coordinates (radius, longitude, latitude). units: ([m], [°], [°]) :rtype: NumPy 3D array """ pos_itrs = self.pos_itrs(epoch) pos_gps_rad = Maths.rectangular2spherical(pos_itrs) lon = np.rad2deg(pos_gps_rad[1]) lat = np.rad2deg(pos_gps_rad[2]) pos_gps = np.array([pos_gps_rad[0], lon, lat]) return pos_gps
def __init__(self, orbit: TypeVar_Orbit, start_epoch: TypeVar_DateTime, simulation_duration: int, sat_name: str, list_gs: list, list_roi: list, time_step=1, print_progress=False): """ Simulation object :param orbit: Orbit of satellite :param start_epoch: Epoch corresponding to beggining of simulation :param simulation_duration: Duration of simulation [s] :param sat_name: Satellite name :param list_gs: List containing dictionaries. Each dictionary contains infos for gs. GPS position in [°], visibility angle in [rad] :param list_roi: List containing the .bmp file names used to create each ROI :param time_step: Time step of simulation. Warning: should not be set to less than one! :param print_progress: if 'True', writes in the console progress of simulation computation :type sat_gp_dict: dict :type start_epoch: Arrow object :type simulation_duration: int :type sat_name: str :type list_gs: list :type list_rois: list :type time_step: float :type print_progress: bool """ start_chrono = time.process_time() self.start_epoch = start_epoch self.stop_epoch = self.start_epoch.shift(seconds=simulation_duration) self.simulation_duration = simulation_duration self.gs = list_gs self.roi = [] for roi_fn in list_roi: # converts the huge matrix containing pixels of image in a list of coordinates corresponding to area if roi_fn.endswith(".bmp"): roi_name = roi_fn.replace( ".bmp", "" ) # get the name of the file (it will be the ROI name inside script) img_as_matrix = mpimg.imread( roi_fn) # read the image using Matplotlib, as a matrix r = img_as_matrix[:, :, 0] g = img_as_matrix[:, :, 1] bool_roi = r != g r = {"name": roi_name, "img": bool_roi} self.roi.append(r) self.body_radius = { # [m] "earth": 6371000.0, "sun": 696340000.0, "moon": 1737100.0 } self.dist_from_earth = { # [m] "moon": 384400000.0, "sun": 149600000000.0 } self.time_step = time_step self.satellite = orbit self.sun = SunOrbit( start_epoch) # orbit for Sun at beggining of simulation self.moon = MoonOrbit( start_epoch) # orbit for Moon at beggining of simulation self.semi_angular_size = { "earth": np.arcsin(self.body_radius["earth"] / self.satellite.orbital_elements["semi_major_axis"]), "sun": np.arcsin(self.body_radius["sun"] / self.dist_from_earth["sun"]), "moon": np.arcsin(self.body_radius["moon"] / self.dist_from_earth["moon"]) } self.total_steps = int(simulation_duration / self.time_step) self.timestamps = [] gs_visi_values = { } # handling successive visibility values for event computation gs_pos_gcrs = {} self.gs_events = {} # events for each groundstation roi_visi_values = { } # handling successive visibility values for event computation self.roi_events = {} # events for each region of interest for el in self.gs: # initialising dict for gs gs_name = el["name"] gs_visi_values[gs_name] = False self.gs_events[gs_name] = [] for el in self.roi: # initialising dict for roi roi_name = el["name"] roi_visi_values[roi_name] = False self.roi_events[roi_name] = [] sun_visi_value = False # handling successive visibility values for event computation moon_visi_value = False # same huh self.sun_events = [] self.moon_events = [] nb_bars = 64 # variable for printing in console if print_progress: print("Simulation for '{}' beggining:".format(sat_name)) print("░" * nb_bars, end="", flush=True) for step in range( 0, self.total_steps ): # computation for every frame (length of 1s if step not modified) if print_progress: if step % 3600 == 0: bars_prog = int(step / self.total_steps * nb_bars) txt_prog = "█" * bars_prog print("\r" + txt_prog, end="", flush=True) epoch = self.start_epoch.shift(seconds=step * self.time_step) sat_posvel_gcrs_dict = self.satellite.pos_vel_gcrs(epoch) sat_pos_gcrs = sat_posvel_gcrs_dict["position"] sat_vel_gcrs = sat_posvel_gcrs_dict["velocity"] sat_pos_itrs = self.satellite.gcrs2itrs(sat_pos_gcrs, epoch) sat_pos_itrs_sphe = Maths.rectangular2spherical(sat_pos_itrs) r = sat_pos_itrs_sphe[0] # [m] lon = np.rad2deg(sat_pos_itrs_sphe[1]) # [°] lat = np.rad2deg(sat_pos_itrs_sphe[2]) # [°] sat_pos_gps = np.array([r, lon, lat]) sun_pos_gcrs = self.sun.pos_gcrs(epoch) moon_pos_gcrs = self.moon.pos_gcrs(epoch) sun_visi = self.check_visibility_star( sat_pos_gcrs, sun_pos_gcrs, self.semi_angular_size["sun"]) moon_visi = self.check_visibility_star( sat_pos_gcrs, moon_pos_gcrs, self.semi_angular_size["moon"]) self.computing_events(self.sun_events, sun_visi_value, sun_visi, step, "sun") self.computing_events(self.moon_events, moon_visi_value, moon_visi, step, "moon") sun_visi_value = sun_visi moon_visi_value = moon_visi for el in self.gs: gs_name = el["name"] gs_gps = np.array([el["distance"], el["lon"], el["lat"]]) gs_itrs = Orbit.gps2itrs(gs_gps) last_visi = gs_visi_values[gs_name] curr_visi = self.check_gs_visibility( sat_pos_itrs, gs_itrs, el["semi_angle_visibility"]) self.computing_events(self.gs_events[gs_name], last_visi, curr_visi, step, gs_name) # updating list of events... gs_visi_values[ gs_name] = curr_visi # overwrite last visibility gs_pos_gcrs[gs_name] = Orbit.itrs2gcrs(gs_itrs, epoch) for el in self.roi: roi_name = el["name"] last_visi = roi_visi_values[roi_name] curr_visi = self.check_above_roi(sat_pos_gps, el["img"]) self.computing_events(self.roi_events[roi_name], last_visi, curr_visi, step, roi_name) roi_visi_values[roi_name] = curr_visi # overwrite last visi timestamp = { "sat_pos_gcrs": sat_pos_gcrs, "sat_pos_itrs": sat_pos_itrs, "sat_pos_gps": sat_pos_gps, "sat_vel_gcrs": sat_vel_gcrs, "moon_pos_gcrs": moon_pos_gcrs, "moon_visibility": moon_visi, "sun_pos_gcrs": sun_pos_gcrs, "sun_visibility": sun_visi, "gs_visibilities": gs_visi_values, "gs_pos_gcrs": gs_pos_gcrs, "roi_visibilities": roi_visi_values } self.timestamps.append(timestamp) self.computation_duration = time.process_time( ) - start_chrono # time ellapsed for program to compute all the timestamps [s] if print_progress: print( "\nDone! Time ellapsed during computation: {} seconds".format( self.computation_duration))