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
def gen_event_data() -> ComputedEventData: # gs_fits = [plot_common.get_gs_fit(err) for err in video_data.ErrorDirection] gs_fits = get_gs_fits_corrected() # Find initial start and distance start_times = [np.roots(list(reversed(v)))[-1] for v in gs_fits] # These are the location of the aircraft from the beginning of the runway at t=0 offsets = [ video_data.RUNWAY_LEN_M - video_analysis.ground_speed_integral( 0, video_data.TIME_VIDEO_END_ASPHALT.time, gs_fit) for gs_fit in gs_fits ] gs_fit_mid = gs_fits[1] for event in EVENTS_TIMED: t_video = event.t if t_video is None: # Compute t_video from estimated start t_video = start_times[1] t_start = 0.0 t_err = max([ abs(start_times[1] - start_times[0]), abs(start_times[1] - start_times[2]) ]) gs_err = None else: t_start = t_video - start_times[1] t_err = None gs_err = video_utils.knots_to_m_p_s( 5.0) #max([abs(v) for v in GROUND_SPEED_OFFSETS]) gs = video_analysis.ground_speed_from_fit(t_video, gs_fit_mid) accl = video_analysis.ground_speed_differential(t_video, gs_fit_mid) d_from_start = offsets[1] + video_analysis.ground_speed_integral( 0.0, t_video, gs_fits[1]) d_from_start_min = offsets[0] + video_analysis.ground_speed_integral( 0.0, t_video, gs_fits[0]) d_from_start_max = offsets[2] + video_analysis.ground_speed_integral( 0.0, t_video, gs_fits[2]) d_from_start_error = max([ abs(d_from_start - d_from_start_min), abs(d_from_start - d_from_start_max), ]) # Transit calculations improve integrated distance if t_video >= 0.0: d_from_start_error = 25.0 d_from_start_error = max([d_from_start_error, 25.0]) yield ComputedEventData( event.label, ValueAndError(t_video, t_err), ValueAndError(t_start, t_err), ValueAndError(gs, gs_err), ValueAndError(accl, 0.17 / 2), # Hard coded ValueAndError(d_from_start, d_from_start_error), ValueAndError(video_data.RUNWAY_LEN_M - d_from_start, d_from_start_error), event.notes, )
def x_offset(): """The x offset at t=0 from the runway start based on integrating the ground speed integral.""" distance_to_end = video_analysis.ground_speed_integral( 0, video_data.TIME_VIDEO_END_ASPHALT.time, get_gs_fit(video_data.ErrorDirection.MID)) result = video_data.RUNWAY_LEN_M - distance_to_end return result
def get_distances_min_mid_max( offset_distance_at_t: float) -> typing.Tuple[np.ndarray]: """Returns a tuple of three np.ndarray of (time, distance) corresponding to the the -10, mid, +10 knot fits of ground speed. If offset_distance_at_t is non-zero an offset will be applied, that is the runway length - the distance at that offset time. So if the time is video_data.TIME_VIDEO_END_ASPHALT.time the distance is from the runway start. """ gs_fits = [get_gs_fit(err) for err in video_data.ErrorDirection] three_dist_arrays = [] # Three different fits: -10, 0, +10 knots if offset_distance_at_t != 0.0: # Offsets of: [3240 - 1919, 3240 - 2058, 3240 - 2197,] offsets = [ video_data.RUNWAY_LEN_M - video_analysis.ground_speed_integral( 0, offset_distance_at_t, gs_fit) for gs_fit in gs_fits ] else: offsets = [0.0] * len(gs_fits) for i, gs_fit in enumerate(gs_fits): t = np.roots(list(reversed(gs_fit)))[-1] times = [] while t < plot_constants.EXTRAPOLATED_RANGE.stop: times.append(t) t += 1 # Add as special cases: t=0, t=27+24/30 - end of asphalt, t=end. for special_t in ( 0.0, video_data.TIME_VIDEO_NOSEWHEEL_OFF.time, video_data.TIME_VIDEO_MAINWHEEL_OFF.time, video_data.TIME_VIDEO_END_ASPHALT.time, video_data.TIME_VIDEO_END.time, ): if special_t not in times: times.append(special_t) array = [] for t in sorted(times): array.append( (t, video_analysis.ground_speed_integral(0, t, gs_fit) + offsets[i])) three_dist_arrays.append(np.array(array)) return tuple(three_dist_arrays)
def markdown_table_equations_of_motion( ) -> typing.Tuple[typing.List[str], str]: """ Returns equations of motion as a list of strings and the title in markdown format. For example:: | Measure | Units | Formulae | Tolerance | Notes | | --- | --- | --- | --- | --- | | Ground speed | m/s | 58.3 + 1.48 * t - 0.00794 * t^2 - 0.0000418 * t^3 | ±2.5 | See note 1 below. | | Acceleration | m/s^s | 1.48 - 0.0159 * t - 0.000125 * t^2 | ±0.17 | See note 2 below. | | Distance | m | 1110 + 58.3 * t + 0.741 * t^2 - 0.00265 * t^3 - 0.0000104 * t^4 | ±25 for t>=0 | See note 3 below. | """ ret = [ '| Measure | Units | Formulae | Tolerance | Notes |', '| --- | --- | --- | --- | --- |', ] gs_fit = get_gs_fits_corrected()[1] offset_video_start = video_data.RUNWAY_LEN_M offset_video_start -= video_analysis.ground_speed_integral( 0, video_data.TIME_VIDEO_END_ASPHALT.time, gs_fit) values = [gs_fit[i] for i in range(4)] ret.append( '| Ground speed | m/s | {:.2e} {:+.2e} * t {:+.2e} * t^2 {:+.2e} * t^3 | {} | {} |' .format( *values, '±2.5', 'See note 1 below.', )) values = [i * gs_fit[i] for i in range(1, 4)] ret.append( '| Acceleration | m/s^2 | {:.2e} {:+.2e} * t {:+.2e} * t^2 | {} | {} |' .format( *values, '±0.17', 'See note 2 below.', )) values = [offset_video_start] values += [gs_fit[i] / (i + 1) for i in range(4)] ret.append( '| Distance | m | {:.2e} + {:.2e} * t {:+.2e} * t^2 {:+.2e} * t^3 {:+.2e} * t^4 | {} | {} |' .format( *values, '±25 for t>=0', 'See note 3 below.', )) return ret, 'Equations of Motion'
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 []