Beispiel #1
0
def gnuplot_aircraft_yaw(
        stream: typing.TextIO = sys.stdout) -> typing.List[str]:
    result = ['# "{}"'.format('Estimated yaw of aircraft.')]
    notes = ['time yaw(degrees)']
    if len(notes):
        stream.write('#\n')
        stream.write('# Notes:\n')
        for note in notes:
            stream.write('# {}\n'.format(note))
    gs_fit = video_analysis.ground_speed_curve_fit(
        video_data.ErrorDirection.MID)
    # time_dist_brng = video_analysis.observer_time_distance_bearing(gs_fit, video_data.ErrorDirection.MID)
    time_dist_brng = video_analysis.observer_time_distance_bearing_from_wing_tips(
        gs_fit, video_data.ErrorDirection.MID)
    # time_dist_brng = video_analysis.time_distance_bearing_from_fits(time_interval=1.0)

    # time_dist_brng is a four column array of (time, x_distance, aspect, aspect_error)
    # from the observed aspect data.
    # Units are (seconds, metres, degrees).

    time_yaw = []
    # ((x_mean, x_std), (y_mean, y_std)) = video_analysis.observer_position_mean_std_from_aspects(
    #     baseline=plot_constants.OBSERVER_XY_MINIMUM_BASELINE,
    #     ignore_first_n=plot_constants.OBSERVER_XY_IGNORE_N_FIRST_BEARINGS,
    #     t_range=plot_constants.OBSERVER_XY_TIME_RANGE,
    # )
    ((x_mean, x_std),
     (y_mean,
      y_std)) = video_analysis.observer_position_mean_std_from_full_transits()
    observer_error = math.sqrt(x_std**2 + y_std**2)
    # Observer from bearings    : x=3480.0 y=-763.0
    # Observer from google earth: x=3457.9 y=-655.5
    #       Diff (bearings - ge): x=  22.1 y=-107.5
    # x_mean = 3457.9 - 1214
    # y_mean = -655.5
    # y_mean = -744.88
    # y_mean = -754.88
    # y_mean = -764.88
    for t, x_distance, aspect, aspect_error in time_dist_brng:
        # Calculate the bearing from the observers assumed position to the aircraft position
        x_obs_aircraft = x_mean - x_distance - plot_common.x_offset()
        obs_brng = math.degrees(math.atan2(y_mean, x_obs_aircraft))
        obs_brng %= 360
        yaw = (obs_brng - aspect) % 360
        if yaw > 180.0:
            yaw -= 360
        # Compute error as the angle:
        # 2.0 * atan(OBSERVER_ASSUMED_POSITION_ERROR / observer-to_aircraft_distance)
        obs_aircraft_distance = math.sqrt(y_mean**2 + x_obs_aircraft**2)
        error = 2.0 * math.degrees(
            math.atan(observer_error / obs_aircraft_distance))
        error += aspect_error
        time_yaw.append((t, yaw, yaw - error, yaw + error))
        # print('TRACE: t={:8.1f} yaw={:6.3f}),'.format(t, yaw))
    # print('TRACE: time_yaw:')
    # pprint.pprint(time_yaw)
    plot_common.gnuplot_write_arrays(stream, np.array(time_yaw))
    return ['']
