source: src/mlx/acft.py@ 353:f3c95dc2eaea

Last change on this file since 353:f3c95dc2eaea was 350:c014a60676dc, checked in by István Váradi <ivaradi@…>, 12 years ago

The speed checkers are determined in a type-specific manner (#143)

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