source: src/mlx/acft.py@ 512:46bd71540346

Last change on this file since 512:46bd71540346 was 512:46bd71540346, checked in by István Váradi <ivaradi@…>, 11 years ago

Implemented the new derate handling method (re #202)

File size: 40.6 KB
Line 
1
2import const
3import checks
4import fs
5from i18n import xstr
6import util
7
8import sys
9import time
10import traceback
11
12from collections import deque
13
14#---------------------------------------------------------------------------------------
15
16## @package mlx.acft
17#
18# The simulator-independent aircraft classes.
19#
20# This module contains the aircraft classes that contain some general data
21# about each aircraft type in the MAVA Fleet. The base class, \ref Aircraft
22# also implements some parts of the logging and traces some data. The classes
23# are also responsible for creating the \ref mlx.checks "checkers". Most of
24# them are created by the \ref Aircraft class' constructor, but there can be
25# type-specific differences. For example the lights are different for different
26# types, so there is a \ref Aircraft._appendLightsLoggers "function" which can
27# be reimplemented in child classes, if needed. This class maintains also the
28# \ref SmoothedValue "smoothed values" of the IAS and the VS and set these
29# values in the \ref mlx.fs.AircraftState "aircraft state" when it is received
30# from the simulator.
31
32#---------------------------------------------------------------------------------------
33
34# Derate type: no derate possible
35DERATE_NONE = 0
36
37# Derate type: Boeing, i.e. a percentage value.
38# For logging, the percentage value is expected as a string (i.e. whatever the
39# pilot enters into the text field).
40DERATE_BOEING = 1
41
42# Derate type: EPR, i.e. an EPR value.
43# For logging, the EPR value is expected as a string (i.e. whatever the pilot
44# enters into the text field).
45DERATE_EPR = 2
46
47# Derate type: Tupolev, i.e. nominal or takeoff
48# For logging, one of the DERATE_TUPOLEV_xxx values are expected.
49DERATE_TUPOLEV = 3
50
51# Tupolev derate value: nominal
52DERATE_TUPOLEV_NOMINAL = 1
53
54# Tupolev derate value: takeoff
55DERATE_TUPOLEV_TAKEOFF = 2
56
57# Derate type: BAe-146, i.e. enabled or not
58# For logging, a boolean is expected.
59DERATE_B462 = 4
60
61#---------------------------------------------------------------------------------------
62
63class SmoothedValue(object):
64 """A smoothed value."""
65 def __init__(self):
66 """Construct the value."""
67 self._deque = deque()
68 self._sum = 0
69
70 def add(self, length, value):
71 """Add the given value and smooth with the given length."""
72 dequeLength = len(self._deque)
73 while dequeLength>=length:
74 self._sum -= self._deque.popleft()
75 dequeLength -= 1
76
77 self._sum += value
78 self._deque.append(value)
79
80 def get(self):
81 """Get the average."""
82 return self._sum / len(self._deque)
83
84#---------------------------------------------------------------------------------------
85
86class Aircraft(object):
87 """Base class for aircraft."""
88 @staticmethod
89 def create(flight):
90 """Create an aircraft instance for the type in the given flight."""
91 return _classes[flight.aircraftType](flight)
92
93 def __init__(self, flight):
94 """Construct the aircraft for the given type."""
95 self._flight = flight
96
97 self._name = None
98 self._modelName = None
99
100 self._aircraftState = None
101
102 self._maxVS = -10000.0
103 self._minVS = 10000.0
104
105 self._v1r2LineIndex = None
106 self._derateLineID = None
107 self._takeoffAntiIceLineID = None
108 self._vrefLineIndex = None
109 self._landingAntiIceLineID = None
110
111 self.humanWeight = 82.0
112
113 self.reverseMinSpeed = 60
114
115 self._checkers = []
116
117 config = flight.config
118 # Loggers
119
120 self._checkers.append(checks.StageChecker())
121 self._checkers.append(checks.TakeOffLogger())
122
123 self._checkers.append(checks.AltimeterLogger())
124
125 self._ilsLogger = checks.ILSLogger()
126 self._checkers.append(self._ilsLogger)
127 self._nav1Logger = checks.NAV1Logger()
128 self._checkers.append(self._nav1Logger)
129 self._nav2Logger = checks.NAV2Logger()
130 self._checkers.append(self._nav2Logger)
131
132 self._adf1Logger = checks.ADF1Logger()
133 self._checkers.append(self._adf1Logger)
134 self._adf2Logger = checks.ADF2Logger()
135 self._checkers.append(self._adf2Logger)
136
137 self._checkers.append(checks.SquawkLogger())
138
139 self._appendLightsLoggers()
140
141 self._checkers.append(checks.FlapsLogger())
142
143 self._checkers.append(checks.GearsLogger())
144 self._checkers.append(checks.CruiseSpeedLogger())
145 self._checkers.append(checks.SpoilerLogger())
146 self._checkers.append(checks.APLogger())
147
148 if config.isMessageTypeFS(const.MESSAGETYPE_VISIBILITY):
149 self._checkers.append(checks.VisibilityChecker())
150
151 # FIXME: we should have a central data model object, and not collect
152 # the data from the GUI. However, some pieces of data (e.g. V-speeds,
153 # etc. that is entered into the GUI) *should* be a part of the GUI and
154 # queried from it, so the model should have a reference to the GUI as
155 # well and access such data via the GUI!
156 if config.onlineACARS and flight.loggedIn and not flight.entranceExam:
157 self._checkers.append(checks.ACARSSender(flight._gui))
158
159 # Fault checkers
160
161 self._appendLightsCheckers()
162
163 self._checkers.append(checks.TransponderChecker())
164
165 self._checkers.append(checks.BankChecker())
166
167 self._checkers.append(checks.FlapsRetractChecker())
168 self._checkers.append(checks.FlapsSpeedLimitChecker())
169
170 self._checkers.append(checks.GearsDownChecker())
171 self._checkers.append(checks.GearSpeedLimitChecker())
172
173 self._checkers.append(checks.GLoadChecker())
174
175 self._checkers.append(checks.MLWChecker())
176 self._checkers.append(checks.MTOWChecker())
177 self._checkers.append(checks.MZFWChecker())
178 self._checkers.append(checks.PayloadChecker())
179
180 self._appendSpeedChecker()
181 self._checkers.append(checks.VSChecker())
182
183 timeout = 30.0 + config.realIASSmoothingLength - 1
184 self._checkers.append(checks.OverspeedChecker(timeout = timeout))
185
186 self._checkers.append(checks.StallChecker())
187
188 self._checkers.append(checks.PitotChecker())
189
190 self._checkers.append(checks.ReverserChecker())
191
192 if flight.aircraftType is not None and config.enableApproachCallouts:
193 approachCallouts = flight.config.getApproachCallouts(flight.aircraftType)
194 if approachCallouts:
195 self._checkers.append(checks.ApproachCalloutsPlayer(approachCallouts))
196
197 self._smoothedIAS = SmoothedValue()
198 self._smoothedVS = SmoothedValue()
199
200 @property
201 def type(self):
202 """Get the type of the aircraft."""
203 return self._flight.aircraftType
204
205 @property
206 def flight(self):
207 """Get the flight the aircraft belongs to."""
208 return self._flight
209
210 @property
211 def logger(self):
212 """Get the logger to use for the aircraft."""
213 return self._flight.logger
214
215 @property
216 def state(self):
217 """Get the current aircraft state."""
218 return self._aircraftState
219
220 @property
221 def speedInKnots(self):
222 """Indicate if the speed is in knots.
223
224 This default implementation returns True."""
225 return True
226
227 @property
228 def timestamp(self):
229 """Get the timestamp of the current state."""
230 return None if self._aircraftState is None \
231 else self._aircraftState.timestamp
232
233 @property
234 def derateType(self):
235 """Get the derate type for this aircraft.
236
237 This default implementation returns DERATE_NONE."""
238 return DERATE_NONE
239
240 def getDerateLine(self, value):
241 """Get the log line for the given derate value.
242
243 It uses the the derate type and produces the standard message for
244 each. This children need not override it, although they can."""
245 dt = self.derateType
246
247 if dt==DERATE_BOEING:
248 return "Derate calculated by the pilot: %s %%" % \
249 ("-" if value is None else value,)
250 elif dt==DERATE_EPR:
251 return "EPR calculated by the pilot: %s" % \
252 ("-" if value is None else value,)
253 elif dt==DERATE_TUPOLEV:
254 return "Thrust setting calculated by the pilot: %s" % \
255 ("-" if value is None else
256 "nominal" if value==DERATE_TUPOLEV_NOMINAL else "takeoff",)
257 elif dt==DERATE_B462:
258 return "Derate setting: %s" % \
259 ("-" if value is None else "enabled" if value else "disabled",)
260 elif dt!=DERATE_NONE:
261 print "mlx.acft.getDerateLine: invalid derate type: " + dt
262
263 return None
264
265 def getFlapsSpeedLimit(self, flaps):
266 """Get the speed limit for the given flaps setting."""
267 return self.flapSpeedLimits[flaps] if flaps in self.flapSpeedLimits \
268 else None
269
270 def modelChanged(self, timestamp, aircraftName, modelName):
271 """Called when the simulator's aircraft changes."""
272 self._name = aircraftName
273 self._modelName = modelName
274 if self._flight.stage is not None:
275 self._logNameAndModel(timestamp)
276
277 def handleState(self, aircraftState):
278 """Called when the state of the aircraft changes.
279
280 This is the function that the simulator calls directly with the new
281 state."""
282 try:
283 config = self._flight.config
284
285 self._smoothedIAS.add(config.realIASSmoothingLength, aircraftState.ias)
286 aircraftState.smoothedIAS = self._smoothedIAS.get()
287
288 self._smoothedVS.add(config.realVSSmoothingLength, aircraftState.vs)
289 aircraftState.smoothedVS = self._smoothedVS.get()
290
291 for checker in self._checkers:
292 try:
293 checker.check(self._flight, self, self._flight.logger,
294 self._aircraftState, aircraftState)
295 except:
296 print >> sys.stderr, "Checker", checker, "failed"
297 traceback.print_exc()
298
299 self._flight.handleState(self._aircraftState, aircraftState)
300
301 self._maxVS = max(self._maxVS, aircraftState.vs)
302 self._minVS = min(self._minVS, aircraftState.vs)
303 except:
304 print >> sys.stderr, "Failed to handle the state"
305 traceback.print_exc()
306 finally:
307 self._aircraftState = aircraftState
308
309 def setStage(self, aircraftState, newStage):
310 """Set the given stage as the new one and do whatever should be
311 done."""
312 if newStage==const.STAGE_BOARDING:
313 self._logNameAndModel(aircraftState.timestamp)
314
315 if self._flight.setStage(aircraftState.timestamp, newStage):
316 if newStage==const.STAGE_PUSHANDTAXI:
317 self.logger.message(aircraftState.timestamp, "Block time start")
318 self._flight.logFuel(aircraftState)
319 self.logger.message(aircraftState.timestamp,
320 "ZFW: %.2f kg" % (aircraftState.zfw))
321 flight = self._flight
322 if flight.v1 is None or flight.vr is None or flight.v2 is None:
323 fs.sendMessage(const.MESSAGETYPE_HELP,
324 "Don't forget to set the takeoff V-speeds!",
325 5)
326 elif newStage==const.STAGE_TAKEOFF:
327 self.logger.message(aircraftState.timestamp,
328 "Flight time start")
329 self.logger.message(aircraftState.timestamp,
330 "Takeoff weight: %.0f kg, MTOW: %.0f kg" % \
331 (aircraftState.grossWeight, self.mtow))
332 self._logQNH(aircraftState)
333 self.logger.message(aircraftState.timestamp,
334 "Wind %03.0f/%.0f" % \
335 (aircraftState.windDirection,
336 aircraftState.windSpeed))
337 self._logRadios(aircraftState)
338 self._logV1R2(aircraftState)
339 self._logDerate(aircraftState)
340 self._logTakeoffAntiIce(aircraftState)
341 elif newStage==const.STAGE_DESCENT or newStage==const.STAGE_LANDING:
342 self._logRadios(aircraftState)
343 if newStage==const.STAGE_LANDING:
344 self._logQNH(aircraftState)
345 elif newStage==const.STAGE_TAXIAFTERLAND:
346 flight = self._flight
347 bookedFlight = flight.bookedFlight
348 config = flight.config
349 if config.onlineGateSystem and \
350 flight.loggedIn and \
351 not flight.entranceExam and \
352 bookedFlight.arrivalICAO=="LHBP" and \
353 config.isMessageTypeFS(const.MESSAGETYPE_GATE_SYSTEM):
354 self._flight.getFleet(callback = self._fleetRetrieved,
355 force = True)
356 self.logger.message(aircraftState.timestamp, "Flight time end")
357 self._flight.logFuel(aircraftState)
358 self.logger.message(aircraftState.timestamp,
359 "Landing weight: %.0f kg, MLW: %.0f" % \
360 (aircraftState.grossWeight, self.mlw))
361 self.logger.message(aircraftState.timestamp,
362 "Vertical speed range: %.0f..%.0f feet/min" % \
363 (self._minVS, self._maxVS))
364 # elif newStage==const.STAGE_PARKING:
365 # self.logger.message(aircraftState.timestamp, "Block time end")
366 elif newStage==const.STAGE_END:
367 flightLength = self._flight.flightTimeEnd - self._flight.flightTimeStart
368 self.logger.message(aircraftState.timestamp, "Block time end")
369 self.logger.message(aircraftState.timestamp,
370 "Flight time: " +
371 util.getTimeIntervalString(flightLength))
372 self.logger.message(aircraftState.timestamp,
373 "Flown distance: %.2f NM" % \
374 (self._flight.flownDistance,))
375 blockLength = self._flight.blockTimeEnd - self._flight.blockTimeStart
376 self.logger.message(aircraftState.timestamp,
377 "Block time: " +
378 util.getTimeIntervalString(blockLength))
379
380 def prepareFlare(self):
381 """Called when it is detected that we will soon flare.
382
383 On the first call, it should start monitoring some parameters more
384 closely to determine flare time."""
385 self.flight.simulator.startFlare()
386
387 def flareStarted(self, windSpeed, windDirection, visibility,
388 flareStart, flareStartFS):
389 """Called when the flare has started."""
390 self.logger.message(self._aircraftState.timestamp, "The flare has begun")
391 self.logger.message(self._aircraftState.timestamp,
392 "Wind %03.0f/%.0f" % \
393 (windDirection, windSpeed))
394 self.logger.message(self._aircraftState.timestamp,
395 "Visibility: %.0f metres" % (visibility,))
396 self._logQNH(self._aircraftState)
397 self._logVRef()
398 self._logLandingAntiIce(self._aircraftState)
399 self.flight.flareStarted(flareStart, flareStartFS)
400 fs.sendMessage(const.MESSAGETYPE_INFORMATION, "Flare-time", 3)
401
402 def flareFinished(self, flareEnd, flareEndFS, tdRate, tdRateCalculatedByFS,
403 ias, pitch, bank, heading):
404 """Called when the flare has finished."""
405 (flareTimeFromFS, flareTime) = self.flight.flareFinished(flareEnd,
406 flareEndFS,
407 tdRate)
408 self.logger.message(self._aircraftState.timestamp,
409 "Flaretime: %.3f (from %s)" % \
410 (flareTime,
411 "the simulator" if flareTimeFromFS else "real time",))
412 self.logger.message(self._aircraftState.timestamp,
413 "Touchdown rate: %.0f feet/min" % (tdRate,))
414 self.logger.message(self._aircraftState.timestamp,
415 "Touchdown rate was calculated by the %s" % \
416 ("simulator" if tdRateCalculatedByFS else "logger",))
417 flight = self._flight
418 self.logger.message(self._aircraftState.timestamp,
419 "Touchdown speed: %.0f %s" % \
420 (flight.speedFromKnots(ias),
421 flight.getEnglishSpeedUnit()))
422 self.logger.message(self._aircraftState.timestamp,
423 "Touchdown pitch: %.1f degrees" % (pitch,))
424 self.logger.message(self._aircraftState.timestamp,
425 "Touchdown bank: %.1f degrees" % (bank,))
426 self.logger.message(self._aircraftState.timestamp,
427 "Touchdown heading: %03.0f degrees" % (heading,))
428 self.logger.message(self._aircraftState.timestamp,
429 "CG: %.1f%%" % \
430 (self._aircraftState.cog*100.0,))
431
432 def cancelFlare(self):
433 """Cancel flare, if it has started."""
434 self.flight.simulator.cancelFlare()
435
436 def checkFlightEnd(self, aircraftState):
437 """Check if the end of the flight has arrived.
438
439 This default implementation checks the N1 values, but for
440 piston-powered aircraft you need to check the RPMs."""
441 for n1 in aircraftState.n1:
442 if n1>=0.5: return False
443 return True
444
445 def updateV1R2(self):
446 """Update the V1, Vr and V2 values from the flight, if the these values
447 have already been logged."""
448 if self._v1r2LineIndex is not None:
449 self._logV1R2()
450
451 def updateDerate(self):
452 """Update the derate value from the flight, if the these values
453 have already been logged."""
454 if self._derateLineID is not None:
455 self._logDerate()
456
457 def updateTakeoffAntiIce(self):
458 """Update the take-off anti-ice setting."""
459 if self._takeoffAntiIceLineID is not None:
460 self._logTakeoffAntiIce()
461
462 def _appendLightsLoggers(self):
463 """Append the loggers needed for the lights.
464
465 This default implementation adds the loggers for the anti-collision
466 lights, the landing lights, the strobe lights and the NAV lights."""
467 self._checkers.append(checks.AnticollisionLightsLogger())
468 self._checkers.append(checks.LandingLightsLogger())
469 self._checkers.append(checks.StrobeLightsLogger())
470 self._checkers.append(checks.NavLightsLogger())
471
472 def _appendLightsCheckers(self):
473 """Append the checkers needed for the lights.
474
475 This default implementation adds the checkers for the anti-collision
476 lights, the landing lights, the strobe lights and the NAV lights."""
477 self._checkers.append(checks.AntiCollisionLightsChecker())
478 self._checkers.append(checks.LandingLightsChecker())
479 self._checkers.append(checks.NavLightsChecker())
480 self._checkers.append(checks.StrobeLightsChecker())
481
482 def _appendSpeedChecker(self):
483 """Append the speed checker.
484
485 This default implementation used the SpeedChecker."""
486 self._checkers.append(checks.SpeedChecker())
487
488 def _speedToLog(self, speed):
489 """Convert the given speed (being either None or expressed in the
490 flight's speed unit into a string."""
491 if speed is None:
492 return "-"
493 else:
494 return str(speed) + " " + self._flight.getEnglishSpeedUnit()
495
496 def _logV1R2(self, state = None):
497 """Log the V1, Vr and V2 value either newly, or by updating the
498 corresponding line."""
499 message = "Speeds calculated by the pilot: V1: %s, VR: %s, V2: %s" % \
500 (self._speedToLog(self._flight.v1),
501 self._speedToLog(self._flight.vr),
502 self._speedToLog(self._flight.v2))
503
504 if self._v1r2LineIndex is None:
505 if state is None:
506 state = self._aircraftState
507 self._v1r2LineIndex = \
508 self.logger.message(state.timestamp, message)
509 else:
510 self.logger.updateLine(self._v1r2LineIndex, message)
511
512 def _logDerate(self, state = None):
513 """Log the derate values either newly or by updating the corresponding
514 line."""
515 dt = self.derateType
516 if dt==DERATE_NONE:
517 return
518
519 message = self.getDerateLine(self._flight.derate)
520 if message is not None:
521 if self._derateLineID is None:
522 if state is None:
523 state = self._aircraftState
524 self._derateLineID = \
525 self.logger.message(state.timestamp, message)
526 else:
527 self.logger.updateLine(self._derateLineID, message)
528
529 def _logTakeoffAntiIce(self, state = None):
530 """Log the take-off anti-ice setting either newly or by updating the
531 corresponding line."""
532 antiIceOn = self._flight.takeoffAntiIceOn
533 if state is not None:
534 antiIceOn = antiIceOn or state.antiIceOn is True
535 self._flight.takeoffAntiIceOn = antiIceOn
536
537 message = "Anti-ice was turned %s" % \
538 ("ON" if antiIceOn else "OFF")
539
540 if self._takeoffAntiIceLineID is None:
541 if state is None:
542 state = self._aircraftState
543 self._takeoffAntiIceLineID = \
544 self.logger.message(state.timestamp, message)
545 else:
546 self.logger.updateLine(self._takeoffAntiIceLineID, message)
547
548 def updateVRef(self):
549 """Update the Vref value from the flight, if the Vref value has already
550 been logged."""
551 if self._vrefLineIndex is not None:
552 self._logVRef()
553
554 def _logVRef(self):
555 """Log the Vref value either newly, or by updating the corresponding
556 line."""
557 message = "VRef speed calculated by the pilot: %s" % \
558 (self._speedToLog(self._flight.vref),)
559 if self._vrefLineIndex is None:
560 self._vrefLineIndex = \
561 self.logger.message(self._aircraftState.timestamp, message)
562 else:
563 self.logger.updateLine(self._vrefLineIndex, message)
564
565 def updateLandingAntiIce(self):
566 """Update the landing anti-ice setting."""
567 if self._landingAntiIceLineID is not None:
568 self._logLandingAntiIce()
569
570 def _logLandingAntiIce(self, state = None):
571 """Log the landing anti-ice setting either newly or by updating the
572 corresponding line."""
573 antiIceOn = self._flight.landingAntiIceOn
574 if state is not None:
575 antiIceOn = antiIceOn or state.antiIceOn is True
576 self._flight.landingAntiIceOn = antiIceOn
577
578 message = "Anti-ice was turned %s" % \
579 ("ON" if antiIceOn else "OFF")
580
581 if self._landingAntiIceLineID is None:
582 if state is None:
583 state = self._aircraftState
584 self._landingAntiIceLineID = \
585 self.logger.message(state.timestamp, message)
586 else:
587 self.logger.updateLine(self._landingAntiIceLineID, message)
588
589 def _fleetRetrieved(self, fleet):
590 """Callback for the fleet retrieval result."""
591 if fleet is not None:
592 gateList = ""
593 occupiedGateNumbers = fleet.getOccupiedGateNumbers()
594 for gateNumber in const.lhbpGateNumbers:
595 if gateNumber not in occupiedGateNumbers:
596 if gateList: gateList += ", "
597 gateList += gateNumber
598 fs.sendMessage(const.MESSAGETYPE_GATE_SYSTEM,
599 "Free gates: " + gateList, 20)
600
601
602 def _logRadios(self, aircraftState):
603 """Log the radios from the given aircraft state."""
604 flight = self._flight
605 logger = flight.logger
606
607 self._ilsLogger.forceLog(flight, logger, aircraftState)
608 self._nav1Logger.forceLog(flight, logger, aircraftState)
609 self._nav2Logger.forceLog(flight, logger, aircraftState)
610 self._adf1Logger.forceLog(flight, logger, aircraftState)
611 self._adf2Logger.forceLog(flight, logger, aircraftState)
612
613 def _logQNH(self, aircraftState):
614 """Log the current QNH along with the altimeter setting."""
615 self.logger.message(aircraftState.timestamp,
616 "QNH: %.2f hPa, altimeter: %.2f hPa" % \
617 (aircraftState.qnh, aircraftState.altimeter))
618
619 def _logNameAndModel(self, timestamp):
620 """Log the aircraft's name and model with taking the timestamp from the
621 given state."""
622 self._flight.logger.message(timestamp,
623 "Aircraft: name='%s', model='%s'" % \
624 (self._name, self._modelName))
625
626#---------------------------------------------------------------------------------------
627
628class Boeing737(Aircraft):
629 """Base class for the various aircraft in the Boeing 737 family.
630
631 The aircraft type-specific values in the aircraft state have the following
632 structure:
633 - fuel: left, centre, right
634 - n1: left, right
635 - reverser: left, right"""
636 def __init__(self, flight):
637 super(Boeing737, self).__init__(flight)
638
639 self.gearSpeedLimit = 270
640 self.flapSpeedLimits = { 1 : 260,
641 2 : 260,
642 5 : 250,
643 10 : 210,
644 15 : 200,
645 25 : 190,
646 30 : 175,
647 40 : 162 }
648
649 @property
650 def derateType(self):
651 """Get the derate type for this type."""
652 return DERATE_BOEING
653
654 # def _appendSpeedChecker(self):
655 # """Append the NoStrobeSpeedChecker to the checkers.
656
657 # FOR TESTING ONLY, THIS FUNCTION SHOULD NORMALLY BE COMMENTED OUT!!!"""
658 # self._checkers.append(checks.NoStrobeSpeedChecker())
659
660#---------------------------------------------------------------------------------------
661
662class B736(Boeing737):
663 """Boeing 737-600 aircraft."""
664 def __init__(self, flight):
665 super(B736, self).__init__(flight)
666 self.dow = 38307
667 self.mtow = 58328
668 self.mlw = 54657
669 self.mzfw = 51482
670
671#---------------------------------------------------------------------------------------
672
673class B737(Boeing737):
674 """Boeing 737-700 aircraft."""
675 def __init__(self, flight):
676 super(B737, self).__init__(flight)
677 self.dow = 39250
678 self.mtow = 61410
679 self.mlw = 58059
680 self.mzfw = 54657
681
682#---------------------------------------------------------------------------------------
683
684class B738(Boeing737):
685 """Boeing 737-800 aircraft."""
686 def __init__(self, flight):
687 super(B738, self).__init__(flight)
688 self.dow = 42690
689 self.mtow = 71709
690 self.mlw = 65317
691 self.mzfw = 61688
692
693#---------------------------------------------------------------------------------------
694
695class B738Charter(B738):
696 """Boeing 737-800 aircraft used for charters."""
697 def __init__(self, flight):
698 super(B738Charter, self).__init__(flight)
699 self.mtow = 77791
700
701#---------------------------------------------------------------------------------------
702
703class B733(Boeing737):
704 """Boeing 737-300 aircraft."""
705 def __init__(self, flight):
706 super(B733, self).__init__(flight)
707 self.dow = 32700
708 self.mtow = 62820
709 self.mlw = 51700
710 self.mzfw = 48410
711
712#---------------------------------------------------------------------------------------
713
714class B734(Boeing737):
715 """Boeing 737-400 aircraft."""
716 def __init__(self, flight):
717 super(B734, self).__init__(flight)
718 self.dow = 33200
719 self.mtow = 68050
720 self.mlw = 56200
721 self.mzfw = 53100
722
723#---------------------------------------------------------------------------------------
724
725class B735(Boeing737):
726 """Boeing 737-500 aircraft."""
727 def __init__(self, flight):
728 super(B735, self).__init__(flight)
729 self.dow = 31300
730 self.mtow = 60550
731 self.mlw = 50000
732 self.mzfw = 46700
733
734#---------------------------------------------------------------------------------------
735
736class DH8D(Aircraft):
737 """Bombardier Dash-8 Q400 aircraft.
738
739 The aircraft type-specific values in the aircraft state have the following
740 structure:
741 - fuel: left, right
742 - n1: left, right
743 - reverser: left, right."""
744
745 def __init__(self, flight):
746 super(DH8D, self).__init__(flight)
747 self.dow = 17185
748 self.mtow = 29257
749 self.mlw = 28009
750 self.mzfw = 25855
751 self.gearSpeedLimit = 215
752 self.flapSpeedLimits = { 5 : 200,
753 10 : 181,
754 15 : 172,
755 35 : 158 }
756
757#---------------------------------------------------------------------------------------
758
759class Boeing767(Aircraft):
760 """Base class for the various aircraft in the Boeing 767 family.
761
762 The aircraft type-specific values in the aircraft state have the following
763 structure:
764 - fuel: left, centre, right
765 - n1: left, right
766 - reverser: left, right"""
767
768 def __init__(self, flight):
769 super(Boeing767, self).__init__(flight)
770 self.gearSpeedLimit = 270
771 self.flapSpeedLimits = { 1 : 255,
772 5 : 235,
773 10 : 215,
774 20 : 215,
775 25 : 185,
776 30 : 175 }
777
778 @property
779 def derateType(self):
780 """Get the derate type for this type."""
781 return DERATE_BOEING
782
783#---------------------------------------------------------------------------------------
784
785class B762(Boeing767):
786 """Boeing 767-200 aircraft."""
787 def __init__(self, flight):
788 super(B762, self).__init__(flight)
789 self.dow = 84507
790 self.mtow = 175540
791 self.mlw = 126098
792 self.mzfw = 114758
793
794#---------------------------------------------------------------------------------------
795
796class B763(Boeing767):
797 """Boeing 767-300 aircraft."""
798 def __init__(self, flight):
799 super(B763, self).__init__(flight)
800 self.dow = 91311
801 self.mtow = 181436
802 self.mlw = 137892
803 self.mzfw = 130635
804
805#---------------------------------------------------------------------------------------
806
807class CRJ2(Aircraft):
808 """Bombardier CRJ-200 aircraft.
809
810 The aircraft type-specific values in the aircraft state have the following
811 structure:
812 - fuel: left, centre, right
813 - n1: left, right
814 - reverser: left, right."""
815 def __init__(self, flight):
816 super(CRJ2, self).__init__(flight)
817 self.dow = 14549
818 self.mtow = 22995
819 self.mlw = 21319
820 self.mzfw = 19958
821 self.gearSpeedLimit = 240
822 self.flapSpeedLimits = { 8 : 260,
823 20 : 220,
824 30 : 190,
825 45 : 175 }
826
827#---------------------------------------------------------------------------------------
828
829class F70(Aircraft):
830 """Fokker 70 aircraft.
831
832 The aircraft type-specific values in the aircraft state have the following
833 structure:
834 - fuel: left, centre, right
835 - n1: left, right
836 - reverser: left, right."""
837 def __init__(self, flight):
838 super(F70, self).__init__(flight)
839 self.dow = 24283
840 self.mtow = 38100 # FIXME: differentiate by registration number,
841 # MTOW of HA-LMF: 41955
842 self.mlw = 36740
843 self.mzfw = 32655
844 self.gearSpeedLimit = 200
845 self.flapSpeedLimits = { 8 : 250,
846 15 : 220,
847 25 : 220,
848 42 : 180 }
849 self.reverseMinSpeed = 50
850
851 @property
852 def derateType(self):
853 """Get the derate type for this type."""
854 return DERATE_EPR
855
856#---------------------------------------------------------------------------------------
857
858class DC3(Aircraft):
859 """Lisunov Li-2 (DC-3) aircraft.
860
861 The aircraft type-specific values in the aircraft state have the following
862 structure:
863 - fuel: left aux, left, right, right aux
864 - rpm: left, right
865 - reverser: left, right."""
866 def __init__(self, flight):
867 super(DC3, self).__init__(flight)
868 self.dow = 8627
869 self.mtow = 11884
870 self.mlw = 11793
871 self.mzfw = 11780
872 self.gearSpeedLimit = 148
873 self.flapSpeedLimits = { 15 : 135,
874 30 : 99,
875 45 : 97 }
876
877 def _checkFlightEnd(self, aircraftState):
878 """Check if the end of the flight has arrived.
879
880 This implementation checks the RPM values to be 0."""
881 for rpm in aircraftState.rpm:
882 if rpm>0: return False
883 return True
884
885#---------------------------------------------------------------------------------------
886
887class T134(Aircraft):
888 """Tupolev Tu-134 aircraft.
889
890 The aircraft type-specific values in the aircraft state have the following
891 structure:
892 - fuel: left tip, left aux, centre, right aux, right tip, external 1,
893 external 2
894 - n1: left, right
895 - reverser: left, right."""
896 def __init__(self, flight):
897 super(T134, self).__init__(flight)
898 self.dow = 29500
899 self.mtow = 49000
900 self.mlw = 43000
901 self.mzfw = 38500
902 self.gearSpeedLimit = 216
903 self.flapSpeedLimits = { 10 : 450,
904 20 : 400,
905 30 : 300 }
906 self.reverseMinSpeed = 50
907
908 @property
909 def derateType(self):
910 """Get the derate type for this type."""
911 return DERATE_TUPOLEV
912
913 @property
914 def speedInKnots(self):
915 """Indicate if the speed is in knots."""
916 return False
917
918 def _appendLightsLoggers(self):
919 """Append the loggers needed for the lights."""
920 self._checkers.append(checks.AnticollisionLightsLogger())
921 self._checkers.append(checks.LandingLightsLogger())
922 self._checkers.append(checks.NavLightsLogger())
923
924 def _appendLightsCheckers(self):
925 """Append the checkers needed for the lights."""
926 self._checkers.append(checks.TupolevAntiCollisionLightsChecker())
927 self._checkers.append(checks.LandingLightsChecker())
928 self._checkers.append(checks.NavLightsChecker())
929
930 def _appendSpeedChecker(self):
931 """Append the NoStrobeSpeedChecker to the checkers."""
932 self._checkers.append(checks.NoStrobeSpeedChecker())
933
934#---------------------------------------------------------------------------------------
935
936class T154(Aircraft):
937 """Tupolev Tu-154 aircraft.
938
939 The aircraft type-specific values in the aircraft state have the following
940 structure:
941 - fuel: left aux, left, centre, centre 2, right, right aux
942 - n1: left, centre, right
943 - reverser: left, right"""
944 def __init__(self, flight):
945 super(T154, self).__init__(flight)
946 self.dow = 53259
947 self.mtow = 98000
948 self.mlw = 78000
949 self.mzfw = 72000
950 self.gearSpeedLimit = 216
951 self.flapSpeedLimits = { 15 : 227,
952 28 : 194,
953 45 : 162 }
954 self.reverseMinSpeed = 50
955
956 @property
957 def speedInKnots(self):
958 """Indicate if the speed is in knots."""
959 return False
960
961 @property
962 def derateType(self):
963 """Get the derate type for this type."""
964 return DERATE_TUPOLEV
965
966 def _appendLightsLoggers(self):
967 """Append the loggers needed for the lights."""
968 self._checkers.append(checks.AnticollisionLightsLogger())
969 self._checkers.append(checks.LandingLightsLogger())
970 self._checkers.append(checks.NavLightsLogger())
971
972 def _appendLightsCheckers(self):
973 """Append the checkers needed for the lights."""
974 self._checkers.append(checks.AntiCollisionLightsChecker())
975 self._checkers.append(checks.LandingLightsChecker())
976 self._checkers.append(checks.NavLightsChecker())
977
978 def _appendSpeedChecker(self):
979 """Append the NoStrobeSpeedChecker to the checkers."""
980 self._checkers.append(checks.NoStrobeSpeedChecker())
981
982#---------------------------------------------------------------------------------------
983
984class YK40(Aircraft):
985 """Yakovlev Yak-40 aircraft.
986
987 The aircraft type-specific values in the aircraft state have the following
988 structure:
989 - fuel: left, right
990 - n1: left, right
991 - reverser: left, right"""
992 def __init__(self, flight):
993 super(YK40, self).__init__(flight)
994 self.dow = 9400
995 self.mtow = 17200
996 self.mlw = 16800
997 self.mzfw = 12100
998 self.gearSpeedLimit = 165
999 self.flapSpeedLimits = { 20 : 165,
1000 35 : 135 }
1001
1002 @property
1003 def speedInKnots(self):
1004 """Indicate if the speed is in knots."""
1005 return False
1006
1007 @property
1008 def derateType(self):
1009 """Get the derate type for this type."""
1010 return DERATE_TUPOLEV
1011
1012 def _appendLightsLoggers(self):
1013 """Append the loggers needed for the lights."""
1014 self._checkers.append(checks.AnticollisionLightsLogger())
1015 self._checkers.append(checks.LandingLightsLogger())
1016 self._checkers.append(checks.NavLightsLogger())
1017
1018 def _appendLightsCheckers(self):
1019 """Append the checkers needed for the lights."""
1020 self._checkers.append(checks.AntiCollisionLightsChecker())
1021 self._checkers.append(checks.LandingLightsChecker())
1022 self._checkers.append(checks.NavLightsChecker())
1023
1024 def _appendSpeedChecker(self):
1025 """Append the NoStrobeSpeedChecker to the checkers."""
1026 self._checkers.append(checks.NoStrobeSpeedChecker())
1027
1028#---------------------------------------------------------------------------------------
1029
1030class B462(Aircraft):
1031 """British Aerospace BAe-146 aircraft.
1032
1033 The aircraft type-specific values in the aircraft state have the following
1034 structure:
1035 - fuel: left, centre, right
1036 - n1: left outer, left inner, right inner, right outer
1037 - reverser: empty (the plane has no reversers)"""
1038 def __init__(self, flight):
1039 super(B462, self).__init__(flight)
1040 self.dow = 25706
1041 self.mtow = 43998
1042 self.mlw = 38599
1043 self.mzfw = 33792
1044 self.gearSpeedLimit = 210
1045 self.flapSpeedLimits = { 18 : 217,
1046 24 : 180,
1047 30 : 170,
1048 33 : 150 }
1049
1050 @property
1051 def derateType(self):
1052 """Get the derate type for this type."""
1053 return DERATE_B462
1054
1055#---------------------------------------------------------------------------------------
1056
1057mostFuelTanks = [const.FUELTANK_LEFT_TIP, const.FUELTANK_EXTERNAL1,
1058 const.FUELTANK_LEFT_AUX,
1059 const.FUELTANK_CENTRE,
1060 const.FUELTANK_RIGHT_AUX,
1061 const.FUELTANK_EXTERNAL2, const.FUELTANK_RIGHT_TIP]
1062
1063#---------------------------------------------------------------------------------------
1064
1065_classes = { const.AIRCRAFT_B736 : B736,
1066 const.AIRCRAFT_B737 : B737,
1067 const.AIRCRAFT_B738 : B738,
1068 const.AIRCRAFT_B738C : B738Charter,
1069 const.AIRCRAFT_B733 : B733,
1070 const.AIRCRAFT_B734 : B734,
1071 const.AIRCRAFT_B735 : B735,
1072 const.AIRCRAFT_DH8D : DH8D,
1073 const.AIRCRAFT_B762 : B762,
1074 const.AIRCRAFT_B763 : B763,
1075 const.AIRCRAFT_CRJ2 : CRJ2,
1076 const.AIRCRAFT_F70 : F70,
1077 const.AIRCRAFT_DC3 : DC3,
1078 const.AIRCRAFT_T134 : T134,
1079 const.AIRCRAFT_T154 : T154,
1080 const.AIRCRAFT_YK40 : YK40,
1081 const.AIRCRAFT_B462 : B462 }
1082
1083#---------------------------------------------------------------------------------------
1084
1085if __name__ == "__main__":
1086 value = SmoothedValue()
1087
1088 print "Adding 1, 12.0"
1089 value.add(1, 12.0)
1090 print value.get()
1091
1092 print "Adding 1, 15.0"
1093 value.add(1, 15.0)
1094 print value.get()
1095
1096 print "Adding 2, 18.0"
1097 value.add(2, 18.0)
1098 print value.get()
1099
1100 print "Adding 2, 20.0"
1101 value.add(2, 20.0)
1102 print value.get()
1103
1104 print "Adding 5, 22.0"
1105 value.add(5, 22.0)
1106 print value.get()
1107
1108 print "Adding 5, 25.0"
1109 value.add(5, 25.0)
1110 print value.get()
1111
1112 print "Adding 5, 29.0"
1113 value.add(5, 29.0)
1114 print value.get()
1115
1116 print "Adding 5, 21.0"
1117 value.add(5, 21.0)
1118 print value.get()
1119
1120 print "Adding 5, 26.0"
1121 value.add(5, 26.0)
1122 print value.get()
1123
1124 print "Adding 2, 30.0"
1125 value.add(2, 30.0)
1126 print value.get()
1127
1128 print "Adding 2, 55.0"
1129 value.add(2, 55.0)
1130 print value.get()
1131
1132#---------------------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.