def derive(self,
            eng_stops=KTI('Eng Stop'),
            eng_count=A('Engine Count'),
            touchdowns=KTI('Touchdown'),
            duration=A('HDF Duration')):
     pass
Ejemplo n.º 2
0
    
    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)
Ejemplo n.º 4
0
 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
Ejemplo n.º 6
0
    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)
Ejemplo n.º 7
0
 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
Ejemplo n.º 9
0
    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
Ejemplo n.º 16
0
 def derive(self, start_datetime=A('Start Datetime')):
     self.create_kpv(3.0, 999.9)
Ejemplo n.º 17
0
    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)
Ejemplo n.º 18
0
 def derive(self, start_datetime=A('Start Datetime')):
     self.set_flight_attr('Keith')
Ejemplo n.º 19
0
 def can_operate(cls, available, ac_type=A('Aircraft Type')):
     return ac_type == helicopter and \
            all_of(('Altitude AGL', 'Airborne', 'Hover'), available)
Ejemplo n.º 20
0
 def derive(self, filename=A('Myfile')):
     self.set_flight_attr(filename.value)
Ejemplo n.º 21
0
 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)
Ejemplo n.º 22
0
 def derive(self, mydict=A('Mydict')):
     mydict.value['testkey'] = [1, 2, 3]
     self.set_flight_attr(mydict.value)
Ejemplo n.º 23
0
 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
Ejemplo n.º 24
0
 def derive(self, start_datetime=A('Start Datetime')):
     #print 'in SimpleKTI'
     self.create_kti(3)
Ejemplo n.º 25
0
 def can_operate(cls, available, ac_type=A('Aircraft Type')):
     return ac_type == helicopter and any_of(cls.get_dependency_names(), available)
Ejemplo n.º 26
0
 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)
Ejemplo n.º 27
0
 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()
Ejemplo n.º 29
0
    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