Beispiel #1
0
    def test_reduce_poi_with_access_file(self, test_data):
        """Test reduce_poi with access file"""

        access_file, interval, error_threshold = test_data
        interval = TimeInterval(*interval)

        # Get access information
        access_info = self.parse_access_file(access_file)
        trimmed_accesses = time_intervals.trim_poi_segments(
            access_info.accesses, interval)

        # Gather data for every 24 hour period of the input interval
        q_mag = Satellite.get_by_name(access_info.sat_name)[0].maximum_altitude
        sat_platform_id = Satellite.get_by_name(
            access_info.sat_name)[0].platform_id
        sat_irp = Interpolator(sat_platform_id)

        poi_list = [
            TimeInterval(start, start + 24 * 60 * 60)
            for start in range(interval[0], interval[1], 24 * 60 * 60)
        ]

        sampling_time_list = [time.start for time in poi_list]
        sampling_time_list.append(interval[1])

        sat_pos_ecef_list, sat_vel_ecef_list = map(
            list, zip(*[sat_irp.interpolate(t) for t in sampling_time_list]))
        sat_position_velocity_pairs = ecef_to_eci(
            np.transpose(np.asarray(sat_pos_ecef_list)),
            np.transpose(np.asarray(sat_vel_ecef_list)), sampling_time_list)

        # Run viewing cone
        reduced_poi_list = [
            reduced_poi for idx, poi in enumerate(poi_list)
            for reduced_poi in view_cone.reduce_poi(
                access_info.target, sat_position_velocity_pairs[idx:idx +
                                                                2], q_mag, poi)
        ]

        reduced_poi_list = time_intervals.fuse_neighbor_intervals(
            reduced_poi_list)

        # Check coverage
        for poi in reduced_poi_list:
            trimmed_accesses = filter(
                lambda access: not (
                    (poi.start - error_threshold < access.start) and
                    (poi.end + error_threshold > access.end)),
                trimmed_accesses)

        if trimmed_accesses:
            print("Remaining accesses: ", trimmed_accesses)
            raise Exception("Some accesses are not covered")
Beispiel #2
0
    def test_full_visibility(self, test_data):
        """Tests that the visibility finder produces the same results as the access file.

        Args:
            test_data (tuple): A three tuple containing the:
                                1 - The path of KAOS access test file
                                2 - A tuple of the desired test duration
                                3 - The maximum tolerated deviation in seconds
        Note:
            Ranges provided must not start or end at an access boundary. This is a result of the
            strict checking method provided.
        """
        access_file, interval, max_error = test_data

        access_info = self.parse_access_file(access_file)
        finder = VisibilityFinder(
            Satellite.get_by_name(access_info.sat_name)[0].platform_id,
            access_info.target, interval)
        access_times = finder.determine_visibility()

        for predicted_access in access_times:
            found = False
            for actual_access in access_info.accesses:
                if (interval[0] > actual_access[0]) and (interval[1] <
                                                         actual_access[1]):
                    if ((abs(interval[0] - predicted_access[0]) < max_error)
                            and
                        (abs(interval[1] - predicted_access[1]) < max_error)):
                        found = True
                        break
                if interval[0] > actual_access[0]:
                    if ((abs(interval[0] - predicted_access[0]) < max_error)
                            and (abs(actual_access[1] - predicted_access[1]) <
                                 max_error)):
                        found = True
                        break
                elif interval[1] < actual_access[1]:
                    if ((abs(actual_access[0] - predicted_access[0]) <
                         max_error) and
                        (abs(interval[1] - predicted_access[1]) < max_error)):
                        found = True
                        break

                if ((abs(actual_access[0] - predicted_access[0]) < max_error)
                        and
                    (abs(actual_access[1] - predicted_access[1]) < max_error)):
                    found = True
                    break

            if not found:
                raise Exception('Wrong access: {}'.format(predicted_access))
