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'), 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')): pass
def derive(self, ac_type=A('Aircraft Type'), alt_aal=P('Altitude AAL For Flight Phases'), level_flights=S('Level Flight'), apps=S('Approach'), landings=S('Landing')): pass
def test_derive_without_turning(self): # Empty 'Turning'. turning = S('Turning On Ground') start_datetime = A(name='Start Datetime', value=datetime.now()) off_blocks_datetime = OnBlocksDatetime() off_blocks_datetime.set_flight_attr = Mock() off_blocks_datetime.derive(turning, start_datetime) off_blocks_datetime.set_flight_attr.assert_called_once_with(None) # 'Turning On Ground'. turning = S('Turning On Ground', items=[KeyPointValue(name='Turning On Ground', slice=slice(20, 60))]) off_blocks_datetime.set_flight_attr = Mock() off_blocks_datetime.derive(turning, start_datetime) off_blocks_datetime.set_flight_attr.assert_called_once_with( start_datetime.value + timedelta(seconds=60)) turning = S('Turning', items=[KeyPointValue(name='Turning On Ground', slice=slice(10, 20)), KeyPointValue(name='Turning In Air', slice=slice(20, 60)), KeyPointValue(name='Turning On Ground', slice=slice(70, 90))]) off_blocks_datetime.set_flight_attr = Mock() off_blocks_datetime.derive(turning, start_datetime) off_blocks_datetime.set_flight_attr.assert_called_once_with( start_datetime.value + timedelta(seconds=90))
def derive(self, takeoff=S('Takeoff'), initial_climb=S('Initial Climb'), climb=S('Climb'), alt_aal=P('Altitude AAL'), alt_std=P('Altitude STD Smoothed')): pass
def derive(self, alt_agl=P('Altitude AGL'), airs=S('Airborne'), hovers=S('Hover'), trans_hfs=S('Transition Hover To Flight'), trans_fhs=S('Transition Flight To Hover')): air_taxis = [] taxis = [] if airs: for air in airs: lows = slices_below(alt_agl.array[air.slice], HOVER_TAXI_HEIGHT)[1] taxis = shift_slices(lows, air.slice.start) # Remove periods identified already as transitions. if taxis: for taxi in slices_and_not(taxis, [h.slice for h in hovers]): if trans_fhs: for trans_fh in trans_fhs: if slices_overlap(taxi, trans_fh.slice): taxi = slice(trans_fh.slice.stop, taxi.stop) if trans_hfs: for trans_hf in trans_hfs: if slices_overlap(taxi, trans_hf.slice): taxi = slice(taxi.start, trans_hf.slice.start) air_taxis.extend([taxi]) self.create_phases(air_taxis)
def derive(self, alt_agl=P('Altitude AGL'), airs=S('Airborne'), hovers=S('Hover'), trans_hfs=S('Transition Hover To Flight'), trans_fhs=S('Transition Flight To Hover')): pass
def derive(self, pilot_flying=M('Pilot Flying'), pitch_capt=P('Pitch (Capt)'), pitch_fo=P('Pitch (FO)'), roll_capt=P('Roll (Capt)'), roll_fo=P('Roll (FO)'), cc_capt=P('Control Column Force (Capt)'), cc_fo=P('Control Column Force (FO)'), ap1_eng=M('AP (1) Engaged'), ap2_eng=M('AP (2) Engaged'), takeoffs=S('Takeoff'), liftoffs=KTI('Liftoff'), rejected_toffs=S('Rejected Takeoff')): #TODO: Tidy phase = takeoffs or rejected_toffs or None if phase is None: # Nothing to do as no attempt to takeoff return lift = liftoffs.get_first() if liftoffs else None if lift and ap1_eng and ap2_eng: # check AP state at the floored index (just before lift) ap1 = ap1_eng.array[lift.index] == 'Engaged' ap2 = ap2_eng.array[lift.index] == 'Engaged' else: ap1 = ap2 = None args = (pilot_flying, pitch_capt, pitch_fo, roll_capt, roll_fo, cc_capt, cc_fo, phase.get_first(), ap1, ap2) self.set_flight_attr(self._determine_pilot(*args))
def derive(self, offshores=M('Offshore'), liftoffs=KTI('Liftoff'), hovers=S('Hover'), nose_downs=S('Nose Down Attitude Adoption'), rad_alt=P('Altitude Radio'), alt_aal=P('Altitude AAL For Flight Phases')): pass
def derive(self, ac_type=A('Aircraft Type'), alt_aal=P('Altitude AAL For Flight Phases'), level_flights=S('Level Flight'), landings=S('Landing'), alt_agl=P('Altitude AGL'), alt_std=P('Altitude STD')): pass
def derive( self, head=P('Heading Continuous'), alt_aal=P('Altitude AAL For Flight Phases'), fast=S('Fast'), airs=S('Airborne'), ): pass
def derive( self, rot=P('Heading Rate'), gspd=P('Groundspeed'), airs=S('Airborne'), fast=S('Fast'), ): pass
def derive(self, mobiles=S('Mobile'), gspd=P('Groundspeed'), toffs=S('Takeoff'), lands=S('Landing'), rtos=S('Rejected Takeoff'), airs=S('Airborne')): pass
def derive(self, afr_type=A('AFR Type'), fast=S('Fast'), liftoffs=KTI('Liftoff'), touchdowns=KTI('Touchdown'), touch_and_gos=S('Touch And Go'), groundspeed=P('Groundspeed')): ''' TODO: Detect MID_FLIGHT. ''' afr_type = afr_type.value if afr_type else None 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 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 [FlightType.Type.FERRY, FlightType.Type.LINE_TRAINING, FlightType.Type.POSITIONING, FlightType.Type.TEST, FlightType.Type.TRAINING]: flight_type = afr_type else: flight_type = FlightType.Type.COMPLETE elif fast: flight_type = FlightType.Type.REJECTED_TAKEOFF elif groundspeed and groundspeed.array.ptp() > 10: # The aircraft moved on the ground. flight_type = FlightType.Type.GROUND_RUN else: flight_type = FlightType.Type.ENGINE_RUN_UP self.set_flight_attr(flight_type)
def derive( self, collective=P('Collective'), nr=P('Nr'), grounded=S('Grounded'), stationary=S('Stationary'), pedal=P('Tail Rotor Pedal'), ): pass
def derive( self, tcas_ops=S('TCAS Operational'), tcas_ta1=M('TCAS TA'), tcas_ta2=M('TCAS All Threat Traffic'), tcas_ta3=M('TCAS Traffic Alert'), tcas_ta4=M('TCAS TA (1)'), tcas_ras=S('TCAS Resolution Advisory'), ): pass
def derive(self, accel_lon=P('Acceleration Longitudinal Offset Removed'), eng_running=M('Eng (*) All Running'), groundeds=S('Grounded'), eng_n1=P('Eng (*) N1 Max'), toff_acc=KTI('Takeoff Acceleration Start'), toff_rwy_hdg=S('Takeoff Runway Heading'), seg_type=A('Segment Type'), toga=M('Takeoff And Go Around')): pass
def derive(self, ac_type=A('Aircraft Type'), head=P('Heading Continuous'), alt_aal=P('Altitude AAL For Flight Phases'), fast=S('Fast'), mobile=S('Mobile'), alt_agl=P('Altitude AGL'), coll=P('Collective'), airs=S('Airborne')): pass
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')): pass
def derive(self, acc_norm=P('Acceleration Normal'), acc_long=P('Acceleration Longitudinal Offset Removed'), alt=P('Altitude AAL'), alt_rad=P('Altitude Radio'), gog=M('Gear On Ground'), lands=S('Landing'), flap=P('Flap'), manufacturer=A('Manufacturer'), family=A('Family'), airs=S('Airborne'), ac_type=A('Aircraft Type'), accel=P('Acceleration Longitudinal')): pass
def derive(self, pilot_flying=M('Pilot Flying'), pitch_capt=P('Pitch (Capt)'), pitch_fo=P('Pitch (FO)'), roll_capt=P('Roll (Capt)'), roll_fo=P('Roll (FO)'), cc_capt=P('Control Column Force (Capt)'), cc_fo=P('Control Column Force (FO)'), ap1_eng=M('AP (1) Engaged'), ap2_eng=M('AP (2) Engaged'), takeoffs=S('Takeoff'), liftoffs=KTI('Liftoff'), rejected_toffs=S('Rejected Takeoff'), afr_takeoff_pilot=A('AFR Takeoff Pilot')): pass
def derive(self, ils_localizer=P('ILS Localizer'), alt_aal=P('Altitude AAL For Flight Phases'), approaches=S('Approach And Landing'), runway=A('FDR Landing Runway')): if 'glideslope' in runway.value: for app in approaches: if ils_localizer: alt_bands = alt_aal.slices_from_to(1000, 500) ils_run = sustained_max_abs(ils_localizer, window=5, _slice=app) x = np.ma.zeros(len(ils_localizer.array)) x.data[app.slice] = ils_run self.create_kpvs_within_slices( abs(x), alt_bands, max_abs_value, ) else: self.warning("ILS Localizer not measured on approach") return else: self.warning("Runway not equipped with ILS Localizer") return
def get_params(self, hdf_path, _slice, phase_name): import shutil import tempfile from hdfaccess.file import hdf_file with tempfile.NamedTemporaryFile() as temp_file: shutil.copy(hdf_path, temp_file.name) with hdf_file(hdf_path) as hdf: pitch_capt = hdf.get('Pitch (Capt)') pitch_fo = hdf.get('Pitch (FO)') roll_capt = hdf.get('Roll (Capt)') roll_fo = hdf.get('Roll (FO)') cc_capt = hdf.get('Control Column Force (Capt)') cc_fo = hdf.get('Control Column Force (FO)') for par in pitch_capt, pitch_fo, roll_capt, roll_fo, cc_capt, \ cc_fo: if par is not None: ref_par = par break phase = S(name=phase_name, frequency=1) phase.create_section(_slice) phase = phase.get_aligned(ref_par)[0] # Align the arrays, usually done in the Nodes for par in pitch_fo, roll_capt, roll_fo, cc_capt, cc_fo: if par is None: continue par.array = align(par, ref_par) par.hz = ref_par.hz return pitch_capt, pitch_fo, roll_capt, roll_fo, cc_capt, cc_fo, phase
def derive(self, liftoff=KTI('Liftoff'), rto=S('Rejected Takeoff'), off_blocks=KTI('Off Blocks'), start_dt=A('Start Datetime')): if liftoff: # Flight - use first liftoff index first_liftoff = liftoff.get_first() liftoff_index = first_liftoff.index frequency = liftoff.frequency elif rto: # RTO - use start index of first RTO first_rto = rto.get_first() liftoff_index = first_rto.slice.start frequency = rto.frequency elif off_blocks: # Ground Only - use first off blocks index first_off_blocks = off_blocks.get_first() liftoff_index = first_off_blocks.index frequency = off_blocks.frequency else: # Incomplete - use start of data liftoff_index = 0 frequency = 1 takeoff_dt = datetime_of_index(start_dt.value, liftoff_index, frequency=frequency) self.set_flight_attr(takeoff_dt)
def setUp(self): self.node_class = ApproachInformation self.alt_aal = P(name='Altitude AAL', array=np.ma.array([ 10, 5, 0, 0, 5, 10, 20, 30, 40, 50, # Touch & Go 50, 45, 30, 35, 30, 30, 35, 40, 40, 40, # Go Around 30, 20, 10, 0, 0, 0, 0, 0, 0, 0, # Landing ])) self.app = ApproachAndLanding() self.fast = S(name='Fast', items=[ Section(name='Fast', slice=slice(0, 22), start_edge=0, stop_edge=22.5), ]) self.land_hdg = KPV(name='Heading During Landing', items=[ KeyPointValue(index=22, value=60), ]) self.land_lat = KPV(name='Latitude At Touchdown', items=[ KeyPointValue(index=22, value=10), ]) self.land_lon = KPV(name='Longitude At Touchdown', items=[ KeyPointValue(index=22, value=-2), ]) self.appr_hdg = KPV(name='Heading At Lowest Altitude During Approach', items=[ KeyPointValue(index=5, value=25), KeyPointValue(index=12, value=35), ]) self.appr_lat = KPV(name='Latitude At Lowest Altitude During Approach', items=[ KeyPointValue(index=5, value=8), ]) self.appr_lon = KPV(name='Longitude At Lowest Altitude During Approach', items=[ KeyPointValue(index=5, value=4), ]) self.land_afr_apt_none = A(name='AFR Landing Airport', value=None) self.land_afr_rwy_none = A(name='AFR Landing Runway', value=None)
def derive(self, eng2_np=P('Eng (2) Np'), eng1_n1=P('Eng (1) N1'), eng2_n1=P('Eng (2) N1'), groundeds=S('Grounded'), prop_brake=M('Propeller Brake')): pass
def derive(self, alt_agl=P('Altitude AGL'), ias=P('Airspeed'), airs=S('Airborne'), pitch_rate=P('Pitch Rate')): for air in airs: lows = np.ma.clump_unmasked( np.ma.masked_greater(alt_agl.array[air.slice], ROTOR_TRANSITION_ALTITUDE)) for low in lows: trans_slices = slices_from_to(ias.array[air.slice][low], ROTOR_TRANSITION_SPEED_LOW, ROTOR_TRANSITION_SPEED_HIGH, threshold=1.0)[1] if trans_slices: for trans in trans_slices: base = air.slice.start + low.start ext_start = int(base + trans.start - 20 * ias.frequency) if alt_agl.array[ext_start] == 0.0: trans_start = index_at_value( ias.array, 0.0, _slice=slice(base + trans.start, ext_start, -1), endpoint='first_closing') else: trans_start = np.ma.argmin( pitch_rate.array[ext_start:base + trans.start]) + ext_start self.create_phase(slice(trans_start, trans.stop + base))
def derive(self, alt_rad=P('Altitude Radio'), alt_agl=P('Altitude AGL'), gog=M('Gear On Ground'), rtr=S('Rotors Turning')): # When was the gear in the air? gear_off_grounds = runs_of_ones(gog.array == 'Air') if alt_rad and alt_agl and rtr: # We can do a full analysis. # First, confirm that the rotors were turning at this time: gear_off_grounds = slices_and(gear_off_grounds, rtr.get_slices()) # When did the radio altimeters indicate airborne? airs = slices_remove_small_gaps( np.ma.clump_unmasked( np.ma.masked_less_equal(alt_agl.array, 1.0)), time_limit=AIRBORNE_THRESHOLD_TIME_RW, hz=alt_agl.frequency) # Both is a reliable indication of being in the air. for air in airs: for goff in gear_off_grounds: # Providing they relate to each other :o) if slices_overlap(air, goff): start_index = max(air.start, goff.start) end_index = min(air.stop, goff.stop) better_begin = index_at_value( alt_rad.array, 1.0, _slice=slice( max(start_index - 5 * alt_rad.frequency, 0), start_index + 5 * alt_rad.frequency)) if better_begin: begin = better_begin else: begin = start_index better_end = index_at_value( alt_rad.array, 1.0, _slice=slice( max(end_index + 5 * alt_rad.frequency, 0), end_index - 5 * alt_rad.frequency, -1)) if better_end: end = better_end else: end = end_index duration = end - begin if (duration / alt_rad.hz) > AIRBORNE_THRESHOLD_TIME_RW: self.create_phase(slice(begin, end)) else: # During data validation we can select just sensible flights; # short hops make parameter validation tricky! self.create_phases( slices_remove_small_gaps( slices_remove_small_slices(gear_off_grounds, time_limit=30)))
def derive(self, gnds=S('Grounded'), pitch=P('Pitch'), roll=P('Roll')): decks = [] for gnd in gnds: # The fourier transform for pitching motion... p = pitch.array[gnd.slice] if np.all(p.mask): continue n = float( len(p)) # Scaling the result to be independet of data length. fft_p = np.abs(np.fft.rfft(p - moving_average(p))) / n # similarly for roll r = roll.array[gnd.slice] if np.all(r.mask): continue fft_r = np.abs(np.fft.rfft(r - moving_average(r))) / n # What was the maximum harmonic seen? fft_max = np.ma.max(fft_p + fft_r) # Values of less than 0.1 were on the ground, and 0.34 on deck for the one case seen to date. if fft_max > 0.2: decks.append(gnd.slice) if decks: self.create_sections(decks)
def derive(self, pilot_flying=M('Pilot Flying'), pitch_capt=P('Pitch (Capt)'), pitch_fo=P('Pitch (FO)'), roll_capt=P('Roll (Capt)'), roll_fo=P('Roll (FO)'), cc_capt=P('Control Column Force (Capt)'), cc_fo=P('Control Column Force (FO)'), ap1_eng=M('AP (1) Engaged'), ap2_eng=M('AP (2) Engaged'), landings=S('Landing'), touchdowns=KTI('Touchdown'), afr_landing_pilot=A('AFR Landing Pilot')): if afr_landing_pilot and afr_landing_pilot.value: self.set_flight_attr(afr_landing_pilot.value.replace('_', ' ').title()) return phase = landings.get_last() if landings else None tdwn = touchdowns.get_last() if touchdowns else None if tdwn and ap1_eng and ap2_eng: # check AP state at the floored index (just before tdwn) ap1 = ap1_eng.array[int(tdwn.index)] == 'Engaged' ap2 = ap2_eng.array[int(tdwn.index)] == 'Engaged' else: ap1 = ap2 = None args = (pilot_flying, pitch_capt, pitch_fo, roll_capt, roll_fo, cc_capt, cc_fo, phase, ap1, ap2) self.set_flight_attr(self._determine_pilot(*args))
def derive(self, takeoffs=S('Takeoff'), climb_starts=KTI('Climb Start'), tocs=KTI('Top Of Climb'), alt=P('Altitude STD'), ac_type=A('Aircraft Type')): pass