示例#1
0
    def test_TimeProfile_interpolate_by_distance(self):
        profile_0 = TimeProfile(START_TIME, DISTANCES, ELAPSED_TIMES)

        distances_0 = np.array([0., 2 * NM, 8 * NM, DISTANCES[2]])
        times_0 = profile_0.interpolate_by_distance(distances_0)
        self.assertEqual(len(times_0), len(distances_0))
        self.assertEqual(times_0[0], ELAPSED_TIMES[0])
        self.assertEqual(times_0[-1], ELAPSED_TIMES[2])
示例#2
0
    def test_TimeProfile_interpolate_by_elapsed_time(self):
        profile_0 = TimeProfile(START_TIME, DISTANCES, ELAPSED_TIMES)

        times_0 = np.array([0.0, 292.0, 500.0, 718.0])
        distances_0 = profile_0.interpolate_by_elapsed_time(times_0)
        self.assertEqual(len(distances_0), len(times_0))
        self.assertEqual(distances_0[0], DISTANCES[0])
        assert_almost_equal(distances_0[2], 51.053368441692193 * NM)
        self.assertEqual(distances_0[-1], DISTANCES[2])
示例#3
0
    def test_TimeProfile_json(self):

        profile_0 = TimeProfile(START_TIME, DISTANCES, ELAPSED_TIMES)
        s = profile_0.dumps()
        # print(s)

        json_1 = json.loads(s)
        profile_1 = TimeProfile.loads(json_1)

        self.assertEqual(profile_1.start_time, START_TIME)
        assert_array_almost_equal(profile_1.distances, profile_0.distances)
        assert_array_almost_equal(profile_1.elapsed_times, profile_0.elapsed_times)
def analyse_times(distances, times, duplicate_positions, method=LM):
    """
    Create an TimeProfile and quality metrics.

    Cruise positions are calculated and removed from the arrays of
    distances and altitudes.

    Parameters
    ----------
    distances : numpy float array
        An array of distances [Nautical Miles]

    times: numpy datetime64 array
        An array of datetimes [seconds]

    duplicate_positions: numpy bool array
        An array indicating duplicate distance positions.

    Returns
    -------
    TimeProfile: the time profile.

    time_sd: the time standard deviation.

    max_time_diff: the maximum time difference.

    """
    # calculate time differences from non-duplicate positions
    elapsed_times = calculate_elapsed_times(times[~duplicate_positions],
                                            times[0])

    # dicatnces between non-duplicate positions
    valid_distances = distances[~duplicate_positions]

    # attempt to fit a curve to the distances and times
    # Using the Levenberg-Marquardt algorithm
    def polynomial_5d(x, a, b, c, d, e, f):
        return a * x**5 + b * x**4 + c * x**3 + d * x**2 + e * x + f

    popt, pcov = scipy.optimize.curve_fit(polynomial_5d,
                                          valid_distances,
                                          elapsed_times,
                                          method=method)
    # calculate time standard deviation
    time_sd = np.sqrt(np.sum(np.diag(pcov)))

    # Adjust times to smoothed times and output quality metrics
    smoothed_times = polynomial_5d(valid_distances, *popt)

    # calculate the maximum time difference
    delta_times = smoothed_times - elapsed_times
    max_time_diff, max_time_index = find_most_extreme_value(delta_times)

    # Don't output duplicate positions in the time profile
    return TimeProfile(times[0], valid_distances, smoothed_times), \
        time_sd, max_time_diff, max_time_index
示例#5
0
    def test_SmoothedTrajectories(self):
        path_0 = HorizontalPath(ROUTE_LATS, ROUTE_LONS, TURN_DISTANCES)
        timep_0 = TimeProfile(START_TIME, TIME_DISTANCES, ELAPSED_TIMES)
        altp_0 = AltitudeProfile(ALT_DISTANCES, ALTITUDES)

        traj_0 = SmoothedTrajectory('123-456-789', path_0, timep_0, altp_0)

        trajs_0 = [traj_0, traj_0, traj_0]

        s = dumps_SmoothedTrajectories(trajs_0, 'mas', 0.5, 5, 3, 120.0)
        # print(s)

        json_1 = json.loads(s)
        trajs_1 = loads_SmoothedTrajectories(json_1)
        self.assertEqual(len(trajs_1), len(trajs_0))
示例#6
0
    def test_TimeProfile_calculate_average_period(self):

        profile_0 = TimeProfile(START_TIME, DISTANCES, ELAPSED_TIMES)

        period_0 = profile_0.calculate_average_period(75. * NM, 75. * NM)
        self.assertEqual(period_0, 0.0)
        period_1 = profile_0.calculate_average_period(0.0, 75. * NM)
        self.assertEqual(period_1, 0.0)
        period_2 = profile_0.calculate_average_period(0.0, 225. * NM)
        assert_almost_equal(period_2, 1125.5)
        period_3 = profile_0.calculate_average_period(225. * NM, 233.645865 * NM)
        assert_almost_equal(period_3, 26.571428571428573)
        period_4 = profile_0.calculate_average_period(225. * NM, 235.0 * NM)
        assert_almost_equal(period_4, 26.571428571428573)