Beispiel #2
0
def create_svg_transit_to_observer_xy() -> typing.List[str]:
    """
    Returns a list of SVG strings for the transit lines to the estimated observer position.
    """
    result = []
    # TODO: Have a common API for observer postion
    observer_xy_array, _possible = video_analysis.observer_position_combinations_from_aspects(
        baseline=plot_constants.OBSERVER_XY_MINIMUM_BASELINE,
        ignore_first_n=plot_constants.OBSERVER_XY_IGNORE_N_FIRST_BEARINGS,
    )
    observer_xy = video_utils.XY(
        np.mean(observer_xy_array[:, 0]) + plot_common.x_offset(),
        np.mean(observer_xy_array[:, 1]))

    result.append('<!-- {} -->'.format(
        'create_svg_transit_to_observer_xy()'.center(75)))
    colour = 'black'
    radius = plot_constants.distance_m_to_pixels(15)
    for transit_line in video_data.GOOGLE_EARTH_FULL_TRANSITS:
        x_0, y_0 = transit_line.frm.xy
        circle_pos_0 = plot_constants.position_m_to_pixels(
            plot_constants.PosXY(x_0, y_0))
        result.append(
            '<circle cx="{cx:.1f}" cy="{cy:.1f}" r="{r:.1f}" stroke="{colour:}" stroke-width="1" fill="none" />'
            .format(
                colour=colour,
                cx=circle_pos_0.x,
                cy=circle_pos_0.y,
                r=radius,
            ))
        x_1, y_1 = transit_line.to.xy
        circle_pos_1 = plot_constants.position_m_to_pixels(
            plot_constants.PosXY(x_1, y_1))
        result.append(
            '<circle cx="{cx:.1f}" cy="{cy:.1f}" r="{r:.1f}" stroke="{colour:}" stroke-width="1" fill="none" />'
            .format(
                colour=colour,
                cx=circle_pos_1.x,
                cy=circle_pos_1.y,
                r=radius,
            ))
        end_point = video_utils.transit_line_past_observer(
            transit_line.frm.xy, transit_line.to.xy, observer_xy, 250.0)
        # print('TRACE: create_svg_transit_to_observer_xy():', end_point)
        circle_pos_2 = plot_constants.position_m_to_pixels(end_point)
        result.append(
            '<line x1="{x1:.1f}" y1="{y1:.1f}" x2="{x2:.1f}" y2="{y2:.1f}" stroke="{colour:}" stroke-width="1" />'
            .format(
                colour=colour,
                x1=circle_pos_0.x,
                y1=circle_pos_0.y,
                x2=circle_pos_2.x,
                y2=circle_pos_2.y,
            ))
    result.append('<!-- DONE {} -->'.format(
        'create_svg_transit_to_observer_xy()'.center(75)))
    return result
Beispiel #3
0
def gnuplot_distance_from_transits(
        stream: typing.TextIO = sys.stdout) -> typing.List[str]:
    """
    Creates the data that compares distance computed by integrating ground speed with
    transit data.
    """
    print()
    print('TRACE: Distance fit from transits:',
          video_analysis.distance_fit_from_transits())

    notes = [
        'Distance of aircraft down the runway from comparing integrated ground speed and transit lines.',
        'time x_transit(m) x_min(m) x_mid(m) x_max(m) x_transit(m)',
    ]
    if len(notes):
        stream.write('#\n')
        stream.write('# Notes:\n')
        for note in notes:
            stream.write('# {}\n'.format(note))

    # Get the min/mid/max ground speed fits
    offset_distance_at_t = video_data.TIME_VIDEO_END_ASPHALT.time
    gs_fits = [
        plot_common.get_gs_fit(err) for err in video_data.ErrorDirection
    ]
    offsets = [
        video_data.RUNWAY_LEN_M -
        video_analysis.ground_speed_integral(0, offset_distance_at_t, gs_fit)
        for gs_fit in gs_fits
    ]
    # Establish observer
    observer_xy_start_runway = plot_common.observer_xy()

    result = []
    for event in video_analysis.transit_x_axis_distances(
            *observer_xy_start_runway):
        stream.write(
            '{t:<6.1f} {d_transit:.1f} {d_min:.1f} {d_mid:.1f} {d_max:.1f} # "{label:}"'
            .format(
                t=event.time,
                d_transit=event.distance,
                d_min=video_analysis.ground_speed_integral(
                    0.0, event.time, gs_fits[0]) + offsets[0],
                # 1182 metres
                d_mid=video_analysis.ground_speed_integral(
                    0.0, event.time, gs_fits[1]) + offsets[1],
                d_max=video_analysis.ground_speed_integral(
                    0.0, event.time, gs_fits[2]) + offsets[2],
                label=event.label,
            ))
        stream.write('\n')
        d = event.distance - video_analysis.ground_speed_integral(
            0.0, event.time, gs_fits[1]) + 3 - plot_common.x_offset()
        result.append(
            'set label "{label:} t={t:.1f}s ∆d={d:.0f}" at {t:.1f},{d:.1f} right font ",6" rotate by -35'
            .format(label=event.label, t=event.time - 0.5, d=d))
    return result
