def derive(self, eng_stops=KTI('Eng Stop'), eng_count=A('Engine Count'), touchdowns=KTI('Touchdown'), duration=A('HDF Duration')): pass
print 'master head', ffd_master.head() print search_ffd_master('flap') #hdf_plot(series['Vertical Speed']) from collections import OrderedDict from analysis_engine.node import ( A, FlightAttributeNode, # one of these per flight. mostly arrival and departure stuff App, ApproachNode, # per approach P, DerivedParameterNode, # time series with continuous values M, MultistateDerivedParameterNode, # time series with discrete values KTI, KeyTimeInstanceNode, # a list of time points meeting some criteria KPV, KeyPointValueNode, # a list of measures meeting some criteria; multiples are allowed and common S, SectionNode, FlightPhaseNode, # Sections=Phases KeyPointValue, KeyTimeInstance, Section # data records, a list of which goes into the corresponding node ) class SimplerKPV(KeyPointValueNode): '''just build it manually''' units='deg' def derive(self, start_datetime=A('Start Datetime')): self.append(KeyPointValue(index=42.5, value=666.6,name='My Simpler KPV')) k = SimplerKPV() k.derive( A('Start Datetime',666) ) print 'kpv', k sk= OrderedDict() sk['SimplerKPV'] = k print derived_table(sk) print 'done'
def derive(self, flight_id=A('AFR Flight ID')): self.set_flight_attr(flight_id.value)
def can_operate(cls, available, seg_type=A('Segment Type')): if seg_type and seg_type.value in ('GROUND_ONLY', 'NO_MOVEMENT', 'STOP_ONLY'): return False else: return all_of(('Altitude AGL', 'Liftoff'), available)
def can_operate(cls, available, ac_type=A('Aircraft Type')): return any_of(('MGB Oil Press (1)', 'MGB Oil Press (2)'), available) \ and ac_type == helicopter
def derive(self, afr_type=A('AFR Type'), fast=S('Fast'), mobile=S('Mobile'), liftoffs=KTI('Liftoff'), touchdowns=KTI('Touchdown'), touch_and_gos=S('Touch And Go'), rejected_to=S('Rejected Takeoff'), eng_start=KTI('Eng Start'), seg_type=A('Segment Type')): ''' TODO: Detect MID_FLIGHT. ''' afr_type = afr_type.value if afr_type else None if not seg_type or seg_type.value == 'START_AND_STOP': if liftoffs and not touchdowns: # In the air without having touched down. self.warning("'Liftoff' KTI exists without 'Touchdown'.") raise InvalidFlightType('LIFTOFF_ONLY') #self.set_flight_attr('LIFTOFF_ONLY') #return elif not liftoffs and touchdowns: # In the air without having lifted off. self.warning("'Touchdown' KTI exists without 'Liftoff'.") raise InvalidFlightType('TOUCHDOWN_ONLY') #self.set_flight_attr('TOUCHDOWN_ONLY') #return types = FlightType.Type if liftoffs and touchdowns: first_touchdown = touchdowns.get_first() first_liftoff = liftoffs.get_first() if first_touchdown.index < first_liftoff.index: # Touchdown before having lifted off, data must be INCOMPLETE. self.warning("'Touchdown' KTI index before 'Liftoff'.") raise InvalidFlightType('TOUCHDOWN_BEFORE_LIFTOFF') #self.set_flight_attr('TOUCHDOWN_BEFORE_LIFTOFF') #return last_touchdown = touchdowns.get_last() # TODO: Delete line. if touch_and_gos: last_touchdown = touchdowns.get_last() last_touch_and_go = touch_and_gos.get_last() if last_touchdown.index <= last_touch_and_go.index: self.warning("A 'Touch And Go' KTI exists after the last " "'Touchdown'.") raise InvalidFlightType('LIFTOFF_ONLY') #self.set_flight_attr('LIFTOFF_ONLY') #return if afr_type in {types.COMMERCIAL, types.FERRY, types.LINE_TRAINING, types.POSITIONING, types.TEST, types.TRAINING}: flight_type = afr_type else: # TODO: Raise exception if AFR flight type was one of the below? flight_type = types.COMPLETE elif rejected_to: # Rejected takeoff but no takeoff or landing flight_type = types.REJECTED_TAKEOFF elif fast: # Midflight as no takeoff, rejected takeoff or landing but went fast flight_type = types.INCOMPLETE elif mobile: # The aircraft moved on the ground. flight_type = types.GROUND_RUN elif eng_start: # Engines were running at some point flight_type = types.ENGINE_RUN_UP else: # TODO: not detected flight type should we fall back to No Movement? # should we raise an error flight_type = types.INCOMPLETE self.set_flight_attr(flight_type)
def can_operate(cls, available, family=A('Family')): return family and family.value == 'H175' and all_of( ('Pitch', 'Initial Climb'), available)
def derive(self, lon=P('Longitude Smoothed'), lat=P('Latitude Smoothed'), airs=S('Airborne'), rwy=A('FDR Landing Runway')): pass
def derive(self, alt_aal=P('Altitude AAL'), alt_agl=P('Altitude AGL'), ac_type=A('Aircraft Type'), app=S('Approach And Landing'), hdg=P('Heading Continuous'), lat=P('Latitude Prepared'), lon=P('Longitude Prepared'), ils_loc=P('ILS Localizer'), ils_gs=S('ILS Glideslope'), ils_freq=P('ILS Frequency'), land_afr_apt=A('AFR Landing Airport'), land_afr_rwy=A('AFR Landing Runway'), lat_land=KPV('Latitude At Touchdown'), lon_land=KPV('Longitude At Touchdown'), precision=A('Precise Positioning'), fast=S('Fast'), #lat_smoothed=P('Latitude Smoothed'), #lon_smoothed=P('Longitude Smoothed'), u=P('Airspeed'), gspd=P('Groundspeed'), height_from_rig=P('Altitude ADH'), hdot=P('Vertical Speed'), roll=P('Roll'), heading=P('Heading'), distance_land=P('Distance To Landing'), tdwns=KTI('Touchdown'), offshore=M('Offshore'), takeoff=S('Takeoff') ): precise = bool(getattr(precision, 'value', False)) alt = alt_agl if ac_type == helicopter else alt_aal app_slices = sorted(app.get_slices()) for index, _slice in enumerate(app_slices): # a) The last approach is assumed to be landing: if index == len(app_slices) - 1: approach_type = 'LANDING' landing = True # b) We have a touch and go if Altitude AAL reached zero: #elif np.ma.any(alt.array[_slice] <= 0): elif np.ma.any(alt.array[slices_int(_slice.start, _slice.stop+(5*alt.frequency))] <= 0): if ac_type == aeroplane: approach_type = 'TOUCH_AND_GO' landing = False elif ac_type == helicopter: approach_type = 'LANDING' landing = True else: raise ValueError('Not doing hovercraft!') # c) In any other case we have a go-around: else: approach_type = 'GO_AROUND' landing = False # Rough reference index to allow for go-arounds ref_idx = int(index_at_value(alt.array, 0.0, _slice=_slice, endpoint='nearest')) turnoff = None if landing: search_end = fast.get_surrounding(_slice.start) if search_end and search_end[0].slice.stop >= ref_idx: search_end = min(search_end[0].slice.stop, _slice.stop) else: search_end = _slice.stop tdn_hdg = np.ma.median(hdg.array[slices_int(ref_idx, search_end+1)]) # Complex trap for the all landing heading data is masked case... if (tdn_hdg % 360.0) is np.ma.masked: lowest_hdg = bearing_and_distance( lat.array[ref_idx], lon.array[ref_idx], lat.array[int(search_end)], lon.array[int(search_end)])[0] else: lowest_hdg = (tdn_hdg % 360.0).item() # While we're here, let's compute the turnoff index for this landing. head_landing = hdg.array[slices_int((ref_idx+_slice.stop)/2, _slice.stop)] if len(head_landing) > 2: peak_bend = peak_curvature(head_landing, curve_sense='Bipolar') fifteen_deg = index_at_value( np.ma.abs(head_landing - head_landing[0]), 15.0) if peak_bend: turnoff = (ref_idx+_slice.stop)/2 + peak_bend else: if fifteen_deg and fifteen_deg < peak_bend: turnoff = start_search + landing_turn else: # No turn, so just use end of landing run. turnoff = _slice.stop else: # No turn, so just use end of landing run. turnoff = _slice.stop else: # We didn't land, but this is indicative of the runway heading lowest_hdg = (hdg.array[ref_idx] % 360.0).item() # Pass latitude, longitude and heading lowest_lat = None lowest_lon = None if lat and lon and ref_idx: lowest_lat = lat.array[ref_idx] or None lowest_lon = lon.array[ref_idx] or None if lowest_lat and lowest_lon and approach_type == 'GO_AROUND': # Doing a go-around, we extrapolate to the threshold # in case we abort the approach abeam a different airport, # using the rule of three miles per thousand feet. distance = np.ma.array([ut.convert(alt_aal.array[ref_idx] * (3 / 1000.0), ut.NM, ut.METER)]) bearing = np.ma.array([lowest_hdg]) reference = {'latitude': lowest_lat, 'longitude': lowest_lon} lat_ga, lon_ga = latitudes_and_longitudes(bearing, distance, reference) lowest_lat = lat_ga[0] lowest_lon = lon_ga[0] if lat_land and lon_land and not (lowest_lat and lowest_lon): # use lat/lon at landing if values at ref_idx are masked # only interested in landing within approach slice. lat_land = lat_land.get(within_slice=_slice) lon_land = lon_land.get(within_slice=_slice) if lat_land and lon_land: lowest_lat = lat_land[0].value or None lowest_lon = lon_land[0].value or None kwargs = dict( precise=precise, _slice=_slice, lowest_lat=lowest_lat, lowest_lon=lowest_lon, lowest_hdg=lowest_hdg, appr_ils_freq=None, ac_type=ac_type, ) # If the approach is a landing, pass through information from the # achieved flight record in case we cannot determine airport and # runway: if landing: kwargs.update( land_afr_apt=land_afr_apt, land_afr_rwy=land_afr_rwy, hint='landing', ) if landing or approach_type == 'GO_AROUND': # if we have a frequency and valid localiser signal at lowest point in approach appr_ils_freq = None if ils_freq: appr_ils_freq = np.ma.round(ils_freq.array[ref_idx] or 0, 2) if not precise and appr_ils_freq and ils_loc and np.ma.abs(ils_loc.array[ref_idx]) < 2.5: kwargs['appr_ils_freq'] = appr_ils_freq airport, landing_runway = self._lookup_airport_and_runway(**kwargs) if not airport and ac_type == aeroplane: continue if ac_type == aeroplane and not airport.get('runways'): self.error("Airport %s: contains no runways", airport['code']) # Simple determination of heliport. heliport = is_heliport(ac_type, airport, landing_runway) for touchdown, tkoff in zip(tdwns.get_ordered_by_index(), takeoff.get_ordered_by_index()): # If both the takeoff and touchdown point are offshore then we consider # the approach to be a 'SHUTTLING APPROACH'. Else we continue to look for # an 'AIRBORNE RADAR DIRECT/OVERHEAD APPROACH' or a 'STANDARD APPROACH' # # A couple of seconds are added to the end of the slice as some flights used # to test this had the touchdown a couple of seconds outside the approach slice if is_index_within_slice(touchdown.index, slice(_slice.start, _slice.stop+5*alt.frequency)): if offshore and \ offshore.array[int(touchdown.index)] == 'Offshore' and \ tkoff.start < touchdown.index: if not distance_land: if offshore.array[tkoff.start] == 'Offshore': approach_type = 'SHUTTLING' elif offshore.array[tkoff.start] == 'Offshore' and \ tkoff.start < len(distance_land.array) and \ distance_land.array[int(tkoff.start)] <= 40: approach_type = 'SHUTTLING' elif height_from_rig: Vy = 80.0 # Type dependent? # conditions_defs is a dict of condition name : expression to evaluate pairs, listed this way for clarity condition_defs={'Below 120 kts' : lambda p : p['Airspeed'] < 120, 'Below Vy+5' : lambda p : p['Airspeed'] < Vy+5.0, 'Over Vy' : lambda p : p['Airspeed'] > Vy, 'Over Vy-5' : lambda p : p['Airspeed'] > Vy-5.0, 'Below 70 gspd' : lambda p : p['Groundspeed'] < 72, 'Below 60 gspd' : lambda p : p['Groundspeed'] < 60, #'Below Vy-10' : lambda p : p['Airspeed'] < Vy-10.0, #'Over Vy-10' : lambda p : p['Airspeed'] > Vy-10.0, #'Above 30 gspd' : lambda p : p['Groundspeed'] > 30, 'Over 900 ft' : lambda p : p['Altitude ADH'] > 900, 'Over 200 ft' : lambda p : p['Altitude ADH'] > 200, 'Below 1750 ft': lambda p : p['Altitude ADH'] < 1750, 'Below 1100 ft' : lambda p : p['Altitude ADH'] < 1100, 'Over 350 ft' : lambda p : p['Altitude ADH'] > 350, 'Below 700 ft' : lambda p : p['Altitude ADH'] < 700, 'ROD < 700 fpm' : lambda p : p['Vertical Speed'] > -700, 'ROD > 200 fpm' : lambda p : p['Vertical Speed'] < -200, 'Not climbing' : lambda p : p['Vertical Speed'] < 200, #'Over 400 ft' : lambda p : p['Altitude ADH'] > 400, #'Below 1500 ft': lambda p : p['Altitude ADH'] < 1500, #'Below 1300 ft': lambda p : p['Altitude ADH'] < 1300, 'Roll below 25 deg' : lambda p : valid_between(p['Roll'], -25.0, 25.0), 'Wings Level' : lambda p : valid_between(p['Roll'], -10.0, 10.0), 'Within 20 deg of final heading' : lambda p : np.ma.abs(p['head_off_final']) < 20.0, #'Within 45 deg of downwind leg' : 'valid_between(np.ma.abs(head_off_final), 135.0, 225.0)', #'15 deg off final heading' : lambda p : np.ma.abs(np.ma.abs(p['head_off_two_miles'])-15.0) < 5.0, #'Heading towards oil rig' : lambda p : np.ma.abs(p['head_off_two_miles']) < 6.0, 'Beyond 0.7 NM' : lambda p : p['Distance To Landing'] > 0.7, 'Within 0.8 NM' : lambda p : p['Distance To Landing'] < 0.8, 'Beyond 1.5 NM' : lambda p : p['Distance To Landing'] > 1.5, 'Within 2.0 NM' : lambda p : p['Distance To Landing'] < 2.0, 'Within 3.0 NM' : lambda p : p['Distance To Landing'] < 3.0, 'Beyond 3.0 NM' : lambda p : p['Distance To Landing'] > 3.0, 'Within 10.0 NM' : lambda p : p['Distance To Landing'] < 10.0, #'Within 1.5 NM' : lambda p : p['Distance To Landing'] < 1.5, } # Phase map is a dict of the flight phases with the list of conditions which must be # satisfied for the phase to be active. phase_map={'Circuit':['Below 120 kts', 'Over Vy', 'Below 1100 ft', 'Over 900 ft', 'Roll below 25 deg', # includes downwind turn ], 'Level within 2NM':['Below Vy+5', 'Over Vy-5', 'Below 1100 ft', 'Over 900 ft', 'Wings Level', 'Within 20 deg of final heading', 'Within 2.0 NM', 'Beyond 1.5 NM', ], 'Initial Descent':['Wings Level', 'Within 20 deg of final heading', 'ROD < 700 fpm', 'ROD > 200 fpm', 'Beyond 0.7 NM', 'Over 350 ft', ], 'Final Approach':['Wings Level', 'Within 20 deg of final heading', 'ROD < 700 fpm', 'Within 0.8 NM', 'Below 60 gspd', 'Below 700 ft', ], # Phases for ARDA/AROA # # All heading conditions are commented out as the pilots usually # go outside the boundaries; the other conditions seem to be # enough to detect them 'ARDA/AROA 10 to 3':['Within 10.0 NM', 'Beyond 3.0 NM', 'Below 1750 ft', 'Not climbing', #'Heading towards oil rig', ], 'ARDA/AROA Level within 3NM':['Below 70 gspd', 'Over 200 ft', 'Wings Level', 'Within 3.0 NM', 'Beyond 1.5 NM', #'Within 20 deg of final heading', ], 'ARDA/AROA Final':['Not climbing', 'Within 2.0 NM', #'15 deg off final heading' ], } """ #Phases that can be used to tighten the conditions for ARDA/AROA 'Radar Heading Change':['15 deg off final heading', 'Within 1.5 NM', 'Beyond 0.7 NM'], 'Low Approach':['Below Vy+5', 'Below 700 ft', 'Over 350 ft', 'Within 20 deg of final heading', 'Wings Level'], 'Low Circuit':['Below 120 kts', 'Over Vy-5', 'Below 700 ft', 'Over 350 ft', 'Roll below 25 deg'] """ approach_map = {'RIG': ['Circuit', 'Level within 2NM', 'Initial Descent', 'Final Approach'], 'AIRBORNE_RADAR': ['ARDA/AROA 10 to 3', 'ARDA/AROA Level within 3NM', 'ARDA/AROA Final']} # Making sure the approach slice contains enough information to be able # to properly identify ARDA/AROA approaches (the procedure starts from 10NM # before touchdown) app_slice = slice(index_at_value(distance_land.array, 11, _slice=slice(0,touchdown.index)), touchdown.index) heading_repaired = repair_mask(heading.array[app_slice], frequency=heading.frequency, repair_duration=np.ma.count_masked(heading.array[app_slice]), copy=True, extrapolate=True) param_arrays = { 'Airspeed': u.array[app_slice], 'Groundspeed': gspd.array[app_slice], 'Altitude ADH': height_from_rig.array[app_slice], 'Vertical Speed': hdot.array[app_slice], 'Roll': roll.array[app_slice], 'Distance To Landing': distance_land.array[app_slice], 'Heading': heading_repaired, 'Latitude': lat.array[app_slice], 'Longitude': lon.array[app_slice], } longest_approach_type, longest_approach_durn, longest_approach_slice = find_rig_approach(condition_defs, phase_map, approach_map, Vy, None, param_arrays, debug=False) if longest_approach_type is not None: approach_type = longest_approach_type.upper() _slice = slice(app_slice.start + longest_approach_slice.start, app_slice.stop) if heliport: self.create_approach( approach_type, _slice, runway_change=False, offset_ils=False, airport=airport, landing_runway=None, approach_runway=None, gs_est=None, loc_est=None, ils_freq=None, turnoff=None, lowest_lat=lowest_lat, lowest_lon=lowest_lon, lowest_hdg=lowest_hdg, ) continue ######################################################################### ## Analysis of fixed wing approach to a runway ## ## First step is to check the ILS frequency for the runway in use ## and cater for a change from the approach runway to the landing runway. ######################################################################### appr_ils_freq = None runway_change = False offset_ils = False # Do we have a recorded ILS frequency? If so, what was it tuned to at the start of the approach?? if ils_freq: appr_ils_freq = ils_freq.array[int(_slice.start)] # Was this valid, and if so did the start of the approach match the landing runway? if appr_ils_freq and not (np.isnan(appr_ils_freq) or np.ma.is_masked(appr_ils_freq)): appr_ils_freq = round(appr_ils_freq, 2) runway_kwargs = { 'ilsfreq': appr_ils_freq, 'latitude': lowest_lat, 'longitude': lowest_lon, } if not precise: runway_kwargs['hint'] = kwargs.get('hint', 'approach') approach_runway = nearest_runway(airport, lowest_hdg, **runway_kwargs) # Have we have identified runways for both conditions that are both different and parallel? if all((approach_runway, landing_runway)) \ and approach_runway['id'] != landing_runway['id'] \ and approach_runway['identifier'][:2] == landing_runway['identifier'][:2]: runway_change = True else: # Without a frequency source, we just have to hope any localizer signal is for this runway! approach_runway = landing_runway if approach_runway and 'frequency' in approach_runway['localizer']: if np.ma.count(ils_loc.array[slices_int(_slice)]) > 10: if runway_change: # We only use the first frequency tuned. This stops scanning across both runways if the pilot retunes. loc_slice = shift_slices( runs_of_ones(np.ma.abs(ils_freq.array[slices_int(_slice)] - appr_ils_freq) < 0.001), _slice.start )[0] else: loc_slice = _slice else: # No localizer or inadequate data for this approach. loc_slice = None else: # The approach was to a runway without an ILS, so even if it was tuned, we ignore this. appr_ils_freq = None loc_slice = None if np.ma.is_masked(appr_ils_freq): loc_slice = None appr_ils_freq = None else: if appr_ils_freq and loc_slice: if appr_ils_freq != round(ut.convert(approach_runway['localizer']['frequency'], ut.KHZ, ut.MHZ), 2): loc_slice = None ####################################################################### ## Identification of the period established on the localizer ####################################################################### loc_est = None if loc_slice: valid_range = np.ma.flatnotmasked_edges(ils_loc.array[slices_int(_slice)]) # I have some data to scan. Shorthand names; loc_start = valid_range[0] + _slice.start loc_end = valid_range[1] + _slice.start scan_back = slice(ref_idx, loc_start, -1) # If we are turning in, we are not interested in signals that are not related to this approach. # The value of 45 deg was selected to encompass Washington National airport with a 40 deg offset. hdg_diff = np.ma.abs(np.ma.mod((hdg.array-lowest_hdg)+180.0, 360.0)-180.0) ils_hdg_45 = index_at_value(hdg_diff, 45.0, _slice=scan_back) # We are not interested above 1,500 ft, so may trim back the start point to that point: ils_alt_1500 = index_at_value(alt_aal.array, 1500.0, _slice=scan_back) # The criteria for start of established phase is the latter of the approach phase start, the turn-in or 1500ft. # The "or 0" allow for flights that do not turn through 45 deg or keep below 1500ft. loc_start = max(loc_start, ils_hdg_45 or 0, ils_alt_1500 or 0) if loc_start < ref_idx: # Did I get established on the localizer, and if so, # when? We only look AFTER the aircraft is already within # 45deg of the runway heading, below 1500ft and the data # is valid for this runway. Testing that the aircraft is # not just passing across the localizer is built into the # ils_established function. loc_estab = ils_established(ils_loc.array, slice(loc_start, ref_idx), ils_loc.hz) else: # If localiser start is after we touchdown bail. loc_estab = None if loc_estab: # Refine the end of the localizer established phase... if (approach_runway and approach_runway['localizer']['is_offset']): offset_ils = True # The ILS established phase ends when the deviation becomes large. loc_end = ils_established(ils_loc.array, slice(ref_idx, loc_estab, -1), ils_loc.hz, point='immediate') elif approach_type in ['TOUCH_AND_GO', 'GO_AROUND']: # We finish at the lowest point loc_end = ref_idx elif runway_change: # Use the end of localizer phase as this already reflects the tuned frequency. est_end = ils_established(ils_loc.array, slice(loc_estab, ref_idx), ils_loc.hz, point='end') # Make sure we dont end up with a negative slice i.e. end before we are established. loc_end = min([x for x in (loc_slice.stop, loc_end, est_end or np.inf) if x > loc_estab]) elif approach_type == 'LANDING': # Just end at 2 dots where we turn off the runway loc_end_2_dots = index_at_value(np.ma.abs(ils_loc.array), 2.0, _slice=slice(turnoff+5*(_slice.stop-_slice.start)/100, loc_estab, -1)) if loc_end_2_dots and \ is_index_within_slice(loc_end_2_dots, _slice) and \ not np.ma.is_masked(ils_loc.array[int(loc_end_2_dots)]) and \ loc_end_2_dots > loc_estab: loc_end = loc_end_2_dots loc_est = slice(loc_estab, loc_end+1) ####################################################################### ## Identification of the period established on the glideslope ####################################################################### gs_est = None if loc_est and 'glideslope' in approach_runway and ils_gs: # We only look for glideslope established periods if the localizer is already established. # The range to scan for the glideslope starts with localizer capture and ends at # 200ft or the minimum height point for a go-around or the end of # localizer established, if either is earlier. ils_gs_start = loc_estab ils_gs_200 = index_at_value(alt.array, 200.0, _slice=slice(loc_end, ils_gs_start, -1)) # The expression "ils_gs_200 or np.inf" caters for the case where the aircraft did not pass # through 200ft, so the result is None, in which case any other value is left to be the minimum. ils_gs_end = min(ils_gs_200 or np.inf, ref_idx, loc_end) # Look for ten seconds within half a dot ils_gs_estab = ils_established(ils_gs.array, slice(ils_gs_start, ils_gs_end), ils_gs.hz) if ils_gs_estab: gs_est = slice(ils_gs_estab, ils_gs_end+1) ''' # These statements help set up test cases. print() print(airport['name']) print(approach_runway['identifier']) print(landing_runway['identifier']) print(_slice) if loc_est: print('Localizer established ', loc_est.start, loc_est.stop) if gs_est: print('Glideslope established ', gs_est.start, gs_est.stop) print() ''' self.create_approach( approach_type, _slice, runway_change=runway_change, offset_ils=offset_ils, airport=airport, landing_runway=landing_runway, approach_runway=approach_runway, gs_est=gs_est, loc_est=loc_est, ils_freq=appr_ils_freq, turnoff=turnoff, lowest_lat=lowest_lat, lowest_lon=lowest_lon, lowest_hdg=lowest_hdg, )
def derive(self, ap=M('AP Channels Engaged'), touchdowns=KTI('Touchdown'), family=A('Family')): pass
def derive(self, lon=P('Longitude Smoothed'), lat=P('Latitude Smoothed'), airs=S('Airborne'), apt=A('FDR Landing Airport')): pass
def can_operate(cls, available, seg_type=A('Segment Type')): if seg_type and seg_type.value in ('GROUND_ONLY', 'NO_MOVEMENT', 'MID_FLIGHT', 'STOP_ONLY'): return False return 'Airborne' in available
def can_operate(cls, available, ac_type=A('Aircraft Type')): if ac_type and ac_type.value == 'helicopter': return False else: return all_deps(cls, available)
def can_operate(cls, available, ac_type=A('Aircraft Type')): if ac_type != helicopter: return all_deps(cls, available) else: return all_of(('Gear Up Selected', 'Airborne'), available)
def can_operate(cls, available, ac_type=A('Aircraft Type')): return ac_type and ac_type.value == 'helicopter' and len( available) >= 2
def derive(self, start_datetime=A('Start Datetime')): self.create_kpv(3.0, 999.9)
def derive(self, toff_fdr_apt=A('FDR Takeoff Airport'), toff_afr_rwy=A('AFR Takeoff Runway'), toff_hdg=KPV('Heading During Takeoff'), toff_lat=KPV('Latitude At Liftoff'), toff_lon=KPV('Longitude At Liftoff'), accel_start_lat=KPV('Latitude At Takeoff Acceleration Start'), accel_start_lon=KPV('Longitude At Takeoff Acceleration Start'), precision=A('Precise Positioning')): ''' ''' fallback = False precise = bool(getattr(precision, 'value', False)) try: airport = toff_fdr_apt.value # FIXME except AttributeError: self.warning('Invalid airport... Fallback to AFR Takeoff Runway.') fallback = True else: if airport is None: fallback = True try: heading = toff_hdg.get_first().value if heading is None: raise ValueError except (AttributeError, ValueError): self.warning('Invalid heading... Fallback to AFR Takeoff Runway.') fallback = True # 1. If we have airport and heading, look for the nearest runway: if not fallback: kwargs = {} # Even if we do not have precise latitude and longitude # information, we still use this for the takeoff runway detection # as it is often accurate at the start of a flight, and in the # absence of an ILS tuned frequency we have no better option. (We # did consider using the last direction of turn onto the runway, # but this would require an airport database with terminal and # taxiway details that was not felt justified). if toff_lat and toff_lon: lats = [toff_lat.get_first()] lons = [toff_lon.get_first()] if accel_start_lat and accel_start_lon: lats.append(accel_start_lat.get_first()) lons.append(accel_start_lon.get_first()) lats = [l.value for l in lats if l] lons = [l.value for l in lons if l] if lats and lons: kwargs.update( latitude=np.array(lats), longitude=np.array(lons), ) else: self.warning('No coordinates for takeoff runway lookup.') if not precise: kwargs.update(hint='takeoff') runway = nearest_runway(airport, heading, **kwargs) if not runway: msg = 'No runway found for airport #%d @ %03.1f deg with %s.' self.warning(msg, airport['id'], heading, kwargs) # No runway was found, so fall through and try AFR. else: self.info('Detected takeoff runway: %s for airport #%d @ %03.1f deg with %s', runway['identifier'], airport['id'], heading, kwargs) self.set_flight_attr(runway) return # We found a runway, so finish here. # 2. If we have a runway provided in achieved flight record, use it: if toff_afr_rwy: runway = toff_afr_rwy.value self.debug('Using takeoff runway from AFR: %s', runway) self.set_flight_attr(runway) return # We found a runway in the AFR, so finish here. # 3. After all that, we still couldn't determine a runway... self.error('Unable to determine runway at takeoff!') self.set_flight_attr(None)
def derive(self, start_datetime=A('Start Datetime')): self.set_flight_attr('Keith')
def can_operate(cls, available, ac_type=A('Aircraft Type')): return ac_type == helicopter and \ all_of(('Altitude AGL', 'Airborne', 'Hover'), available)
def derive(self, filename=A('Myfile')): self.set_flight_attr(filename.value)
def can_operate(cls, available, seg_type=A('Segment Type')): if seg_type and seg_type.value in ('GROUND_ONLY', 'NO_MOVEMENT'): return False return all_of(('Gear On Ground', ), available)
def derive(self, mydict=A('Mydict')): mydict.value['testkey'] = [1, 2, 3] self.set_flight_attr(mydict.value)
def can_operate(cls, available, ac_type=A('Aircraft Type')): if ac_type == helicopter: return all_of(('Altitude Radio', 'Altitude STD Smoothed', 'Gear On Ground'), available) or \ ('Altitude Radio' not in available and 'Altitude AAL' in available) else: return False
def derive(self, start_datetime=A('Start Datetime')): #print 'in SimpleKTI' self.create_kti(3)
def can_operate(cls, available, ac_type=A('Aircraft Type')): return ac_type == helicopter and any_of(cls.get_dependency_names(), available)
def derive(self, start_datetime=A('Start Datetime')): #print 'in SimpleKTI' kti = KeyTimeInstance( index=700., name='My Simpler KTI') #freq=1hz and offset=0 by default self.append(kti)
def derive(self, start_datetime=A('Start Datetime')): self.append(KeyPointValue(index=42.5, value=666.6,name='My Simpler KPV'))
def derive(self, gl=M('Gear (L) On Ground'), gr=M('Gear (R) On Ground'), vert_spd=P('Vertical Speed'), torque=P('Eng (*) Torque Avg'), ac_series=A('Series'), collective=P('Collective')): if gl and gr: delta = abs((gl.offset - gr.offset) * gl.frequency) if 0.75 < delta or delta < 0.25: # If the samples of the left and right gear are close together, # the best representation is to map them onto a single # parameter in which we accept that either wheel on the ground # equates to gear on ground. self.array = np.ma.logical_or(gl.array, gr.array) self.frequency = gl.frequency self.offset = gl.offset return else: # If the paramters are not co-located, then # merge_two_parameters creates the best combination possible. self.array, self.frequency, self.offset = merge_two_parameters( gl, gr) return elif gl or gr: gear = gl or gr self.array = gear.array self.frequency = gear.frequency self.offset = gear.offset elif vert_spd and torque: vert_spd_limit = 100.0 torque_limit = 30.0 if ac_series and ac_series.value == 'Columbia 234': vert_spd_limit = 125.0 torque_limit = 22.0 collective_limit = 15.0 vert_spd_array = align( vert_spd, torque) if vert_spd.hz != torque.hz else vert_spd.array collective_array = align( collective, torque) if collective.hz != torque.hz else collective.array vert_spd_array = moving_average(vert_spd_array) torque_array = moving_average(torque.array) collective_array = moving_average(collective_array) roo_vs_array = runs_of_ones( abs(vert_spd_array) < vert_spd_limit, min_samples=1) roo_torque_array = runs_of_ones(torque_array < torque_limit, min_samples=1) roo_collective_array = runs_of_ones( collective_array < collective_limit, min_samples=1) vs_and_torque = slices_and(roo_vs_array, roo_torque_array) grounded = slices_and(vs_and_torque, roo_collective_array) array = np_ma_zeros_like(vert_spd_array) for _slice in slices_remove_small_slices(grounded, count=2): array[_slice] = 1 array.mask = vert_spd_array.mask | torque_array.mask array.mask = array.mask | collective_array.mask self.array = nearest_neighbour_mask_repair(array) self.frequency = torque.frequency self.offset = torque.offset else: vert_spd_array = align( vert_spd, torque) if vert_spd.hz != torque.hz else vert_spd.array # Introducted for S76 and Bell 212 which do not have Gear On Ground available vert_spd_array = moving_average(vert_spd_array) torque_array = moving_average(torque.array) grounded = slices_and( runs_of_ones(abs(vert_spd_array) < vert_spd_limit, min_samples=1), runs_of_ones(torque_array < torque_limit, min_samples=1)) array = np_ma_zeros_like(vert_spd_array) for _slice in slices_remove_small_slices(grounded, count=2): array[_slice] = 1 array.mask = vert_spd_array.mask | torque_array.mask self.array = nearest_neighbour_mask_repair(array) self.frequency = torque.frequency self.offset = torque.offset else: # should not get here if can_operate is correct raise NotImplementedError()
def derive(self, land_fdr_apt=A('FDR Landing Airport'), land_afr_rwy=A('AFR Landing Runway'), land_hdg=KPV('Heading During Landing'), land_lat=KPV('Latitude At Touchdown'), land_lon=KPV('Longitude At Touchdown'), precision=A('Precise Positioning'), approaches=S('Approach And Landing'), ils_freq_on_app=KPV('ILS Frequency During Approach')): ''' ''' fallback = False precise = bool(getattr(precision, 'value', False)) try: airport = int(land_fdr_apt.value['id']) except (AttributeError, KeyError, TypeError, ValueError): self.warning('Invalid airport... Fallback to AFR Landing Runway.') fallback = True try: heading = land_hdg.get_last().value if heading is None: raise ValueError except (AttributeError, ValueError): self.warning('Invalid heading... Fallback to AFR Landing Runway.') fallback = True try: landing = approaches.get_last() if landing is None: raise ValueError except (AttributeError, ValueError): self.warning('No approaches... Fallback to AFR Landing Runway.') # Don't set fallback - can still attempt to use heading only... # 1. If we have airport and heading, look for the nearest runway: if not fallback: kwargs = {} # The last approach is assumed to be the landing. # XXX: Last approach may not be landing for partial data?! if ils_freq_on_app: if landing.start_edge: ils_app_slice = slice(landing.start_edge, landing.slice.stop) else: ils_app_slice = landing.slice ils_freq = ils_freq_on_app.get_last(within_slice=ils_app_slice) if ils_freq: kwargs.update(ils_freq=ils_freq.value) # We only provide coordinates when looking up a landing runway if # the recording of latitude and longitude on the aircraft is # precise. Inertial recordings are too inaccurate to pinpoint the # correct runway and we use ILS frequencies if possible to get a # more exact match. if precise and landing and land_lat and land_lon: lat = land_lat.get_last(within_slice=landing.slice) lon = land_lon.get_last(within_slice=landing.slice) if lat and lon: kwargs.update( latitude=lat.value, longitude=lon.value, ) else: self.warning('No coordinates for landing runway lookup.') else: kwargs.update(hint='landing') api = get_api_handler(settings.API_HANDLER) try: runway = api.get_nearest_runway(airport, heading, **kwargs) except NotFoundError: msg = 'No runway found for airport #%d @ %03.1f deg with %s.' self.warning(msg, airport, heading, kwargs) # No runway was found, so fall through and try AFR. if 'ils_freq' in kwargs: # This is a trap for airports where the ILS data is not # available, but the aircraft approached with the ILS # tuned. A good prompt for an omission in the database. self.warning('Fix database? No runway but ILS was tuned.') else: self.debug('Detected landing runway: %s', runway) self.set_flight_attr(runway) return # We found a runway, so finish here. # 2. If we have a runway provided in achieved flight record, use it: if land_afr_rwy: runway = land_afr_rwy.value self.debug('Using landing runway from AFR: %s', runway) self.set_flight_attr(runway) return # We found a runway in the AFR, so finish here. # 3. After all that, we still couldn't determine a runway... self.error('Unable to determine runway at landing!') self.set_flight_attr(None)
def derive(self, eng_starts=KTI('Eng Start'), eng_count=A('Engine Count'), liftoffs=KTI('Liftoff')): pass