source: src/checks.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: 15.2 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: %.3f 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 SpoilerLogger(StateChecker):
120 """Logger for the cruise speed."""
121 def __init__(self):
122 """Construct the logger."""
123 self._logged = False
124 self._spoilerExtension = None
125
126 def check(self, flight, aircraft, logger, oldState, state):
127 """Log the cruise speed if necessary."""
128 if flight.stage==const.STAGE_LANDING and not self._logged:
129 if state.onTheGround:
130 if state.spoilerExtension!=self._spoilerExtension:
131 logger.message(state.timestamp, "Spoilers deployed")
132 self._logged = True
133 else:
134 self._spoilerExtension = state.spoilerExtension
135
136#---------------------------------------------------------------------------------------
137
138class StateChangeLogger(StateChecker):
139 """Base class for classes the instances of which check if a specific change has
140 occured in the aircraft's state, and log such change."""
141 def __init__(self, logInitial = True):
142 """Construct the logger.
143
144 If logInitial is True, the initial value will be logged, not just the
145 changes later.
146
147 Child classes should define the following functions:
148 - _changed(self, oldState, state): returns a boolean indicating if the
149 value has changed or not
150 - _getMessage(self, state): return a strings containing the message to log
151 with the new value
152 """
153 self._logInitial = logInitial
154
155 def check(self, flight, aircraft, logger, oldState, state):
156 """Check if the state has changed, and if so, log the new state."""
157 shouldLog = False
158 if oldState is None:
159 shouldLog = self._logInitial
160 else:
161 shouldLog = self._changed(oldState, state)
162
163 if shouldLog:
164 logger.message(state.timestamp, self._getMessage(state))
165
166#---------------------------------------------------------------------------------------
167
168class SimpleChangeMixin(object):
169 """A mixin that defines a _changed() function which simply calls a function
170 to retrieve the value two monitor for both states and compares them.
171
172 Child classes should define the following function:
173 - _getValue(state): get the value we are interested in."""
174 def _changed(self, oldState, state):
175 """Determine if the value has changed."""
176 return self._getValue(oldState)!=self._getValue(state)
177
178#---------------------------------------------------------------------------------------
179
180class SingleValueMixin(object):
181 """A mixin that provides a _getValue() function to query a value from the
182 state using the name of the attribute."""
183 def __init__(self, attrName):
184 """Construct the mixin with the given attribute name."""
185 self._attrName = attrName
186
187 def _getValue(self, state):
188 """Get the value of the attribute from the state."""
189 return getattr(state, self._attrName)
190
191#---------------------------------------------------------------------------------------
192
193class DelayedChangeMixin(object):
194 """A mixin to a StateChangeLogger that stores the old value and reports a
195 change only if the change has been there for a certain amount of time.
196
197 Child classes should define the following function:
198 - _getValue(state): get the value we are interested in."""
199 def __init__(self, delay = 10.0):
200 """Construct the mixin with the given delay in seconds."""
201 self._delay = delay
202 self._oldValue = None
203 self._firstChange = None
204
205 def _changed(self, oldState, state):
206 """Determine if the value has changed."""
207 if self._oldValue is None:
208 self._oldValue = self._getValue(oldState)
209
210 newValue = self._getValue(state)
211 if newValue!=self._oldValue:
212 if self._firstChange is None:
213 self._firstChange = state.timestamp
214 if state.timestamp >= (self._firstChange + self._delay):
215 self._oldValue = newValue
216 self._firstChange = None
217 return True
218 else:
219 self._firstChange = None
220
221 return False
222
223#---------------------------------------------------------------------------------------
224
225class TemplateMessageMixin(object):
226 """Mixin to generate a message based on a template.
227
228 Child classes should define the following function:
229 - _getValue(state): get the value we are interested in."""
230 def __init__(self, template):
231 """Construct the mixin."""
232 self._template = template
233
234 def _getMessage(self, state):
235 """Get the message."""
236 return self._template % (self._getValue(state),)
237
238#---------------------------------------------------------------------------------------
239
240class GenericStateChangeLogger(StateChangeLogger, SingleValueMixin,
241 DelayedChangeMixin, TemplateMessageMixin):
242 """Base for generic state change loggers that monitor a single value in the
243 state possibly with a delay and the logged message comes from a template"""
244 def __init__(self, attrName, template, logInitial = True, delay = 0.0):
245 """Construct the object."""
246 StateChangeLogger.__init__(self, logInitial = logInitial)
247 SingleValueMixin.__init__(self, attrName)
248 DelayedChangeMixin.__init__(self, delay = delay)
249 TemplateMessageMixin.__init__(self, template)
250
251#---------------------------------------------------------------------------------------
252
253class AltimeterLogger(StateChangeLogger, SingleValueMixin,
254 DelayedChangeMixin):
255 """Logger for the altimeter setting."""
256 def __init__(self):
257 """Construct the logger."""
258 StateChangeLogger.__init__(self, logInitial = True)
259 SingleValueMixin.__init__(self, "altimeter")
260 DelayedChangeMixin.__init__(self)
261
262 def _getMessage(self, state):
263 """Get the message to log on a change."""
264 return "Altimeter: %.0f hPa at %.0f feet" % (state.altimeter, state.altitude)
265
266#---------------------------------------------------------------------------------------
267
268class NAV1Logger(GenericStateChangeLogger):
269 """Logger for the NAV1 radio setting."""
270 def __init__(self):
271 """Construct the logger."""
272 super(NAV1Logger, self).__init__("nav1", "NAV1 frequency: %s MHz")
273
274#---------------------------------------------------------------------------------------
275
276class NAV2Logger(GenericStateChangeLogger):
277 """Logger for the NAV2 radio setting."""
278 def __init__(self):
279 """Construct the logger."""
280 super(NAV2Logger, self).__init__("nav2", "NAV2 frequency: %s MHz")
281
282#---------------------------------------------------------------------------------------
283
284class SquawkLogger(GenericStateChangeLogger):
285 """Logger for the squawk setting."""
286 def __init__(self):
287 """Construct the logger."""
288 super(SquawkLogger, self).__init__("squawk", "Squawk code: %s",
289 delay = 10.0)
290
291#---------------------------------------------------------------------------------------
292
293class LightsLogger(StateChangeLogger, SingleValueMixin, SimpleChangeMixin):
294 """Base class for the loggers of the various lights."""
295 def __init__(self, attrName, template):
296 """Construct the logger."""
297 StateChangeLogger.__init__(self)
298 SingleValueMixin.__init__(self, attrName)
299
300 self._template = template
301
302 def _getMessage(self, state):
303 """Get the message from the given state."""
304 return self._template % ("ON" if self._getValue(state) else "OFF")
305
306#---------------------------------------------------------------------------------------
307
308class AnticollisionLightsLogger(LightsLogger):
309 """Logger for the anti-collision lights."""
310 def __init__(self):
311 LightsLogger.__init__(self, "antiCollisionLightsOn",
312 "Anti-collision lights: %s")
313
314#---------------------------------------------------------------------------------------
315
316class LandingLightsLogger(LightsLogger):
317 """Logger for the landing lights."""
318 def __init__(self):
319 LightsLogger.__init__(self, "landingLightsOn",
320 "Landing lights: %s")
321
322#---------------------------------------------------------------------------------------
323
324class StrobeLightsLogger(LightsLogger):
325 """Logger for the strobe lights."""
326 def __init__(self):
327 LightsLogger.__init__(self, "strobeLightsOn",
328 "Strobe lights: %s")
329
330#---------------------------------------------------------------------------------------
331
332class NavLightsLogger(LightsLogger):
333 """Logger for the navigational lights."""
334 def __init__(self):
335 LightsLogger.__init__(self, "navLightsOn",
336 "Navigational lights: %s")
337
338#---------------------------------------------------------------------------------------
339
340class FlapsLogger(StateChangeLogger, SingleValueMixin, SimpleChangeMixin):
341 """Logger for the flaps setting."""
342 def __init__(self):
343 """Construct the logger."""
344 StateChangeLogger.__init__(self, logInitial = True)
345 SingleValueMixin.__init__(self, "flapsSet")
346
347 def _getMessage(self, state):
348 """Get the message to log on a change."""
349 speed = state.groundSpeed if state.groundSpeed<80.0 else state.ias
350 return "Flaps set to %.0f at %.0f knots" % (state.flapsSet, speed)
351
352#---------------------------------------------------------------------------------------
353
354class GearsLogger(StateChangeLogger, SingleValueMixin, SimpleChangeMixin):
355 """Logger for the gears state."""
356 def __init__(self):
357 """Construct the logger."""
358 StateChangeLogger.__init__(self, logInitial = True)
359 SingleValueMixin.__init__(self, "gearsDown")
360
361 def _getMessage(self, state):
362 """Get the message to log on a change."""
363 return "Gears %s at %.0f knots, %.0f feet" % \
364 ("DOWN" if state.gearsDown else "UP", state.ias, state.altitude)
365
366#---------------------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.