Beispiel #4
0
def gnuplot_observer_xy(stream: typing.TextIO=sys.stdout) -> typing.List[str]:
    notes = [
        '"{}"'.format('Estimated x/y of observer.'),
        'Columns:',
        '1: x (m)',
        '2: y minumum (m)',
        '3: y mid (m)',
        '4: y maximum (m)',
    ]
    if len(notes):
        stream.write('# Notes:\n')
        for note in notes:
            stream.write('# {}\n'.format(note))
    # observer_xy array
    observations = [
        video_analysis.observer_position_combinations_from_aspects(
            min_mid_max=error_direction,
            baseline=plot_constants.OBSERVER_XY_MINIMUM_BASELINE,
            ignore_first_n=plot_constants.OBSERVER_XY_IGNORE_N_FIRST_BEARINGS,
            t_range=plot_constants.OBSERVER_XY_TIME_RANGE,
        )[0] for error_direction in list(video_data.ErrorDirection)
    ]
    for obs in observations:
        obs[:,0] += plot_common.x_offset()
    plot_common.gnuplot_write_arrays(stream, *observations)
    # Print header twice, once for x, once for y.
    print('TRACE: gnuplot_observer_xy()')
    for i in range(2):
        axis_name = 'X' if i == 0 else 'Y'
        print('{}: {:>8s} {:>8s} {:>8s} {:>8s} {:>8s} {:>8s} {:>8s}  '.format(
            axis_name, 'Count', 'Min', 'Median', 'Mean', 'Max', 'Std', 'Range'), end=''
        )
    print()
    for obs in observations:
        for i in range(2):
            axis_name = 'X' if i == 0 else 'Y'
            print('{}: {:8d} {:8.0f} {:8.0f} {:8.0f} {:8.0f} {:8.0f} {:8.0f}  '.format(
                axis_name, len(obs),
                np.min(obs, axis=0)[i], np.median(obs, axis=0)[i],
                np.mean(obs, axis=0)[i], np.max(obs, axis=0)[i],
                np.std(obs, axis=0)[i], np.max(obs, axis=0)[i] - np.min(obs, axis=0)[i],
            ), end='')
        print()
    # x_mean = np.mean(observations[1], axis=0)[0]
    # x_min = np.min(observations[1], axis=0)[0]
    # x_max = np.max(observations[1], axis=0)[0]
    # x_std = np.std(observations[1], axis=0)[0]
    # y_mean = np.mean(observations[1], axis=0)[1]
    # y_min = np.min(observations[1], axis=0)[1]
    # y_max = np.max(observations[1], axis=0)[1]
    # y_std = np.std(observations[1], axis=0)[1]
    offset_label_x = -35
    ((x_mean, x_std), (y_mean, y_std)) = video_analysis.observer_position_mean_std_from_aspects(
        baseline=plot_constants.OBSERVER_XY_MINIMUM_BASELINE,
        ignore_first_n=plot_constants.OBSERVER_XY_IGNORE_N_FIRST_BEARINGS,
        t_range=plot_constants.OBSERVER_XY_TIME_RANGE,
    )
    x_mean += plot_common.x_offset()

    ret = [
        'set title "Observers Position [{:d} observations]"'.format(len(observations[1]))
        ]
    # Label and arrow for observer position from bearings
    ret.extend(
        [
            'set label "X={x_mean:.0f} ±{x_err:.0f}m Y={y_mean:.0f} ±{y_err:.0f} m" at {x:.0f},{y:.0f} right font ",12" textcolor rgb "#007F00"'.format(
                x_mean=x_mean,
                x_err=x_std,
                y_mean=y_mean,
                y_err=y_std,
                x=x_mean+offset_label_x,
                y=y_mean,
            ),
            'set arrow from {:.0f},{:.0f} to {:.0f},{:.0f} lt -1 lw 2 empty'.format(
                x_mean+offset_label_x+1, y_mean, x_mean, y_mean,
            ),
        ]
    )
    # Add transit lines
    # ret.extend(plot_common.full_transit_labels_and_arrows('#FF00FF'))
    ret.extend(plot_common.full_transit_labels_and_arrows('#FF00FF', 1.5))
    # Apply positional error and plot
    # 808080
    error = video_data.GOOGLE_EARTH_ERROR
    ret.extend(
        plot_common.full_transit_arrows_with_position_error('#00D0D0', error, 1.5)
    )
    ret.extend(
        plot_common.full_transit_arrows_with_position_error('#D0D000', -error, 1.5)
    )
    # Add transit label
    x, dx, y, dy = plot_common.observer_position_from_full_transits()
    # Add label and arrow for observer position from full transits
    ret.extend(
        [
            'set label "X={x_mean:.0f} ±{x_err:.0f}m Y={y_mean:.0f} ±{y_err:.0f} m" at {x:.0f},{y:.0f} right font ",12" textcolor rgb "#FF00FF"'.format(
                x_mean=x,
                x_err=dx,
                y_mean=y,
                y_err=dy,
                x=x+offset_label_x,
                y=y,
            ),
            'set arrow from {:.0f},{:.0f} to {:.0f},{:.0f} lt -1 lw 2 empty'.format(
                x+offset_label_x+1, y, x, y,
            ),
        ]
    )
    return ret
