def camera_angle_of_view( min_mid_max: video_data.ErrorDirection = video_data.ErrorDirection.MID ) -> np.ndarray: # TODO: Figure out min/max error terms. # Max value is obtained with: # max alpha, min d, min pitch # Min value is obtained with: # min alpha, max d, max pitch gs_fit = ground_speed_curve_fit(-min_mid_max) # aspect_fit = aspect.aspects_curve_fit(min_mid_max) pitch_data = pitch.pitches(-min_mid_max) OBSERVER_POSITION_X = 2250 OBSERVER_POSITION_Y = -750 for data in video_data.AIRCRAFT_LENGTH_IN_PIXELS: t = data.video_time.time px = data.length_px x = OBSERVER_POSITION_X - ground_speed_integral(0, t, gs_fit) d = math.sqrt(x**2 + OBSERVER_POSITION_Y**2) alpha = abs(math.atan2(OBSERVER_POSITION_Y, x)) pitch_angle = video_utils.interpolate(pitch_data[:, 0], pitch_data[:, 1], t) apparent_length = video_data.TRANSIT_REFERENCE_LENGTH * math.sin( alpha) * math.cos(math.radians(pitch_angle)) px_per_m = px / apparent_length width_in_m = video_data.SCREENSHOT_WIDTH / px_per_m angle_of_view = math.degrees(2 * math.atan(width_in_m / (2 * d))) print('{:<4.1f} {:6.3f}'.format(t, angle_of_view))
def markdown_table_aircraft_start() -> typing.Tuple[typing.List[str], str]: """ Returns a markdown table and a title for the distance estimates at start of take off. """ ret = [ '| Calculation | Video Time t (s) | Distance from start of Runway (m) | Distance from start of Runway at t=0 (m) |', '| --- | --: | --: | --: |', ] labels = ( 'Mid speed -10 knots', 'Mid speed', 'Mid speed +10 knots', ) three_dist_arrays = get_distances_min_mid_max( video_data.TIME_VIDEO_END_ASPHALT.time) # Time ranges for min/mid/max of start of take off t_range = [arr[0][0] for arr in three_dist_arrays] # Distance of start of take off from start of runway for min/mid/max d_range = [arr[0][1] for arr in three_dist_arrays] # Distance of start of video from start of runway for min/mid/max d_range_video_start = [ video_utils.interpolate(arr[:, 0], arr[:, 1], 0.0) for arr in three_dist_arrays ] for label, arr, d_video_start in zip(labels, three_dist_arrays, d_range_video_start): t, d = arr[0] ret.append('| {} | {:.1f} | {:.0f} | {:.0f} |'.format( label, t, d, d_video_start)) ret.append( '| **{}** | **{:.1f} ±{:.1f}** | **{:.0f} ±{:.0f}** | **{:.0f} ±{:.0f}** |' .format( 'Range and worst error', t_range[1], max(abs(t_range[2] - t_range[1]), abs(t_range[0] - t_range[1])), d_range[1], max(abs(d_range[2] - d_range[1]), abs(d_range[0] - d_range[1])), d_range_video_start[1], max(abs(d_range_video_start[2] - d_range_video_start[1]), abs(d_range_video_start[0] - d_range_video_start[1])), )) return ret, 'Distance Estimates for the Start of Take off'
def _transit(t: float) -> float: """Returns the apparent transit time, dt, of the aircraft fuselage at time t.""" xS = [v.time for v in video_data.AIRCRAFT_TRANSITS] yS = [v.dt for v in video_data.AIRCRAFT_TRANSITS] return video_utils.interpolate(xS, yS, t)
def _pitch(t: float) -> float: """Returns the apparent pitch angle of the aircraft at time t. Due to camera roll this may not be accurate.""" xS = [v.video_time.time for v in video_data.AIRCRAFT_PITCHES] yS = [v.angle for v in video_data.AIRCRAFT_PITCHES] return video_utils.interpolate(xS, yS, t)
def test_interpolate(x, y): # [4, 8, 12, 16] xS = list(range(4, 17, 4)) # [8, 16, 24, 32] yS = [v * 2 for v in xS] assert y == video_utils.interpolate(xS, yS, x)
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_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