source: src/mlx/acft.py@ 1185:a48a0883c767

python3
Last change on this file since 1185:a48a0883c767 was 1185:a48a0883c767, checked in by István Váradi <ivaradi@…>, 2 days ago

The SimBrief profiles are updated

File size: 51.7 KB
RevLine 
[298]1
[919]2from . import const
3from . import gates
4from . import checks
5from . import fs
6from .i18n import xstr
7from . import util
[298]8
9import sys
10import time
11import traceback
12
13from collections import deque
14
15#---------------------------------------------------------------------------------------
16
[297]17## @package mlx.acft
18#
19# The simulator-independent aircraft classes.
20#
21# This module contains the aircraft classes that contain some general data
22# about each aircraft type in the MAVA Fleet. The base class, \ref Aircraft
23# also implements some parts of the logging and traces some data. The classes
24# are also responsible for creating the \ref mlx.checks "checkers". Most of
25# them are created by the \ref Aircraft class' constructor, but there can be
26# type-specific differences. For example the lights are different for different
27# types, so there is a \ref Aircraft._appendLightsLoggers "function" which can
28# be reimplemented in child classes, if needed. This class maintains also the
29# \ref SmoothedValue "smoothed values" of the IAS and the VS and set these
30# values in the \ref mlx.fs.AircraftState "aircraft state" when it is received
31# from the simulator.
[4]32
33#---------------------------------------------------------------------------------------
34
[512]35# Derate type: no derate possible
36DERATE_NONE = 0
37
38# Derate type: Boeing, i.e. a percentage value.
39# For logging, the percentage value is expected as a string (i.e. whatever the
40# pilot enters into the text field).
41DERATE_BOEING = 1
42
43# Derate type: EPR, i.e. an EPR value.
44# For logging, the EPR value is expected as a string (i.e. whatever the pilot
45# enters into the text field).
46DERATE_EPR = 2
47
48# Derate type: Tupolev, i.e. nominal or takeoff
49# For logging, one of the DERATE_TUPOLEV_xxx values are expected.
50DERATE_TUPOLEV = 3
51
52# Tupolev derate value: nominal
53DERATE_TUPOLEV_NOMINAL = 1
54
55# Tupolev derate value: takeoff
56DERATE_TUPOLEV_TAKEOFF = 2
57
58# Derate type: BAe-146, i.e. enabled or not
59# For logging, a boolean is expected.
60DERATE_B462 = 4
61
62#---------------------------------------------------------------------------------------
63
[197]64class SmoothedValue(object):
65 """A smoothed value."""
66 def __init__(self):
67 """Construct the value."""
68 self._deque = deque()
69 self._sum = 0
70
71 def add(self, length, value):
72 """Add the given value and smooth with the given length."""
73 dequeLength = len(self._deque)
74 while dequeLength>=length:
75 self._sum -= self._deque.popleft()
76 dequeLength -= 1
77
78 self._sum += value
79 self._deque.append(value)
80
81 def get(self):
82 """Get the average."""
83 return self._sum / len(self._deque)
[331]84
[4]85#---------------------------------------------------------------------------------------
86
[709]87class SimBriefData(object):
88 """Data to be used when creating SimBrief briefings."""
[1087]89 def __init__(self, climbProfiles, cruiseProfiles, descentProfiles,
90 cruiseParameters = {}):
91 """Construct the SimBrief data with the given profiles.
92
93 cruiseParameters is a dictionary keyed by the cruise profile index. It
94 contains a tuple of:
95 - a boolean indicating if the parameter is mandatory,
96 - the name of the parameter for the SimBrief API
97 """
[709]98 self.climbProfiles = climbProfiles
99 self.cruiseProfiles = cruiseProfiles
100 self.descentProfiles = descentProfiles
[1087]101 self.cruiseParameters = cruiseParameters
[709]102
103#---------------------------------------------------------------------------------------
104
[4]105class Aircraft(object):
106 """Base class for aircraft."""
[8]107 @staticmethod
[798]108 def create(flight, bookedFlight):
[8]109 """Create an aircraft instance for the type in the given flight."""
[798]110 acft = _classes[flight.aircraftType](flight)
111 acft.setBookedFlight(bookedFlight)
112 return acft
[8]113
[592]114 def __init__(self, flight, minLandingFuel = None,
115 recommendedLandingFuel = None):
[4]116 """Construct the aircraft for the given type."""
[8]117 self._flight = flight
[591]118 self._minLandingFuel = minLandingFuel
[592]119 self._recommendedLandingFuel = recommendedLandingFuel
[369]120
121 self._name = None
122 self._modelName = None
123
[4]124 self._aircraftState = None
[331]125
[9]126 self._maxVS = -10000.0
127 self._minVS = 10000.0
[4]128
[101]129 self._v1r2LineIndex = None
[384]130 self._derateLineID = None
[391]131 self._takeoffAntiIceLineID = None
[96]132 self._vrefLineIndex = None
[391]133 self._landingAntiIceLineID = None
[96]134
[117]135 self.humanWeight = 82.0
136
[598]137 self.initialClimbSpeedAltitude = 1500
138 self.reverseMinSpeed = 50
[360]139
[644]140 self.hasStrobeLight = True
141
[611]142 self.maxTakeOffPitch = 15.0
143 self.maxTouchDownPitch = 15.0
[624]144 self.brakeCoolTime = 10.0
[611]145
[709]146 self.simBriefData = None
147
[8]148 self._checkers = []
149
[197]150 config = flight.config
[11]151 # Loggers
152
[8]153 self._checkers.append(checks.StageChecker())
[9]154 self._checkers.append(checks.TakeOffLogger())
[8]155
156 self._checkers.append(checks.AltimeterLogger())
[321]157
[366]158 self._ilsLogger = checks.ILSLogger()
159 self._checkers.append(self._ilsLogger)
[321]160 self._nav1Logger = checks.NAV1Logger()
161 self._checkers.append(self._nav1Logger)
162 self._nav2Logger = checks.NAV2Logger()
163 self._checkers.append(self._nav2Logger)
164
165 self._adf1Logger = checks.ADF1Logger()
166 self._checkers.append(self._adf1Logger)
167 self._adf2Logger = checks.ADF2Logger()
168 self._checkers.append(self._adf2Logger)
[331]169
[8]170 self._checkers.append(checks.SquawkLogger())
171
[211]172 self._appendLightsLoggers()
[8]173
174 self._checkers.append(checks.FlapsLogger())
175
176 self._checkers.append(checks.GearsLogger())
[601]177 self._checkers.append(checks.InitialClimbSpeedLogger())
[9]178 self._checkers.append(checks.CruiseSpeedLogger())
[10]179 self._checkers.append(checks.SpoilerLogger())
[338]180 self._checkers.append(checks.APLogger())
[9]181
[197]182 if config.isMessageTypeFS(const.MESSAGETYPE_VISIBILITY):
[134]183 self._checkers.append(checks.VisibilityChecker())
184
[139]185 # FIXME: we should have a central data model object, and not collect
186 # the data from the GUI. However, some pieces of data (e.g. V-speeds,
187 # etc. that is entered into the GUI) *should* be a part of the GUI and
188 # queried from it, so the model should have a reference to the GUI as
189 # well and access such data via the GUI!
[215]190 if config.onlineACARS and flight.loggedIn and not flight.entranceExam:
[139]191 self._checkers.append(checks.ACARSSender(flight._gui))
192
[11]193 # Fault checkers
[211]194
195 self._appendLightsCheckers()
[11]196
[335]197 self._checkers.append(checks.TransponderChecker())
198
[11]199 self._checkers.append(checks.BankChecker())
200
201 self._checkers.append(checks.FlapsRetractChecker())
202 self._checkers.append(checks.FlapsSpeedLimitChecker())
203
204 self._checkers.append(checks.GearsDownChecker())
205 self._checkers.append(checks.GearSpeedLimitChecker())
206
207 self._checkers.append(checks.GLoadChecker())
208
209 self._checkers.append(checks.MLWChecker())
210 self._checkers.append(checks.MTOWChecker())
211 self._checkers.append(checks.MZFWChecker())
212 self._checkers.append(checks.PayloadChecker())
213
[539]214 self._checkers.append(checks.SpeedChecker())
[11]215 self._checkers.append(checks.VSChecker())
[197]216
[447]217 timeout = 30.0 + config.realIASSmoothingLength - 1
[622]218 self._checkers.append(checks.OverspeedChecker(faultTimeout = timeout))
[331]219
[11]220 self._checkers.append(checks.StallChecker())
221
222 self._checkers.append(checks.PitotChecker())
[331]223
[598]224 self._checkers.append(checks.ReverserLogger())
[11]225 self._checkers.append(checks.ReverserChecker())
226
[273]227 if flight.aircraftType is not None and config.enableApproachCallouts:
228 approachCallouts = flight.config.getApproachCallouts(flight.aircraftType)
229 if approachCallouts:
230 self._checkers.append(checks.ApproachCalloutsPlayer(approachCallouts))
231
[197]232 self._smoothedIAS = SmoothedValue()
233 self._smoothedVS = SmoothedValue()
234
[4]235 @property
236 def type(self):
237 """Get the type of the aircraft."""
[8]238 return self._flight.aircraftType
239
240 @property
241 def flight(self):
242 """Get the flight the aircraft belongs to."""
243 return self._flight
[4]244
[8]245 @property
[592]246 def minLandingFuel(self):
247 """Get the minimum acceptable amount of the landing fuel."""
248 return self._minLandingFuel
249
250 @property
251 def recommendedLandingFuel(self):
252 """Get the recommended amount of the landing fuel."""
253 return self._recommendedLandingFuel
254
255 @property
[8]256 def logger(self):
257 """Get the logger to use for the aircraft."""
258 return self._flight.logger
259
[139]260 @property
261 def state(self):
262 """Get the current aircraft state."""
263 return self._aircraftState
[241]264
265 @property
266 def speedInKnots(self):
267 """Indicate if the speed is in knots.
268
269 This default implementation returns True."""
270 return True
[304]271
272 @property
[635]273 def aglInFeet(self):
274 """Indicate if AGL altitudes are to be logged in feet.
275
276 This default implementation returns True."""
277 return True
278
279 @property
[304]280 def timestamp(self):
281 """Get the timestamp of the current state."""
282 return None if self._aircraftState is None \
283 else self._aircraftState.timestamp
[331]284
[384]285 @property
[512]286 def derateType(self):
287 """Get the derate type for this aircraft.
288
289 This default implementation returns DERATE_NONE."""
290 return DERATE_NONE
[384]291
[1165]292 @property
293 def machSpeedAbove(self):
294 """Get the altitude above which the cruise speed should be reported
295 in Machs."""
296 return 24500
297
[798]298 def setBookedFlight(self, bookedFlight):
299 """Update the aircraft based on the booked flight data (e.g. tail number).
300
301 This default implementation does nothing."""
302
[512]303 def getDerateLine(self, value):
304 """Get the log line for the given derate value.
305
306 It uses the the derate type and produces the standard message for
307 each. This children need not override it, although they can."""
308 dt = self.derateType
[384]309
[512]310 if dt==DERATE_BOEING:
311 return "Derate calculated by the pilot: %s %%" % \
312 ("-" if value is None else value,)
313 elif dt==DERATE_EPR:
314 return "EPR calculated by the pilot: %s" % \
315 ("-" if value is None else value,)
316 elif dt==DERATE_TUPOLEV:
317 return "Thrust setting calculated by the pilot: %s" % \
318 ("-" if value is None else
319 "nominal" if value==DERATE_TUPOLEV_NOMINAL else "takeoff",)
320 elif dt==DERATE_B462:
321 return "Derate setting: %s" % \
322 ("-" if value is None else "enabled" if value else "disabled",)
323 elif dt!=DERATE_NONE:
[919]324 print("mlx.acft.getDerateLine: invalid derate type: " + dt)
[384]325
326 return None
327
[11]328 def getFlapsSpeedLimit(self, flaps):
329 """Get the speed limit for the given flaps setting."""
330 return self.flapSpeedLimits[flaps] if flaps in self.flapSpeedLimits \
331 else None
332
[8]333 def modelChanged(self, timestamp, aircraftName, modelName):
[4]334 """Called when the simulator's aircraft changes."""
[369]335 self._name = aircraftName
336 self._modelName = modelName
337 if self._flight.stage is not None:
338 self._logNameAndModel(timestamp)
[4]339
340 def handleState(self, aircraftState):
[197]341 """Called when the state of the aircraft changes.
342
343 This is the function that the simulator calls directly with the new
344 state."""
[274]345 try:
346 config = self._flight.config
[197]347
[274]348 self._smoothedIAS.add(config.realIASSmoothingLength, aircraftState.ias)
349 aircraftState.smoothedIAS = self._smoothedIAS.get()
350
351 self._smoothedVS.add(config.realVSSmoothingLength, aircraftState.vs)
352 aircraftState.smoothedVS = self._smoothedVS.get()
[197]353
[274]354 for checker in self._checkers:
355 try:
356 checker.check(self._flight, self, self._flight.logger,
357 self._aircraftState, aircraftState)
358 except:
[919]359 print("Checker", checker, "failed", file=sys.stderr)
[274]360 traceback.print_exc()
[7]361
[274]362 self._flight.handleState(self._aircraftState, aircraftState)
[89]363
[274]364 self._maxVS = max(self._maxVS, aircraftState.vs)
365 self._minVS = min(self._minVS, aircraftState.vs)
366 except:
[919]367 print("Failed to handle the state", file=sys.stderr)
[274]368 traceback.print_exc()
369 finally:
370 self._aircraftState = aircraftState
[331]371
[8]372 def setStage(self, aircraftState, newStage):
373 """Set the given stage as the new one and do whatever should be
374 done."""
[369]375 if newStage==const.STAGE_BOARDING:
376 self._logNameAndModel(aircraftState.timestamp)
377
[624]378 oldStage = self._flight.stage
379
[9]380 if self._flight.setStage(aircraftState.timestamp, newStage):
381 if newStage==const.STAGE_PUSHANDTAXI:
382 self.logger.message(aircraftState.timestamp, "Block time start")
[274]383 self._flight.logFuel(aircraftState)
[331]384 self.logger.message(aircraftState.timestamp,
[313]385 "ZFW: %.2f kg" % (aircraftState.zfw))
[134]386 flight = self._flight
387 if flight.v1 is None or flight.vr is None or flight.v2 is None:
388 fs.sendMessage(const.MESSAGETYPE_HELP,
389 "Don't forget to set the takeoff V-speeds!",
390 5)
[9]391 elif newStage==const.STAGE_TAKEOFF:
[624]392 if oldStage == const.STAGE_RTO and self._flight.hasRTO:
393 rtoState = self._flight.rtoState
394 if (aircraftState.timestamp - rtoState.timestamp) < \
395 (self.brakeCoolTime * 60.0):
396 self.logger.fault("brakeCoolTime",
397 aircraftState.timestamp,
398 "Did not cool the brakes for at least %.f minutes after the RTO" % (self.brakeCoolTime,),
399 15.0)
[241]400 self.logger.message(aircraftState.timestamp,
401 "Flight time start")
[331]402 self.logger.message(aircraftState.timestamp,
[9]403 "Takeoff weight: %.0f kg, MTOW: %.0f kg" % \
404 (aircraftState.grossWeight, self.mtow))
[409]405 self._logQNH(aircraftState)
[9]406 self.logger.message(aircraftState.timestamp,
[333]407 "Wind %03.0f/%.0f" % \
[331]408 (aircraftState.windDirection,
[9]409 aircraftState.windSpeed))
[321]410 self._logRadios(aircraftState)
[345]411 self._logV1R2(aircraftState)
[384]412 self._logDerate(aircraftState)
[391]413 self._logTakeoffAntiIce(aircraftState)
[321]414 elif newStage==const.STAGE_DESCENT or newStage==const.STAGE_LANDING:
415 self._logRadios(aircraftState)
[409]416 if newStage==const.STAGE_LANDING:
417 self._logQNH(aircraftState)
[634]418 elif newStage==const.STAGE_GOAROUND:
[919]419 from .logger import Logger
[634]420 self._flight.handleFault("goaround",
421 aircraftState.timestamp,
422 "Go-around detected, please, explain!",
423 Logger.NO_SCORE)
[9]424 elif newStage==const.STAGE_TAXIAFTERLAND:
[184]425 flight = self._flight
426 bookedFlight = flight.bookedFlight
427 config = flight.config
[136]428 if config.onlineGateSystem and \
[215]429 flight.loggedIn and \
[184]430 not flight.entranceExam and \
[136]431 bookedFlight.arrivalICAO=="LHBP" and \
432 config.isMessageTypeFS(const.MESSAGETYPE_GATE_SYSTEM):
[134]433 self._flight.getFleet(callback = self._fleetRetrieved,
434 force = True)
[9]435 self.logger.message(aircraftState.timestamp, "Flight time end")
[274]436 self._flight.logFuel(aircraftState)
[591]437 if self._minLandingFuel is not None and \
438 aircraftState.totalFuel<self._minLandingFuel:
[597]439 self._flight.handleFault(self.__class__,
440 aircraftState.timestamp,
441 "The amount of the landing fuel is less than the minimum for this type: %ukgs (possible NO GO!)" %
442 (self._minLandingFuel,), 0)
[9]443 self.logger.message(aircraftState.timestamp,
444 "Landing weight: %.0f kg, MLW: %.0f" % \
445 (aircraftState.grossWeight, self.mlw))
446 self.logger.message(aircraftState.timestamp,
447 "Vertical speed range: %.0f..%.0f feet/min" % \
[12]448 (self._minVS, self._maxVS))
[359]449 # elif newStage==const.STAGE_PARKING:
450 # self.logger.message(aircraftState.timestamp, "Block time end")
[89]451 elif newStage==const.STAGE_END:
452 flightLength = self._flight.flightTimeEnd - self._flight.flightTimeStart
[359]453 self.logger.message(aircraftState.timestamp, "Block time end")
[89]454 self.logger.message(aircraftState.timestamp,
455 "Flight time: " +
456 util.getTimeIntervalString(flightLength))
457 self.logger.message(aircraftState.timestamp,
458 "Flown distance: %.2f NM" % \
[331]459 (self._flight.flownDistance,))
[89]460 blockLength = self._flight.blockTimeEnd - self._flight.blockTimeStart
461 self.logger.message(aircraftState.timestamp,
462 "Block time: " +
463 util.getTimeIntervalString(blockLength))
[8]464
[9]465 def prepareFlare(self):
466 """Called when it is detected that we will soon flare.
[8]467
468 On the first call, it should start monitoring some parameters more
469 closely to determine flare time."""
[9]470 self.flight.simulator.startFlare()
471
[331]472 def flareStarted(self, windSpeed, windDirection, visibility,
[9]473 flareStart, flareStartFS):
474 """Called when the flare has started."""
475 self.logger.message(self._aircraftState.timestamp, "The flare has begun")
476 self.logger.message(self._aircraftState.timestamp,
[333]477 "Wind %03.0f/%.0f" % \
[9]478 (windDirection, windSpeed))
479 self.logger.message(self._aircraftState.timestamp,
480 "Visibility: %.0f metres" % (visibility,))
[409]481 self._logQNH(self._aircraftState)
[101]482 self._logVRef()
[391]483 self._logLandingAntiIce(self._aircraftState)
[9]484 self.flight.flareStarted(flareStart, flareStartFS)
[134]485 fs.sendMessage(const.MESSAGETYPE_INFORMATION, "Flare-time", 3)
[331]486
[9]487 def flareFinished(self, flareEnd, flareEndFS, tdRate, tdRateCalculatedByFS,
[1137]488 ias, pitch, bank, heading, gLoad):
[9]489 """Called when the flare has finished."""
490 (flareTimeFromFS, flareTime) = self.flight.flareFinished(flareEnd,
[170]491 flareEndFS,
492 tdRate)
[9]493 self.logger.message(self._aircraftState.timestamp,
[153]494 "Flaretime: %.3f (from %s)" % \
[331]495 (flareTime,
[9]496 "the simulator" if flareTimeFromFS else "real time",))
497 self.logger.message(self._aircraftState.timestamp,
498 "Touchdown rate: %.0f feet/min" % (tdRate,))
499 self.logger.message(self._aircraftState.timestamp,
500 "Touchdown rate was calculated by the %s" % \
501 ("simulator" if tdRateCalculatedByFS else "logger",))
[1137]502 self.logger.message(self._aircraftState.timestamp,
503 "Touchdown G-load: %.2f" % (gLoad,))
[241]504 flight = self._flight
[9]505 self.logger.message(self._aircraftState.timestamp,
[241]506 "Touchdown speed: %.0f %s" % \
507 (flight.speedFromKnots(ias),
508 flight.getEnglishSpeedUnit()))
[9]509 self.logger.message(self._aircraftState.timestamp,
510 "Touchdown pitch: %.1f degrees" % (pitch,))
511 self.logger.message(self._aircraftState.timestamp,
512 "Touchdown bank: %.1f degrees" % (bank,))
513 self.logger.message(self._aircraftState.timestamp,
514 "Touchdown heading: %03.0f degrees" % (heading,))
[331]515 self.logger.message(self._aircraftState.timestamp,
[340]516 "CG: %.1f%%" % \
[271]517 (self._aircraftState.cog*100.0,))
[8]518
[611]519 if abs(pitch)>self.maxTouchDownPitch:
520 self._flight.handleNoGo("TDPitch", self._aircraftState.timestamp,
521 "Touchdown pitch higher than aircraft maximum (%.2f)" % \
522 (self.maxTouchDownPitch,),
523 "TD TAILSTRIKE NO GO")
524
[8]525 def cancelFlare(self):
526 """Cancel flare, if it has started."""
[9]527 self.flight.simulator.cancelFlare()
[8]528
529 def checkFlightEnd(self, aircraftState):
530 """Check if the end of the flight has arrived.
531
532 This default implementation checks the N1 values, but for
533 piston-powered aircraft you need to check the RPMs."""
[1043]534 if aircraftState.n1 is not None:
535 for n1 in aircraftState.n1:
536 if n1 is not None and n1>=0.5: return False
[8]537 return True
538
[101]539 def updateV1R2(self):
540 """Update the V1, Vr and V2 values from the flight, if the these values
541 have already been logged."""
542 if self._v1r2LineIndex is not None:
543 self._logV1R2()
544
[384]545 def updateDerate(self):
546 """Update the derate value from the flight, if the these values
547 have already been logged."""
548 if self._derateLineID is not None:
549 self._logDerate()
550
[391]551 def updateTakeoffAntiIce(self):
552 """Update the take-off anti-ice setting."""
553 if self._takeoffAntiIceLineID is not None:
554 self._logTakeoffAntiIce()
555
[211]556 def _appendLightsLoggers(self):
557 """Append the loggers needed for the lights.
558
559 This default implementation adds the loggers for the anti-collision
560 lights, the landing lights, the strobe lights and the NAV lights."""
561 self._checkers.append(checks.AnticollisionLightsLogger())
562 self._checkers.append(checks.LandingLightsLogger())
563 self._checkers.append(checks.StrobeLightsLogger())
564 self._checkers.append(checks.NavLightsLogger())
565
566 def _appendLightsCheckers(self):
567 """Append the checkers needed for the lights.
568
569 This default implementation adds the checkers for the anti-collision
570 lights, the landing lights, the strobe lights and the NAV lights."""
571 self._checkers.append(checks.AntiCollisionLightsChecker())
572 self._checkers.append(checks.LandingLightsChecker())
573 self._checkers.append(checks.NavLightsChecker())
574 self._checkers.append(checks.StrobeLightsChecker())
575
[241]576 def _speedToLog(self, speed):
577 """Convert the given speed (being either None or expressed in the
578 flight's speed unit into a string."""
579 if speed is None:
580 return "-"
581 else:
582 return str(speed) + " " + self._flight.getEnglishSpeedUnit()
583
[345]584 def _logV1R2(self, state = None):
[101]585 """Log the V1, Vr and V2 value either newly, or by updating the
586 corresponding line."""
[526]587 message = "Calc. TO speeds: V1: %s, VR: %s, V2: %s" % \
[241]588 (self._speedToLog(self._flight.v1),
589 self._speedToLog(self._flight.vr),
590 self._speedToLog(self._flight.v2))
[101]591
592 if self._v1r2LineIndex is None:
[345]593 if state is None:
594 state = self._aircraftState
[101]595 self._v1r2LineIndex = \
[345]596 self.logger.message(state.timestamp, message)
[101]597 else:
598 self.logger.updateLine(self._v1r2LineIndex, message)
599
[384]600 def _logDerate(self, state = None):
601 """Log the derate values either newly or by updating the corresponding
602 line."""
[512]603 dt = self.derateType
604 if dt==DERATE_NONE:
[384]605 return
606
[512]607 message = self.getDerateLine(self._flight.derate)
608 if message is not None:
609 if self._derateLineID is None:
610 if state is None:
611 state = self._aircraftState
612 self._derateLineID = \
613 self.logger.message(state.timestamp, message)
614 else:
615 self.logger.updateLine(self._derateLineID, message)
[384]616
[391]617 def _logTakeoffAntiIce(self, state = None):
618 """Log the take-off anti-ice setting either newly or by updating the
619 corresponding line."""
620 antiIceOn = self._flight.takeoffAntiIceOn
621 if state is not None:
622 antiIceOn = antiIceOn or state.antiIceOn is True
623 self._flight.takeoffAntiIceOn = antiIceOn
624
625 message = "Anti-ice was turned %s" % \
626 ("ON" if antiIceOn else "OFF")
627
628 if self._takeoffAntiIceLineID is None:
629 if state is None:
630 state = self._aircraftState
631 self._takeoffAntiIceLineID = \
632 self.logger.message(state.timestamp, message)
633 else:
634 self.logger.updateLine(self._takeoffAntiIceLineID, message)
635
[96]636 def updateVRef(self):
637 """Update the Vref value from the flight, if the Vref value has already
638 been logged."""
639 if self._vrefLineIndex is not None:
640 self._logVRef()
641
642 def _logVRef(self):
643 """Log the Vref value either newly, or by updating the corresponding
644 line."""
645 message = "VRef speed calculated by the pilot: %s" % \
[241]646 (self._speedToLog(self._flight.vref),)
[96]647 if self._vrefLineIndex is None:
648 self._vrefLineIndex = \
649 self.logger.message(self._aircraftState.timestamp, message)
650 else:
651 self.logger.updateLine(self._vrefLineIndex, message)
652
[391]653 def updateLandingAntiIce(self):
654 """Update the landing anti-ice setting."""
655 if self._landingAntiIceLineID is not None:
656 self._logLandingAntiIce()
657
658 def _logLandingAntiIce(self, state = None):
659 """Log the landing anti-ice setting either newly or by updating the
660 corresponding line."""
661 antiIceOn = self._flight.landingAntiIceOn
662 if state is not None:
663 antiIceOn = antiIceOn or state.antiIceOn is True
664 self._flight.landingAntiIceOn = antiIceOn
665
666 message = "Anti-ice was turned %s" % \
667 ("ON" if antiIceOn else "OFF")
668
669 if self._landingAntiIceLineID is None:
670 if state is None:
671 state = self._aircraftState
672 self._landingAntiIceLineID = \
673 self.logger.message(state.timestamp, message)
674 else:
675 self.logger.updateLine(self._landingAntiIceLineID, message)
676
[134]677 def _fleetRetrieved(self, fleet):
678 """Callback for the fleet retrieval result."""
679 if fleet is not None:
680 gateList = ""
[1154]681 for gate in fleet.iterAvailableLHBPGates(self.flight.bookedFlight.tailNumber):
682 if gateList: gateList += ", "
683 gateList += gate.number
[134]684 fs.sendMessage(const.MESSAGETYPE_GATE_SYSTEM,
685 "Free gates: " + gateList, 20)
[331]686
[134]687
[321]688 def _logRadios(self, aircraftState):
689 """Log the radios from the given aircraft state."""
690 flight = self._flight
691 logger = flight.logger
692
[366]693 self._ilsLogger.forceLog(flight, logger, aircraftState)
[321]694 self._nav1Logger.forceLog(flight, logger, aircraftState)
695 self._nav2Logger.forceLog(flight, logger, aircraftState)
[329]696 self._adf1Logger.forceLog(flight, logger, aircraftState)
697 self._adf2Logger.forceLog(flight, logger, aircraftState)
[321]698
[409]699 def _logQNH(self, aircraftState):
700 """Log the current QNH along with the altimeter setting."""
701 self.logger.message(aircraftState.timestamp,
702 "QNH: %.2f hPa, altimeter: %.2f hPa" % \
703 (aircraftState.qnh, aircraftState.altimeter))
704
[369]705 def _logNameAndModel(self, timestamp):
706 """Log the aircraft's name and model with taking the timestamp from the
707 given state."""
708 self._flight.logger.message(timestamp,
709 "Aircraft: name='%s', model='%s'" % \
710 (self._name, self._modelName))
711
[4]712#---------------------------------------------------------------------------------------
[7]713
714class Boeing737(Aircraft):
715 """Base class for the various aircraft in the Boeing 737 family.
716
717 The aircraft type-specific values in the aircraft state have the following
718 structure:
[140]719 - fuel: left, centre, right
[7]720 - n1: left, right
[331]721 - reverser: left, right"""
[592]722 def __init__(self, flight, minLandingFuel = 2500,
723 recommendedLandingFuel = 3500):
724 super(Boeing737, self).__init__(flight,
725 minLandingFuel = minLandingFuel,
726 recommendedLandingFuel =
727 recommendedLandingFuel)
[95]728
[9]729 self.gearSpeedLimit = 270
730 self.flapSpeedLimits = { 1 : 260,
731 2 : 260,
732 5 : 250,
733 10 : 210,
734 15 : 200,
735 25 : 190,
736 30 : 175,
737 40 : 162 }
[7]738
[384]739 @property
[512]740 def derateType(self):
741 """Get the derate type for this type."""
742 return DERATE_BOEING
[384]743
[7]744#---------------------------------------------------------------------------------------
745
746class B736(Boeing737):
747 """Boeing 737-600 aircraft."""
[861]748 dow = 38307
749
[8]750 def __init__(self, flight):
751 super(B736, self).__init__(flight)
[9]752 self.mtow = 58328
753 self.mlw = 54657
754 self.mzfw = 51482
[611]755 self.maxTakeOffPitch = 16.2
756 self.maxTouchDownPitch = 14.7
[709]757 self.simBriefData = SimBriefData(["250/280/78"],
758 ["CI", "M75", "M78", "M79", "M80", "LRC"],
[1087]759 ["78/280/250"],
760 cruiseParameters = {0: (False, "civalue")})
[7]761
762#---------------------------------------------------------------------------------------
763
764class B737(Boeing737):
765 """Boeing 737-700 aircraft."""
[861]766 dow = 39250
767
[8]768 def __init__(self, flight):
769 super(B737, self).__init__(flight)
[9]770 self.mtow = 61410
771 self.mlw = 58059
772 self.mzfw = 54657
[611]773 self.maxTakeOffPitch = 14.7
774 self.maxTouchDownPitch = 13.2
[709]775 self.simBriefData = SimBriefData(["250/280/78"],
776 ["CI", "M75", "M78", "M79", "M80", "LRC"],
[1087]777 ["78/280/250", "78/250/250"],
778 cruiseParameters = {0: (False, "civalue")})
[7]779
780#---------------------------------------------------------------------------------------
781
782class B738(Boeing737):
783 """Boeing 737-800 aircraft."""
[861]784 dow = 42690
785
[8]786 def __init__(self, flight):
787 super(B738, self).__init__(flight)
[797]788 self.mtow = 71791
[9]789 self.mlw = 65317
790 self.mzfw = 61688
[611]791 self.maxTakeOffPitch = 11
792 self.maxTouchDownPitch = 9.5
[709]793 self.simBriefData = SimBriefData(["250/280/78"],
794 ["CI", "M76", "M78", "M79", "M80", "LRC"],
[1185]795 ["78/280/250"],
[1087]796 cruiseParameters = {0: (False, "civalue")})
[9]797
798#---------------------------------------------------------------------------------------
799
800class B738Charter(B738):
801 """Boeing 737-800 aircraft used for charters."""
802 def __init__(self, flight):
803 super(B738Charter, self).__init__(flight)
804 self.mtow = 77791
[7]805
806#---------------------------------------------------------------------------------------
807
[591]808class Boeing737CL(Boeing737):
809 """Base class for the various aircraft in the Boeing 737 Classic family."""
810 def __init__(self, flight):
[592]811 super(Boeing737CL, self).__init__(flight, minLandingFuel = 3500,
812 recommendedLandingFuel = None)
[591]813
814#---------------------------------------------------------------------------------------
815
[790]816class B732(Boeing737CL):
817 """Boeing 737-200 aircraft."""
[861]818 dow = 27646
819
[790]820 def __init__(self, flight):
821 super(B732, self).__init__(flight)
[796]822 self.mtow = 52390
823 self.mlw = 46720
824 self.mzfw = 43091
825 self.maxTakeOffPitch = 15.5
826 self.maxTouchDownPitch = 15.5
[1116]827 self.simBriefData = SimBriefData(["250/280/70"],
828 ["LRC", "M72", "M73", "M74"],
829 ["74/320/250"])
[790]830
831#---------------------------------------------------------------------------------------
832
[591]833class B733(Boeing737CL):
[7]834 """Boeing 737-300 aircraft."""
[861]835 dow = 32900
836
[8]837 def __init__(self, flight):
838 super(B733, self).__init__(flight)
[797]839 self.mtow = 56472
840 self.mlw = 51710
841 self.mzfw = 47625
[611]842 self.maxTakeOffPitch = 13.4
843 self.maxTouchDownPitch = 12.0
[1116]844 self.simBriefData = SimBriefData(["250/280/74"],
845 ["CI", "M74", "M76", "M78", "LRC"],
846 ["74/280/250"],
847 cruiseParameters = {0: (False, "civalue")})
[7]848
849#---------------------------------------------------------------------------------------
850
[591]851class B734(Boeing737CL):
[7]852 """Boeing 737-400 aircraft."""
[8]853 def __init__(self, flight):
854 super(B734, self).__init__(flight)
[797]855 self.dow = 35100
856 self.mtow = 62822
857 self.mlw = 54885
858 self.mzfw = 51256
[611]859 self.maxTakeOffPitch = 11.4
860 self.maxTouchDownPitch = 10
[1116]861 self.simBriefData = SimBriefData(["250/280/74"],
862 ["CI", "M74", "M76", "M78", "LRC"],
863 ["74/280/250"],
864 cruiseParameters = {0: (False, "civalue")})
[7]865
866#---------------------------------------------------------------------------------------
867
[591]868class B735(Boeing737CL):
[7]869 """Boeing 737-500 aircraft."""
[861]870 dow = 31900
871
[8]872 def __init__(self, flight):
873 super(B735, self).__init__(flight)
[797]874 self.mtow = 62823
875 self.mlw = 49895
876 self.mzfw = 46720
[611]877 self.maxTakeOffPitch = 14.7
878 self.maxTouchDownPitch = 13.2
[1116]879 self.simBriefData = SimBriefData(["250/280/74"],
880 ["CI", "M74", "M76", "M78", "LRC"],
881 ["74/280/250"],
882 cruiseParameters = {0: (False, "civalue")})
[7]883
884#---------------------------------------------------------------------------------------
885
886class DH8D(Aircraft):
887 """Bombardier Dash-8 Q400 aircraft.
888
889 The aircraft type-specific values in the aircraft state have the following
890 structure:
[140]891 - fuel: left, right
[7]892 - n1: left, right
893 - reverser: left, right."""
[861]894 dow = 18508
[140]895
[8]896 def __init__(self, flight):
[591]897 super(DH8D, self).__init__(flight, minLandingFuel = 2000)
[797]898 self.mtow = 29574
899 self.mlw = 28123
900 self.mzfw = 26308
[9]901 self.gearSpeedLimit = 215
902 self.flapSpeedLimits = { 5 : 200,
903 10 : 181,
904 15 : 172,
905 35 : 158 }
[611]906 self.maxTakeOffPitch = 8.0
907 self.maxTouchDownPitch = 7.0
[709]908 self.simBriefData = SimBriefData(["I-900", "II-900", "III-900",
909 "I-850", "II-850", "III-850"],
910 ["MCR", "ISC", "LRC", "HSC"],
911 ["I-850", "II-850", "III-850"])
[9]912
[7]913#---------------------------------------------------------------------------------------
914
915class Boeing767(Aircraft):
916 """Base class for the various aircraft in the Boeing 767 family.
917
918 The aircraft type-specific values in the aircraft state have the following
919 structure:
[140]920 - fuel: left, centre, right
[7]921 - n1: left, right
922 - reverser: left, right"""
[140]923
[612]924 def __init__(self, flight, minLandingFuel = 7000):
[591]925 super(Boeing767, self).__init__(flight, minLandingFuel = minLandingFuel)
[9]926 self.gearSpeedLimit = 270
927 self.flapSpeedLimits = { 1 : 255,
928 5 : 235,
929 10 : 215,
930 20 : 215,
931 25 : 185,
932 30 : 175 }
[7]933
[384]934 @property
[512]935 def derateType(self):
936 """Get the derate type for this type."""
937 return DERATE_BOEING
[384]938
[7]939#---------------------------------------------------------------------------------------
940
941class B762(Boeing767):
942 """Boeing 767-200 aircraft."""
[861]943 dow = 84507
944
[8]945 def __init__(self, flight):
946 super(B762, self).__init__(flight)
[797]947 self.mtow = 159210
[9]948 self.mlw = 126098
949 self.mzfw = 114758
[611]950 self.maxTakeOffPitch = 13.1
951 self.maxTouchDownPitch = 11.6
[1116]952 self.simBriefData = SimBriefData(["250/290/78"],
953 ["CI", "M76", "M78", "M80", "M82",
954 "M84", "M85", "LRC"],
955 ["78/290/250"],
956 cruiseParameters = {0: (False, "civalue")})
[7]957
958#---------------------------------------------------------------------------------------
959
960class B763(Boeing767):
961 """Boeing 767-300 aircraft."""
[861]962 dow = 91311
963
[8]964 def __init__(self, flight):
[331]965 super(B763, self).__init__(flight)
[9]966 self.mtow = 181436
967 self.mlw = 137892
[797]968 self.mzfw = 114758
[611]969 self.maxTakeOffPitch = 9.6
970 self.maxTouchDownPitch = 8.1
[709]971 self.simBriefData = SimBriefData(["250/290/78"],
972 ["CI", "M76", "M78", "M80", "M82", "M84", "LRC"],
[1116]973 ["78/290/250"],
974 cruiseParameters = {0: (False, "civalue")})
[7]975
[799]976 def setBookedFlight(self, bookedFlight):
977 """Update the aircraft based on the booked flight data (e.g. tail number)."""
978 if bookedFlight.tailNumber=="HA-LHD":
979 self.mtow = 159210
980 self.mlw = 126098
981
[7]982#---------------------------------------------------------------------------------------
983
984class CRJ2(Aircraft):
985 """Bombardier CRJ-200 aircraft.
986
987 The aircraft type-specific values in the aircraft state have the following
988 structure:
[140]989 - fuel: left, centre, right
[7]990 - n1: left, right
991 - reverser: left, right."""
[861]992 dow = 14549
993
[8]994 def __init__(self, flight):
[591]995 super(CRJ2, self).__init__(flight, minLandingFuel = 1000)
[9]996 self.mtow = 22995
997 self.mlw = 21319
998 self.mzfw = 19958
999 self.gearSpeedLimit = 240
1000 self.flapSpeedLimits = { 8 : 260,
1001 20 : 220,
1002 30 : 190,
1003 45 : 175 }
[611]1004 self.maxTakeOffPitch = 18.0
1005 self.maxTouchDownPitch = 18.0
[709]1006 self.simBriefData = SimBriefData(["250/70", "290/74"],
1007 ["CI", "LRC", "M70", "M72", "M74", "M77", "M80"],
[1116]1008 ["74/290/250", "77/320/250"],
1009 cruiseParameters = {0: (False, "civalue")})
[7]1010
1011#---------------------------------------------------------------------------------------
1012
1013class F70(Aircraft):
1014 """Fokker 70 aircraft.
1015
1016 The aircraft type-specific values in the aircraft state have the following
1017 structure:
[140]1018 - fuel: left, centre, right
[7]1019 - n1: left, right
1020 - reverser: left, right."""
[861]1021 dow = 24283
1022
[8]1023 def __init__(self, flight):
[591]1024 super(F70, self).__init__(flight, minLandingFuel = 1900)
[9]1025 self.mtow = 38100 # FIXME: differentiate by registration number,
1026 # MTOW of HA-LMF: 41955
1027 self.mlw = 36740
1028 self.mzfw = 32655
1029 self.gearSpeedLimit = 200
1030 self.flapSpeedLimits = { 8 : 250,
1031 15 : 220,
1032 25 : 220,
1033 42 : 180 }
[360]1034 self.reverseMinSpeed = 50
[611]1035 self.maxTakeOffPitch = 16.0
1036 self.maxTouchDownPitch = 16.0
[1116]1037 self.simBriefData = SimBriefData(["250/280/70"],
1038 ["M70", "LRC"],
1039 ["70/280/250"])
[7]1040
[384]1041 @property
[512]1042 def derateType(self):
1043 """Get the derate type for this type."""
1044 return DERATE_EPR
[384]1045
[7]1046#---------------------------------------------------------------------------------------
1047
1048class DC3(Aircraft):
1049 """Lisunov Li-2 (DC-3) aircraft.
1050
1051 The aircraft type-specific values in the aircraft state have the following
1052 structure:
[140]1053 - fuel: left aux, left, right, right aux
[7]1054 - rpm: left, right
1055 - reverser: left, right."""
[861]1056 dow = 8627
1057
[8]1058 def __init__(self, flight):
1059 super(DC3, self).__init__(flight)
[9]1060 self.mtow = 11884
1061 self.mlw = 11793
1062 self.mzfw = 11780
1063 self.gearSpeedLimit = 148
1064 self.flapSpeedLimits = { 15 : 135,
1065 30 : 99,
1066 45 : 97 }
[1185]1067 self.simBriefData = SimBriefData(["Normal"],
1068 ["600BHP", "400BHP", "700BHP"],
1069 ["500FPM"])
[8]1070
1071 def _checkFlightEnd(self, aircraftState):
1072 """Check if the end of the flight has arrived.
1073
1074 This implementation checks the RPM values to be 0."""
1075 for rpm in aircraftState.rpm:
[29]1076 if rpm>0: return False
1077 return True
[7]1078
1079#---------------------------------------------------------------------------------------
1080
1081class T134(Aircraft):
1082 """Tupolev Tu-134 aircraft.
1083
1084 The aircraft type-specific values in the aircraft state have the following
1085 structure:
[140]1086 - fuel: left tip, left aux, centre, right aux, right tip, external 1,
[7]1087 external 2
1088 - n1: left, right
1089 - reverser: left, right."""
[861]1090 dow = 29500
1091
[8]1092 def __init__(self, flight):
[591]1093 super(T134, self).__init__(flight, minLandingFuel = 3000)
[210]1094 self.mtow = 49000
[9]1095 self.mlw = 43000
1096 self.mzfw = 38500
1097 self.gearSpeedLimit = 216
[210]1098 self.flapSpeedLimits = { 10 : 450,
1099 20 : 400,
1100 30 : 300 }
[360]1101 self.reverseMinSpeed = 50
[7]1102
[644]1103 self.hasStrobeLight = False
1104
[611]1105 self.maxTakeOffPitch = 16.0
1106 self.maxTouchDownPitch = 16.0
[1185]1107 self.simBriefData = SimBriefData(["250/270/70"],
1108 ["MRC"],
1109 ["82/320/250"])
[611]1110
[241]1111 @property
[512]1112 def derateType(self):
1113 """Get the derate type for this type."""
1114 return DERATE_TUPOLEV
[384]1115
1116 @property
[241]1117 def speedInKnots(self):
1118 """Indicate if the speed is in knots."""
1119 return False
[331]1120
[635]1121 @property
1122 def aglInFeet(self):
1123 """Indicate if AGL altituedes are in feet."""
1124 return False
1125
[211]1126 def _appendLightsLoggers(self):
1127 """Append the loggers needed for the lights."""
1128 self._checkers.append(checks.AnticollisionLightsLogger())
1129 self._checkers.append(checks.LandingLightsLogger())
1130 self._checkers.append(checks.NavLightsLogger())
1131
1132 def _appendLightsCheckers(self):
1133 """Append the checkers needed for the lights."""
1134 self._checkers.append(checks.TupolevAntiCollisionLightsChecker())
[631]1135 self._checkers.append(checks.TupolevLandingLightsChecker())
[211]1136 self._checkers.append(checks.LandingLightsChecker())
1137 self._checkers.append(checks.NavLightsChecker())
1138
[7]1139#---------------------------------------------------------------------------------------
1140
1141class T154(Aircraft):
1142 """Tupolev Tu-154 aircraft.
1143
1144 The aircraft type-specific values in the aircraft state have the following
1145 structure:
[140]1146 - fuel: left aux, left, centre, centre 2, right, right aux
[7]1147 - n1: left, centre, right
1148 - reverser: left, right"""
[888]1149 dow = 53259
[861]1150
[8]1151 def __init__(self, flight):
[591]1152 super(T154, self).__init__(flight, minLandingFuel = 5000)
[9]1153 self.mtow = 98000
1154 self.mlw = 78000
1155 self.mzfw = 72000
1156 self.gearSpeedLimit = 216
1157 self.flapSpeedLimits = { 15 : 227,
1158 28 : 194,
1159 45 : 162 }
[360]1160 self.reverseMinSpeed = 50
[9]1161
[644]1162 self.hasStrobeLight = False
1163
[611]1164 self.maxTakeOffPitch = 16.0
1165 self.maxTouchDownPitch = 16.0
[709]1166 self.simBriefData = SimBriefData(["AUTO"],
[1116]1167 ["AUTO"],
[709]1168 ["AUTO"])
[611]1169
[241]1170 @property
1171 def speedInKnots(self):
1172 """Indicate if the speed is in knots."""
1173 return False
[331]1174
[384]1175 @property
[635]1176 def aglInFeet(self):
1177 """Indicate if AGL altituedes are in feet."""
1178 return False
1179
1180 @property
[512]1181 def derateType(self):
1182 """Get the derate type for this type."""
1183 return DERATE_TUPOLEV
[384]1184
[1166]1185 @property
1186 def machSpeedAbove(self):
1187 """Get the altitude above which the cruise speed should be reported
1188 in Machs."""
1189 return 32000
1190
[799]1191 def setBookedFlight(self, bookedFlight):
1192 """Update the aircraft based on the booked flight data (e.g. tail number)."""
1193 if bookedFlight.tailNumber in ["HA-LCM", "HA-LCN", "HA-LCO", "HA-LCP",
1194 "HA-LCR", "HA-LCU", "HA-LCV"]:
1195 self.mtow = 100000
1196 self.mlw = 80000
[904]1197 elif bookedFlight.tailNumber=="HA-LCX":
1198 self.mtow = 100000
1199 self.mlw = 80000
1200 self.mzfw = 74000
1201
1202 self.flapSpeedLimits = { 15 : 227,
1203 28 : 194,
[905]1204 36 : 178,
[904]1205 45 : 162 }
[799]1206
[211]1207 def _appendLightsLoggers(self):
1208 """Append the loggers needed for the lights."""
1209 self._checkers.append(checks.AnticollisionLightsLogger())
1210 self._checkers.append(checks.LandingLightsLogger())
1211 self._checkers.append(checks.NavLightsLogger())
1212
1213 def _appendLightsCheckers(self):
1214 """Append the checkers needed for the lights."""
1215 self._checkers.append(checks.AntiCollisionLightsChecker())
[631]1216 self._checkers.append(checks.TupolevLandingLightsChecker())
[211]1217 self._checkers.append(checks.LandingLightsChecker())
1218 self._checkers.append(checks.NavLightsChecker())
1219
[539]1220#---------------------------------------------------------------------------------------
1221
1222class YK40(Aircraft):
1223 """Yakovlev Yak-40 aircraft.
1224
1225 The aircraft type-specific values in the aircraft state have the following
1226 structure:
1227 - fuel: left, right
1228 - n1: left, right
1229 - reverser: left, right"""
[861]1230 dow = 9400
1231
[539]1232 def __init__(self, flight):
1233 super(YK40, self).__init__(flight)
1234 self.mtow = 17200
1235 self.mlw = 16800
1236 self.mzfw = 12100
1237 self.gearSpeedLimit = 165
1238 self.flapSpeedLimits = { 20 : 165,
1239 35 : 135 }
1240
[644]1241 self.hasStrobeLight = False
[1185]1242 self.simBriefData = SimBriefData(["250/280/70"],
1243 ["M70", "LRC"],
1244 ["70/280/250"])
[644]1245
[539]1246 @property
1247 def speedInKnots(self):
1248 """Indicate if the speed is in knots."""
1249 return False
1250
1251 @property
[635]1252 def aglInFeet(self):
1253 """Indicate if AGL altituedes are in feet."""
1254 return False
1255
1256 @property
[539]1257 def derateType(self):
1258 """Get the derate type for this type."""
1259 return DERATE_TUPOLEV
1260
1261 def _appendLightsLoggers(self):
1262 """Append the loggers needed for the lights."""
1263 self._checkers.append(checks.AnticollisionLightsLogger())
1264 self._checkers.append(checks.LandingLightsLogger())
1265 self._checkers.append(checks.NavLightsLogger())
1266
1267 def _appendLightsCheckers(self):
1268 """Append the checkers needed for the lights."""
1269 self._checkers.append(checks.AntiCollisionLightsChecker())
1270 self._checkers.append(checks.LandingLightsChecker())
1271 self._checkers.append(checks.NavLightsChecker())
[403]1272
[7]1273#---------------------------------------------------------------------------------------
1274
[443]1275class B462(Aircraft):
1276 """British Aerospace BAe-146 aircraft.
1277
1278 The aircraft type-specific values in the aircraft state have the following
1279 structure:
1280 - fuel: left, centre, right
1281 - n1: left outer, left inner, right inner, right outer
1282 - reverser: empty (the plane has no reversers)"""
[861]1283 dow = 25706
1284
[443]1285 def __init__(self, flight):
1286 super(B462, self).__init__(flight)
1287 self.mtow = 43998
1288 self.mlw = 38599
1289 self.mzfw = 33792
1290 self.gearSpeedLimit = 210
1291 self.flapSpeedLimits = { 18 : 217,
1292 24 : 180,
1293 30 : 170,
1294 33 : 150 }
[1116]1295 self.simBriefData = SimBriefData(["HighSpeed", "LongRange"],
1296 ["M70", "MCR", "LRC"],
1297 ["HighSpeed", "LongRange"])
[445]1298 @property
[512]1299 def derateType(self):
1300 """Get the derate type for this type."""
1301 return DERATE_B462
[445]1302
[443]1303#---------------------------------------------------------------------------------------
1304
[274]1305mostFuelTanks = [const.FUELTANK_LEFT_TIP, const.FUELTANK_EXTERNAL1,
1306 const.FUELTANK_LEFT_AUX,
1307 const.FUELTANK_CENTRE,
1308 const.FUELTANK_RIGHT_AUX,
1309 const.FUELTANK_EXTERNAL2, const.FUELTANK_RIGHT_TIP]
[141]1310
1311#---------------------------------------------------------------------------------------
1312
[191]1313_classes = { const.AIRCRAFT_B736 : B736,
1314 const.AIRCRAFT_B737 : B737,
1315 const.AIRCRAFT_B738 : B738,
1316 const.AIRCRAFT_B738C : B738Charter,
[790]1317 const.AIRCRAFT_B732 : B732,
[191]1318 const.AIRCRAFT_B733 : B733,
1319 const.AIRCRAFT_B734 : B734,
1320 const.AIRCRAFT_B735 : B735,
1321 const.AIRCRAFT_DH8D : DH8D,
1322 const.AIRCRAFT_B762 : B762,
1323 const.AIRCRAFT_B763 : B763,
1324 const.AIRCRAFT_CRJ2 : CRJ2,
1325 const.AIRCRAFT_F70 : F70,
1326 const.AIRCRAFT_DC3 : DC3,
1327 const.AIRCRAFT_T134 : T134,
1328 const.AIRCRAFT_T154 : T154,
[443]1329 const.AIRCRAFT_YK40 : YK40,
1330 const.AIRCRAFT_B462 : B462 }
[8]1331
1332#---------------------------------------------------------------------------------------
[197]1333
[862]1334def getClass(aircraftType):
1335 """Get the class representing the given aircraft types"""
1336 return _classes[aircraftType]
1337
1338#---------------------------------------------------------------------------------------
1339
[197]1340if __name__ == "__main__":
1341 value = SmoothedValue()
1342
[919]1343 print("Adding 1, 12.0")
[197]1344 value.add(1, 12.0)
[919]1345 print(value.get())
[197]1346
[919]1347 print("Adding 1, 15.0")
[197]1348 value.add(1, 15.0)
[919]1349 print(value.get())
[197]1350
[919]1351 print("Adding 2, 18.0")
[197]1352 value.add(2, 18.0)
[919]1353 print(value.get())
[197]1354
[919]1355 print("Adding 2, 20.0")
[197]1356 value.add(2, 20.0)
[919]1357 print(value.get())
[197]1358
[919]1359 print("Adding 5, 22.0")
[197]1360 value.add(5, 22.0)
[919]1361 print(value.get())
[197]1362
[919]1363 print("Adding 5, 25.0")
[197]1364 value.add(5, 25.0)
[919]1365 print(value.get())
[197]1366
[919]1367 print("Adding 5, 29.0")
[197]1368 value.add(5, 29.0)
[919]1369 print(value.get())
[197]1370
[919]1371 print("Adding 5, 21.0")
[197]1372 value.add(5, 21.0)
[919]1373 print(value.get())
[197]1374
[919]1375 print("Adding 5, 26.0")
[197]1376 value.add(5, 26.0)
[919]1377 print(value.get())
[197]1378
[919]1379 print("Adding 2, 30.0")
[197]1380 value.add(2, 30.0)
[919]1381 print(value.get())
[197]1382
[919]1383 print("Adding 2, 55.0")
[197]1384 value.add(2, 55.0)
[919]1385 print(value.get())
[197]1386
1387#---------------------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.