Ignore:
Timestamp:
02/08/12 16:28:21 (13 years ago)
Author:
István Váradi <ivaradi@…>
Branch:
default
Phase:
public
Message:

Added the checks

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/checks.py

    r10 r11  
    365365
    366366#---------------------------------------------------------------------------------------
     367
     368class FaultChecker(StateChecker):
     369    """Base class for checkers that look for faults."""
     370    @staticmethod
     371    def _appendDuring(flight, message):
     372        """Append a 'during XXX' test to the given message, depending on the
     373        flight stage."""
     374        stageStr = const.stage2string(flight.stage)
     375        return message if stageStr is None \
     376               else (message + " during " + stageStr.upper())
     377
     378    @staticmethod
     379    def _getLinearScore(minFaultValue, maxFaultValue, minScore, maxScore,
     380                        value):
     381        """Get the score for a faulty value where the score is calculated
     382        linearly within a certain range."""
     383        if value<minFaultValue:
     384            return 0
     385        elif value>maxFaultValue:
     386            return maxScore
     387        else:
     388            return minScore + (maxScore-minScore) * (value-minFaultValue) / \
     389                   (maxFaultValue - minFaultValue)
     390
     391#---------------------------------------------------------------------------------------
     392
     393class SimpleFaultChecker(FaultChecker):
     394    """Base class for fault checkers that check for a single occurence of a
     395    faulty condition.
     396
     397    Child classes should implement the following functions:
     398    - isCondition(self, flight, aircraft, oldState, state): should return whether the
     399    condition holds
     400    - logFault(self, flight, aircraft, logger, oldState, state): log the fault
     401    via the logger."""
     402    def check(self, flight, aircraft, logger, oldState, state):
     403        """Perform the check."""
     404        if self.isCondition(flight, aircraft, oldState, state):
     405            self.logFault(flight, aircraft, logger, oldState, state)
     406
     407#---------------------------------------------------------------------------------------
     408
     409class PatientFaultChecker(FaultChecker):
     410    """A fault checker that does not decides on a fault when the condition
     411    arises immediately, but can wait some time.
     412
     413    Child classes should implement the following functions:
     414    - isCondition(self, flight, aircraft, oldState, state): should return whether the
     415    condition holds
     416    - logFault(self, flight, aircraft, logger, oldState, state): log the fault
     417    via the logger
     418    """
     419    def __init__(self, timeout = 2.0):
     420        """Construct the fault checker with the given timeout."""
     421        self._timeout = timeout
     422        self._faultStarted = None
     423
     424    def getTimeout(self, flight, aircraft, oldState, state):
     425        """Get the timeout.
     426
     427        This default implementation returns the timeout given in the
     428        constructor, but child classes might want to enforce a different
     429        policy."""
     430        return self._timeout
     431
     432    def check(self, flight, aircraft, logger, oldState, state):
     433        """Perform the check."""
     434        if self.isCondition(flight, aircraft, oldState, state):
     435            if self._faultStarted is None:
     436                self._faultStarted = state.timestamp
     437            timeout = self.getTimeout(flight, aircraft, oldState, state)
     438            if state.timestamp>=(self._faultStarted + timeout):
     439                self.logFault(flight, aircraft, logger, oldState, state)
     440                self._faulted = True
     441                self._faultStarted = state.timestamp
     442        else:
     443            self._faultStarted = None
     444               
     445#---------------------------------------------------------------------------------------
     446
     447class AntiCollisionLightsChecker(PatientFaultChecker):
     448    """Check for the anti-collision light being off at high N1 values."""
     449    def isCondition(self, flight, aircraft, oldState, state):
     450        """Check if the fault condition holds."""
     451        return (flight.stage!=const.STAGE_PARKING or \
     452                not flight.options.fs2Crew) and \
     453                not state.antiCollisionLightsOn and \
     454                max(state.n1)>5
     455
     456    def logFault(self, flight, aircraft, logger, oldState, state):
     457        """Log the fault."""
     458        logger.fault(AntiCollisionLightChecker, state.timestamp,
     459                     FaultChecker._appendDuring(flight, "Anti-collision lights were off"),
     460                     1)
     461
     462#---------------------------------------------------------------------------------------
     463
     464class BankChecker(SimpleFaultChecker):
     465    """Check for the anti-collision light being off at high N1 values."""
     466    def isCondition(self, flight, aircraft, oldState, state):
     467        """Check if the fault condition holds."""
     468        if flight.stage==const.STAGE_CRUISE:
     469            bankLimit = 30
     470        elif flight.stage in [const.STAGE_TAKEOFF, const.STAGE_CLIMB,
     471                              const.STAGE_DESCENT, const.STAGE_LANDING]:
     472            bankLimit = 35
     473        else:
     474            return False
     475
     476        return state.bank>bankLimit or state.bank<-bankLimit
     477
     478    def logFault(self, flight, aircraft, logger, oldState, state):
     479        """Log the fault."""
     480        logger.fault(BankChecker, state.timestamp,
     481                     FaultChecker._appendDuring(flight, "Bank too steep"),
     482                     2)
     483
     484#---------------------------------------------------------------------------------------
     485
     486class FlapsRetractChecker(SimpleFaultChecker):
     487    """Check if the flaps are not retracted too early."""
     488    def isCondition(self, flight, aircraft, oldState, state):
     489        """Check if the fault condition holds.
     490
     491        FIXME: check if this really is the intention (FlapsRetractedMistake.java)"""
     492        if (flight.stage==const.STAGE_TAKEOFF and not state.onTheGround) or \
     493           (flight.stage==const.STAGE_LANDING and state.onTheGround):
     494            if self._timeStart is None:
     495                self._timeStart = state.timestamp
     496
     497            if state.flapsSet==0 and state.timestamp<=(self._timeStart+2.0):
     498                return True
     499        return False
     500
     501    def logFault(self, flight, aircraft, logger, oldState, state):
     502        """Log the fault."""
     503        logger.fault(FlapsRetractChecker, state.timestamp,
     504                     FaultChecker._appendDuring(flight, "Flaps retracted"),
     505                     20)
     506
     507#---------------------------------------------------------------------------------------
     508
     509class FlapsSpeedLimitChecker(SimpleFaultChecker):
     510    """Check if the flaps are extended only at the right speeds."""
     511    def isCondition(self, flight, aircraft, oldState, state):
     512        """Check if the fault condition holds."""
     513        speedLimit = aircraft.getFlapsSpeedLimit(state.flapsSet)
     514        return speedLimit is not None and state.ias>speedLimit
     515
     516    def logFault(self, flight, aircraft, logger, oldState, state):
     517        """Log the fault."""
     518        logger.fault(FlapsSpeedLimitChecker, state.timestamp,
     519                     FaultChecker._appendDuring(flight, "Flap speed limit fault"),
     520                     5)
     521
     522#---------------------------------------------------------------------------------------
     523
     524class GearsDownChecker(SimpleFaultChecker):
     525    """Check if the gears are down at low altitudes."""
     526    def isCondition(self, flight, aircraft, oldState, state):
     527        """Check if the fault condition holds."""
     528        return state.radioAltitude<10 and not state.gearsDown and \
     529               flight.stage!=const.STAGE_TAKEOFF
     530
     531    def logFault(self, flight, aircraft, logger, oldState, state):
     532        """Log the fault."""
     533        logger.noGo(GearsDownChecker, state.timestamp,
     534                    "Gears not down at %.0f feet radio altitude" % \
     535                    (state.radioAltitude,),
     536                    "GEAR DOWN NO GO")
     537
     538#---------------------------------------------------------------------------------------
     539
     540class GearSpeedLimitChecker(PatientFaultChecker):
     541    """Check if the gears not down at too high a speed."""
     542    def isCondition(self, flight, aircraft, oldState, state):
     543        """Check if the fault condition holds."""
     544        return state.gearsDown and state.ias>gearSpeedLimit
     545
     546    def logFault(self, flight, aircraft, logger, oldState, state):
     547        """Log the fault."""
     548        logger.fault(GearSpeedLinmitChecker, state.timestamp,
     549                     FaultChecker._appendDuring(flight, "Gear speed limit fault"),
     550                     5)
     551
     552#---------------------------------------------------------------------------------------
     553
     554class GLoadChecker(SimpleFaultChecker):
     555    """Check if the G-load does not exceed 2 except during flare."""
     556    def isCondition(self, flight, aircraft, oldState, state):
     557        """Check if the fault condition holds."""
     558        return state.gLoad>2.0 and (flight.stage!=const.STAGE_LANDING or \
     559                                    state.radioAltitude>=50)
     560               
     561    def logFault(self, flight, aircraft, logger, oldState, state):
     562        """Log the fault."""
     563        logger.fault(GLoadChecker, state.timestamp,
     564                     "G-load was %.2f" % (state.gLoad,),
     565                     10)
     566
     567#---------------------------------------------------------------------------------------
     568
     569class LandingLightsChecker(PatientFaultChecker):
     570    """Check if the landing lights are used properly."""
     571    def getTimeout(self, flight, aircraft, oldState, state):
     572        """Get the timeout.
     573
     574        It is the default timeout except for landing and takeoff."""
     575        return 0.0 if flight.stage in [const.STAGE_TAKEOFF,
     576                                       const.STAGE_LANDING] else self._timeout
     577
     578    def isCondition(self, flight, aircraft, oldState, state):
     579        """Check if the fault condition holds."""
     580        return (flight.stage==const.STAGE_BOARDING and \
     581                state.landingLightsOn and state.onTheGround) or \
     582               (flight.stage==const.STAGE_TAKEOFF and \
     583                not state.landingLightsOn and not state.onTheGround) or \
     584               (flight.stage in [const.STAGE_CLIMB, const.STAGE_CRUISE,
     585                                 const.STAGE_DESCENT] and \
     586                state.landingLightsOn and state.altitude>12500) or \
     587               (flight.stage==const.STAGE_LANDING and \
     588                not state.landingLightsOn and state.onTheGround) or \
     589               (flight.stage==const.STAGE_PARKING and \
     590                state.landingLightsOn and state.onTheGround)
     591               
     592    def logFault(self, flight, aircraft, logger, oldState, state):
     593        """Log the fault."""
     594        score = 0 if flight.stage==const.STAGE_LANDING else 1
     595        message = "Landing lights were %s" % (("on" if state.landingLightsOn else "off"),)
     596        logger.fault(LandingLightsChecker, state.timestamp,
     597                     FaultChecker._appendDuring(flight, message),
     598                     score)       
     599
     600#---------------------------------------------------------------------------------------
     601
     602class WeightChecker(PatientFaultChecker):
     603    """Base class for checkers that check that some limit is not exceeded."""
     604    def __init__(self, name):
     605        """Construct the checker."""
     606        super(WeightChecker, self).__init__(timeout = 5.0)
     607        self._name = name
     608
     609    def isCondition(self, flight, aircraft, oldState, state):
     610        """Check if the fault condition holds."""
     611        if flight.entranceExam:
     612            return False
     613
     614        limit = self.getLimit(flight, aircraft, state)
     615        if limit is not None:
     616            if flight.options.compensation is not None:
     617                limit += flight.options.compensation
     618            return state.grossWeight>mlw
     619
     620        return False
     621
     622    def logFault(self, flight, aircraft, logger, oldState, state):
     623        """Log the fault."""
     624        logger.noGo(self.__class__, state.timestamp,
     625                    "%s exceeded: %.0f kg" % (self._name, state.grossWeight),
     626                    "%s NO GO" % (self._name,))
     627
     628#---------------------------------------------------------------------------------------
     629
     630class MLWChecker(WeightChecker):
     631    """Checks if the MLW is not exceeded on landing."""
     632    def __init__(self):
     633        """Construct the checker."""
     634        super(MLWChecker, self).__init__("MLW")
     635
     636    def getLimit(flight, aircraft, state):
     637        """Get the limit if we are in the right state."""
     638        return aircraft.mlw if flight.stage==const.STAGE_LANDING and \
     639                               state.onTheGround else None
     640
     641#---------------------------------------------------------------------------------------
     642
     643class MTOWChecker(WeightChecker):
     644    """Checks if the MTOW is not exceeded on landing."""
     645    def __init__(self):
     646        """Construct the checker."""
     647        super(MTOWChecker, self).__init__("MTOW")
     648
     649    def getLimit(flight, aircraft, state):
     650        """Get the limit if we are in the right state."""
     651        return aircraft.mtow if flight.stage==const.STAGE_TAKEOFF else None
     652
     653#---------------------------------------------------------------------------------------
     654
     655class MZFWChecker(WeightChecker):
     656    """Checks if the MTOW is not exceeded on landing."""
     657    def __init__(self):
     658        """Construct the checker."""
     659        super(MZFWChecker, self).__init__("MZFW")
     660
     661    def getLimit(flight, aircraft, state):
     662        """Get the limit if we are in the right state."""
     663        return aircraft.mzfw
     664
     665#---------------------------------------------------------------------------------------
     666
     667class NavLightsChecker(PatientFaultChecker):
     668    """Check if the navigational lights are used properly."""
     669    def isCondition(self, flight, aircraft, oldState, state):
     670        """Check if the fault condition holds."""
     671        return flight.stage!=const.STAGE_BOARDING and \
     672               flight.stage!=const.STAGE_PARKING and \
     673               not state.navLightsOn
     674               
     675    def logFault(self, flight, aircraft, logger, oldState, state):
     676        """Log the fault."""
     677        logger.fault(NavLightsChecker, state.timestamp,
     678                     FaultChecker._appendDuring(flight, "Navigation lights were off"),
     679                     1)       
     680
     681#---------------------------------------------------------------------------------------
     682
     683class OverspeedChecker(PatientFaultChecker):
     684    """Check if Vne has been exceeded."""
     685    def __init__(self):
     686        """Construct the checker."""
     687        super(OverspeedChecker, self).__init__(timeout = 5.0)
     688
     689    def isCondition(self, flight, aircraft, oldState, state):
     690        """Check if the fault condition holds."""
     691        return state.overspeed
     692               
     693    def logFault(self, flight, aircraft, logger, oldState, state):
     694        """Log the fault."""
     695        logger.fault(OverspeedChecker, state.timestamp,
     696                     FaultChecker._appendDuring(flight, "Overspeed"),
     697                     20)       
     698
     699#---------------------------------------------------------------------------------------
     700
     701class PayloadChecker(SimpleFaultChecker):
     702    """Check if the payload matches the specification."""
     703    TOLERANCE=550
     704   
     705    def isCondition(self, flight, aircraft, oldState, state):
     706        """Check if the fault condition holds."""
     707        return flight.stage==const.STAGE_PUSHANDTAXI and \
     708               (state.zfw < (flight.zfw - PayloadChecker.TOLERANCE) or \
     709                state.zfw > (flight.zfw + PayloadChecker.TOLERANCE))
     710               
     711    def logFault(self, flight, aircraft, logger, oldState, state):
     712        """Log the fault."""
     713        logger.noGo(PayloadChecker, state.timestamp,
     714                    "ZFW difference is more than %d kgs" % (PayloadChecker.TOLERANCE,),
     715                    "ZFW NO GO")
     716
     717#---------------------------------------------------------------------------------------
     718
     719class PitotChecker(PatientFaultChecker):
     720    """Check if pitot heat is on."""
     721    def __init__(self):
     722        """Construct the checker."""
     723        super(PitotChecker, self).__init__(timeout = 3.0)
     724
     725    def isCondition(self, flight, aircraft, oldState, state):
     726        """Check if the fault condition holds."""
     727        return state.groundSpeed>80 and not current.pitotHeatOn
     728               
     729    def logFault(self, flight, aircraft, logger, oldState, state):
     730        """Log the fault."""
     731        score = 2 if flight.stage in [const.STAGE_TAKEOFF, const.STAGE_CLIMB,
     732                                      const.STAGE_CRUISE, const.STAGE_DESCENT,
     733                                      const.STAGE_LANDING] else 0
     734        logger.fault(PitotChecker, state.timestamp,
     735                     FaultChecker._appendDuring(flight, "Pitot heat was off"),
     736                     score)       
     737
     738#---------------------------------------------------------------------------------------
     739
     740class ReverserChecker(SimpleFaultChecker):
     741    """Check if the reverser is not used below 60 knots."""
     742    def isCondition(self, flight, aircraft, oldState, state):
     743        """Check if the fault condition holds."""
     744        return flight.stage in [const.STAGE_DESCENT, const.STAGE_LANDING,
     745                                const.STAGE_TAXIAFTERLAND] and \
     746            state.groundSpeed<80 and max(state.reverser)
     747                           
     748    def logFault(self, flight, aircraft, logger, oldState, state):
     749        """Log the fault."""
     750        logger.fault(ReverserChecker, state.timestamp,
     751                     FaultChecker._appendDuring(flight, "Reverser used below 60 knots"),
     752                     15)       
     753
     754#---------------------------------------------------------------------------------------
     755
     756class SpeedChecker(SimpleFaultChecker):
     757    """Check if the speed is in the prescribed limits."""
     758    def isCondition(self, flight, aircraft, oldState, state):
     759        """Check if the fault condition holds."""
     760        return flight.stage in [const.STAGE_PUSHANDTAXI,
     761                                const.STAGE_TAXIAFTERLAND] and \
     762            state.groundSpeed>50
     763                           
     764    def logFault(self, flight, aircraft, logger, oldState, state):
     765        """Log the fault."""
     766        logger.fault(SpeedChecker, state.timestamp,
     767                     FaultChecker._appendDuring(flight, "Reverser used below 60 knots"),
     768                     FaultChecker._getLinearScore(50, 80, 10, 15, state.groundSpeed))
     769
     770#---------------------------------------------------------------------------------------
     771
     772class StallChecker(PatientFaultChecker):
     773    """Check if stall occured."""
     774    def isCondition(self, flight, aircraft, oldState, state):
     775        """Check if the fault condition holds."""
     776        return flight.stage in [const.STAGE_TAKEOFF, const.STAGE_CLIMB,
     777                                const.STAGE_CRUISE, const.STAGE_DESCENT,
     778                                const.STAGE_LANDING] and state.stalled
     779               
     780    def logFault(self, flight, aircraft, logger, oldState, state):
     781        """Log the fault."""
     782        score = 40 if flight.stage in [const.STAGE_TAKEOFF,
     783                                       const.STAGE_LANDING] else 30
     784        logger.fault(StallChecker, state.timestamp,
     785                     FaultChecker._appendDuring(flight, "Stalled"),
     786                     score)       
     787
     788#---------------------------------------------------------------------------------------
     789
     790class StrobeLightsChecker(PatientFaultChecker):
     791    """Check if the strobe lights are used properly."""
     792    def isCondition(self, flight, aircraft, oldState, state):
     793        """Check if the fault condition holds."""
     794        return (flight.stage==const.STAGE_BOARDING and \
     795                state.strobeLightsOn and state.onTheGround) or \
     796               (flight.stage==const.STAGE_TAKEOFF and \
     797                not state.strobeLightsOn and not state.gearsDown) or \
     798               (flight.stage in [const.STAGE_CLIMB, const.STAGE_CRUISE,
     799                                 const.STAGE_DESCENT] and \
     800                not state.strobeLightsOn and not state.onTheGround) or \
     801               (flight.stage==const.STAGE_PARKING and \
     802                state.strobeLightsOn and state.onTheGround)
     803               
     804    def logFault(self, flight, aircraft, logger, oldState, state):
     805        """Log the fault."""
     806        message = "Strobe lights were %s" % (("on" if state.strobeLightsOn else "off"),)
     807        logger.fault(StrobeLightsChecker, state.timestamp,
     808                     FaultChecker._appendDuring(flight, message),
     809                     1)       
     810
     811#---------------------------------------------------------------------------------------
     812
     813class ThrustChecker(SimpleFaultChecker):
     814    """Check if the thrust setting is not too high during takeoff.
     815
     816    FIXME: is this really so general, for all aircraft?"""
     817    def isCondition(self, flight, aircraft, oldState, state):
     818        """Check if the fault condition holds."""
     819        return flight.stage==const.STAGE_TAKEOFF and max(state.n1)>97
     820               
     821    def logFault(self, flight, aircraft, logger, oldState, state):
     822        """Log the fault."""
     823        logger.fault(LandingLightsChecker, state.timestamp,
     824                     FaultChecker._appendDuring(flight, "Thrust setting was too high (>97%)"),
     825                     FaultChecker._getLinearScore(97, 110, 0, 10, max(state.n1)))
     826
     827#---------------------------------------------------------------------------------------
     828
     829class VSChecker(SimpleFaultChecker):
     830    """Check if the vertical speed is not too low at certain altitudes"""
     831    BELOW10000 = -5000
     832    BELOW5000 = -2500
     833    BELOW2500 = -1500
     834    BELOW500 = -1000
     835    TOLERANCE = 1.2
     836
     837    def isCondition(self, flight, aircraft, oldState, state):
     838        """Check if the fault condition holds."""
     839        vs = state.vs
     840        altitude = state.altitude
     841        return vs < -8000 or vs > 8000 or \
     842               (altitude<500 and vs < (VSChecker.BELOW500 *
     843                                       VSCHECKER.TOLERANCE)) or \
     844               (altitude<2500 and vs < (VSChecker.BELOW2500 *
     845                                        VSCHECKER.TOLERANCE)) or \
     846               (altitude<5000 and vs < (VSChecker.BELOW5000 *
     847                                        VSCHECKER.TOLERANCE)) or \
     848               (altitude<10000 and vs < (VSChecker.BELOW10000 *
     849                                         VSCHECKER.TOLERANCE))
     850               
     851    def logFault(self, flight, aircraft, logger, oldState, state):
     852        """Log the fault."""
     853        vs = state.vs
     854
     855        message = "Vertical speed was %.0f feet/min" % (vs,)
     856        if vs>-8000 and vs<8000:
     857            message += " at %.0f feet (exceeds company limit)" % (state.altitude,)
     858
     859        score = 10 if vs<-8000 or vs>8000 else 0
     860
     861        logger.fault(VSChecker, state.timestamp,
     862                     FaultChecker._appendDuring(flight, message),
     863                     score)
     864
     865#---------------------------------------------------------------------------------------
Note: See TracChangeset for help on using the changeset viewer.