Beispiel #5
0
def gnuplot_observer_time_distance_bearing_with_yaw(stream: typing.TextIO=sys.stdout) -> typing.List[str]:
    result = [
        '# "{}"'.format('Video time, distance and bearing (s, m, degrees).')
    ]
    notes = [
        't(s) x_0(m) y_0(m) bearing(deg) x_1(m) y_1(m)'
    ]
    if len(notes):
        stream.write('#\n')
        stream.write('# Notes:\n')
        for note in notes:
            stream.write('# {}\n'.format(note))
    FORMAT = '{:8.3f}'
    x_offset = plot_common.x_offset()
    gs_fit = video_analysis.ground_speed_curve_fit(video_data.ErrorDirection.MID)
    # time_dist_brng = video_analysis.observer_time_distance_bearing(gs_fit, video_data.ErrorDirection.MID)
    time_dist_brng = video_analysis.observer_time_distance_bearing_from_wing_tips(gs_fit, video_data.ErrorDirection.MID)
    # time_dist_brng = video_analysis.time_distance_bearing_from_fits(time_interval=1.0)
    # ((x_mean, x_std), (y_mean, y_std)) = video_analysis.observer_position_mean_std_from_aspects(
    #     baseline=plot_constants.OBSERVER_XY_MINIMUM_BASELINE,
    #     ignore_first_n=plot_constants.OBSERVER_XY_IGNORE_N_FIRST_BEARINGS,
    #     t_range=plot_constants.OBSERVER_XY_TIME_RANGE,
    # )
    ((x_mean, x_std), (y_mean, y_std)) = video_analysis.observer_position_mean_std_from_full_transits()
    # print('Observer at:', ((x_mean+x_offset, x_std), (y_mean, y_std)))

    y_value = -950
    y_0 = 0.0
    arrow_texts = []
    label_texts = []
    for i in range(len(time_dist_brng)):
        t = time_dist_brng[i, 0]
        x_0 = time_dist_brng[i, 1] + x_offset
        bearing = time_dist_brng[i, 2]
        computed_bearing = math.degrees(math.atan2(y_mean, x_mean - x_0))
        computed_bearing %= 360
        distance = math.sqrt(y_mean**2 + (x_mean - x_0)**2)
        # Allow for assumed yaw of the aircraft from video_date.YAW_PROFILE
        # yaw = video_utils.interpolate(video_data.YAW_PROFILE[:, 0], video_data.YAW_PROFILE[:, 1], t)
        yaw = computed_bearing - bearing
        y_err = math.sin(math.radians(yaw)) * distance
        # print('TRACE: t={:6.1f} x_0={:6.1f} bearing={:6.1f} computed_bearing={:6.1f} yaw={:6.1f} y_err={:6.1f}'.format(
        #     t, x_0, bearing, computed_bearing, yaw, y_err
        # ))
        bearing += yaw
        if abs(math.sin(math.radians(bearing))) < 0.01:
            radius = abs(y_value - y_0)
        else:
            radius = abs(y_value / math.sin(math.radians(bearing)))
        x_1 = x_0 + radius * math.cos(math.radians(bearing))
        y_1 = y_0 + radius * math.sin(math.radians(bearing))
        part_line = ['{:.1f}'.format(t),]
        part_line.extend([FORMAT.format(v) for v in (x_0, y_0, bearing, x_1, y_1)])
        result.append(' '.join(part_line))
        if t < video_data.TIME_VIDEO_NOSEWHEEL_OFF.time:
            line_style = 7
        elif t >= video_data.TIME_VIDEO_MAINWHEEL_OFF.time:
            line_style = 14
        else:
            line_style = 6
        # Arrow line styles, SVG terminal.
        # 0 Dotted grey
        # 1 thin blue
        # 2 green
        # 3 blue
        # 4 cyan
        # 5 Dark green
        # 6 Dark blue
        # 14 Red
        arrow_texts.append(
            'set arrow from {:.0f},{:.0f} to {:.0f},{:.0f} ls {ls:d} nohead'.format(
                x_0, y_0, x_1, y_1,
                ls=4 if i < plot_constants.OBSERVER_XY_IGNORE_N_FIRST_BEARINGS else line_style
                # ls=i
            )
        )
        label_texts.append(
            # Gnuplot label numbering starts from 1
            'set label {} "t={:.1f}" at {:.0f},20 right rotate by 60 font ",9"'.format(
                i + 1, time_dist_brng[i, 0], x_0# - 25
            )
        )
    # observer_error = math.sqrt(x_std**2 + y_std**2)
    # Add annotation to identify observer
    label_texts.append(
        'set label "Observer assumed at x={x:.0f}, y={y:.0f}" at {x_pos:.0f},{y_pos:.0f} right font ",14"'.format(
            x=x_mean,
            y=y_mean,
            x_pos=x_mean - 500,
            y_pos=y_mean,
        )
    )
    arrow_texts.append(
        'set arrow from {:.0f},{:.0f} to {:.0f},{:.0f} lw 3'.format(
            x_mean - 500 + 25,
            y_mean,
            x_mean,
            y_mean,
        )
    )
    # print('# Arrows:')
    # print('\n'.join(arrow_texts))
    # print('# Labels:')
    # print('\n'.join(label_texts))
    stream.write('\n'.join(result))
    return arrow_texts + label_texts
