source: src/acft.py@ 9:3dac12e8914d

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

Flare calculations are handled and added some other printouts

File size: 22.2 KB
Line 
1# Module for the simulator-independent aircraft classes
2
3#---------------------------------------------------------------------------------------
4
5import const
6import checks
7
8import time
9
10#---------------------------------------------------------------------------------------
11
12class Aircraft(object):
13 """Base class for aircraft."""
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):
20 """Construct the aircraft for the given type."""
21 self._flight = flight
22 self._aircraftState = None
23
24 self._maxVS = -10000.0
25 self._minVS = 10000.0
26
27 self._checkers = []
28
29 self._checkers.append(checks.StageChecker())
30 self._checkers.append(checks.TakeOffLogger())
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())
46
47 self._checkers.append(checks.CruiseSpeedLogger())
48
49 @property
50 def type(self):
51 """Get the type of the aircraft."""
52 return self._flight.aircraftType
53
54 @property
55 def flight(self):
56 """Get the flight the aircraft belongs to."""
57 return self._flight
58
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):
65 """Called when the simulator's aircraft changes."""
66 self._flight.logger.message(timestamp,
67 "Aircraft: name='%s', model='%s'" % \
68 (aircraftName, modelName))
69
70 def handleState(self, aircraftState):
71 """Called when the state of the aircraft changes."""
72 for checker in self._checkers:
73 checker.check(self._flight, self, self._flight.logger,
74 self._aircraftState, aircraftState)
75
76 self._maxVS = max(self._maxVS, aircraftState.vs)
77 self._minVS = min(self._minVS, aircraftState.vs)
78
79 self._aircraftState = aircraftState
80
81 def setStage(self, aircraftState, newStage):
82 """Set the given stage as the new one and do whatever should be
83 done."""
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")
110
111 def prepareFlare(self):
112 """Called when it is detected that we will soon flare.
113
114 On the first call, it should start monitoring some parameters more
115 closely to determine flare time."""
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,))
154
155 def cancelFlare(self):
156 """Cancel flare, if it has started."""
157 self.flight.simulator.cancelFlare()
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
168#---------------------------------------------------------------------------------------
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"""
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 }
189
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
199#---------------------------------------------------------------------------------------
200
201class B736(Boeing737):
202 """Boeing 737-600 aircraft."""
203 def __init__(self, flight):
204 super(B736, self).__init__(flight)
205 self.dow = 38307
206 self.mtow = 58328
207 self.mlw = 54657
208 self.mzfw = 51482
209
210#---------------------------------------------------------------------------------------
211
212class B737(Boeing737):
213 """Boeing 737-700 aircraft."""
214 def __init__(self, flight):
215 super(B737, self).__init__(flight)
216 self.dow = 39250
217 self.mtow = 61410
218 self.mlw = 58059
219 self.mzfw = 54657
220
221#---------------------------------------------------------------------------------------
222
223class B738(Boeing737):
224 """Boeing 737-800 aircraft."""
225 def __init__(self, flight):
226 super(B738, self).__init__(flight)
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
239
240#---------------------------------------------------------------------------------------
241
242class B733(Boeing737):
243 """Boeing 737-300 aircraft."""
244 def __init__(self, flight):
245 super(B733, self).__init__(flight)
246 self.dow = 32700
247 self.mtow = 62820
248 self.mlw = 51700
249 self.mzfw = 48410
250
251#---------------------------------------------------------------------------------------
252
253class B734(Boeing737):
254 """Boeing 737-400 aircraft."""
255 def __init__(self, flight):
256 super(B734, self).__init__(flight)
257 self.dow = 33200
258 self.mtow = 68050
259 self.mlw = 56200
260 self.mzfw = 53100
261
262#---------------------------------------------------------------------------------------
263
264class B735(Boeing737):
265 """Boeing 737-500 aircraft."""
266 def __init__(self, flight):
267 super(B735, self).__init__(flight)
268 self.dow = 31300
269 self.mtow = 60550
270 self.mlw = 50000
271 self.mzfw = 46700
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."""
283 def __init__(self, flight):
284 super(DH8D, self).__init__(flight)
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),))
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"""
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 }
323
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
333#---------------------------------------------------------------------------------------
334
335class B762(Boeing767):
336 """Boeing 767-200 aircraft."""
337 def __init__(self, flight):
338 super(B762, self).__init__(flight)
339 self.dow = 84507
340 self.mtow = 175540
341 self.mlw = 126098
342 self.mzfw = 114758
343
344#---------------------------------------------------------------------------------------
345
346class B763(Boeing767):
347 """Boeing 767-300 aircraft."""
348 def __init__(self, flight):
349 super(B763, self).__init__(cflight)
350 self.dow = 91311
351 self.mtow = 181436
352 self.mlw = 137892
353 self.mzfw = 130635
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."""
365 def __init__(self, flight):
366 super(CRJ2, self).__init__(flight)
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 }
376
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
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."""
396 def __init__(self, flight):
397 super(F70, self).__init__(flight)
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 }
408
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
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."""
428 def __init__(self, flight):
429 super(DC3, self).__init__(flight)
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 }
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)
446
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
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."""
467 def __init__(self, flight):
468 super(T134, self).__init__(flight)
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 }
477
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
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"""
499 def __init__(self, flight):
500 super(T154, self).__init__(flight)
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),))
519
520#---------------------------------------------------------------------------------------
521
522
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"""
531 def __init__(self, flight):
532 super(YK40, self).__init__(flight)
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),))
548
549#---------------------------------------------------------------------------------------
550
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.