Changeset 11:433f7e61f9f3 for src/checks.py
- Timestamp:
- 02/08/12 16:28:21 (13 years ago)
- Branch:
- default
- Phase:
- public
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/checks.py
r10 r11 365 365 366 366 #--------------------------------------------------------------------------------------- 367 368 class 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 393 class 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 409 class 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 447 class 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 464 class 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 486 class 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 509 class 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 524 class 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 540 class 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 554 class 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 569 class 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 602 class 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 630 class 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 643 class 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 655 class 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 667 class 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 683 class 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 701 class 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 719 class 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 740 class 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 756 class 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 772 class 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 790 class 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 813 class 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 829 class 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.