1 | /* |
2 | * Prerelease License - for engineering feedback and testing purposes |
3 | * only. Not for sale. |
4 | * |
5 | * File: fuel_rate_control.c |
6 | * |
7 | * Code generated for Simulink model 'fuel_rate_control'. |
8 | * |
9 | * Model version : 1.742 |
10 | * Simulink Coder version : 9.3 (R2020a) 18-Nov-2019 |
11 | * C/C++ source code generated on : Wed Nov 27 12:21:15 2019 |
12 | * |
13 | * Target selection: ert.tlc |
14 | * Embedded hardware selection: Specified |
15 | * Code generation objectives: Unspecified |
16 | * Validation result: Not run |
17 | */ |
18 | |
19 | #include "fuel_rate_control.h" |
20 | #include "fuel_rate_control_private.h" |
21 | |
22 | /* Named constants for Chart: '<S1>/control_logic' */ |
23 | #define CALL_EVENT (-1) |
24 | #define IN_A ((uint8_T)1U) |
25 | #define IN_Four ((uint8_T)1U) |
26 | #define IN_Fuel_Disabled ((uint8_T)1U) |
27 | #define IN_Low_Emissions ((uint8_T)1U) |
28 | #define IN_Multi ((uint8_T)1U) |
29 | #define IN_NO_ACTIVE_CHILD ((uint8_T)0U) |
30 | #define IN_None ((uint8_T)2U) |
31 | #define IN_Normal ((uint8_T)1U) |
32 | #define IN_O2_failure ((uint8_T)1U) |
33 | #define IN_O2_normal ((uint8_T)2U) |
34 | #define IN_O2_warmup ((uint8_T)3U) |
35 | #define IN_One ((uint8_T)3U) |
36 | #define IN_Overspeed ((uint8_T)1U) |
37 | #define IN_Rich_Mixture ((uint8_T)2U) |
38 | #define IN_Running ((uint8_T)2U) |
39 | #define IN_Shutdown ((uint8_T)2U) |
40 | #define IN_Single_Failure ((uint8_T)1U) |
41 | #define IN_Three ((uint8_T)2U) |
42 | #define IN_Two ((uint8_T)3U) |
43 | #define IN_Warmup ((uint8_T)2U) |
44 | #define IN_fail ((uint8_T)1U) |
45 | #define IN_normal ((uint8_T)2U) |
46 | #define entry_to_Multi (23) |
47 | #define event_DEC (0) |
48 | #define event_INC (1) |
49 | #define exit_from_Multi (24) |
50 | |
51 | /* Block signals (default storage) */ |
52 | BlockIO rtB; |
53 | |
54 | /* Block states (default storage) */ |
55 | D_Work rtDWork; |
56 | |
57 | /* External inputs (root inport signals with default storage) */ |
58 | ExternalInputs rtU; |
59 | |
60 | /* External outputs (root outports fed by signals with default storage) */ |
61 | ExternalOutputs rtY; |
62 | |
63 | /* Real-time model */ |
64 | RT_MODEL rtM_; |
65 | RT_MODEL *const rtM = &rtM_; |
66 | |
67 | /* Forward declaration for local functions */ |
68 | static void Fueling_Mode(const int32_T *sfEvent); |
69 | static void Fail(int32_T *sfEvent); |
70 | real32_T look2_iflf_linlca(real32_T u0, real32_T u1, const real32_T bp0[], const |
71 | real32_T bp1[], const real32_T table[], const uint32_T maxIndex[], uint32_T |
72 | stride) |
73 | { |
74 | real32_T y; |
75 | real32_T frac; |
76 | uint32_T bpIndices[2]; |
77 | real32_T fractions[2]; |
78 | real32_T yR_1d; |
79 | uint32_T offset_1d; |
80 | uint32_T bpIdx; |
81 | |
82 | /* Column-major Lookup 2-D |
83 | Search method: 'linear' |
84 | Use previous index: 'off' |
85 | Interpolation method: 'Linear point-slope' |
86 | Extrapolation method: 'Clip' |
87 | Use last breakpoint for index at or above upper limit: 'on' |
88 | Remove protection against out-of-range input in generated code: 'off' |
89 | */ |
90 | /* Prelookup - Index and Fraction |
91 | Index Search method: 'linear' |
92 | Extrapolation method: 'Clip' |
93 | Use previous index: 'off' |
94 | Use last breakpoint for index at or above upper limit: 'on' |
95 | Remove protection against out-of-range input in generated code: 'off' |
96 | */ |
97 | if (u0 <= bp0[0U]) { |
98 | bpIdx = 0U; |
99 | frac = 0.0F; |
100 | } else if (u0 < bp0[maxIndex[0U]]) { |
101 | /* Linear Search */ |
102 | for (bpIdx = maxIndex[0U] >> 1U; u0 < bp0[bpIdx]; bpIdx--) { |
103 | } |
104 | |
105 | while (u0 >= bp0[bpIdx + 1U]) { |
106 | bpIdx++; |
107 | } |
108 | |
109 | frac = (u0 - bp0[bpIdx]) / (bp0[bpIdx + 1U] - bp0[bpIdx]); |
110 | } else { |
111 | bpIdx = maxIndex[0U]; |
112 | frac = 0.0F; |
113 | } |
114 | |
115 | fractions[0U] = frac; |
116 | bpIndices[0U] = bpIdx; |
117 | |
118 | /* Prelookup - Index and Fraction |
119 | Index Search method: 'linear' |
120 | Extrapolation method: 'Clip' |
121 | Use previous index: 'off' |
122 | Use last breakpoint for index at or above upper limit: 'on' |
123 | Remove protection against out-of-range input in generated code: 'off' |
124 | */ |
125 | if (u1 <= bp1[0U]) { |
126 | bpIdx = 0U; |
127 | frac = 0.0F; |
128 | } else if (u1 < bp1[maxIndex[1U]]) { |
129 | /* Linear Search */ |
130 | for (bpIdx = maxIndex[1U] >> 1U; u1 < bp1[bpIdx]; bpIdx--) { |
131 | } |
132 | |
133 | while (u1 >= bp1[bpIdx + 1U]) { |
134 | bpIdx++; |
135 | } |
136 | |
137 | frac = (u1 - bp1[bpIdx]) / (bp1[bpIdx + 1U] - bp1[bpIdx]); |
138 | } else { |
139 | bpIdx = maxIndex[1U]; |
140 | frac = 0.0F; |
141 | } |
142 | |
143 | /* Column-major Interpolation 2-D |
144 | Interpolation method: 'Linear point-slope' |
145 | Use last breakpoint for index at or above upper limit: 'on' |
146 | Overflow mode: 'wrapping' |
147 | */ |
148 | offset_1d = bpIdx * stride + bpIndices[0U]; |
149 | if (bpIndices[0U] == maxIndex[0U]) { |
150 | y = table[offset_1d]; |
151 | } else { |
152 | y = (table[offset_1d + 1U] - table[offset_1d]) * fractions[0U] + |
153 | table[offset_1d]; |
154 | } |
155 | |
156 | if (bpIdx == maxIndex[1U]) { |
157 | } else { |
158 | bpIdx = offset_1d + stride; |
159 | if (bpIndices[0U] == maxIndex[0U]) { |
160 | yR_1d = table[bpIdx]; |
161 | } else { |
162 | yR_1d = (table[bpIdx + 1U] - table[bpIdx]) * fractions[0U] + table[bpIdx]; |
163 | } |
164 | |
165 | y += (yR_1d - y) * frac; |
166 | } |
167 | |
168 | return y; |
169 | } |
170 | |
171 | /* Function for Chart: '<S1>/control_logic' */ |
172 | static void Fueling_Mode(const int32_T *sfEvent) |
173 | { |
174 | /* During 'Fueling_Mode': '<S3>:21' */ |
175 | /* This state interprets the other states in the chart to directly control the fueling mode. */ |
176 | switch (rtDWork.is_Fueling_Mode) { |
177 | case IN_Fuel_Disabled: |
178 | rtB.fuel_mode = DISABLED; |
179 | |
180 | /* During 'Fuel_Disabled': '<S3>:22' */ |
181 | /* The fuel is completely shut off while in this state. */ |
182 | switch (rtDWork.is_Fuel_Disabled) { |
183 | case IN_Overspeed: |
184 | /* Inport: '<Root>/sensors' */ |
185 | /* During 'Overspeed': '<S3>:24' */ |
186 | /* The speed is dangerously high, so shut off the fuel. */ |
187 | if ((rtDWork.is_Speed == IN_normal) && (rtU.sensors.speed < 603.0F)) { |
188 | /* Transition: '<S3>:54' */ |
189 | if (rtDWork.is_Fail != IN_Multi) { |
190 | /* Transition: '<S3>:55' */ |
191 | rtDWork.is_Fuel_Disabled = IN_NO_ACTIVE_CHILD; |
192 | rtDWork.is_Fueling_Mode = IN_Running; |
193 | |
194 | /* Entry Internal 'Running': '<S3>:23' */ |
195 | switch (rtDWork.was_Running) { |
196 | case IN_Low_Emissions: |
197 | rtDWork.is_Running = IN_Low_Emissions; |
198 | rtDWork.was_Running = IN_Low_Emissions; |
199 | |
200 | /* Entry 'Low_Emissions': '<S3>:25' */ |
201 | rtB.fuel_mode = LOW; |
202 | |
203 | /* Entry Internal 'Low_Emissions': '<S3>:25' */ |
204 | switch (rtDWork.was_Low_Emissions) { |
205 | case IN_Normal: |
206 | rtDWork.is_Low_Emissions = IN_Normal; |
207 | rtDWork.was_Low_Emissions = IN_Normal; |
208 | break; |
209 | |
210 | case IN_Warmup: |
211 | rtDWork.is_Low_Emissions = IN_Warmup; |
212 | rtDWork.was_Low_Emissions = IN_Warmup; |
213 | break; |
214 | |
215 | default: |
216 | rtDWork.is_Low_Emissions = IN_NO_ACTIVE_CHILD; |
217 | break; |
218 | } |
219 | break; |
220 | |
221 | case IN_Rich_Mixture: |
222 | rtDWork.is_Running = IN_Rich_Mixture; |
223 | rtDWork.was_Running = IN_Rich_Mixture; |
224 | |
225 | /* Entry 'Rich_Mixture': '<S3>:26' */ |
226 | rtB.fuel_mode = RICH; |
227 | |
228 | /* Entry Internal 'Rich_Mixture': '<S3>:26' */ |
229 | rtDWork.is_Rich_Mixture = IN_Single_Failure; |
230 | break; |
231 | |
232 | default: |
233 | rtDWork.is_Running = IN_NO_ACTIVE_CHILD; |
234 | break; |
235 | } |
236 | } else { |
237 | if (rtDWork.is_Fail == IN_Multi) { |
238 | /* Transition: '<S3>:60' */ |
239 | rtDWork.is_Fuel_Disabled = IN_Shutdown; |
240 | } |
241 | } |
242 | } |
243 | |
244 | /* End of Inport: '<Root>/sensors' */ |
245 | break; |
246 | |
247 | case IN_Shutdown: |
248 | /* During 'Shutdown': '<S3>:29' */ |
249 | /* Cut off system operation due to multiple sensor failures. */ |
250 | if (*sfEvent == exit_from_Multi) { |
251 | /* Transition: '<S3>:63' */ |
252 | rtDWork.is_Fuel_Disabled = IN_NO_ACTIVE_CHILD; |
253 | rtDWork.is_Fueling_Mode = IN_Running; |
254 | rtDWork.is_Running = IN_Rich_Mixture; |
255 | rtDWork.was_Running = IN_Rich_Mixture; |
256 | |
257 | /* Entry 'Rich_Mixture': '<S3>:26' */ |
258 | rtB.fuel_mode = RICH; |
259 | |
260 | /* Entry Internal 'Rich_Mixture': '<S3>:26' */ |
261 | rtDWork.is_Rich_Mixture = IN_Single_Failure; |
262 | } |
263 | break; |
264 | |
265 | default: |
266 | /* Unreachable state, for coverage only */ |
267 | rtDWork.is_Fuel_Disabled = IN_NO_ACTIVE_CHILD; |
268 | break; |
269 | } |
270 | break; |
271 | |
272 | case IN_Running: |
273 | /* During 'Running': '<S3>:23' */ |
274 | /* The fuel is actively controlled while in this state. */ |
275 | if (*sfEvent == entry_to_Multi) { |
276 | /* Transition: '<S3>:61' */ |
277 | /* Exit Internal 'Running': '<S3>:23' */ |
278 | /* Exit Internal 'Low_Emissions': '<S3>:25' */ |
279 | rtDWork.is_Low_Emissions = IN_NO_ACTIVE_CHILD; |
280 | |
281 | /* Exit Internal 'Rich_Mixture': '<S3>:26' */ |
282 | rtDWork.is_Rich_Mixture = IN_NO_ACTIVE_CHILD; |
283 | rtDWork.is_Running = IN_NO_ACTIVE_CHILD; |
284 | rtDWork.is_Fueling_Mode = IN_Fuel_Disabled; |
285 | |
286 | /* Entry 'Fuel_Disabled': '<S3>:22' */ |
287 | rtB.fuel_mode = DISABLED; |
288 | rtDWork.is_Fuel_Disabled = IN_Shutdown; |
289 | } else if (rtU.sensors.speed > 628.0F) { |
290 | /* Transition: '<S3>:53' */ |
291 | /* Exit Internal 'Running': '<S3>:23' */ |
292 | /* Exit Internal 'Low_Emissions': '<S3>:25' */ |
293 | rtDWork.is_Low_Emissions = IN_NO_ACTIVE_CHILD; |
294 | |
295 | /* Exit Internal 'Rich_Mixture': '<S3>:26' */ |
296 | rtDWork.is_Rich_Mixture = IN_NO_ACTIVE_CHILD; |
297 | rtDWork.is_Running = IN_NO_ACTIVE_CHILD; |
298 | rtDWork.is_Fueling_Mode = IN_Fuel_Disabled; |
299 | |
300 | /* Entry 'Fuel_Disabled': '<S3>:22' */ |
301 | rtB.fuel_mode = DISABLED; |
302 | rtDWork.is_Fuel_Disabled = IN_Overspeed; |
303 | } else { |
304 | switch (rtDWork.is_Running) { |
305 | case IN_Low_Emissions: |
306 | rtB.fuel_mode = LOW; |
307 | |
308 | /* During 'Low_Emissions': '<S3>:25' */ |
309 | switch (rtDWork.is_Low_Emissions) { |
310 | case IN_Normal: |
311 | /* During 'Normal': '<S3>:28' */ |
312 | /* All sensors are in correct operating modes, so effective closed-loop mixture control can be used. */ |
313 | if (rtDWork.is_Fail == IN_One) { |
314 | /* Transition: '<S3>:56' */ |
315 | rtDWork.is_Low_Emissions = IN_NO_ACTIVE_CHILD; |
316 | rtDWork.is_Running = IN_Rich_Mixture; |
317 | rtDWork.was_Running = IN_Rich_Mixture; |
318 | |
319 | /* Entry 'Rich_Mixture': '<S3>:26' */ |
320 | rtB.fuel_mode = RICH; |
321 | rtDWork.is_Rich_Mixture = IN_Single_Failure; |
322 | } |
323 | break; |
324 | |
325 | case IN_Warmup: |
326 | /* During 'Warmup': '<S3>:30' */ |
327 | /* The sensors are all operational, but the oxygen (EGO) sensor is warming up. We'll target a stoichiometric ratio, nonetheless, but won't close the loop around exhaust gas oxygen. */ |
328 | if (rtDWork.is_A == IN_O2_normal) { |
329 | /* Transition: '<S3>:62' */ |
330 | if (rtDWork.is_Fail == IN_One) { |
331 | /* Transition: '<S3>:59' */ |
332 | rtDWork.is_Low_Emissions = IN_NO_ACTIVE_CHILD; |
333 | rtDWork.is_Running = IN_Rich_Mixture; |
334 | rtDWork.was_Running = IN_Rich_Mixture; |
335 | |
336 | /* Entry 'Rich_Mixture': '<S3>:26' */ |
337 | rtB.fuel_mode = RICH; |
338 | rtDWork.is_Rich_Mixture = IN_Single_Failure; |
339 | } else { |
340 | /* Transition: '<S3>:58' */ |
341 | rtDWork.is_Low_Emissions = IN_Normal; |
342 | rtDWork.was_Low_Emissions = IN_Normal; |
343 | } |
344 | } |
345 | break; |
346 | |
347 | default: |
348 | /* Unreachable state, for coverage only */ |
349 | rtDWork.is_Low_Emissions = IN_NO_ACTIVE_CHILD; |
350 | break; |
351 | } |
352 | break; |
353 | |
354 | case IN_Rich_Mixture: |
355 | rtB.fuel_mode = RICH; |
356 | |
357 | /* During 'Rich_Mixture': '<S3>:26' */ |
358 | /* This mode enriches the mixture, lowering the air/fuel ratio. */ |
359 | if ((rtDWork.is_Rich_Mixture == IN_Single_Failure) && (rtDWork.is_Fail == |
360 | IN_None)) { |
361 | /* During 'Single_Failure': '<S3>:27' */ |
362 | /* Continue uninterrupted engine operation, but with a richer mixture. */ |
363 | /* Transition: '<S3>:57' */ |
364 | rtDWork.is_Rich_Mixture = IN_NO_ACTIVE_CHILD; |
365 | rtDWork.is_Running = IN_Low_Emissions; |
366 | rtDWork.was_Running = IN_Low_Emissions; |
367 | |
368 | /* Entry 'Low_Emissions': '<S3>:25' */ |
369 | rtB.fuel_mode = LOW; |
370 | rtDWork.is_Low_Emissions = IN_Normal; |
371 | rtDWork.was_Low_Emissions = IN_Normal; |
372 | } |
373 | break; |
374 | |
375 | default: |
376 | /* Unreachable state, for coverage only */ |
377 | rtDWork.is_Running = IN_NO_ACTIVE_CHILD; |
378 | break; |
379 | } |
380 | } |
381 | break; |
382 | |
383 | default: |
384 | /* Unreachable state, for coverage only */ |
385 | rtDWork.is_Fueling_Mode = IN_NO_ACTIVE_CHILD; |
386 | break; |
387 | } |
388 | } |
389 | |
390 | /* Function for Chart: '<S1>/control_logic' */ |
391 | static void Fail(int32_T *sfEvent) |
392 | { |
393 | int32_T c_previousEvent; |
394 | |
395 | /* During 'Fail': '<S3>:14' */ |
396 | /* This state maintains a count of the number of sensors in failure mode. */ |
397 | switch (rtDWork.is_Fail) { |
398 | case IN_Multi: |
399 | /* During 'Multi': '<S3>:15' */ |
400 | /* This state represents any of the conditions in which more than one sensor is in failure mode. */ |
401 | switch (rtDWork.is_Multi) { |
402 | case IN_Four: |
403 | /* During 'Four': '<S3>:17' */ |
404 | /* All four of the engine sensors have failed. */ |
405 | if (*sfEvent == event_DEC) { |
406 | /* Transition: '<S3>:49' */ |
407 | rtDWork.is_Multi = IN_Three; |
408 | } |
409 | break; |
410 | |
411 | case IN_Three: |
412 | /* During 'Three': '<S3>:16' */ |
413 | /* Three of the engine sensors have failed. */ |
414 | if (*sfEvent == event_INC) { |
415 | /* Transition: '<S3>:45' */ |
416 | rtDWork.is_Multi = IN_Four; |
417 | } else { |
418 | if (*sfEvent == event_DEC) { |
419 | /* Transition: '<S3>:50' */ |
420 | rtDWork.is_Multi = IN_Two; |
421 | } |
422 | } |
423 | break; |
424 | |
425 | case IN_Two: |
426 | /* During 'Two': '<S3>:18' */ |
427 | /* Two of the engine sensors have failed. */ |
428 | if (*sfEvent == event_DEC) { |
429 | /* Transition: '<S3>:51' */ |
430 | rtDWork.is_Multi = IN_NO_ACTIVE_CHILD; |
431 | rtDWork.is_Fail = IN_NO_ACTIVE_CHILD; |
432 | c_previousEvent = *sfEvent; |
433 | *sfEvent = exit_from_Multi; |
434 | if (rtDWork.is_active_Fueling_Mode != 0U) { |
435 | Fueling_Mode(sfEvent); |
436 | } |
437 | |
438 | *sfEvent = c_previousEvent; |
439 | rtDWork.is_Fail = IN_One; |
440 | } else { |
441 | if (*sfEvent == event_INC) { |
442 | /* Transition: '<S3>:47' */ |
443 | rtDWork.is_Multi = IN_Three; |
444 | } |
445 | } |
446 | break; |
447 | |
448 | default: |
449 | /* Unreachable state, for coverage only */ |
450 | rtDWork.is_Multi = IN_NO_ACTIVE_CHILD; |
451 | break; |
452 | } |
453 | break; |
454 | |
455 | case IN_None: |
456 | /* During 'None': '<S3>:20' */ |
457 | /* Zero failures; all sensors are operational. */ |
458 | if (*sfEvent == event_INC) { |
459 | /* Transition: '<S3>:46' */ |
460 | rtDWork.is_Fail = IN_One; |
461 | } |
462 | break; |
463 | |
464 | case IN_One: |
465 | /* During 'One': '<S3>:19' */ |
466 | /* One of the engine sensors has failed. */ |
467 | if (*sfEvent == event_INC) { |
468 | /* Transition: '<S3>:48' */ |
469 | rtDWork.is_Fail = IN_Multi; |
470 | c_previousEvent = *sfEvent; |
471 | *sfEvent = entry_to_Multi; |
472 | if (rtDWork.is_active_Fueling_Mode != 0U) { |
473 | Fueling_Mode(sfEvent); |
474 | } |
475 | |
476 | *sfEvent = c_previousEvent; |
477 | rtDWork.is_Multi = IN_Two; |
478 | } else { |
479 | if (*sfEvent == event_DEC) { |
480 | /* Transition: '<S3>:52' */ |
481 | rtDWork.is_Fail = IN_None; |
482 | } |
483 | } |
484 | break; |
485 | |
486 | default: |
487 | /* Unreachable state, for coverage only */ |
488 | rtDWork.is_Fail = IN_NO_ACTIVE_CHILD; |
489 | break; |
490 | } |
491 | } |
492 | |
493 | /* Model step function */ |
494 | void fuel_rate_control_step(void) |
495 | { |
496 | real32_T denAccum; |
497 | real32_T rtb_MultiportSwitch; |
498 | int32_T sfEvent; |
499 | real32_T u0; |
500 | |
501 | /* Outputs for Atomic SubSystem: '<Root>/fuel_rate_control' */ |
502 | /* Chart: '<S1>/control_logic' incorporates: |
503 | * Inport: '<Root>/sensors' |
504 | * Lookup_n-D: '<S7>/Pressure Estimation' |
505 | * Lookup_n-D: '<S9>/Throttle Estimation' |
506 | * |
507 | * Block description for '<S1>/control_logic': |
508 | * Stateflow diagram to determine control system operating mode |
509 | */ |
510 | /* Gateway: fuel_rate_control/control_logic */ |
511 | sfEvent = CALL_EVENT; |
512 | if (rtDWork.temporalCounter_i1 < 511U) { |
513 | rtDWork.temporalCounter_i1++; |
514 | } |
515 | |
516 | /* During: fuel_rate_control/control_logic */ |
517 | if (rtDWork.is_active_c1_fuel_rate_control == 0U) { |
518 | /* Entry: fuel_rate_control/control_logic */ |
519 | rtDWork.is_active_c1_fuel_rate_control = 1U; |
520 | |
521 | /* Entry Internal: fuel_rate_control/control_logic */ |
522 | rtDWork.is_active_O2 = 1U; |
523 | |
524 | /* Entry Internal 'O2': '<S3>:1' */ |
525 | /* Transition: '<S3>:180' */ |
526 | rtDWork.is_O2 = IN_A; |
527 | |
528 | /* Entry Internal 'A': '<S3>:171' */ |
529 | /* Transition: '<S3>:35' */ |
530 | rtDWork.is_A = IN_O2_warmup; |
531 | rtDWork.temporalCounter_i1 = 0U; |
532 | rtDWork.is_active_Pressure = 1U; |
533 | |
534 | /* Entry 'Pressure': '<S3>:2' */ |
535 | /* Entry Internal 'Pressure': '<S3>:2' */ |
536 | /* Transition: '<S3>:34' */ |
537 | rtDWork.is_Pressure = IN_normal; |
538 | rtDWork.is_active_Throttle = 1U; |
539 | |
540 | /* Entry 'Throttle': '<S3>:8' */ |
541 | /* Entry Internal 'Throttle': '<S3>:8' */ |
542 | /* Transition: '<S3>:39' */ |
543 | rtDWork.is_Throttle = IN_normal; |
544 | rtDWork.is_active_Speed = 1U; |
545 | |
546 | /* Entry 'Speed': '<S3>:9' */ |
547 | /* Entry Internal 'Speed': '<S3>:9' */ |
548 | /* Transition: '<S3>:41' */ |
549 | rtDWork.is_Speed = IN_normal; |
550 | rtDWork.is_active_Fail = 1U; |
551 | |
552 | /* Entry Internal 'Fail': '<S3>:14' */ |
553 | /* Transition: '<S3>:44' */ |
554 | rtDWork.is_Fail = IN_None; |
555 | rtDWork.is_active_Fueling_Mode = 1U; |
556 | |
557 | /* Entry Internal 'Fueling_Mode': '<S3>:21' */ |
558 | /* Transition: '<S3>:64' */ |
559 | rtB.es_o = rtU.sensors; |
560 | |
561 | /* Need to copy the sensors to the output on entry since the individual elements of the bus signal are only updated in the during function. */ |
562 | rtDWork.is_Fueling_Mode = IN_Running; |
563 | rtDWork.is_Running = IN_Low_Emissions; |
564 | rtDWork.was_Running = IN_Low_Emissions; |
565 | |
566 | /* Entry 'Low_Emissions': '<S3>:25' */ |
567 | rtB.fuel_mode = LOW; |
568 | rtDWork.is_Low_Emissions = IN_Warmup; |
569 | rtDWork.was_Low_Emissions = IN_Warmup; |
570 | } else { |
571 | if ((rtDWork.is_active_O2 != 0U) && (rtDWork.is_O2 == IN_A)) { |
572 | /* During 'O2': '<S3>:1' */ |
573 | /* This state determines the validity of the exhaust gas oxygen sensor (EGO) data. */ |
574 | /* During 'A': '<S3>:171' */ |
575 | rtB.es_o.ego = rtU.sensors.ego; |
576 | switch (rtDWork.is_A) { |
577 | case IN_O2_failure: |
578 | /* During 'O2_failure': '<S3>:3' */ |
579 | /* The EGO sensor has failed. */ |
580 | if (rtU.sensors.ego < 1.2F) { |
581 | /* Transition: '<S3>:32' */ |
582 | rtDWork.is_A = IN_NO_ACTIVE_CHILD; |
583 | |
584 | /* Event: '<S3>:91' */ |
585 | sfEvent = event_DEC; |
586 | if (rtDWork.is_active_Fail != 0U) { |
587 | Fail(&sfEvent); |
588 | } |
589 | |
590 | sfEvent = CALL_EVENT; |
591 | rtDWork.is_A = IN_O2_normal; |
592 | rtB.bitsForTID0.O2_normal = true; |
593 | } |
594 | break; |
595 | |
596 | case IN_O2_normal: |
597 | /* During 'O2_normal': '<S3>:7' */ |
598 | /* Normal EGO sensor operation gives a reliable indication of excess oxygen in the exhaust gas, from which air/fuel mixture can be inferred. */ |
599 | if (rtU.sensors.ego > 1.2F) { |
600 | /* Transition: '<S3>:33' */ |
601 | /* The failure condition is indicated by excessive output voltage. */ |
602 | rtB.bitsForTID0.O2_normal = false; |
603 | rtDWork.is_A = IN_NO_ACTIVE_CHILD; |
604 | |
605 | /* Event: '<S3>:92' */ |
606 | sfEvent = event_INC; |
607 | if (rtDWork.is_active_Fail != 0U) { |
608 | Fail(&sfEvent); |
609 | } |
610 | |
611 | sfEvent = CALL_EVENT; |
612 | rtDWork.is_A = IN_O2_failure; |
613 | } |
614 | break; |
615 | |
616 | case IN_O2_warmup: |
617 | /* During 'O2_warmup': '<S3>:4' */ |
618 | /* The EGO sensor must come up to temperature before its data is reliable. */ |
619 | if (rtDWork.temporalCounter_i1 >= 480) { |
620 | /* Transition: '<S3>:36' */ |
621 | /* The value for sufficient warm up to operational temperature (nominally 4.8 seconds). */ |
622 | rtDWork.is_A = IN_O2_normal; |
623 | rtB.bitsForTID0.O2_normal = true; |
624 | } |
625 | break; |
626 | |
627 | default: |
628 | /* Unreachable state, for coverage only */ |
629 | rtDWork.is_A = IN_NO_ACTIVE_CHILD; |
630 | break; |
631 | } |
632 | } |
633 | |
634 | if (rtDWork.is_active_Pressure != 0U) { |
635 | /* During 'Pressure': '<S3>:2' */ |
636 | /* This state assesses the validity of the manifold absolute pressure (MAP) sensor. */ |
637 | switch (rtDWork.is_Pressure) { |
638 | case IN_fail: |
639 | /* During 'fail': '<S3>:6' */ |
640 | /* The pressure sensor (manifold, or MAP) no longer produces reliable data. */ |
641 | if ((rtU.sensors.map > 0.05F) && (rtU.sensors.map < 0.95F)) { |
642 | /* Transition: '<S3>:37' */ |
643 | /* Event: '<S3>:91' */ |
644 | sfEvent = event_DEC; |
645 | if (rtDWork.is_active_Fail != 0U) { |
646 | Fail(&sfEvent); |
647 | } |
648 | |
649 | sfEvent = -1; |
650 | rtDWork.is_Pressure = IN_normal; |
651 | } else { |
652 | /* Outputs for Function Call SubSystem: '<S3>/Pressure.map_estimate' */ |
653 | /* Simulink Function 'map_estimate': '<S3>:112' */ |
654 | rtB.es_o.map = look2_iflf_linlca(rtU.sensors.speed, |
655 | rtU.sensors.throttle, rtConstP.pooled1, rtConstP.pooled2, |
656 | rtConstP.PressureEstimation_tableData, |
657 | rtConstP.PressureEstimation_maxIndex, 18U); |
658 | |
659 | /* End of Outputs for SubSystem: '<S3>/Pressure.map_estimate' */ |
660 | } |
661 | break; |
662 | |
663 | case IN_normal: |
664 | /* During 'normal': '<S3>:5' */ |
665 | /* The manifold pressure sensor gives a reliable indication of absolute pressure (MAP). */ |
666 | if ((rtU.sensors.map > 0.95F) || (rtU.sensors.map < 0.05F)) { |
667 | /* Transition: '<S3>:31' */ |
668 | /* Event: '<S3>:92' */ |
669 | sfEvent = event_INC; |
670 | if (rtDWork.is_active_Fail != 0U) { |
671 | Fail(&sfEvent); |
672 | } |
673 | |
674 | sfEvent = -1; |
675 | rtDWork.is_Pressure = IN_fail; |
676 | } else { |
677 | rtB.es_o.map = rtU.sensors.map; |
678 | } |
679 | break; |
680 | |
681 | default: |
682 | /* Unreachable state, for coverage only */ |
683 | rtDWork.is_Pressure = IN_NO_ACTIVE_CHILD; |
684 | break; |
685 | } |
686 | } |
687 | |
688 | if (rtDWork.is_active_Throttle != 0U) { |
689 | /* During 'Throttle': '<S3>:8' */ |
690 | /* This state determines the validity of the throttle sensor signal. */ |
691 | switch (rtDWork.is_Throttle) { |
692 | case IN_fail: |
693 | /* During 'fail': '<S3>:11' */ |
694 | /* Signal levels indicate that the throttle sensor data is no longer valid. */ |
695 | if ((rtU.sensors.throttle > 3.0F) && (rtU.sensors.throttle < 90.0F)) { |
696 | /* Transition: '<S3>:42' */ |
697 | /* Event: '<S3>:91' */ |
698 | sfEvent = event_DEC; |
699 | if (rtDWork.is_active_Fail != 0U) { |
700 | Fail(&sfEvent); |
701 | } |
702 | |
703 | sfEvent = -1; |
704 | rtDWork.is_Throttle = IN_normal; |
705 | } else { |
706 | /* Outputs for Function Call SubSystem: '<S3>/Throttle.throttle_estimate' */ |
707 | /* Simulink Function 'throttle_estimate': '<S3>:107' */ |
708 | rtB.es_o.throttle = look2_iflf_linlca(rtU.sensors.speed, |
709 | rtU.sensors.map, rtConstP.pooled1, rtConstP.pooled3, |
710 | rtConstP.ThrottleEstimation_tableData, rtConstP.pooled8, 18U); |
711 | |
712 | /* End of Outputs for SubSystem: '<S3>/Throttle.throttle_estimate' */ |
713 | } |
714 | break; |
715 | |
716 | case IN_normal: |
717 | /* During 'normal': '<S3>:10' */ |
718 | /* The throttle sensor gives a reliable indication of the angle of the throttle plate. */ |
719 | if ((rtU.sensors.throttle > 90.0F) || (rtU.sensors.throttle < 3.0F)) { |
720 | /* Transition: '<S3>:38' */ |
721 | /* A failure is indicated by data which is outside the expected range, typically due to an open or short circuit. */ |
722 | /* Event: '<S3>:92' */ |
723 | sfEvent = event_INC; |
724 | if (rtDWork.is_active_Fail != 0U) { |
725 | Fail(&sfEvent); |
726 | } |
727 | |
728 | sfEvent = -1; |
729 | rtDWork.is_Throttle = IN_fail; |
730 | } else { |
731 | rtB.es_o.throttle = rtU.sensors.throttle; |
732 | } |
733 | break; |
734 | |
735 | default: |
736 | /* Unreachable state, for coverage only */ |
737 | rtDWork.is_Throttle = IN_NO_ACTIVE_CHILD; |
738 | break; |
739 | } |
740 | } |
741 | |
742 | if (rtDWork.is_active_Speed != 0U) { |
743 | /* During 'Speed': '<S3>:9' */ |
744 | /* This state infers the validity of the speed sensor data. A failure is indicated by the presence of manifold vacuum at zero speed. */ |
745 | switch (rtDWork.is_Speed) { |
746 | case IN_fail: |
747 | /* During 'fail': '<S3>:13' */ |
748 | /* The engine speed data is no longer available. */ |
749 | if (rtU.sensors.speed > 0.0F) { |
750 | /* Transition: '<S3>:43' */ |
751 | rtDWork.is_Speed = IN_NO_ACTIVE_CHILD; |
752 | |
753 | /* Event: '<S3>:91' */ |
754 | sfEvent = event_DEC; |
755 | if (rtDWork.is_active_Fail != 0U) { |
756 | Fail(&sfEvent); |
757 | } |
758 | |
759 | sfEvent = -1; |
760 | rtDWork.is_Speed = IN_normal; |
761 | } else { |
762 | /* Outputs for Function Call SubSystem: '<S3>/Speed.speed_estimate' */ |
763 | /* Lookup_n-D: '<S8>/Speed Estimation' */ |
764 | /* Simulink Function 'speed_estimate': '<S3>:119' */ |
765 | u0 = look2_iflf_linlca(rtU.sensors.throttle, rtU.sensors.map, |
766 | rtConstP.pooled2, rtConstP.pooled3, |
767 | rtConstP.SpeedEstimation_tableData, |
768 | rtConstP.SpeedEstimation_maxIndex, 17U); |
769 | |
770 | /* Saturate: '<S8>/Saturation' */ |
771 | if (u0 > 628.0F) { |
772 | rtB.es_o.speed = 628.0F; |
773 | } else if (u0 < 0.0F) { |
774 | rtB.es_o.speed = 0.0F; |
775 | } else { |
776 | rtB.es_o.speed = u0; |
777 | } |
778 | |
779 | /* End of Saturate: '<S8>/Saturation' */ |
780 | /* End of Outputs for SubSystem: '<S3>/Speed.speed_estimate' */ |
781 | } |
782 | break; |
783 | |
784 | case IN_normal: |
785 | /* During 'normal': '<S3>:12' */ |
786 | /* The speed sensor data accurately represents the engine speed. */ |
787 | if ((rtU.sensors.speed == 0.0F) && (rtU.sensors.map < 250.0F)) { |
788 | /* Transition: '<S3>:40' */ |
789 | /* Loss of a reliable speed sensor signal will indicate zero speed. This is deemed invalid when the manifold vacuum indicates otherwise. */ |
790 | rtDWork.is_Speed = IN_NO_ACTIVE_CHILD; |
791 | |
792 | /* Event: '<S3>:92' */ |
793 | sfEvent = event_INC; |
794 | if (rtDWork.is_active_Fail != 0U) { |
795 | Fail(&sfEvent); |
796 | } |
797 | |
798 | sfEvent = -1; |
799 | rtDWork.is_Speed = IN_fail; |
800 | } else { |
801 | rtB.es_o.speed = rtU.sensors.speed; |
802 | } |
803 | break; |
804 | |
805 | default: |
806 | /* Unreachable state, for coverage only */ |
807 | rtDWork.is_Speed = IN_NO_ACTIVE_CHILD; |
808 | break; |
809 | } |
810 | } |
811 | |
812 | if (rtDWork.is_active_Fail != 0U) { |
813 | Fail(&sfEvent); |
814 | } |
815 | |
816 | if (rtDWork.is_active_Fueling_Mode != 0U) { |
817 | Fueling_Mode(&sfEvent); |
818 | } |
819 | } |
820 | |
821 | /* End of Chart: '<S1>/control_logic' */ |
822 | |
823 | /* DiscreteFilter: '<S2>/Throttle Transient' */ |
824 | u0 = rtB.es_o.throttle - -0.8F * rtDWork.ThrottleTransient_states; |
825 | |
826 | /* MultiPortSwitch: '<S10>/Multiport Switch' incorporates: |
827 | * Constant: '<S10>/normal' |
828 | * Constant: '<S10>/rich' |
829 | * Constant: '<S10>/shutdown' |
830 | */ |
831 | switch (rtB.fuel_mode) { |
832 | case LOW: |
833 | rtb_MultiportSwitch = 0.0684931502F; |
834 | break; |
835 | |
836 | case RICH: |
837 | rtb_MultiportSwitch = 0.0856164396F; |
838 | break; |
839 | |
840 | default: |
841 | rtb_MultiportSwitch = 0.0F; |
842 | break; |
843 | } |
844 | |
845 | /* End of MultiPortSwitch: '<S10>/Multiport Switch' */ |
846 | |
847 | /* SwitchCase: '<S11>/Switch Case' */ |
848 | switch (rtB.fuel_mode) { |
849 | case LOW: |
850 | /* Outputs for IfAction SubSystem: '<S11>/low_mode' incorporates: |
851 | * ActionPort: '<S13>/Action Port' |
852 | */ |
853 | /* DiscreteFilter: '<S13>/Discrete Filter' incorporates: |
854 | * DiscreteIntegrator: '<S2>/Discrete Integrator' |
855 | */ |
856 | denAccum = rtDWork.DiscreteIntegrator_DSTATE - -0.7408F * |
857 | rtDWork.DiscreteFilter_states_i; |
858 | |
859 | /* Outport: '<Root>/fuel_rate' incorporates: |
860 | * DiscreteFilter: '<S13>/Discrete Filter' |
861 | * DiscreteFilter: '<S2>/Throttle Transient' |
862 | * Lookup_n-D: '<S2>/Pumping Constant' |
863 | * Product: '<S10>/Product' |
864 | * Product: '<S2>/Product' |
865 | * Product: '<S2>/Product2' |
866 | * Sum: '<S13>/Sum3' |
867 | * Sum: '<S2>/Sum' |
868 | */ |
869 | rtY.fuel_rate = ((0.01F * u0 + -0.01F * rtDWork.ThrottleTransient_states) + |
870 | rtB.es_o.speed * look2_iflf_linlca(rtB.es_o.speed, |
871 | rtB.es_o.map, rtConstP.pooled1, rtConstP.pooled3, |
872 | rtConstP.PumpingConstant_tableData, rtConstP.pooled8, 18U) * rtB.es_o.map) |
873 | * rtb_MultiportSwitch + (8.7696F * denAccum + -8.5104F * |
874 | rtDWork.DiscreteFilter_states_i); |
875 | |
876 | /* Update for DiscreteFilter: '<S13>/Discrete Filter' */ |
877 | rtDWork.DiscreteFilter_states_i = denAccum; |
878 | |
879 | /* End of Outputs for SubSystem: '<S11>/low_mode' */ |
880 | break; |
881 | |
882 | case RICH: |
883 | /* Outputs for IfAction SubSystem: '<S11>/rich_mode' incorporates: |
884 | * ActionPort: '<S14>/Action Port' |
885 | */ |
886 | /* Outport: '<Root>/fuel_rate' incorporates: |
887 | * DiscreteFilter: '<S14>/Discrete Filter' |
888 | */ |
889 | rtY.fuel_rate = 0.2592F * rtDWork.DiscreteFilter_states; |
890 | |
891 | /* Update for DiscreteFilter: '<S14>/Discrete Filter' incorporates: |
892 | * DiscreteFilter: '<S2>/Throttle Transient' |
893 | * DiscreteIntegrator: '<S2>/Discrete Integrator' |
894 | * Lookup_n-D: '<S2>/Pumping Constant' |
895 | * Product: '<S10>/Product' |
896 | * Product: '<S2>/Product' |
897 | * Product: '<S2>/Product2' |
898 | * Sum: '<S14>/Sum2' |
899 | * Sum: '<S2>/Sum' |
900 | */ |
901 | rtDWork.DiscreteFilter_states = (((0.01F * u0 + -0.01F * |
902 | rtDWork.ThrottleTransient_states) + rtB.es_o.speed * look2_iflf_linlca |
903 | (rtB.es_o.speed, rtB.es_o.map, rtConstP.pooled1, rtConstP.pooled3, |
904 | rtConstP.PumpingConstant_tableData, rtConstP.pooled8, 18U) * rtB.es_o.map) |
905 | * rtb_MultiportSwitch + rtDWork.DiscreteIntegrator_DSTATE) - -0.7408F * |
906 | rtDWork.DiscreteFilter_states; |
907 | |
908 | /* End of Outputs for SubSystem: '<S11>/rich_mode' */ |
909 | break; |
910 | |
911 | default: |
912 | /* Outputs for IfAction SubSystem: '<S11>/disabled_mode' incorporates: |
913 | * ActionPort: '<S12>/Action Port' |
914 | */ |
915 | /* Outport: '<Root>/fuel_rate' incorporates: |
916 | * Constant: '<S12>/shutoff' |
917 | */ |
918 | rtY.fuel_rate = 0.0F; |
919 | |
920 | /* End of Outputs for SubSystem: '<S11>/disabled_mode' */ |
921 | break; |
922 | } |
923 | |
924 | /* End of SwitchCase: '<S11>/Switch Case' */ |
925 | |
926 | /* Switch: '<S2>/hold integrator' incorporates: |
927 | * Constant: '<S2>/Constant' |
928 | * Constant: '<S2>/Constant2' |
929 | * Constant: '<S2>/Oxygen Sensor Switching Threshold' |
930 | * Constant: '<S6>/Constant' |
931 | * DataTypeConversion: '<S2>/Data Type Conversion' |
932 | * Logic: '<S2>/Logic1' |
933 | * Lookup_n-D: '<S2>/Ramp Rate Ki' |
934 | * Product: '<S2>/Product1' |
935 | * RelationalOperator: '<S2>/Relational Operator1' |
936 | * RelationalOperator: '<S2>/Relational Operator3' |
937 | * Sum: '<S2>/Sum1' |
938 | */ |
939 | if (rtB.bitsForTID0.O2_normal && (rtB.fuel_mode == LOW)) { |
940 | rtb_MultiportSwitch = ((real32_T)(rtB.es_o.ego <= 0.5F) - 0.5F) * |
941 | look2_iflf_linlca(rtB.es_o.speed, rtB.es_o.map, |
942 | rtConstP.RampRateKi_bp01Data, |
943 | rtConstP.RampRateKi_bp02Data, |
944 | rtConstP.RampRateKi_tableData, |
945 | rtConstP.RampRateKi_maxIndex, 6U); |
946 | } else { |
947 | rtb_MultiportSwitch = 0.0F; |
948 | } |
949 | |
950 | /* End of Switch: '<S2>/hold integrator' */ |
951 | |
952 | /* Update for DiscreteIntegrator: '<S2>/Discrete Integrator' */ |
953 | rtDWork.DiscreteIntegrator_DSTATE += 0.01F * rtb_MultiportSwitch; |
954 | |
955 | /* Update for DiscreteFilter: '<S2>/Throttle Transient' */ |
956 | rtDWork.ThrottleTransient_states = u0; |
957 | |
958 | /* End of Outputs for SubSystem: '<Root>/fuel_rate_control' */ |
959 | } |
960 | |
961 | /* Model initialize function */ |
962 | void fuel_rate_control_initialize(void) |
963 | { |
964 | /* Registration code */ |
965 | |
966 | /* block I/O */ |
967 | { |
968 | rtB.fuel_mode = LOW; |
969 | } |
970 | |
971 | /* SystemInitialize for Atomic SubSystem: '<Root>/fuel_rate_control' */ |
972 | /* SystemInitialize for Chart: '<S1>/control_logic' |
973 | * |
974 | * Block description for '<S1>/control_logic': |
975 | * Stateflow diagram to determine control system operating mode |
976 | */ |
977 | rtB.es_o.throttle = 0.0F; |
978 | rtB.es_o.speed = 0.0F; |
979 | rtB.es_o.ego = 0.0F; |
980 | rtB.es_o.map = 0.0F; |
981 | rtB.fuel_mode = LOW; |
982 | |
983 | /* End of SystemInitialize for SubSystem: '<Root>/fuel_rate_control' */ |
984 | } |
985 | |
986 | /* |
987 | * File trailer for generated code. |
988 | * |
989 | * [EOF] |
990 | */ |
991 | |