source: src/mlx/acft.py@ 273:066f7271e849

Last change on this file since 273:066f7271e849 was 273:066f7271e849, checked in by István Váradi <ivaradi@…>, 12 years ago

Added the playback of approach callouts

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