def test_absolute_time_converter_utc_string(self): """ absolute_time_converter_utc_string tests """ self.assertTrue( orekit_utils.absolute_time_converter_utc_manual( 2020, 12, 2).isEqualTo( orekit_utils.absolute_time_converter_utc_string( '2020-12-02T00:00:00.000'))) self.assertTrue( orekit_utils.absolute_time_converter_utc_manual( 2020, 12, 2, 3).isEqualTo( orekit_utils.absolute_time_converter_utc_string( '2020-12-02T03:00:00.000'))) self.assertTrue( orekit_utils.absolute_time_converter_utc_manual( 2020, 12, 2, 3, 12).isEqualTo( orekit_utils.absolute_time_converter_utc_string( '2020-12-02T03:12:00.000'))) self.assertTrue( orekit_utils.absolute_time_converter_utc_manual( 2020, 12, 2, 3, 12, 13).isEqualTo( orekit_utils.absolute_time_converter_utc_string( '2020-12-02T03:12:13.000'))) self.assertTrue( orekit_utils.absolute_time_converter_utc_manual( 2020, 12, 2, 3, 12, 13.2).isEqualTo( orekit_utils.absolute_time_converter_utc_string( '2020-12-02T03:12:13.200')))
def calculate_position(self, generic, duration, step_count=None): """ Updates position of the satellite for some number of time steps into the future, and update the packet to contain Cartesian coordinates Args: generic (string JSON): CZML boilerplate, from the configuration in config-service duration (float): the duration of time after start that the user wishes to display, in seconds step_count (int): number of positions to include in the packet. Note - Cesium has 5th-order Lagrangian interpolation. 300.0 sec is fine """ # Default step count defined in terms of duration generic = deepcopy(generic) if step_count == None: step_count = int(duration / 300) step_size = float(duration / step_count) stop = orekit_utils.absolute_time_converter_utc_string( self.start).shiftedBy(float(duration)).toString() start = ISO8601_UTC(self.start) stop = ISO8601_UTC(stop) validate_datetime(start) validate_datetime(stop) self.packet["availability"] = f"{start}/{stop}" self.packet["position"]["epoch"] = start prop = orekit_utils.analytical_propagator(self.orbit) positions = [] for i in range(step_count): orekit_time = orekit_utils.absolute_time_converter_utc_string( start).shiftedBy(i * float(step_size)) pos = prop.getPVCoordinates(orekit_time, prop.getFrame()) pos = list(pos.position.toArray()) pos.insert(0, i * float(step_size)) positions.extend(pos) self.packet["position"]["cartesian"] = positions # TODO lead_trail_time = orekit_utils.absolute_time_converter_utc_string( start).shiftedBy(generic["lead_and_trail"]).toString() lead_trail_time = ISO8601_UTC(lead_trail_time) validate_datetime(lead_trail_time) interval = f"{start}/{lead_trail_time}" lead_and_trail = ["leadTime", "trailTime"] for lt in lead_and_trail: self.packet["path"][lt].append({}) self.packet["path"][lt][0]["interval"] = interval self.packet["path"][lt][0]["epoch"] = start self.packet["path"][lt][0]["number"] = [ 0, generic["lead_and_trail_number"], generic["lead_and_trail_number"], 0 ]
def update_packet(self, duration): """ Update the packet attributre Args: duration (float): the duration of time after start that the user wishes to display, in seconds. This should be a big number if the user doesn't want it to disappear. """ start = self.start orbit = self.sat_orbit grstn_latitude = self.grstn_location["latitude"] grstn_longitude = self.grstn_location["longitude"] grstn_altitude = self.grstn_location["altitude"] start_orekit = orekit_utils.absolute_time_converter_utc_string(start) stop_orekit = orekit_utils.absolute_time_converter_utc_string(start).shiftedBy(float(duration)) prop = orekit_utils.analytical_propagator(orbit) eclipses = orekit_utils.get_ground_passes(prop, grstn_latitude, grstn_longitude, grstn_altitude, start_orekit, stop_orekit, ploting_param=False) if len(eclipses): self.packet["polyline"]["show"].append({}) if not eclipses[0]['start']: eclipses[0]['start'] = start_orekit first_end = ISO8601_UTC(eclipses[0]['start'].toString()) validate_datetime(first_end) self.packet["polyline"]["show"][0]["interval"] = f"0000-01-01T00:00:00/{first_end}" self.packet["polyline"]["show"][0]["boolean"] = False for i,d in enumerate(eclipses): show = {} start_vis = ISO8601_UTC(d['start'].toString()) stop_vis = ISO8601_UTC(d['stop'].toString()) validate_datetime(start_vis) validate_datetime(stop_vis) visible_interval = f"{start_vis}/{stop_vis}" show["interval"] = visible_interval show["boolean"] = True self.packet["polyline"]["show"].append(show) self.packet["availability"].append(visible_interval) # only add the period after if it is with the stop time if i + 1 < len(eclipses): dont_show = {} last_interval_start = ISO8601_UTC(eclipses[i]['stop'].toString()) last_interval_stop = ISO8601_UTC(eclipses[i+1]['start'].toString()) validate_datetime(last_interval_start) validate_datetime(last_interval_stop) dont_show["interval"] = f"{last_interval_start}/{last_interval_stop}" dont_show["boolean"] = False self.packet["polyline"]["show"].append(dont_show)
def update_orbit(self, orbit): """ Generate a new orbit packet, with duration as specified in the constructor. Args: orbit (dict): A nested python dictionary with orbital parameters. """ new_date = orekit_utils.absolute_time_converter_utc_string(orbit["orbit_update_date"]) old_date = orekit_utils.absolute_time_converter_utc_string(self.orbit["orbit_update_date"]) if new_date.isAfter(old_date): self.sat_orbit = orbit
def __init__(self, generic, name, start, duration, location): """ Construct a ground station packet. Args: generic (string JSON): CZML boilerplate, from the configuration in config-service name (string): the name of the ground station the user wishes want to display start (string): the current time (from which the user wishes to display) duration (float): the duration of time after start that the user wishes to display, in seconds. This should be a big number if the user doesn't want it to disappear. location (dict): dictionary containing float latitude, longitude, and altitude of the ground station """ generic = deepcopy(generic) latitude = location["latitude"] longitude = location["longitude"] altitude = location["altitude"] self.start = start stop = orekit_utils.absolute_time_converter_utc_string(start).shiftedBy(float(duration)).toString() start = ISO8601_UTC(start) stop = ISO8601_UTC(stop) validate_datetime(start) validate_datetime(stop) _name = name.replace(" ", "_") self.packet = generic["grstn"] self.packet["id"] = f"Facility/{_name}" self.packet["name"] = _name self.packet["availability"] = f"{start}/{stop}" self.packet["position"]["cartographicDegrees"] = [float(longitude), float(latitude), float(altitude)] self.packet["label"]["text"] = name
def __init__(self, generic, start, duration): """ Generate the initial CZML packets from boilerplate Args: generic (string JSON): CZML boilerplate, from the configuration in config-service start (string): the current time (from which the user wishes to display) duration ([type]): the duration of time after start that the user wishes to display, in seconds """ generic = deepcopy(generic) stop = orekit_utils.absolute_time_converter_utc_string( start).shiftedBy(float(duration)).toString() start = ISO8601_UTC(start) stop = ISO8601_UTC(stop) validate_datetime(start) validate_datetime(stop) timestep = generic["timestep"] real_time = generic["real_time"] speed = int(timestep / real_time) generic1 = generic["generic_1"] generic1["clock"]["interval"] = f"{start}/{stop}" generic1["clock"]["currentTime"] = f"{start}" generic1["clock"]["multiplier"] = speed generic2 = generic["generic_2"] self.list = [generic1, generic2]
def test_keplerian_orbit(self): """ keplerian_orbit test """ parameters = { "eccentricity": 0.0008641, "semimajor_axis": 6801395.04, "inclination": radians(87.0), "perigee_argument": radians(20.0), "right_ascension_of_ascending_node":radians(10.0), "anomaly": radians(0.0), "anomaly_type": "TRUE", "orbit_update_date":'2021-12-02T00:00:00.000', "frame": "EME"} k_orbit = keplerian_orbit(parameters) eccentricity = parameters["eccentricity"] semimajor_axis = parameters["semimajor_axis"] inclination = parameters["inclination"] perigee_argument = parameters["perigee_argument"] right_ascension_of_ascending_node = parameters["right_ascension_of_ascending_node"] true_anomaly = parameters["anomaly"] orbit_update_date = parameters["orbit_update_date"] epochDate = absolute_time_converter_utc_string(orbit_update_date) frame = orekit_utils.string_to_frame(parameters["frame"]) self.assertTrue(KeplerianOrbit(semimajor_axis, eccentricity, inclination, perigee_argument, right_ascension_of_ascending_node, true_anomaly, PositionAngle.TRUE, frame, epochDate, Constants.WGS84_EARTH_MU).toString() == k_orbit.toString())
def test_get_keplerian_parameters(self): """ get_keplerian_parameters test """ parameters = { "eccentricity": 0.0008641, "semimajor_axis": 6801395.04, "inclination": radians(87.0), "perigee_argument": radians(20.0), "right_ascension_of_ascending_node": radians(10.0), "anomaly": radians(0.0), "anomaly_type": "TRUE", "orbit_update_date":'2021-12-02T00:00:00.000', "frame": "EME"} propagator_1 = analytical_propagator(parameters) orbit = keplerian_orbit(parameters) new_state = SpacecraftState(orbit) new_parameters = orekit_utils.get_keplerian_parameters(new_state) propagator_2 = keplerian_orbit(new_parameters) new_time = absolute_time_converter_utc_string('2021-12-05T00:00:00.000') distance = orekit_utils.find_sat_distance(propagator_1, propagator_2, new_time) # parameters value change but define same orbit self.assertTrue(distance <= 0.000001)
def test_analytical_propagator(self): """ analytical_propagator test """ parameters = { "eccentricity": 0.0008641, "semimajor_axis": 6801395.04, "inclination": radians(87.0), "perigee_argument": radians(20.0), "right_ascension_of_ascending_node": radians(10.0), "anomaly": radians(0.0), "anomaly_type": "TRUE", "orbit_update_date": '2021-12-02T00:00:00.000', "frame": "EME" } k_orbit = keplerian_orbit(parameters) test1 = analytical_propagator(parameters) test2 = KeplerianPropagator(keplerian_orbit(parameters), Constants.WGS84_EARTH_MU) time1 = orekit_utils.absolute_time_converter_utc_string( '2022-01-02T00:00:00.000') self.assertTrue( test1.getPVCoordinates(time1, FramesFactory.getEME2000()).toString( ) == test2.getPVCoordinates(time1, FramesFactory.getEME2000()).toString())
def test_str_tle_propagator(self): tle_line1 = "1 25544U 98067A 20174.66385417 .00000447 00000-0 16048-4 0 9992" tle_line2 = "2 25544 51.6446 321.3575 0002606 75.8243 105.9183 15.49453790232862" propagator_1 = orekit_utils.str_tle_propagator(tle_line1, tle_line2) TLE = orekit_utils.convert_tle_string_to_TLE(tle_line1, tle_line2) propagator_2 = TLEPropagator.selectExtrapolator(TLE) time = absolute_time_converter_utc_string('2020-12-02T00:00:00.000') self.assertTrue(propagator_1.propagate(time).getOrbit().toString() == propagator_2.propagate(time).getOrbit().toString())
def __init__(self, generic, name, start, duration, orbit): """ Generate a standard CZML packet for displaying a satellite in Cesium, with configuration specified in "generic" argument Args: generic (string JSON): CZML boilerplate, from the configuration in config-service name (string): the name of the satellite the user wishes want to display start (string): the current time (from which the user wishes to display) duration (float): the duration of time after start that the user wishes to display, in seconds orbit (dict): dict containing the satellites keplerian orbital elements """ generic = deepcopy(generic) # need to save before it is converted to a different format self.start = start stop = orekit_utils.absolute_time_converter_utc_string( start).shiftedBy(float(duration)).toString() start = ISO8601_UTC(start) stop = ISO8601_UTC(stop) validate_datetime(start) validate_datetime(stop) self.orbit = orbit self.name = name packet = {} _name = name.replace(" ", "_") self._name = name packet['id'] = f"Satellite/{_name}" packet['name'] = _name billboard = generic["billboard"] label = generic["label"] path = generic["path"] position = generic["position"] satellite_description = generic["satellite_description"] # set availability from the current date/time until a very long time in the future availability = f"{start}/{stop}" packet['availability'] = availability packet['description'] = satellite_description packet['billboard'] = billboard packet['label'] = label # record the correct name packet['label']['text'] = name # record the templates for updating later packet["path"] = path packet["position"] = position # make path viewable in correct time range #TODO edit this packet["path"]["show"][0]["interval"] = availability self.packet = packet
def produce_links(self, save=False, new_shared_storage = None): """ Args: save (bool, optional): Wether or not the packets should be saved. Defaults to True. new_shared_storage (dictionary, optional): A new dictionary containing satellite orbits, iot sensors, and groundstation to be used. Defaults to None. Returns: list: list of all of the inter satellite link packets """ if new_shared_storage == None: shared_storage = self.shared_storage else: shared_storage = new_shared_storage satellite_links = self.satellite_links packet_links = [] # for each element in the satellite links set make a packet for i in satellite_links: # find the names cubesat_a = i[i.find('/')+1:i.find('-')] cubesat_b = i[i.rfind('/')+1:] # create a orbit propagator for both satellites csat_a_prop = orekit_utils.analytical_propagator(shared_storage["swarm"][cubesat_a]["orbit"]) csat_b_prop = orekit_utils.analytical_propagator(shared_storage["swarm"][cubesat_b]["orbit"]) # create a list of times when the satellites can see each other start_time = orekit_utils.absolute_time_converter_utc_string(shared_storage["time"]) windows_array = orekit_utils.visible_above_horizon(csat_a_prop, csat_b_prop, start_time, self.duration) # create a list of times when the satellites can see and not see each other n_windows_array = self.process_time_window(windows_array) # create a list of objects when the satellite links can be shown for cesium show = self.create_show(n_windows_array) # create a list of times when the satellites can see and not see each other for cesium availability = self.create_availability(show) references = [i[:i.find("-to-")]+'#position', i[i.find("-to-") + 4:]+'#position'] # Construct the packet with a generic link packet and data created above packet = deepcopy(self.shared_storage["generic"]["general_link"]) packet["id"] = i packet["name"] = cubesat_a +" to " + cubesat_b packet["availability"] = availability packet["description"] = "<h1>Blah blah blah</h1>" packet["polyline"]["show"] = show packet["polyline"]["positions"]["references"] = references packet_links.append(packet) # save as json if if save: with open('data.json', 'w') as outfile: json.dump(packet_links, outfile) self.packets = packet_links return packet_links
def test_moving_body_pointing_law(self): """ moving_body_pointing_law test """ parameters = { "eccentricity": 0.0008641, "semimajor_axis": 6801395.04, "inclination": 87.0, "perigee_argument": 20.0, "right_ascension_of_ascending_node": 10.0, "anomaly": radians(0.0), "anomaly_type": "TRUE", "orbit_update_date": '2021-12-02T00:00:00.000', "frame": "EME" } parameters1 = { "eccentricity": 0.0008641, "semimajor_axis": 6801395.04, "inclination": 87.0, "perigee_argument": 10.0, "right_ascension_of_ascending_node": 10.0, "anomaly": radians(0.0), "anomaly_type": "TRUE", "orbit_update_date": '2021-12-02T00:00:00.000', "frame": "EME" } orbit_propagator_1 = analytical_propagator(parameters1) orbit_propagator_2 = analytical_propagator(parameters1) parameters["frame"] = orekit_utils.frame_to_string( orbit_propagator_1.getFrame()) time_to_propagate = orekit_utils.absolute_time_converter_utc_string( '2022-05-02T00:00:00.000') orbit_to_track_propagator = analytical_propagator(parameters) test1 = CelestialBodyPointed(FramesFactory.getEME2000(), orbit_to_track_propagator, Vector3D.PLUS_K, Vector3D.PLUS_K, Vector3D.MINUS_J) test2 = moving_body_pointing_law(orbit_to_track_propagator, parameters) orbit_propagator_1.setAttitudeProvider(test1) orbit_propagator_2.setAttitudeProvider(test2) state_1 = orbit_propagator_1.propagate(time_to_propagate) state_2 = orbit_propagator_2.propagate(time_to_propagate) self.assertTrue((state_1.getAttitude().getSpin().toString() == state_2.getAttitude().getSpin().toString()))
def test_find_sat_distance(self): """ find_distance tests: test some well known distances and zero cases """ tle_line1 = "1 25544U 98067A 20174.66385417 .00000447 00000-0 16048-4 0 9992" tle_line2 = "2 25544 51.6446 321.3575 0002606 75.8243 105.9183 15.49453790232862" tle2_line1 = "1 44235U 19029A 20178.58335648 .01685877 00000-0 31131-1 0 9991" tle2_line2 = "2 44235 52.9995 164.3403 0009519 291.6111 354.0622 15.45232749 61668" prop1 = orekit_utils.str_tle_propagator(tle_line1, tle_line2) prop2 = orekit_utils.str_tle_propagator(tle2_line1, tle2_line2) time = orekit_utils.absolute_time_converter_utc_string('2020-12-02T00:00:00.000') self.assertEqual(orekit_utils.find_sat_distance(prop1,prop2,time),orekit_utils.find_sat_distance(prop1,prop2,time)) self.assertEqual(orekit_utils.find_sat_distance(prop1,prop1,time),0.) self.assertEqual(orekit_utils.find_sat_distance(prop2,prop2,time),0.)
def test_ground_pointing_law(self): """ ground_pointing_law test """ parameters = {"latitude": 12.0, "altitude": 2343.0, "longitude": 12.0} parameters1 = { "eccentricity": 0.0008641, "semimajor_axis": 6801395.04, "inclination": 87.0, "perigee_argument": 10.0, "right_ascension_of_ascending_node": 10.0, "anomaly": radians(0.0), "anomaly_type": "TRUE", "orbit_update_date": '2021-12-02T00:00:00.000', "frame": "EME" } orbit_propagator_1 = analytical_propagator(parameters1) orbit_propagator_2 = analytical_propagator(parameters1) parameters["frame"] = orekit_utils.frame_to_string( orbit_propagator_1.getFrame()) ITRF = FramesFactory.getITRF(IERSConventions.IERS_2010, True) target = GeodeticPoint(parameters["latitude"], parameters["longitude"], parameters["altitude"]) attitude_provider = ground_pointing_law(parameters) attitude_provider_1 = TargetPointing( FramesFactory.getEME2000(), target, OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, Constants.WGS84_EARTH_FLATTENING, ITRF)) orbit_propagator_1.setAttitudeProvider(attitude_provider) orbit_propagator_2.setAttitudeProvider(attitude_provider_1) time_to_propagate = orekit_utils.absolute_time_converter_utc_string( '2022-05-02T00:00:00.000') state_1 = orbit_propagator_1.propagate(time_to_propagate) state_2 = orbit_propagator_2.propagate(time_to_propagate) self.assertTrue((state_1.getAttitude().getSpin().toString() == state_2.getAttitude().getSpin().toString()))
def test_attitude_provider_constructor(self): """ attitude_provider_constructor test """ moving_body = "moving_body_tracking" moving_body_param = { "eccentricity": 0.0008641, "semimajor_axis": 6801395.04, "inclination": 87.0, "perigee_argument": 10.0, "right_ascension_of_ascending_node": 10.0, "anomaly": 0.0, "anomaly_type": "TRUE", "orbit_update_date":"2021-12-02T00:00:00.000", "frame": "EME"} orbit_params = { "eccentricity": 0.0008641, "semimajor_axis": 6801395.04, "inclination": 87.0, "perigee_argument": 20.0, "right_ascension_of_ascending_node": 10.0, "anomaly": 0.0, "anomaly_type": "TRUE", "orbit_update_date":'2021-12-02T00:00:00.000', "frame": "EME"} orbit_propagator_1 = analytical_propagator(orbit_params) orbit_propagator_2 = analytical_propagator(orbit_params) attitude_m_body = attitude_provider_constructor(moving_body, moving_body_param) attitude_m_body_1 = moving_body_pointing_law(analytical_propagator(moving_body_param),moving_body_param) orbit_propagator_1.setAttitudeProvider(attitude_m_body) orbit_propagator_2.setAttitudeProvider(attitude_m_body_1) time_to_propagate = orekit_utils.absolute_time_converter_utc_string('2022-05-02T00:00:00.000') state_1 = orbit_propagator_1.propagate(time_to_propagate) state_2 = orbit_propagator_2.propagate(time_to_propagate) self.assertTrue((state_1.getAttitude().getSpin().toString() == state_2.getAttitude().getSpin().toString())) ground = "ground_tracking" ground_param = { "latitude": 12.0, "altitude": 2343.0, "longitude":12.0 } parameters = { "eccentricity": 0.0008641, "semimajor_axis": 6801395.04, "inclination": 87.0, "perigee_argument": 10.0, "right_ascension_of_ascending_node": 10.0, "anomaly": radians(0.0), "anomaly_type": "TRUE", "orbit_update_date":'2021-12-02T00:00:00.000', "frame": "EME"} orbit_propagator_1 = analytical_propagator(parameters) orbit_propagator_2 = analytical_propagator(parameters) ground_param["frame"] = orekit_utils.frame_to_string(orbit_propagator_1.getFrame()) attitude_provider_1 = attitude_provider_constructor(ground, ground_param) attitude_provider_2 = ground_pointing_law(ground_param) orbit_propagator_1.setAttitudeProvider(attitude_provider_1) orbit_propagator_2.setAttitudeProvider(attitude_provider_2) time_to_propagate = orekit_utils.absolute_time_converter_utc_string('2022-05-02T00:00:00.000') state_1 = orbit_propagator_1.propagate(time_to_propagate) state_2 = orbit_propagator_2.propagate(time_to_propagate) self.assertTrue((state_1.getAttitude().getSpin().toString() == state_2.getAttitude().getSpin().toString()))
async def simulation_timepulse_propagate(message, nats_handler, shared_storage, logger): """ Propagates the satellites current orbit and attitude Args: message (natsmessage): message message.data dictionary with structure as described in message_structure.json message.data["time"] is the time update nats_handler (natsHandler): distributes callbacks according to the message subject shared_storage: dictionary containing information on on the entire swarm, the time, and the particular satellites phonebook """ # Distance that will prevent satellites from communicating max_range = shared_storage["range"] # Updating time shared_storage["time"] = message.data["time"] cubesat_id = nats_handler.sender_id # Making a propagator for satellite running this service self_orbit_propagator = orekit_utils.analytical_propagator( shared_storage["swarm"][cubesat_id]["orbit"]) # Each satellite's state will be upated and the phonebook will be updated for satellite in shared_storage["swarm"]: # Info about each satellite state is accessed to propagate orbit and attitude orbit_propagator = orekit_utils.analytical_propagator( shared_storage["swarm"][satellite]["orbit"]) attitude = shared_storage["swarm"][satellite]["orbit"]["attitude"] attitude_param = dict() frame = shared_storage["swarm"][satellite]["orbit"]["frame"] # Info about satellite attitude is accessed if attitude in shared_storage["swarm"]: attitude_provider_type = orekit_utils.utils.MOVING_BODY_TRACKING attitude_param = shared_storage["swarm"][attitude]["orbit"] elif attitude in shared_storage["grstns"]: attitude_provider_type = orekit_utils.utils.GROUND_TRACKING attitude_param = shared_storage["grstns"][attitude]["location"] elif attitude in shared_storage["iots"]: attitude_provider_type = orekit_utils.utils.GROUND_TRACKING attitude_param = shared_storage["iots"][attitude]["location"] elif attitude == orekit_utils.utils.NADIR_TRACKING: attitude_provider_type = attitude else: raise Exception("attitude unknown") # storing/updating reference frame attitude_param["frame"] = frame # constructing a attitude provider from info gathered above attitude_provider = orekit_utils.attitude_provider_constructor( attitude_provider_type, attitude_param) # the orbit propagator and attitude provider are consolidated orbit_propagator.setAttitudeProvider(attitude_provider) time = orekit_utils.absolute_time_converter_utc_string( shared_storage["time"]) # new satellite state containg attitude and orbit info new_state = orbit_propagator.propagate(time) # the shared storage is updated as necessary shared_storage["swarm"][satellite][ "orbit"] = orekit_utils.get_keplerian_parameters(new_state) shared_storage["swarm"][satellite]["orbit"].update({"frame": frame}) shared_storage["swarm"][satellite]["orbit"].update( {"attitude": attitude}) shared_storage["swarm"][satellite][ "last_update_time"] = shared_storage["time"] # Checking if the satellites target is in view and upating shared storage accordingly if attitude_provider_type == orekit_utils.utils.GROUND_TRACKING: shared_storage["swarm"][satellite][ "target_in_view"] = orekit_utils.check_iot_in_range( orbit_propagator, attitude_param["latitude"], attitude_param["longitude"], attitude_param["altitude"], time) elif attitude_provider_type == orekit_utils.utils.NADIR_TRACKING: shared_storage["swarm"][satellite]["target_in_view"] = True elif attitude_provider_type == orekit_utils.utils.MOVING_BODY_TRACKING: tracked_propagator = orekit_utils.analytical_propagator( attitude_param) shared_storage["swarm"][satellite][ "target_in_view"] = orekit_utils.visible_above_horizon( orbit_propagator, tracked_propagator, time) else: raise Exception("attitude_provider unknown") # Updating phonebook based on the location of the satellites if satellite != cubesat_id: cur_orbit_propagator = orekit_utils.analytical_propagator( shared_storage["swarm"][satellite]["orbit"]) time = orekit_utils.absolute_time_converter_utc_string( shared_storage["time"]) distance = orekit_utils.find_sat_distance(self_orbit_propagator, cur_orbit_propagator, time) if distance < max_range and orekit_utils.visible_above_horizon( self_orbit_propagator, cur_orbit_propagator, time): shared_storage["sat_phonebook"][satellite] = True else: shared_storage["sat_phonebook"][satellite] = False # Message contaning data on the updated state of a satellite is sent for each sent for sat_id in shared_storage["swarm"]: msg = nats_handler.create_message( {"state": { sat_id: shared_storage["swarm"][sat_id] }}, MessageSchemas.STATE_MESSAGE) subject = "state" await nats_handler.send_message(subject, msg) # The satellites updated phonebook is sent sat_phonebook_message = nats_handler.create_message( shared_storage["sat_phonebook"], MessageSchemas.PHONEBOOK_MESSAGE) await nats_handler.send_message("internal.phonebook", sat_phonebook_message) # IOT PHONEBOOK UPDATER for iot_id in shared_storage["iots"]: latitude = shared_storage["iots"][iot_id]["location"]["latitude"] longitude = shared_storage["iots"][iot_id]["location"]["longitude"] altitude = shared_storage["iots"][iot_id]["location"]["altitude"] if orekit_utils.check_iot_in_range( self_orbit_propagator, latitude, longitude, altitude, orekit_utils.absolute_time_converter_utc_string( shared_storage["time"])): shared_storage["iot_phonebook"][iot_id] = True else: shared_storage["iot_phonebook"][iot_id] = False # Sending updated phonebook iot_phonebook_message = nats_handler.create_message( shared_storage["iot_phonebook"], MessageSchemas.PHONEBOOK_MESSAGE) await nats_handler.send_message("internal.iot_phonebook", iot_phonebook_message) #Groundstation Phonebook Updater for ground_id in shared_storage["grstns"]: latitude = shared_storage["grstns"][ground_id]["location"]["latitude"] longitude = shared_storage["grstns"][ground_id]["location"][ "longitude"] altitude = shared_storage["grstns"][ground_id]["location"]["altitude"] if orekit_utils.check_iot_in_range( self_orbit_propagator, latitude, longitude, altitude, orekit_utils.absolute_time_converter_utc_string( shared_storage["time"])): shared_storage["grstn_phonebook"][ground_id] = True else: shared_storage["grstn_phonebook"][ground_id] = False # Sending updated phonebook grstn_phonebook_message = nats_handler.create_message( shared_storage["grstn_phonebook"], MessageSchemas.PHONEBOOK_MESSAGE) await nats_handler.send_message("internal.grnst_phonebook", grstn_phonebook_message)
async def test_simulation_timepulse_propagate(self): """ Test the simulation_timepulse_propagate() callback """ # Creating variables that will be used as arguments for the callback logger = FakeLogger() loop = asyncio.get_running_loop() nats = FakeNatsHandler("cubesat_1", "4222", loop=loop, user="******", password="******") await nats.connect() # opening a file that contains a sample shared storage f = open("test_orbits_config.json") shared_storage = json.load(f) # Testing the callback across mulitple timesteps for i in range(10, 59): # creating sample data data = { "sender_ID": "cubesat_2", "time_sent": "2021-12-05T00:" + str(i) + ":00.000", "data": { "time": "2021-12-05T00:" + str(i) + ":00.000" } } orbit_1 = shared_storage["swarm"]["cubesat_1"]["orbit"] orbit_2 = shared_storage["swarm"]["cubesat_2"]["orbit"] attitude_provider_1 = { "type": "moving_body_tracking", "parameters": shared_storage["swarm"][shared_storage["swarm"]["cubesat_1"] ["orbit"]["attitude"]]["orbit"] } attitude_provider_2 = { "type": "moving_body_tracking", "parameters": shared_storage["swarm"][shared_storage["swarm"]["cubesat_2"] ["orbit"]["attitude"]]["orbit"] } message = Message.decode_json(data, MessageSchemas.TIMESTEP_MESSAGE) await orbit_service.simulation_timepulse_propagate( message, nats, shared_storage, logger) time = absolute_time_converter_utc_string(data["data"]["time"]) # Creating propagators and attitude provider from orbit configuration of satellites propagator_1 = orekit_utils.analytical_propagator(orbit_1) propagator_2 = orekit_utils.analytical_propagator(orbit_2) attitude_provider_1 = orekit_utils.attitude_provider_constructor( attitude_provider_1["type"], attitude_provider_1["parameters"]) attitude_provider_2 = orekit_utils.attitude_provider_constructor( attitude_provider_2["type"], attitude_provider_2["parameters"]) # Setting attitude and propagating the orbit propagator_1.setAttitudeProvider(attitude_provider_1) propagator_2.setAttitudeProvider(attitude_provider_2) state_1 = propagator_1.propagate(time) state_2 = propagator_2.propagate(time) # Updating param cubesat_1_param = orekit_utils.get_keplerian_parameters(state_1) cubesat_1_param.update({"attitude": "cubesat_2"}) cubesat_1_param.update({"frame": "EME"}) cubesat_2_param = orekit_utils.get_keplerian_parameters(state_2) cubesat_2_param.update({"attitude": "cubesat_1"}) cubesat_2_param.update({"frame": "EME"}) # Checking to see if simulation_timestep_propagate updated params correctly self.assertTrue(shared_storage["swarm"]["cubesat_1"]["orbit"] == cubesat_1_param) self.assertTrue(shared_storage["swarm"]["cubesat_2"]["orbit"] == cubesat_2_param) self.assertTrue(shared_storage["swarm"]["cubesat_1"]["orbit"] ["attitude"] == "cubesat_2") self.assertTrue(shared_storage["swarm"]["cubesat_2"]["orbit"] ["attitude"] == "cubesat_1") print(shared_storage["swarm"]["cubesat_1"]["target_in_view"]) print(shared_storage["swarm"]["cubesat_2"]["target_in_view"]) # Making sure that phonebook gets updated properly if i <= 48: self.assertTrue(shared_storage["sat_phonebook"]["cubesat_2"]) self.assertTrue( shared_storage["swarm"]["cubesat_2"]["target_in_view"]) else: self.assertFalse(shared_storage["sat_phonebook"]["cubesat_2"]) self.assertFalse( shared_storage["swarm"]["cubesat_2"]["target_in_view"])