Beispiel #3
0
def parse_ephemeris_file(filename):
    """Parse the given ephemeris file and store the orbital data in OrbitRecords. We assume that
    each row in the ephemeris file is a 7-tuple containing an orbital point, formatted as:

    time posx posy posz velx vely velz

    Calculate the maximum distance from earth center to the position if the satellite. Insert it
    in Satellite.
    """
    sat_name = os.path.splitext(os.path.basename(filename))[0].split('.')[0]
    existing_sat = Satellite.get_by_name(sat_name)
    if not existing_sat:
        sat = Satellite(platform_name=sat_name)
        sat.save()
        DB.session.commit()
        sat_id = -1
    else:
        sat = existing_sat[0]

    max_distance = 0

    with open(filename, "rU") as f:
        segment_boundaries = []
        segment_tuples = []
        start_time = float(0)

        read_segment_boundaries = False
        read_orbital_data = False

        # Remember the last seen segment boundary while reading the ephemeris rows. Needed to
        # differentiate between the beginning of a new segment and the end of en existing segment of
        # data
        last_seen_segment_boundary = 0

        for line in f:
            line = line.rstrip('\n')
            if "Epoch in JDate format:" in line:
                start_time = float(line.split(':')[1])
                start_time = jdate_to_unix(start_time)
                last_seen_segment_boundary = start_time

            # For now, we assume that the coord system will always be J2000
            # if "CoordinateSystem" in line:
            #     coord_system = str(line.split()[1])

            if "END SegmentBoundaryTimes" in line:
                read_segment_boundaries = False

            if read_segment_boundaries:
                line = line.strip()
                if line:
                    segment_boundaries.append(start_time + float(line))

            if "BEGIN SegmentBoundaryTimes" in line:
                read_segment_boundaries = True

            if "END Ephemeris" in line:
                add_segment_to_db(segment_tuples, sat.platform_id)
                read_orbital_data = False

            if read_orbital_data:
                line = line.strip()
                if line:
                    ephemeris_row = [float(num) for num in line.split()]
                    orbit_tuple = OrbitPoint(start_time + ephemeris_row[0],
                                             ephemeris_row[1:4],
                                             ephemeris_row[4:7])
                    segment_tuples.append(orbit_tuple)

                    # Keep track of the magnitude of the position vector and update with a bigger
                    # value
                    max_distance = max(max_distance,
                                       np.linalg.norm(ephemeris_row[1:4]))

                    # The line we just read is a segment boundary, So first check that this is the
                    # *end* of a segment, not the beginning of a new one, and then add this segment
                    # to the db.
                    if (orbit_tuple.time in segment_boundaries and
                            last_seen_segment_boundary != orbit_tuple.time):
                        last_seen_segment_boundary = orbit_tuple.time
                        sat_id = add_segment_to_db(segment_tuples,
                                                   sat.platform_id)
                        segment_tuples = []

            if "EphemerisTimePosVel" in line:
                read_orbital_data = True

            # After getting the q_max, insert it into Satellite"""
            sat.maximum_altitude = max_distance
            sat.save()
        DB.session.commit()
        return sat_id
Beispiel #4
0
    def test_visibility(self, test_data):
        """Tests that the visibility finder produces the same results as the access file.

        Args:
            test_data (tuple): A three tuple containing the:
                                1 - The path of KAOS access test file
                                2 - A tuple of the desired test duration
                                3 - The maximum tolerated deviation in seconds
        Note:
            Ranges provided must not start or end at an access boundary. This is a result of the
            strict checking method provided.
        """
        access_file, interval, max_error = test_data

        posix_interval = (utc_to_unix(interval[0]), utc_to_unix(interval[1]))
        access_info = self.parse_access_file(access_file, posix_interval)
        satellite_id = Satellite.get_by_name(
            access_info.sat_name)[0].platform_id

        request = {
            'Target': access_info.target,
            'POI': {
                'startTime': interval[0],
                'endTime': interval[1]
            },
            'PlatformID': [satellite_id]
        }

        with self.app.test_client() as client:
            response = client.post('/visibility/search', json=request)

        self.assertTrue(response.is_json)
        self.assertEqual(response.status_code, 200)
        self.assertEqual(len(response.json['Opportunities']),
                         len(access_info.accesses))

        for oppertunity in response.json['Opportunities']:
            self.assertEqual(satellite_id, oppertunity['PlatformID'])
            predicted_access = (oppertunity['start_time'],
                                oppertunity['end_time'])
            interval = posix_interval
            found = False
            for actual_access in access_info.accesses:
                if (interval[0] > actual_access[0]) and (interval[1] <
                                                         actual_access[1]):
                    if ((abs(interval[0] - predicted_access[0]) < max_error)
                            and
                        (abs(interval[1] - predicted_access[1]) < max_error)):
                        found = True
                        break
                if interval[0] > actual_access[0]:
                    if ((abs(interval[0] - predicted_access[0]) < max_error)
                            and (abs(actual_access[1] - predicted_access[1]) <
                                 max_error)):
                        found = True
                        break
                elif interval[1] < actual_access[1]:
                    if ((abs(actual_access[0] - predicted_access[0]) <
                         max_error) and
                        (abs(interval[1] - predicted_access[1]) < max_error)):
                        found = True
                        break

                if ((abs(actual_access[0] - predicted_access[0]) < max_error)
                        and
                    (abs(actual_access[1] - predicted_access[1]) < max_error)):
                    found = True
                    break

            if not found:
                raise Exception('Wrong access: {}'.format(predicted_access))
