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) */
52BlockIO rtB;
53
54/* Block states (default storage) */
55D_Work rtDWork;
56
57/* External inputs (root inport signals with default storage) */
58ExternalInputs rtU;
59
60/* External outputs (root outports fed by signals with default storage) */
61ExternalOutputs rtY;
62
63/* Real-time model */
64RT_MODEL rtM_;
65RT_MODEL *const rtM = &rtM_;
66
67/* Forward declaration for local functions */
68static void Fueling_Mode(const int32_T *sfEvent);
69static void Fail(int32_T *sfEvent);
70real32_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' */
172static 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' */
391static 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 */
494void 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 */
962void 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