source: src/mlx/acft.py@ 407:6554b242b7c8

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

Removed the thriwst checker as they are seemingly not needed (re #174)

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