source: src/mlx/acft.py@ 1137:87a29e5e4b2d

python3
Last change on this file since 1137:87a29e5e4b2d was 1137:87a29e5e4b2d, checked in by István Váradi <ivaradi@…>, 8 weeks ago

The G-load is measured during flare and the value at touchdown is logged (re #385)

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