示例#7
0
    def test_find_3D_airspace_intersections(self):

        path_0 = HorizontalPath(ROUTE_LATS, ROUTE_LONS, TURN_DISTANCES)

        timep_0 = TimeProfile(START_TIME, DISTANCES, ELAPSED_TIMES)
        altp_0 = ALTITUDE_PROFILE

        traj_0 = SmoothedTrajectory('123-456-789', path_0, timep_0, altp_0)

        LATS = np.array([0., 20. / 60., 40. / 60., 60. / 60.])
        LONS = np.zeros(4, dtype=float)
        sector_ids = ['1', '2', '3', '1']
        points_0 = global_Point3d(LATS, LONS)
        df_3d = find_3D_airspace_intersections(traj_0, path_0.ecef_path(),
                                               points_0, sector_ids, SECTORS)
        self.assertEqual(df_3d.shape[0], 6)
示例#8
0
    def test_find_3D_airspace_no_intersections(self):

        path_0 = HorizontalPath(ROUTE_LATS, ROUTE_LONS, TURN_DISTANCES)

        timep_0 = TimeProfile(START_TIME, DISTANCES, ELAPSED_TIMES)

        # Create a altitude profile above the sectors
        HIGH_ALTITUDES = np.array([
            10000., 11800., 13000., 13600., 14200., 15400., 16000., 16000.,
            16000., 16000., 15400., 14200.
        ])

        alt_p = AltitudeProfile(DISTANCES, HIGH_ALTITUDES)

        traj_0 = SmoothedTrajectory('123-456-789', path_0, timep_0, alt_p)

        LATS = np.array([0., 20. / 60., 40. / 60., 60. / 60.])
        LONS = np.zeros(4, dtype=float)
        sector_ids = ['1', '2', '3', '1']
        points_0 = global_Point3d(LATS, LONS)
        df_3d = find_3D_airspace_intersections(traj_0, path_0.ecef_path(),
                                               points_0, sector_ids, SECTORS)
        self.assertEqual(df_3d.shape[0], 0)
示例#9
0
    def test_SmoothedTrajectory(self):
        path_0 = HorizontalPath(ROUTE_LATS, ROUTE_LONS, TURN_DISTANCES)
        timep_0 = TimeProfile(START_TIME, TIME_DISTANCES, ELAPSED_TIMES)
        altp_0 = AltitudeProfile(ALT_DISTANCES, ALTITUDES)

        traj_0 = SmoothedTrajectory('123-456-789', path_0, timep_0, altp_0)
        s_list = traj_0.dumps()
        s = ''.join(s_list)

        # print(s)
        json_1 = json.loads(s)
        traj_1 = SmoothedTrajectory.loads(json_1)

        self.assertEqual(traj_1.flight_id, '123-456-789')
        assert_array_almost_equal(traj_1.path.lats, ROUTE_LATS)
        assert_array_almost_equal(traj_1.path.lons, ROUTE_LONS)
        assert_array_almost_equal(traj_1.path.tids, TURN_DISTANCES)

        self.assertEqual(traj_1.timep.start_time, START_TIME)
        assert_array_almost_equal(traj_1.timep.distances, TIME_DISTANCES)
        assert_array_almost_equal(traj_1.timep.elapsed_times, ELAPSED_TIMES)

        assert_array_almost_equal(traj_1.altp.distances, ALT_DISTANCES)
        assert_array_almost_equal(traj_1.altp.altitudes, ALTITUDES)
示例#10
0
def analyse_speeds(distances,
                   times,
                   duplicate_positions,
                   N=5,
                   M=5,
                   max_duration=DEFAULT_SPEED_MAX_DURATION):
    """
    Create an TimeProfile and quality metrics.

    Cruise positions are calculated and removed from the arrays of
    distances and altitudes.

    Parameters
    ----------
    distances : numpy float array
        An array of distances [Nautical Miles]

    times: numpy datetime64 array
        An array of datetimes [seconds]

    duplicate_positions: numpy bool array
        An array indicating duplicate distance positions.

    N : integer
        The number of samples to consider for the moving median filter, default 5.

    M : integer
        The number of samples to consider for the moving average filter, default 5.

    max_duration: float
        The maximum time between points to smooth, default 120 [Seconds].

    Returns
    -------
    TimeProfile: the time profile.

    time_sd: the time standard deviation.

    max_time_diff: the maximum time difference.

    """
    # calculate time differences from non-duplicate positions
    elapsed_times = calculate_elapsed_times(times[~duplicate_positions],
                                            times[0])

    # dicatnces between non-duplicate positions
    valid_distances = distances[~duplicate_positions]

    # Smooth the times
    smoothed_times = smooth_times(valid_distances, elapsed_times, N, M,
                                  max_duration)

    # Adjust for any offset introduced by smoothing
    delta_times = smoothed_times - elapsed_times
    mean_delta = np.sum(delta_times) / len(delta_times)
    smoothed_times = smoothed_times - mean_delta

    # Then calculate deltas from the adjusted mean times
    delta_times = smoothed_times - elapsed_times
    time_sd = delta_times.std()
    max_time_diff, max_time_index = find_most_extreme_value(delta_times)

    # Don't output duplicate positions in the time profile
    return TimeProfile(times[0], valid_distances, smoothed_times), \
        time_sd, max_time_diff, max_time_index