def gnuplot_aspect(stream: typing.TextIO = sys.stdout) -> typing.List[str]: arrays_from_transits = { min_max: aspect.aspects(min_max) for min_max in list(video_data.ErrorDirection) } timebase = arrays_from_transits[video_data.ErrorDirection.MID][:, 0] aspect_from_transits_with_errors = np.column_stack(( timebase, arrays_from_transits[video_data.ErrorDirection.MID][:, 1], arrays_from_transits[video_data.ErrorDirection.MIN][:, 0], arrays_from_transits[video_data.ErrorDirection.MAX][:, 0], arrays_from_transits[video_data.ErrorDirection.MIN][:, 1], arrays_from_transits[video_data.ErrorDirection.MAX][:, 1], )) aspect_from_transits_fitted = aspect.aspect_fitted_line() arrays_from_wing_tips = { min_max: aspect.aspects_from_wing_tips(min_max) for min_max in list(video_data.ErrorDirection) } timebase_from_wing_tips = arrays_from_wing_tips[ video_data.ErrorDirection.MID][:, 0] aspect_from_wing_tips_with_errors = np.column_stack(( timebase_from_wing_tips, arrays_from_wing_tips[video_data.ErrorDirection.MID][:, 1], arrays_from_wing_tips[video_data.ErrorDirection.MIN][:, 0], arrays_from_wing_tips[video_data.ErrorDirection.MAX][:, 0], arrays_from_wing_tips[video_data.ErrorDirection.MIN][:, 1], arrays_from_wing_tips[video_data.ErrorDirection.MAX][:, 1], )) aspect_fitted_from_wing_tips = aspect.aspect_from_wing_tips_fitted_line() # TODO: Make use of notes the same in all functions notes = [ '"{}"'.format('Aspects, errors, and polynomial fit.'), 'Columns:', '1: time (s)', '2: aspect_from_transits (deg)', '3: -dt', '4: +dt', '5: -dy (deg)', '6: +dy (deg)', '7: aspect_from_transit_fit (deg)', '8: aspect_from_wingtips (deg)', '9: -dt', '10: +dt', '11: -dy (deg)', '12: +dy (deg)', '13: aspect_from_wingtips_fit (deg)', ] if len(notes): stream.write('# Notes:\n') for note in notes: stream.write('# {}\n'.format(note)) plot_common.gnuplot_write_arrays( stream, aspect_from_transits_with_errors, aspect_from_transits_fitted, aspect_from_wing_tips_with_errors, aspect_fitted_from_wing_tips, ) return []
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 ['']
def gnuplot_pitch(stream: typing.TextIO=sys.stdout) -> typing.List[str]: arrays = { min_max: pitch.pitches(min_max) for min_max in list(video_data.ErrorDirection) } timebase = arrays[video_data.ErrorDirection.MID][:, 0] aspect_with_errors = np.column_stack( ( timebase, arrays[video_data.ErrorDirection.MID][:, 1], arrays[video_data.ErrorDirection.MIN][:, 0], arrays[video_data.ErrorDirection.MAX][:, 0], arrays[video_data.ErrorDirection.MIN][:, 1], arrays[video_data.ErrorDirection.MAX][:, 1], ) ) aspect_fitted = pitch.pitch_fitted_line() result = [ '# "{}"'.format('Pitch (degrees), errors, and polynomial fit.'), '# "{}"'.format('t, -dt, +dt, -dy, +dy, fit.'), ] notes = [ ] if len(notes): result.append('#') result.append('# Notes:') for note in notes: result.append('# {}'.format(note)) result.append('# {:>2} {:>8} {:>8}'.format( 't', 'speed', 'smoothed' ) ) plot_common.gnuplot_write_arrays( stream, aspect_with_errors, aspect_fitted, ) return []
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
def _gnuplot_distance( offset_distance_at_t: float, include_labels_t_0: bool, stream: typing.TextIO = sys.stdout, ) -> typing.List[str]: """ If offset_distance_at_t is non-zero an offset will be applied that is the runway length - the distance at that offset time. """ three_dist_arrays = get_distances_min_mid_max(offset_distance_at_t) plot_common.gnuplot_write_arrays(stream, *three_dist_arrays) plot_data = ['# Start distance arrows and labels'] if offset_distance_at_t == 0.0: text_offset = 0 else: text_offset = 1000 plot_data.extend([ # set arrow from -30.137,0 to -30.137,-791.8 lt 1 'set arrow from {t:.3f},{offset:d} to {t:.3f},{d:.3f} lt {lt:d}'. format( t=three_dist_arrays[i][0, 0], offset=text_offset + i * 200, d=three_dist_arrays[i][0, 1], lt=i + 1, ) for i in range(len(three_dist_arrays)) ]) plot_data.extend([ # set label 1 "Calculated start at -30s, -790m" at -30.137,100 left font ",10" # rotate by 45 'set label "Calculated start at {t:.1f}s, {d:.0f}m" at {t:.1f},{offset:d} left font ",9"' .format( t=three_dist_arrays[i][0, 0], offset=text_offset + 100 + i * 200, d=three_dist_arrays[i][0, 1], ) for i in range(len(three_dist_arrays)) ]) plot_data.append('# End labels at start of take off') if include_labels_t_0: plot_data.append('# Labels at t=0') for i in range(len(three_dist_arrays)): d = video_utils.interpolate(three_dist_arrays[i][:, 0], three_dist_arrays[i][:, 1], 0.0) plot_data.append( # set arrow from -30.137,0 to -30.137,-791.8 lt 1 'set arrow from {t:.3f},{d:.1f} to 0.0,{d:.3f} lt {lt:d}'. format( t=6.0, d=d, lt=i + 1, )) plot_data.append( # set label 1 "Calculated start at -30s, -790m" at -30.137,100 left font ",10" # rotate by 45 'set label "t=0.0s, d={d:.0f}m" at {t:.1f},{d:.1f} left font ",9"' .format( t=6.0, d=d, )) plot_data.append('# End labels at t=0') if offset_distance_at_t == 0.0: d_to = 1850 else: d_to = video_data.RUNWAY_LEN_M - 100 d_from = d_to - 850 plot_data.append( 'set arrow from {t:.3f},{d_from:d} to {t:.3f},{d_to:d} lt -1'.format( d_from=d_from, d_to=d_to, t=video_data.TIME_VIDEO_END_ASPHALT.time, )) plot_data.append( # set label 7 "End asphalt 27.8s" at 27.8,900 center font ",10" 'set label "End asphalt {t:.1f}s" at {t:.1f},{d:d} center font ",10"'. format( d=d_from - 100, t=video_data.TIME_VIDEO_END_ASPHALT.time, )) if offset_distance_at_t == 0.0: plot_data.extend([ # set arrow from 17.8,1919 to 27.8,1919 as 4 lt 1 'set arrow from {t0:.3f},{distance:.3f} to {t1:.3f},{distance:.3f} lt {lt:d}' .format( t0=video_data.TIME_VIDEO_END_ASPHALT.time - 10, t1=video_data.TIME_VIDEO_END_ASPHALT.time, distance=np.interp( video_data.TIME_VIDEO_END_ASPHALT.time, three_dist_arrays[i][:, 0], three_dist_arrays[i][:, 1], ), lt=i + 1, ) for i in range(len(three_dist_arrays)) ]) plot_data.extend([ # set label 4 "1920m" at 17,1920 right font ",10" # rotate by 45 'set label "{distance:.0f}m" at {t:.1f},{distance:.1f} right font ",10"' .format( t=video_data.TIME_VIDEO_END_ASPHALT.time - 10 - 1, distance=np.interp( video_data.TIME_VIDEO_END_ASPHALT.time, three_dist_arrays[i][:, 0], three_dist_arrays[i][:, 1], ), ) for i in range(len(three_dist_arrays)) ]) else: plot_data.append( 'set arrow from {t0:.3f},{distance:.3f} to {t1:.3f},{distance:.3f} lt {lt:d}' .format( t0=video_data.TIME_VIDEO_END_ASPHALT.time - 10, t1=video_data.TIME_VIDEO_END_ASPHALT.time, distance=video_data.RUNWAY_LEN_M, lt=2, )) plot_data.append( 'set label "{distance:.0f}m" at {t:.1f},{distance:.1f} right font ",10"' .format( t=video_data.TIME_VIDEO_END_ASPHALT.time - 10 - 1, distance=video_data.RUNWAY_LEN_M, )) plot_data.append('# End video') # TODO: Constants here, they should be computed. if offset_distance_at_t == 0.0: d_to = 2350 else: d_to = 3700 d_from = d_to - 850 plot_data.append( # set arrow from 33.7,1500 to 33.7,2350 as 11 lt -1 'set arrow from {t:.3f},{d_from:d} to {t:.3f},{d_to:d} lt -1'.format( t=video_data.TIME_VIDEO_END.time, d_from=d_from, d_to=d_to, )) plot_data.append( # set label 11 "End video 33.7s" at 33.7,1400 center font ",10" # rotate by 45 'set label "End video {t:.1f}s" at {t:.1f},{d:d} center font ",10"'. format(t=video_data.TIME_VIDEO_END.time, d=d_from - 100)) if offset_distance_at_t == 0.0: # Plot individual arrows and labels of end of video plot_data.extend([ # set arrow from 23.7,2432.8 to 33.7,2432.8 as 8 lt 1 'set arrow from {t0:.3f},{distance:.3f} to {t1:.3f},{distance:.3f} lt {lt:d}' .format( t0=video_data.TIME_VIDEO_END.time - 10, t1=video_data.TIME_VIDEO_END.time, distance=np.interp( video_data.TIME_VIDEO_END.time, three_dist_arrays[i][:, 0], three_dist_arrays[i][:, 1], ), lt=i + 1, ) for i in range(len(three_dist_arrays)) ]) plot_data.extend([ # label 10 "2770m" at 23,2770 right font ",10" # rotate by 45 'set label "{distance:.0f}m" at {t:.1f},{distance:.1f} right font ",10"' .format( t=video_data.TIME_VIDEO_END.time - 10 - 1, distance=np.interp( video_data.TIME_VIDEO_END.time, three_dist_arrays[i][:, 0], three_dist_arrays[i][:, 1], ), ) for i in range(len(three_dist_arrays)) ]) return plot_data
def gnuplot_angle_of_view( stream: typing.TextIO = sys.stdout) -> typing.List[str]: for raw_aspect in video_data.AIRCRAFT_ASPECTS_FROM_WING_TIPS: t = raw_aspect.video_time px_len = raw_aspect.length px_span = raw_aspect.span arrays_from_wing_tips = { min_max: aspect.aspects_from_wing_tips(min_max) for min_max in list(video_data.ErrorDirection) } # raw_data = video_data.AIRCRAFT_ASPECTS_FROM_WING_TIPS timebase_from_wing_tips = arrays_from_wing_tips[ video_data.ErrorDirection.MID][:, 0] aspect_from_wing_tips_with_errors = np.column_stack(( timebase_from_wing_tips, arrays_from_wing_tips[video_data.ErrorDirection.MID][:, 1], arrays_from_wing_tips[video_data.ErrorDirection.MIN][:, 0], arrays_from_wing_tips[video_data.ErrorDirection.MAX][:, 0], arrays_from_wing_tips[video_data.ErrorDirection.MIN][:, 1], arrays_from_wing_tips[video_data.ErrorDirection.MAX][:, 1], )) aspect_fitted_from_wing_tips = aspect.aspect_from_wing_tips_fitted_line() # 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() notes = [ '"{}"'.format('Aspects, errors, and polynomial fit.'), 'Columns:', '1: time (s)', '2: horizontal_angle (deg)', '3: -dt', '4: +dt', '5: -dy (deg)', '6: +dy (deg)', '7: horizontal_angle_fit (deg)', '8: vertical_angle (deg)', '9: -dt', '10: +dt', '11: -dy (deg)', '12: +dy (deg)', '13: vertical_angle_fit (deg)', ] if len(notes): stream.write('# Notes:\n') for note in notes: stream.write('# {}\n'.format(note)) plot_common.gnuplot_write_arrays( stream, aspect_from_wing_tips_with_errors, aspect_fitted_from_wing_tips, ) return []
def gnuplot_ground_speed_extrapolated( stream: typing.TextIO = sys.stdout) -> typing.List[str]: gs_arrays = [ video_analysis.ground_speeds(min_max) for min_max in list(video_data.ErrorDirection) ] gs_fits = [ plot_common.get_gs_fit(err) for err in video_data.ErrorDirection ] result = [ '# "{}"'.format( 'Grounds speed, mid data and smoothed data, extrapolated.') ] notes = [ 'Columns', '1: Time (s)', '2: Ground speed, mid values (knots).', '3: Time, minimum (s).', '4: Time, maximum (s).', '5: Ground speed, min values (knots).', '6: Ground speed, max values (knots).', '7: Ground speed extrapolated, mid values (knots).', '8: Ground speed extrapolated, min values (knots).', '9: Ground speed extrapolated, max values (knots).', ] if len(notes): result.append('#') result.append('# Notes:') for note in notes: result.append('# {}'.format(note)) gs_arrays_extrapolated = [] for fit in gs_fits: gs_arrays_extrapolated.append( np.array([(t, video_analysis.ground_speed_from_fit(t, fit)) for t in plot_constants.EXTRAPOLATED_RANGE])) # Convert selected columns to knots k = video_utils.m_p_s_to_knots(1.0) for i in range(3): gs_arrays[i][:, 1] *= k gs_arrays_extrapolated[i][:, 1] *= k stream.write('\n'.join(result)) stream.write('\n') plot_common.gnuplot_write_arrays( stream, gs_arrays[1], np.column_stack((gs_arrays[1][:, 0], gs_arrays[1][:, 0] - video_data.ERROR_TIMESTAMP)), np.column_stack((gs_arrays[1][:, 0], gs_arrays[1][:, 0] + video_data.ERROR_TIMESTAMP)), gs_arrays[0], gs_arrays[2], gs_arrays_extrapolated[1], gs_arrays_extrapolated[0], gs_arrays_extrapolated[2], ) # Print time for v=0 plot_data = [] for i in range(len(gs_arrays_extrapolated)): t = video_utils.interpolate(gs_arrays_extrapolated[i][:, 1], gs_arrays_extrapolated[i][:, 0], 0.0) print('Time start[{:d}] t, v=0: {:.3f} Polynomial roots: {}'.format( i, t, np.roots(list(reversed(gs_fits[i]))))) plot_data.append( 'set arrow from {t:.3f},{offset:d} to {t:.3f},{zero:.3f} lt {lt:d}' .format( t=t, offset=50 + i * 25, zero=0.0, lt=i + 1, )) plot_data.append( 'set label "t={t0:.1f}s" at {t1:.1f},{offset:d} left font ",12"'. format( t0=t, t1=t - 2, offset=54 + i * 25, )) return plot_data