def _compute_speed( frame: int, tile_d_fits: typing.Dict[str, typing.Tuple[np.ndarray, np.ndarray]], slab_v_fits: typing.Dict[str, typing.Tuple[np.ndarray, np.ndarray]] ) -> typing.Tuple[float, float, float]: t = map_funcs.frame_to_time(frame, FRAME_RATE) if frame <= FRAME_THRESHOLD: # Only use the tile_d_fits return (polynomial.polynomial_3_differential(t, *tile_d_fits['d'][0]), polynomial.polynomial_3_differential(t, *tile_d_fits['d+'][0]), polynomial.polynomial_3_differential(t, *tile_d_fits['d-'][0])) else: slab_v = ( polynomial.polynomial_3(t, *slab_v_fits["v"][0]), polynomial.polynomial_3(t, *slab_v_fits["v+"][0]), polynomial.polynomial_3(t, *slab_v_fits["v-"][0]), ) if frame > max(POSITIONS_FROM_TILES.keys()): # Only use the slab_v_fits return slab_v else: # Use both return ( (polynomial.polynomial_3_differential(t, *tile_d_fits['d'][0]) + slab_v[0]) / 2.0, (polynomial.polynomial_3_differential(t, *tile_d_fits['d+'][0]) + slab_v[1]) / 2.0, (polynomial.polynomial_3_differential(t, *tile_d_fits['d-'][0]) + slab_v[2]) / 2.0, )
def print_table_of_events() -> None: tile_d_fits = get_tile_d_fits()[1] slab_v_fits = get_slab_v_fits() print( '| Time (s) | Position (m) | Ground Speed (m/s, knots) | Acceleration (m/s^2 ) | Description |' ) print('| ---: | ---: | ---: | ---: | :--- |') for frame_number in sorted(FRAME_EVENTS.keys()): t = map_funcs.frame_to_time(frame_number, FRAME_RATE) d, d_plus, d_minus = _compute_distance(frame_number, tile_d_fits, slab_v_fits) d_tol = max(abs(d - d_plus), abs(d - d_minus)) v, v_plus, v_minus = _compute_speed(frame_number, tile_d_fits, slab_v_fits) v_tol = max(abs(v - v_plus), abs(v - v_minus)) a, a_plus, a_minus = _compute_acceleration(frame_number, tile_d_fits, slab_v_fits) a_tol = max(abs(a - a_plus), abs(a - a_minus)) print( f'| {t:4.1f} |', f' {d:7.0f}±{d_tol:.0f} |', f' {v:7.1f}±{v_tol:.1f}, ', f' {map_funcs.metres_per_second_to_knots(v):.0f}±{map_funcs.metres_per_second_to_knots(v_tol):.0f} |', f' {a:7.1f}±{a_tol:.1f} |', f' {FRAME_EVENTS[frame_number]} |') print('# Edit the above:') print('# Line 2: Remove -ve signe from acceleration.') print( '# Line 3: Set position to 0, set acceleration to -0.7±0.1 (hand calculated).' ) print( '# Line 9: change to | 56.1 | ~1853 | ~19, 37 | ~ -3.9 | Impact with fence |' ) print( '# Line 9: | 57.0 | ~1889 | ~9, 18 | N/A | Final impact? |') print('# Line 10: remove.')
def write_slab_results(stream: typing.TextIO = sys.stdout): """Writes out the results from the slab data.""" columns = ('Frame', 'Time', 'v', 'v+', 'v-', 'd', 'd+', 'd-', 'a', 'a+', 'a-') # Compute fits # V_ORDER = ('v', 'v+', 'v-') V_FORMULAE = { 'v': 'speed_mid', 'v+': 'speed_plus', 'v-': 'speed_minus', } v_fits = get_slab_v_fits() # print(map_data.SLAB_SPEEDS) # print('v_fits', v_fits) stream.write('# Slab speed data\n') for v in SLAB_V_ORDER: # coeff_str = [f'{value:.3e}' for value in v_fits[v][0]] # stream.write(f'# {v} coefficients: {", ".join(coeff_str)}\n') formulae = polynomial.polynomial_string(V_FORMULAE[v], 't', '.3e', *v_fits[v][0]) stream.write(f'# {formulae}\n') THRESHOLD_TIME = map_funcs.frame_to_time(FRAME_THRESHOLD, FRAME_RATE) d_offsets = [ polynomial.polynomial_3_integral(THRESHOLD_TIME, *v_fits["v"][0]), polynomial.polynomial_3_integral(THRESHOLD_TIME, *v_fits["v+"][0]), polynomial.polynomial_3_integral(THRESHOLD_TIME, *v_fits["v-"][0]), ] stream.write(f'# d_offsets {d_offsets}\n') stream.write( f'# Columns: frame, t, v, v+, v- (m/s), d, d+, d-, a, a+, a-, v, v+, v- (knots)\n' ) for i in range(len(SLAB_SPEEDS)): t = SLAB_SPEEDS[i, 1] v_m_per_second = [SLAB_SPEEDS[i, j] for j in (2, 3, 4)] v_knots = [ map_funcs.metres_per_second_to_knots(v) for v in v_m_per_second ] row = [ f'{SLAB_SPEEDS[i, 0]:<6.0f}', f'{t:6.1f}', f'{v_m_per_second[0]:8.1f}', f'{v_m_per_second[1]:8.1f}', f'{v_m_per_second[2]:8.1f}', f'{polynomial.polynomial_3_integral(t, *v_fits["v"][0]) - d_offsets[0]:8.1f}', f'{polynomial.polynomial_3_integral(t, *v_fits["v+"][0]) - d_offsets[1]:8.1f}', f'{polynomial.polynomial_3_integral(t, *v_fits["v-"][0]) - d_offsets[2]:8.1f}', f'{polynomial.polynomial_3_differential(t, *v_fits["v"][0]):8.1f}', f'{polynomial.polynomial_3_differential(t, *v_fits["v+"][0]):8.1f}', f'{polynomial.polynomial_3_differential(t, *v_fits["v-"][0]):8.1f}', f'{v_knots[0]:8.1f}', f'{v_knots[1]:8.1f}', f'{v_knots[2]:8.1f}', ] stream.write(' '.join((row))) stream.write('\n')
def _compute_distance( frame: int, tile_d_fits: typing.Dict[str, typing.Tuple[np.ndarray, np.ndarray]], slab_v_fits: typing.Dict[str, typing.Tuple[np.ndarray, np.ndarray]] ) -> typing.Tuple[float, float, float]: t = map_funcs.frame_to_time(frame, FRAME_RATE) if frame <= FRAME_THRESHOLD: # Only use the tile_d_fits return (polynomial.polynomial_3(t, *tile_d_fits['d'][0]), polynomial.polynomial_3(t, *tile_d_fits['d+'][0]), polynomial.polynomial_3(t, *tile_d_fits['d-'][0])) else: THRESHOLD_TIME = map_funcs.frame_to_time(FRAME_THRESHOLD, FRAME_RATE) d_offsets = [ polynomial.polynomial_3_integral(THRESHOLD_TIME, *slab_v_fits["v"][0]), polynomial.polynomial_3_integral(THRESHOLD_TIME, *slab_v_fits["v+"][0]), polynomial.polynomial_3_integral(THRESHOLD_TIME, *slab_v_fits["v-"][0]), ] slab_d = ( polynomial.polynomial_3_integral(t, *slab_v_fits["v"][0]) - d_offsets[0], polynomial.polynomial_3_integral(t, *slab_v_fits["v+"][0]) - d_offsets[1], polynomial.polynomial_3_integral(t, *slab_v_fits["v-"][0]) - d_offsets[2], ) if frame > max(POSITIONS_FROM_TILES.keys()): # Only use the slab_v_fits return slab_d else: # Use both return ( (polynomial.polynomial_3(t, *tile_d_fits['d'][0]) + slab_d[0]) / 2.0, (polynomial.polynomial_3(t, *tile_d_fits['d+'][0]) + slab_d[1]) / 2.0, (polynomial.polynomial_3(t, *tile_d_fits['d-'][0]) + slab_d[2]) / 2.0, )
def init_slab_speeds(): slab_speeds = np.empty((len(SLAB_TRANSITS), 5)) for f, frame_number in enumerate(sorted(SLAB_TRANSITS.keys())): d_frame, d_slab = SLAB_TRANSITS[frame_number] dx = d_slab * SLAB_LENGTH t = map_funcs.frame_to_time(frame_number + d_frame / 2, FRAME_RATE) dt = map_funcs.frames_to_dtime(frame_number, frame_number + d_frame, FRAME_RATE) slab_speeds[f][0] = frame_number slab_speeds[f][1] = t slab_speeds[f][2] = dx / dt slab_speeds[f][3] = (dx + SLAB_MEASUREMENT_ERROR) / dt slab_speeds[f][4] = (dx - SLAB_MEASUREMENT_ERROR) / dt return slab_speeds
def print_events() -> None: tile_d_fits = get_tile_d_fits()[1] slab_v_fits = get_slab_v_fits() for frame_number in sorted(FRAME_EVENTS.keys()): t = map_funcs.frame_to_time(frame_number, FRAME_RATE) d, d_plus, d_minus = _compute_distance(frame_number, tile_d_fits, slab_v_fits) d_tol = max(abs(d - d_plus), abs(d - d_minus)) v, v_plus, v_minus = _compute_speed(frame_number, tile_d_fits, slab_v_fits) v_tol = max(abs(v - v_plus), abs(v - v_minus)) print( f'{frame_number:4d}', f'{t:4.1f}', f'{d:7.0f}±{d_tol:.0f} m', f'{v:7.1f}±{v_tol:.1f} m/s', f'{map_funcs.metres_per_second_to_knots(v):7.0f} ±{map_funcs.metres_per_second_to_knots(v_tol):.0f} knots', FRAME_EVENTS[frame_number])
def create_distance_array_of_tile_data() -> typing.Dict[str, np.ndarray]: """Returns a numpy array of time, position from the tile position data.""" columns = ('Frame', 'Time', 'd', 'd+', 'd-') ret = {k: np.empty((len(POSITIONS_FROM_TILES), 1)) for k in columns} for f, frame_number in enumerate(sorted(POSITIONS_FROM_TILES.keys())): t = map_funcs.frame_to_time(frame_number, FRAME_RATE) dx = POSITIONS_FROM_TILES[frame_number][1].x \ - data.tiles.THRESHOLD_ON_EACH_TILE[POSITIONS_FROM_TILES[frame_number][0]].x dy = POSITIONS_FROM_TILES[frame_number][1].y \ - data.tiles.THRESHOLD_ON_EACH_TILE[POSITIONS_FROM_TILES[frame_number][0]].y d_threshold = data.tiles.TILE_SCALE_M_PER_PIXEL * math.sqrt(dx**2 + dy**2) if frame_number < FRAME_THRESHOLD: d_threshold = -d_threshold ret['Frame'][f] = frame_number ret['Time'][f] = t ret['d'][f] = d_threshold ret['d+'][f] = d_threshold + map_funcs.distance_tolerance(d_threshold) ret['d-'][f] = d_threshold - map_funcs.distance_tolerance(d_threshold) return ret
def frame_to_time(frame: int) -> float: """Return the time in seconds from the start of this video.""" return map_funcs.frame_to_time(frame, FRAME_RATE)
1106: (1115 - 1106, 4.0), 1119: (1128 - 1119, 4.0), 1151: (1160 - 1151, 4.0), 1198: (1205 - 1198, 3.0), 1222: (1227 - 1222, 2.0), 1247: (1252 - 1247, 2.0), 1262: (1267 - 1262, 2.0), 1293: (1301 - 1293, 3.0), 1323: (1329 - 1323, 2.2), 1346: (1352 - 1346, 2.1), 1370: (1373 - 1370, 1.0), # 1384 runway dissapears } LAST_MEASURED_FRAME = max(SLAB_TRANSITS.keys()) + SLAB_TRANSITS[max( SLAB_TRANSITS.keys())][0] LAST_MEASURED_TIME = map_funcs.frame_to_time(LAST_MEASURED_FRAME, FRAME_RATE) def init_slab_speeds(): slab_speeds = np.empty((len(SLAB_TRANSITS), 5)) for f, frame_number in enumerate(sorted(SLAB_TRANSITS.keys())): d_frame, d_slab = SLAB_TRANSITS[frame_number] dx = d_slab * SLAB_LENGTH t = map_funcs.frame_to_time(frame_number + d_frame / 2, FRAME_RATE) dt = map_funcs.frames_to_dtime(frame_number, frame_number + d_frame, FRAME_RATE) slab_speeds[f][0] = frame_number slab_speeds[f][1] = t slab_speeds[f][2] = dx / dt slab_speeds[f][3] = (dx + SLAB_MEASUREMENT_ERROR) / dt slab_speeds[f][4] = (dx - SLAB_MEASUREMENT_ERROR) / dt