source: src/acft.py@ 10:103229d7ace5

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

Spoiler deployment is logged

File size: 22.3 KB
RevLine 
[4]1# Module for the simulator-independent aircraft classes
2
3#---------------------------------------------------------------------------------------
4
[8]5import const
6import checks
[4]7
[8]8import time
[7]9
[4]10#---------------------------------------------------------------------------------------
11
12class Aircraft(object):
13 """Base class for aircraft."""
[8]14 @staticmethod
15 def create(flight):
16 """Create an aircraft instance for the type in the given flight."""
17 return _classes[flight.aircraftType](flight)
18
19 def __init__(self, flight):
[4]20 """Construct the aircraft for the given type."""
[8]21 self._flight = flight
[4]22 self._aircraftState = None
[9]23
24 self._maxVS = -10000.0
25 self._minVS = 10000.0
[4]26
[8]27 self._checkers = []
28
29 self._checkers.append(checks.StageChecker())
[9]30 self._checkers.append(checks.TakeOffLogger())
[8]31
32 self._checkers.append(checks.AltimeterLogger())
33
34 self._checkers.append(checks.NAV1Logger())
35 self._checkers.append(checks.NAV2Logger())
36 self._checkers.append(checks.SquawkLogger())
37
38 self._checkers.append(checks.AnticollisionLightsLogger())
39 self._checkers.append(checks.LandingLightsLogger())
40 self._checkers.append(checks.StrobeLightsLogger())
41 self._checkers.append(checks.NavLightsLogger())
42
43 self._checkers.append(checks.FlapsLogger())
44
45 self._checkers.append(checks.GearsLogger())
[9]46 self._checkers.append(checks.CruiseSpeedLogger())
[10]47 self._checkers.append(checks.SpoilerLogger())
[9]48
[4]49 @property
50 def type(self):
51 """Get the type of the aircraft."""
[8]52 return self._flight.aircraftType
53
54 @property
55 def flight(self):
56 """Get the flight the aircraft belongs to."""
57 return self._flight
[4]58
[8]59 @property
60 def logger(self):
61 """Get the logger to use for the aircraft."""
62 return self._flight.logger
63
64 def modelChanged(self, timestamp, aircraftName, modelName):
[4]65 """Called when the simulator's aircraft changes."""
[8]66 self._flight.logger.message(timestamp,
67 "Aircraft: name='%s', model='%s'" % \
68 (aircraftName, modelName))
[4]69
70 def handleState(self, aircraftState):
71 """Called when the state of the aircraft changes."""
[8]72 for checker in self._checkers:
73 checker.check(self._flight, self, self._flight.logger,
74 self._aircraftState, aircraftState)
[7]75
[9]76 self._maxVS = max(self._maxVS, aircraftState.vs)
77 self._minVS = min(self._minVS, aircraftState.vs)
78
[4]79 self._aircraftState = aircraftState
[8]80
81 def setStage(self, aircraftState, newStage):
82 """Set the given stage as the new one and do whatever should be
83 done."""
[9]84 if self._flight.setStage(aircraftState.timestamp, newStage):
85 if newStage==const.STAGE_PUSHANDTAXI:
86 self.logger.message(aircraftState.timestamp, "Block time start")
87 self.logFuel(aircraftState)
88 self.logger.message(aircraftState.timestamp,
89 "Zero-fuel weight: %.0f kg" % (aircraftState.zfw))
90 elif newStage==const.STAGE_TAKEOFF:
91 self.logger.message(aircraftState.timestamp, "Flight time start")
92 self.logger.message(aircraftState.timestamp,
93 "Takeoff weight: %.0f kg, MTOW: %.0f kg" % \
94 (aircraftState.grossWeight, self.mtow))
95 self.logger.message(aircraftState.timestamp,
96 "Wind %03.0f degrees at %.0f knots" % \
97 (aircraftState.windDirection,
98 aircraftState.windSpeed))
99 elif newStage==const.STAGE_TAXIAFTERLAND:
100 self.logger.message(aircraftState.timestamp, "Flight time end")
101 self.logFuel(aircraftState)
102 self.logger.message(aircraftState.timestamp,
103 "Landing weight: %.0f kg, MLW: %.0f" % \
104 (aircraftState.grossWeight, self.mlw))
105 self.logger.message(aircraftState.timestamp,
106 "Vertical speed range: %.0f..%.0f feet/min" % \
107 (self._maxVS, self._minVS))
108 elif newStage==const.STAGE_PARKING:
109 self.logger.message(aircraftState.timestamp, "Block time end")
[8]110
[9]111 def prepareFlare(self):
112 """Called when it is detected that we will soon flare.
[8]113
114 On the first call, it should start monitoring some parameters more
115 closely to determine flare time."""
[9]116 self.flight.simulator.startFlare()
117
118 def flareStarted(self, windSpeed, windDirection, visibility,
119 flareStart, flareStartFS):
120 """Called when the flare has started."""
121 self.logger.message(self._aircraftState.timestamp, "The flare has begun")
122 self.logger.message(self._aircraftState.timestamp,
123 "Wind %03.0f degrees at %.0f knots" % \
124 (windDirection, windSpeed))
125 self.logger.message(self._aircraftState.timestamp,
126 "Visibility: %.0f metres" % (visibility,))
127 self.logger.message(self._aircraftState.timestamp,
128 "Altimeter setting: %.0f hPa" % \
129 (self._aircraftState.altimeter,))
130 self.flight.flareStarted(flareStart, flareStartFS)
131
132 def flareFinished(self, flareEnd, flareEndFS, tdRate, tdRateCalculatedByFS,
133 ias, pitch, bank, heading):
134 """Called when the flare has finished."""
135 (flareTimeFromFS, flareTime) = self.flight.flareFinished(flareEnd,
136 flareEndFS)
137 self.logger.message(self._aircraftState.timestamp,
138 "Flare time: %.1f s (from %s)" % \
139 (flareTime,
140 "the simulator" if flareTimeFromFS else "real time",))
141 self.logger.message(self._aircraftState.timestamp,
142 "Touchdown rate: %.0f feet/min" % (tdRate,))
143 self.logger.message(self._aircraftState.timestamp,
144 "Touchdown rate was calculated by the %s" % \
145 ("simulator" if tdRateCalculatedByFS else "logger",))
146 self.logger.message(self._aircraftState.timestamp,
147 "Touchdown speed: %.0f knots" % (ias,))
148 self.logger.message(self._aircraftState.timestamp,
149 "Touchdown pitch: %.1f degrees" % (pitch,))
150 self.logger.message(self._aircraftState.timestamp,
151 "Touchdown bank: %.1f degrees" % (bank,))
152 self.logger.message(self._aircraftState.timestamp,
153 "Touchdown heading: %03.0f degrees" % (heading,))
[8]154
155 def cancelFlare(self):
156 """Cancel flare, if it has started."""
[9]157 self.flight.simulator.cancelFlare()
[8]158
159 def checkFlightEnd(self, aircraftState):
160 """Check if the end of the flight has arrived.
161
162 This default implementation checks the N1 values, but for
163 piston-powered aircraft you need to check the RPMs."""
164 for n1 in aircraftState.n1:
165 if n1>=0.5: return False
166 return True
167
[4]168#---------------------------------------------------------------------------------------
[7]169
170class Boeing737(Aircraft):
171 """Base class for the various aircraft in the Boeing 737 family.
172
173 The aircraft type-specific values in the aircraft state have the following
174 structure:
175 - fuel: centre, left, right
176 - n1: left, right
177 - reverser: left, right"""
[9]178 def __init__(self, flight):
179 super(Boeing737, self).__init__(flight)
180 self.gearSpeedLimit = 270
181 self.flapSpeedLimits = { 1 : 260,
182 2 : 260,
183 5 : 250,
184 10 : 210,
185 15 : 200,
186 25 : 190,
187 30 : 175,
188 40 : 162 }
[7]189
[9]190 def logFuel(self, aircraftState):
191 """Log the amount of fuel"""
192 self.logger.message(aircraftState.timestamp,
193 "Fuel: left=%.0f kg - centre=%.0f kg - right=%.0f kg" % \
194 (aircraftState.fuel[1], aircraftState.fuel[0],
195 aircraftState.fuel[2]))
196 self.logger.message(aircraftState.timestamp,
197 "Total fuel: %.0f kg" % (sum(aircraftState.fuel),))
198
[7]199#---------------------------------------------------------------------------------------
200
201class B736(Boeing737):
202 """Boeing 737-600 aircraft."""
[8]203 def __init__(self, flight):
204 super(B736, self).__init__(flight)
[9]205 self.dow = 38307
206 self.mtow = 58328
207 self.mlw = 54657
208 self.mzfw = 51482
[7]209
210#---------------------------------------------------------------------------------------
211
212class B737(Boeing737):
213 """Boeing 737-700 aircraft."""
[8]214 def __init__(self, flight):
215 super(B737, self).__init__(flight)
[9]216 self.dow = 39250
217 self.mtow = 61410
218 self.mlw = 58059
219 self.mzfw = 54657
[7]220
221#---------------------------------------------------------------------------------------
222
223class B738(Boeing737):
224 """Boeing 737-800 aircraft."""
[8]225 def __init__(self, flight):
226 super(B738, self).__init__(flight)
[9]227 self.dow = 42690
228 self.mtow = 71709
229 self.mlw = 65317
230 self.mzfw = 61688
231
232#---------------------------------------------------------------------------------------
233
234class B738Charter(B738):
235 """Boeing 737-800 aircraft used for charters."""
236 def __init__(self, flight):
237 super(B738Charter, self).__init__(flight)
238 self.mtow = 77791
[7]239
240#---------------------------------------------------------------------------------------
241
242class B733(Boeing737):
243 """Boeing 737-300 aircraft."""
[8]244 def __init__(self, flight):
245 super(B733, self).__init__(flight)
[9]246 self.dow = 32700
247 self.mtow = 62820
248 self.mlw = 51700
249 self.mzfw = 48410
[7]250
251#---------------------------------------------------------------------------------------
252
253class B734(Boeing737):
254 """Boeing 737-400 aircraft."""
[8]255 def __init__(self, flight):
256 super(B734, self).__init__(flight)
[9]257 self.dow = 33200
258 self.mtow = 68050
259 self.mlw = 56200
260 self.mzfw = 53100
[7]261
262#---------------------------------------------------------------------------------------
263
264class B735(Boeing737):
265 """Boeing 737-500 aircraft."""
[8]266 def __init__(self, flight):
267 super(B735, self).__init__(flight)
[9]268 self.dow = 31300
269 self.mtow = 60550
270 self.mlw = 50000
271 self.mzfw = 46700
[7]272
273#---------------------------------------------------------------------------------------
274
275class DH8D(Aircraft):
276 """Bombardier Dash-8 Q400 aircraft.
277
278 The aircraft type-specific values in the aircraft state have the following
279 structure:
280 - fuel: centre, left, right
281 - n1: left, right
282 - reverser: left, right."""
[8]283 def __init__(self, flight):
284 super(DH8D, self).__init__(flight)
[9]285 self.dow = 17185
286 self.mtow = 29257
287 self.mlw = 28009
288 self.mzfw = 25855
289 self.gearSpeedLimit = 215
290 self.flapSpeedLimits = { 5 : 200,
291 10 : 181,
292 15 : 172,
293 35 : 158 }
294
295 def logFuel(self, aircraftState):
296 """Log the amount of fuel"""
297 self.logger.message(aircraftState.timestamp,
298 "Fuel: left=%.0f kg - centre=%.0f kg - right=%.0f kg" % \
299 (aircraftState.fuel[1], aircraftState.fuel[0],
300 aircraftState.fuel[2]))
301 self.logger.message(aircraftState.timestamp,
302 "Total fuel: %.0f kg" % (sum(aircraftState.fuel),))
[7]303
304#---------------------------------------------------------------------------------------
305
306class Boeing767(Aircraft):
307 """Base class for the various aircraft in the Boeing 767 family.
308
309 The aircraft type-specific values in the aircraft state have the following
310 structure:
311 - fuel: centre, left, right
312 - n1: left, right
313 - reverser: left, right"""
[9]314 def __init__(self, flight):
315 super(Boeing767, self).__init__(flight)
316 self.gearSpeedLimit = 270
317 self.flapSpeedLimits = { 1 : 255,
318 5 : 235,
319 10 : 215,
320 20 : 215,
321 25 : 185,
322 30 : 175 }
[7]323
[9]324 def logFuel(self, aircraftState):
325 """Log the amount of fuel"""
326 self.logger.message(aircraftState.timestamp,
327 "Fuel: left=%.0f kg - centre=%.0f kg - right=%.0f kg" % \
328 (aircraftState.fuel[1], aircraftState.fuel[0],
329 aircraftState.fuel[2]))
330 self.logger.message(aircraftState.timestamp,
331 "Total fuel: %.0f kg" % (sum(aircraftState.fuel),))
332
[7]333#---------------------------------------------------------------------------------------
334
335class B762(Boeing767):
336 """Boeing 767-200 aircraft."""
[8]337 def __init__(self, flight):
338 super(B762, self).__init__(flight)
[9]339 self.dow = 84507
340 self.mtow = 175540
341 self.mlw = 126098
342 self.mzfw = 114758
[7]343
344#---------------------------------------------------------------------------------------
345
346class B763(Boeing767):
347 """Boeing 767-300 aircraft."""
[8]348 def __init__(self, flight):
349 super(B763, self).__init__(cflight)
[9]350 self.dow = 91311
351 self.mtow = 181436
352 self.mlw = 137892
353 self.mzfw = 130635
[7]354
355#---------------------------------------------------------------------------------------
356
357class CRJ2(Aircraft):
358 """Bombardier CRJ-200 aircraft.
359
360 The aircraft type-specific values in the aircraft state have the following
361 structure:
362 - fuel: centre, left, right
363 - n1: left, right
364 - reverser: left, right."""
[8]365 def __init__(self, flight):
366 super(CRJ2, self).__init__(flight)
[9]367 self.dow = 14549
368 self.mtow = 22995
369 self.mlw = 21319
370 self.mzfw = 19958
371 self.gearSpeedLimit = 240
372 self.flapSpeedLimits = { 8 : 260,
373 20 : 220,
374 30 : 190,
375 45 : 175 }
[7]376
[9]377 def logFuel(self, aircraftState):
378 """Log the amount of fuel"""
379 self.logger.message(aircraftState.timestamp,
380 "Fuel: left=%.0f kg - centre=%.0f kg - right=%.0f kg" % \
381 (aircraftState.fuel[1], aircraftState.fuel[0],
382 aircraftState.fuel[2]))
383 self.logger.message(aircraftState.timestamp,
384 "Total fuel: %.0f kg" % (sum(aircraftState.fuel),))
385
[7]386#---------------------------------------------------------------------------------------
387
388class F70(Aircraft):
389 """Fokker 70 aircraft.
390
391 The aircraft type-specific values in the aircraft state have the following
392 structure:
393 - fuel: centre, left, right
394 - n1: left, right
395 - reverser: left, right."""
[8]396 def __init__(self, flight):
397 super(F70, self).__init__(flight)
[9]398 self.dow = 24283
399 self.mtow = 38100 # FIXME: differentiate by registration number,
400 # MTOW of HA-LMF: 41955
401 self.mlw = 36740
402 self.mzfw = 32655
403 self.gearSpeedLimit = 200
404 self.flapSpeedLimits = { 8 : 250,
405 15 : 220,
406 25 : 220,
407 42 : 180 }
[7]408
[9]409 def logFuel(self, aircraftState):
410 """Log the amount of fuel"""
411 self.logger.message(aircraftState.timestamp,
412 "Fuel: left=%.0f kg - centre=%.0f kg - right=%.0f kg" % \
413 (aircraftState.fuel[1], aircraftState.fuel[0],
414 aircraftState.fuel[2]))
415 self.logger.message(aircraftState.timestamp,
416 "Total fuel: %.0f kg" % (sum(aircraftState.fuel),))
417
[7]418#---------------------------------------------------------------------------------------
419
420class DC3(Aircraft):
421 """Lisunov Li-2 (DC-3) aircraft.
422
423 The aircraft type-specific values in the aircraft state have the following
424 structure:
425 - fuel: left, right, left aux, right aix
426 - rpm: left, right
427 - reverser: left, right."""
[8]428 def __init__(self, flight):
429 super(DC3, self).__init__(flight)
[9]430 self.dow = 8627
431 self.mtow = 11884
432 self.mlw = 11793
433 self.mzfw = 11780
434 self.gearSpeedLimit = 148
435 self.flapSpeedLimits = { 15 : 135,
436 30 : 99,
437 45 : 97 }
[8]438
439 def _checkFlightEnd(self, aircraftState):
440 """Check if the end of the flight has arrived.
441
442 This implementation checks the RPM values to be 0."""
443 for rpm in aircraftState.rpm:
444 if rpm>0: return
445 self._setStage(aircraftState, const.STAGE_END)
[7]446
[9]447 def logFuel(self, aircraftState):
448 """Log the amount of fuel"""
449 self.logger.message(aircraftState.timestamp,
450 "Fuel: left aux=%.0f kg - left=%.0f kg - right=%.0f kg - right aux=%.0f kg" % \
451 (aircraftState.fuel[2], aircraftState.fuel[0],
452 aircraftState.fuel[1], aircraftState.fuel[3]))
453 self.logger.message(aircraftState.timestamp,
454 "Total fuel: %.0f kg" % (sum(aircraftState.fuel),))
455
[7]456#---------------------------------------------------------------------------------------
457
458class T134(Aircraft):
459 """Tupolev Tu-134 aircraft.
460
461 The aircraft type-specific values in the aircraft state have the following
462 structure:
463 - fuel: centre, left tip, left aux, right tip, right aux, external 1,
464 external 2
465 - n1: left, right
466 - reverser: left, right."""
[8]467 def __init__(self, flight):
468 super(T134, self).__init__(flight)
[9]469 self.dow = 29927
470 self.mtow = 47600
471 self.mlw = 43000
472 self.mzfw = 38500
473 self.gearSpeedLimit = 216
474 self.flapSpeedLimits = { 10 : 240,
475 20 : 216,
476 30 : 161 }
[7]477
[9]478 def logFuel(self, aircraftState):
479 """Log the amount of fuel"""
480 self.logger.message(aircraftState.timestamp,
481 "Fuel: left aux=%.0f kg - left tip=%.0f kg - centre= %.0f kg - right tip=%.0f kg - right aux=%.0f kg - external 1=%.0f kg - external 2=%.0f kg" % \
482 (aircraftState.fuel[2], aircraftState.fuel[1],
483 aircraftState.fuel[0],
484 aircraftState.fuel[3], aircraftState.fuel[4],
485 aircraftState.fuel[5], aircraftState.fuel[6]))
486 self.logger.message(aircraftState.timestamp,
487 "Total fuel: %.0f kg" % (sum(aircraftState.fuel),))
488
[7]489#---------------------------------------------------------------------------------------
490
491class T154(Aircraft):
492 """Tupolev Tu-154 aircraft.
493
494 The aircraft type-specific values in the aircraft state have the following
495 structure:
496 - fuel: centre, left, right, centre 2, left aux, right aux
497 - n1: left, centre, right
498 - reverser: left, right"""
[8]499 def __init__(self, flight):
500 super(T154, self).__init__(flight)
[9]501 self.dow = 53259
502 self.mtow = 98000
503 self.mlw = 78000
504 self.mzfw = 72000
505 self.gearSpeedLimit = 216
506 self.flapSpeedLimits = { 15 : 227,
507 28 : 194,
508 45 : 162 }
509
510 def logFuel(self, aircraftState):
511 """Log the amount of fuel"""
512 self.logger.message(aircraftState.timestamp,
513 "Fuel: left aux=%.0f kg - left=%.0f kg - centre=%.0f kg - centre 2=%.0f kg - right=%.0f kg - right aux=%.0f kg" % \
514 (aircraftState.fuel[4], aircraftState.fuel[1],
515 aircraftState.fuel[0], aircraftState.fuel[3],
516 aircraftState.fuel[2], aircraftState.fuel[5]))
517 self.logger.message(aircraftState.timestamp,
518 "Total fuel: %.0f kg" % (sum(aircraftState.fuel),))
[7]519
520#---------------------------------------------------------------------------------------
521
[9]522
[7]523class YK40(Aircraft):
524 """Yakovlev Yak-40 aircraft.
525
526 The aircraft type-specific values in the aircraft state have the following
527 structure:
528 - fuel: left, right
529 - n1: left, right
530 - reverser: left, right"""
[8]531 def __init__(self, flight):
532 super(YK40, self).__init__(flight)
[9]533 self.dow = 9400
534 self.mtow = 17200
535 self.mlw = 16800
536 self.mzfw = 12100
537 self.gearSpeedLimit = 165
538 self.flapSpeedLimits = { 20 : 165,
539 35 : 135 }
540
541 def logFuel(self, aircraftState):
542 """Log the amount of fuel"""
543 self.logger.message(aircraftState.timestamp,
544 "Fuel: left=%.0f kg - right=%.0f kg" % \
545 (aircraftState.fuel[0], aircraftState.fuel[1]))
546 self.logger.message(aircraftState.timestamp,
547 "Total fuel: %.0f kg" % (sum(aircraftState.fuel),))
[7]548
549#---------------------------------------------------------------------------------------
550
[8]551_classes = { const.AIRCRAFT_B736 : B736,
552 const.AIRCRAFT_B737 : B737,
553 const.AIRCRAFT_B738 : B738,
554 const.AIRCRAFT_B733 : B733,
555 const.AIRCRAFT_B734 : B734,
556 const.AIRCRAFT_B735 : B735,
557 const.AIRCRAFT_DH8D : DH8D,
558 const.AIRCRAFT_B762 : B762,
559 const.AIRCRAFT_B763 : B763,
560 const.AIRCRAFT_CRJ2 : CRJ2,
561 const.AIRCRAFT_F70 : F70,
562 const.AIRCRAFT_DC3 : DC3,
563 const.AIRCRAFT_T134 : T134,
564 const.AIRCRAFT_T154 : T154,
565 const.AIRCRAFT_YK40 : YK40 }
566
567#---------------------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.