source: src/checks.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: 14.5 KB
Line 
1# The various checks that may be performed during flight
2
3#---------------------------------------------------------------------------------------
4
5import const
6
7#---------------------------------------------------------------------------------------
8
9class StateChecker(object):
10 """Base class for classes the instances of which check the aircraft's state
11 from some aspect.
12
13 As a result of the check they may log something, or notify of some fault, etc."""
14 def check(self, flight, aircraft, logger, oldState, state):
15 """Perform the check and do whatever is needed.
16
17 This default implementation raises a NotImplementedError."""
18 raise NotImplementedError()
19
20#---------------------------------------------------------------------------------------
21
22class StageChecker(StateChecker):
23 """Check the flight stage transitions."""
24 def check(self, flight, aircraft, logger, oldState, state):
25 """Check the stage of the aircraft."""
26 stage = flight.stage
27 if stage==None:
28 aircraft.setStage(state, const.STAGE_BOARDING)
29 elif stage==const.STAGE_BOARDING:
30 if not state.parking or \
31 (not state.trickMode and state.groundSpeed>5.0):
32 aircraft.setStage(state, const.STAGE_PUSHANDTAXI)
33 elif stage==const.STAGE_PUSHANDTAXI or stage==const.STAGE_RTO:
34 if state.landingLightsOn or state.strobeLightsOn or \
35 state.groundSpeed>80.0:
36 aircraft.setStage(state, const.STAGE_TAKEOFF)
37 elif stage==const.STAGE_TAKEOFF:
38 if not state.gearsDown or \
39 (state.radioAltitude>3000.0 and state.vs>0):
40 aircraft.setStage(state, const.STAGE_CLIMB)
41 elif not state.landingLightsOn and \
42 not state.strobeLightsOn and \
43 state.onTheGround and \
44 state.groundSpeed<50.0:
45 aircraft.setStage(state, const.STAGE_RTO)
46 elif stage==const.STAGE_CLIMB:
47 if (state.altitude+2000) > flight.cruiseAltitude:
48 aircraft.setStage(state, const.STAGE_CRUISE)
49 elif state.radioAltitude<2000.0 and \
50 state.vs < 0.0 and state.gearsDown:
51 aircraft.setStage(state, const.STAGE_LANDING)
52 elif stage==const.STAGE_CRUISE:
53 if (state.altitude+2000) < flight.cruiseAltitude:
54 aircraft.setStage(state, const.STAGE_DESCENT)
55 elif stage==const.STAGE_DESCENT or stage==const.STAGE_GOAROUND:
56 if state.gearsDown and state.radioAltitude<2000.0:
57 aircraft.setStage(state, const.STAGE_LANDING)
58 elif (state.altitude+2000) > flight.cruiseAltitude:
59 aircraft.setStage(state, const.STAGE_CRUISE)
60 elif stage==const.STAGE_LANDING:
61 if state.onTheGround and state.groundSpeed<50.0:
62 aircraft.setStage(state, const.STAGE_TAXIAFTERLAND)
63 elif not state.gearsDown:
64 aircraft.setStage(state, const.STAGE_GOAROUND)
65 elif state.radioAltitude>200:
66 aircraft.cancelFlare()
67 elif state.radioAltitude<150 and not state.onTheGround:
68 aircraft.prepareFlare()
69 elif stage==const.STAGE_TAXIAFTERLAND:
70 if state.parking:
71 aircraft.setStage(state, const.STAGE_PARKING)
72 elif stage==const.STAGE_PARKING:
73 if aircraft.checkFlightEnd(state):
74 aircraft.setStage(state, const.STAGE_END)
75
76#---------------------------------------------------------------------------------------
77
78class TakeOffLogger(StateChecker):
79 """Logger for the cruise speed."""
80 def __init__(self):
81 """Construct the logger."""
82 self._onTheGround = True
83
84 def check(self, flight, aircraft, logger, oldState, state):
85 """Log the cruise speed if necessary."""
86 if flight.stage==const.STAGE_TAKEOFF and \
87 self._onTheGround and not state.onTheGround:
88 logger.message(state.timestamp,
89 "Takeoff speed: %.0f knots" % (state.ias,))
90 logger.message(state.timestamp,
91 "Takeoff heading: %03.0f degrees" % (state.heading,))
92 logger.message(state.timestamp,
93 "Takeoff pitch: %.1f degrees" % (state.pitch,))
94 self._onTheGround = False
95
96#---------------------------------------------------------------------------------------
97
98class CruiseSpeedLogger(StateChecker):
99 """Logger for the cruise speed."""
100 def __init__(self):
101 """Construct the logger."""
102 self._lastTime = None
103
104 def check(self, flight, aircraft, logger, oldState, state):
105 """Log the cruise speed if necessary."""
106 if flight.stage==const.STAGE_CRUISE and \
107 (self._lastTime is None or \
108 (self._lastTime+800)<=state.timestamp):
109 if state.altitude>24500.0:
110 logger.message(state.timestamp,
111 "Cruise speed: %.2f mach" % (state.mach,))
112 else:
113 logger.message(state.timestamp,
114 "Cruise speed: %.0f knots" % (state.ias,))
115 self._lastTime = state.timestamp
116
117#---------------------------------------------------------------------------------------
118
119class StateChangeLogger(StateChecker):
120 """Base class for classes the instances of which check if a specific change has
121 occured in the aircraft's state, and log such change."""
122 def __init__(self, logInitial = True):
123 """Construct the logger.
124
125 If logInitial is True, the initial value will be logged, not just the
126 changes later.
127
128 Child classes should define the following functions:
129 - _changed(self, oldState, state): returns a boolean indicating if the
130 value has changed or not
131 - _getMessage(self, state): return a strings containing the message to log
132 with the new value
133 """
134 self._logInitial = logInitial
135
136 def check(self, flight, aircraft, logger, oldState, state):
137 """Check if the state has changed, and if so, log the new state."""
138 shouldLog = False
139 if oldState is None:
140 shouldLog = self._logInitial
141 else:
142 shouldLog = self._changed(oldState, state)
143
144 if shouldLog:
145 logger.message(state.timestamp, self._getMessage(state))
146
147#---------------------------------------------------------------------------------------
148
149class SimpleChangeMixin(object):
150 """A mixin that defines a _changed() function which simply calls a function
151 to retrieve the value two monitor for both states and compares them.
152
153 Child classes should define the following function:
154 - _getValue(state): get the value we are interested in."""
155 def _changed(self, oldState, state):
156 """Determine if the value has changed."""
157 return self._getValue(oldState)!=self._getValue(state)
158
159#---------------------------------------------------------------------------------------
160
161class SingleValueMixin(object):
162 """A mixin that provides a _getValue() function to query a value from the
163 state using the name of the attribute."""
164 def __init__(self, attrName):
165 """Construct the mixin with the given attribute name."""
166 self._attrName = attrName
167
168 def _getValue(self, state):
169 """Get the value of the attribute from the state."""
170 return getattr(state, self._attrName)
171
172#---------------------------------------------------------------------------------------
173
174class DelayedChangeMixin(object):
175 """A mixin to a StateChangeLogger that stores the old value and reports a
176 change only if the change has been there for a certain amount of time.
177
178 Child classes should define the following function:
179 - _getValue(state): get the value we are interested in."""
180 def __init__(self, delay = 10.0):
181 """Construct the mixin with the given delay in seconds."""
182 self._delay = delay
183 self._oldValue = None
184 self._firstChange = None
185
186 def _changed(self, oldState, state):
187 """Determine if the value has changed."""
188 if self._oldValue is None:
189 self._oldValue = self._getValue(oldState)
190
191 newValue = self._getValue(state)
192 if newValue!=self._oldValue:
193 if self._firstChange is None:
194 self._firstChange = state.timestamp
195 if state.timestamp >= (self._firstChange + self._delay):
196 self._oldValue = newValue
197 self._firstChange = None
198 return True
199 else:
200 self._firstChange = None
201
202 return False
203
204#---------------------------------------------------------------------------------------
205
206class TemplateMessageMixin(object):
207 """Mixin to generate a message based on a template.
208
209 Child classes should define the following function:
210 - _getValue(state): get the value we are interested in."""
211 def __init__(self, template):
212 """Construct the mixin."""
213 self._template = template
214
215 def _getMessage(self, state):
216 """Get the message."""
217 return self._template % (self._getValue(state),)
218
219#---------------------------------------------------------------------------------------
220
221class GenericStateChangeLogger(StateChangeLogger, SingleValueMixin,
222 DelayedChangeMixin, TemplateMessageMixin):
223 """Base for generic state change loggers that monitor a single value in the
224 state possibly with a delay and the logged message comes from a template"""
225 def __init__(self, attrName, template, logInitial = True, delay = 0.0):
226 """Construct the object."""
227 StateChangeLogger.__init__(self, logInitial = logInitial)
228 SingleValueMixin.__init__(self, attrName)
229 DelayedChangeMixin.__init__(self, delay = delay)
230 TemplateMessageMixin.__init__(self, template)
231
232#---------------------------------------------------------------------------------------
233
234class AltimeterLogger(StateChangeLogger, SingleValueMixin,
235 DelayedChangeMixin):
236 """Logger for the altimeter setting."""
237 def __init__(self):
238 """Construct the logger."""
239 StateChangeLogger.__init__(self, logInitial = True)
240 SingleValueMixin.__init__(self, "altimeter")
241 DelayedChangeMixin.__init__(self)
242
243 def _getMessage(self, state):
244 """Get the message to log on a change."""
245 return "Altimeter: %.0f hPa at %.0f feet" % (state.altimeter, state.altitude)
246
247#---------------------------------------------------------------------------------------
248
249class NAV1Logger(GenericStateChangeLogger):
250 """Logger for the NAV1 radio setting."""
251 def __init__(self):
252 """Construct the logger."""
253 super(NAV1Logger, self).__init__("nav1", "NAV1 frequency: %s MHz")
254
255#---------------------------------------------------------------------------------------
256
257class NAV2Logger(GenericStateChangeLogger):
258 """Logger for the NAV2 radio setting."""
259 def __init__(self):
260 """Construct the logger."""
261 super(NAV2Logger, self).__init__("nav2", "NAV2 frequency: %s MHz")
262
263#---------------------------------------------------------------------------------------
264
265class SquawkLogger(GenericStateChangeLogger):
266 """Logger for the squawk setting."""
267 def __init__(self):
268 """Construct the logger."""
269 super(SquawkLogger, self).__init__("squawk", "Squawk code: %s",
270 delay = 10.0)
271
272#---------------------------------------------------------------------------------------
273
274class LightsLogger(StateChangeLogger, SingleValueMixin, SimpleChangeMixin):
275 """Base class for the loggers of the various lights."""
276 def __init__(self, attrName, template):
277 """Construct the logger."""
278 StateChangeLogger.__init__(self)
279 SingleValueMixin.__init__(self, attrName)
280
281 self._template = template
282
283 def _getMessage(self, state):
284 """Get the message from the given state."""
285 return self._template % ("ON" if self._getValue(state) else "OFF")
286
287#---------------------------------------------------------------------------------------
288
289class AnticollisionLightsLogger(LightsLogger):
290 """Logger for the anti-collision lights."""
291 def __init__(self):
292 LightsLogger.__init__(self, "antiCollisionLightsOn",
293 "Anti-collision lights: %s")
294
295#---------------------------------------------------------------------------------------
296
297class LandingLightsLogger(LightsLogger):
298 """Logger for the landing lights."""
299 def __init__(self):
300 LightsLogger.__init__(self, "landingLightsOn",
301 "Landing lights: %s")
302
303#---------------------------------------------------------------------------------------
304
305class StrobeLightsLogger(LightsLogger):
306 """Logger for the strobe lights."""
307 def __init__(self):
308 LightsLogger.__init__(self, "strobeLightsOn",
309 "Strobe lights: %s")
310
311#---------------------------------------------------------------------------------------
312
313class NavLightsLogger(LightsLogger):
314 """Logger for the navigational lights."""
315 def __init__(self):
316 LightsLogger.__init__(self, "navLightsOn",
317 "Navigational lights: %s")
318
319#---------------------------------------------------------------------------------------
320
321class FlapsLogger(StateChangeLogger, SingleValueMixin, SimpleChangeMixin):
322 """Logger for the flaps setting."""
323 def __init__(self):
324 """Construct the logger."""
325 StateChangeLogger.__init__(self, logInitial = True)
326 SingleValueMixin.__init__(self, "flapsSet")
327
328 def _getMessage(self, state):
329 """Get the message to log on a change."""
330 speed = state.groundSpeed if state.groundSpeed<80.0 else state.ias
331 return "Flaps set to %.0f at %.0f knots" % (state.flapsSet, speed)
332
333#---------------------------------------------------------------------------------------
334
335class GearsLogger(StateChangeLogger, SingleValueMixin, SimpleChangeMixin):
336 """Logger for the gears state."""
337 def __init__(self):
338 """Construct the logger."""
339 StateChangeLogger.__init__(self, logInitial = True)
340 SingleValueMixin.__init__(self, "gearsDown")
341
342 def _getMessage(self, state):
343 """Get the message to log on a change."""
344 return "Gears %s at %.0f knots, %.0f feet" % \
345 ("DOWN" if state.gearsDown else "UP", state.ias, state.altitude)
346
347#---------------------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.