Beispiel #6
0
def gnuplot_observer_time_distance_bearing(stream: typing.TextIO=sys.stdout) -> typing.List[str]:
    result = [
        '# "{}"'.format('')
    ]
    notes = [
        't(s) x_0(m) y_0(m) bearing(deg) x_1(m) y_1(m)'
    ]
    notes = [
        '"{}"'.format('Video time, distance and bearing (s, m, degrees).'),
        'Mostly this is information only as only the x value in column 2 is used to plot',
        'along the y=0 axis',
        'Columns:',
        '1: t (s)',
        '2: x_from (m)',
        '3: y_from (m)',
        '4: bearing (deg)',
        '5: x_to (m)',
        '6: y_to (m)',
    ]
    if len(notes):
        stream.write('# Notes:\n')
        for note in notes:
            stream.write('# {}\n'.format(note))

    FORMAT = '{:8.3f}'
    gs_fit = video_analysis.ground_speed_curve_fit(video_data.ErrorDirection.MID)
    # These are ndarrays of (time, distance, aspect, aspect_error)
    # time_dist_brng = video_analysis.observer_time_distance_bearing(gs_fit, video_data.ErrorDirection.MID)

    # time_dist_brng = video_analysis.observer_time_distance_bearing_from_wing_tips(gs_fit, video_data.ErrorDirection.MID)

    # Get the errors in bearing. This produces three ndarrays of (time, distance, aspect, aspect_error)
    # where the time and distance are the same (and probably the aspect error) so we can combine them
    # to create an list of (time, distance, bearing_min, bearing_mid, bearing_max)
    time_dist_brng_s = [
        video_analysis.observer_time_distance_bearing_from_wing_tips(gs_fit, err_direction)
        for err_direction in list(video_data.ErrorDirection)
    ]
    assert len(time_dist_brng_s) == 3
    assert len(set([len(v) for v in time_dist_brng_s])) == 1
    rows = len(time_dist_brng_s[0])
    time_distance_bearing_limits = []

    x_offset = plot_common.x_offset()
    for r in range(rows):
        # Time should be the same
        assert time_dist_brng_s[0][r, 0] == time_dist_brng_s[1][r, 0]
        assert time_dist_brng_s[0][r, 0] == time_dist_brng_s[2][r, 0]
        # Distance should be the same
        assert time_dist_brng_s[0][r, 1] == time_dist_brng_s[1][r, 1]
        assert time_dist_brng_s[0][r, 1] == time_dist_brng_s[2][r, 1]
        time_distance_bearing_limits.append(
            (
                time_dist_brng_s[0][r, 0], # time
                time_dist_brng_s[0][r, 1]+x_offset, # distance
                time_dist_brng_s[0][r, 2], # bearing_min
                time_dist_brng_s[1][r, 2], # bearing_mid
                time_dist_brng_s[2][r, 2], # bearing_max
            )
        )
    # print('TRACE: time_distance_bearing_limits')
    # for row in time_distance_bearing_limits:
    #     print('{:6.1f} {:6.1f} {:8.3f} {:8.3f} {:8.3f}'.format(*row))
    y_value = -950
    y_0 = 0.0
    arrow_texts = []
    label_texts = []
    for i in range(len(time_dist_brng_s[1])):
        t = time_dist_brng_s[1][i, 0]
        x_0 = time_dist_brng_s[1][i, 1]
        bearing = time_dist_brng_s[1][i, 2]
        if abs(math.sin(math.radians(bearing))) < 0.01:
            radius = abs(y_value - y_0)
        else:
            radius = abs(y_value / math.sin(math.radians(bearing)))
        x_1 = x_0 + radius * math.cos(math.radians(bearing))
        y_1 = y_0 + radius * math.sin(math.radians(bearing))
        part_line = ['{:.1f}'.format(t),]
        part_line.extend([FORMAT.format(v) for v in (x_0 + x_offset, y_0, bearing, x_1 + x_offset, y_1)])
        result.append(' '.join(part_line))
        if t < video_data.TIME_VIDEO_NOSEWHEEL_OFF.time:
            line_style = 7
        elif t >= video_data.TIME_VIDEO_MAINWHEEL_OFF.time:
            line_style = 14
        else:
            line_style = 6
        # Arrow line styles, SVG terminal.
        # 0 Dotted grey
        # 1 thin blue
        # 2 green
        # 3 blue
        # 4 cyan
        # 5 Dark green
        # 6 Dark blue
        # 14 Red
        arrow_texts.append(
            'set arrow from {:.0f},{:.0f} to {:.0f},{:.0f} ls {ls:d} nohead'.format(
                x_0+x_offset, y_0, x_1+x_offset, y_1,
                ls=4 if i < plot_constants.OBSERVER_XY_IGNORE_N_FIRST_BEARINGS else line_style
                # ls=i
            )
        )
        label_texts.append(
            # Gnuplot label numbering starts from 1
            'set label {} "t={:.1f}" at {:.0f},20 right rotate by 60 font ",9"'.format(
                i + 1, time_dist_brng_s[1][i, 0], x_0 + x_offset# - 25
            )
        )
    # print('# Arrows:')
    # print('\n'.join(arrow_texts))
    # print('# Labels:')
    # print('\n'.join(label_texts))
    stream.write('\n'.join(result))

    # Add annotation to identify observer
    ((x_mean, x_std), (y_mean, y_std)) = video_analysis.observer_position_mean_std_from_aspects(
        baseline=plot_constants.OBSERVER_XY_MINIMUM_BASELINE,
        ignore_first_n=plot_constants.OBSERVER_XY_IGNORE_N_FIRST_BEARINGS,
        t_range=plot_constants.OBSERVER_XY_TIME_RANGE,
    )
    label_texts.append(
        'set label "Mean position at x={x:.0f}, y={y:.0f}" at {x_pos:.0f},{y_pos:.0f} right font ",14"'.format(
            x=x_mean+x_offset,
            y=y_mean,
            x_pos=x_mean + x_offset - 500,
            y_pos=y_mean,
        )
    )
    arrow_texts.append(
        'set arrow from {:.0f},{:.0f} to {:.0f},{:.0f} lw 3'.format(
            x_mean + x_offset - 500 + 25,
            y_mean,
            x_mean + x_offset,
            y_mean,
        )
    )

    return arrow_texts + label_texts