Beispiel #5
0
    def test_visibility_perf(self, test_data):
        """Tests that the visibility finder produces the same results as the access file and prints
        accuracy and performance measurements at the end.
        This test is meant to be run manually (not as part of the automated CI tests).

        Use: pytest -s test/algorithm/perf_visibiliry_finder.py

        Args:
            test_data (tuple): A three tuple containing the:
                                1 - The path of KAOS access test file
                                2 - A tuple of the desired test duration
        """
        # Use viewing cone algorithm or not
        use_view_cone = True
        # Do viewing cone coordinate conversion in series or as a vector
        vectorized = True

        access_file, interval = test_data
        interval = TimeInterval(interval[0], interval[1])
        access_info = self.parse_access_file(access_file)
        sat_id = Satellite.get_by_name(access_info.sat_name)[0].platform_id
        max_q = Satellite.get_by_name(access_info.sat_name)[0].maximum_altitude
        sat_irp = Interpolator(sat_id)
        print("\n")

        if use_view_cone is False:
            finder = VisibilityFinder(sat_id, access_info.target, interval)
            # NOTE: change to burte_force=True to switch to brute-force method.
            access_times = np.asarray(
                finder.profile_determine_visibility(brute_force=False))
        else:
            import cProfile
            import pstats
            import sys
            profile = cProfile.Profile()
            profile.enable()

            # Vectorized
            if vectorized is True:
                poi_list = [
                    TimeInterval(start, start + 24 * 60 * 60)
                    for start in range(interval[0], interval[1], 24 * 60 * 60)
                ]

                sampling_time_list = [time.start for time in poi_list]
                sampling_time_list.append(interval[1])
                sat_pos_ecef_list, sat_vel_ecef_list = map(
                    list,
                    zip(*[sat_irp.interpolate(t) for t in sampling_time_list]))

                sat_position_velocity_pairs = ecef_to_eci(
                    np.transpose(np.asarray(sat_pos_ecef_list)),
                    np.transpose(np.asarray(sat_vel_ecef_list)),
                    sampling_time_list)

                reduced_poi_list = [
                    reduced_poi for idx, poi in enumerate(poi_list)
                    for reduced_poi in view_cone.reduce_poi(
                        access_info.target,
                        sat_position_velocity_pairs[idx:idx + 2], max_q, poi)
                ]
            # NON vectorized
            else:
                reduced_poi_list = []
                for start_time in range(interval[0], interval[1],
                                        24 * 60 * 60):
                    poi = TimeInterval(start_time, start_time + 24 * 60 * 60)
                    # get sat at start_time
                    sat_pos_ecef, sat_vel_ecef = sat_irp.interpolate(
                        start_time + 12 * 60 * 60)
                    sat_pos, sat_vel = ecef_to_eci(np.asarray(sat_pos_ecef),
                                                   np.asarray(sat_vel_ecef),
                                                   start_time + 12 * 60 * 60)

                    reduced_poi_list.extend(
                        view_cone.reduce_poi(access_info.target, sat_pos[0],
                                             sat_vel[0], max_q, poi))

            trimmed_reduced_poi_list = interval_utils.fuse_neighbor_intervals(
                reduced_poi_list)

            access_times = []
            for reduced_poi in trimmed_reduced_poi_list:
                finder = VisibilityFinder(sat_id, access_info.target,
                                          reduced_poi)
                access_times.extend(np.asarray(finder.determine_visibility()))

            profile.disable()
            stats = pstats.Stats(profile, stream=sys.stdout)
            stats.strip_dirs().sort_stats('cumtime').print_stats(50)

            reduced_time = 0
            for time in trimmed_reduced_poi_list:
                reduced_time += time[1] - time[0]
            print("Viewing cone stats:")
            print("Reduced time is: {}".format(mp.nstr(reduced_time, 12)))
            print("Input   time is: {}".format(interval[1] - interval[0]))

        interval = TimeInterval(*interval)
        expected_accesses = interval_utils.trim_poi_segments(
            access_info.accesses, interval)

        # Check the visibility times
        fail = False
        total_error = 0
        print(
            "=============================== visibility report ==============================="
        )
        for exp_start, exp_end in expected_accesses:
            idx = (np.abs(np.transpose(access_times)[0] - exp_start)).argmin()
            error = abs(exp_start -
                        access_times[idx][0]) + abs(exp_end -
                                                    access_times[idx][1])
            if error > 600:
                fail = True
                print("start, {}, ------------, {}".format(
                    exp_start, mp.nstr(access_times[idx][0] - exp_start, 6)))
                print("end,   {}, ------------, {}".format(
                    exp_end, mp.nstr(access_times[idx][1] - exp_end, 6)))
            else:
                print("start, {}, {}, {}".format(
                    exp_start, mp.nstr(access_times[idx][0], 11),
                    mp.nstr(access_times[idx][0] - exp_start, 6)))
                print("end  , {}, {}, {}".format(
                    exp_end, mp.nstr(access_times[idx][1], 11),
                    mp.nstr(access_times[idx][1] - exp_end, 6)))
                total_error += error
                access_times = np.delete(access_times, idx, axis=0)

        print("\nTotal Error: {}".format(mp.nstr(total_error, 12)))
        print("Average Error: {}".format(
            mp.nstr(total_error / (len(expected_accesses) * 2))))
        if fail:
            raise Exception(
                "Missing accesses. Unmatched: {}".format(access_times))
        if access_times.size > 0:
            raise Exception(
                "Extra accesses. Unmatched: {}".format(access_times))