source: src/mlx/acft.py@ 241:dea155dd3ac0

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

Added support for calculating speeds in km/h for Soviet aircraft

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