FreeEMS  0.2.0-SNAPSHOT-282-g9efc524
fuelAndIgnitionCalcs.c
Go to the documentation of this file.
1 /* FreeEMS - the open source engine management system
2  *
3  * Copyright 2008-2013 Fred Cooke
4  *
5  * This file is part of the FreeEMS project.
6  *
7  * FreeEMS software is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * FreeEMS software is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with any FreeEMS software. If not, see http://www.gnu.org/licenses/
19  *
20  * We ask that if you make any changes to this file you email them upstream to
21  * us at admin(at)diyefi(dot)org or, even better, fork the code on github.com!
22  *
23  * Thank you for choosing FreeEMS to run your engine!
24  */
25 
26 
27 /** @file
28  *
29  * @ingroup measurementsAndCalculations
30  *
31  * @brief Fuel and ignition calculations.
32  *
33  * This file contains all of the main fuel and ignition calculations based
34  * upon the variables that we have already determined in previous stages.
35  */
36 
37 
38 #define FUELANDIGNITIONCALCS_C
39 #include "inc/freeEMS.h"
40 #include "inc/utils.h"
41 #include "inc/locationIDs.h"
42 #include "inc/tableLookup.h"
44 
45 
46 /**
47  * Final fuel and ignition calculations. Using a variety of primary algorithms
48  * calculate a base pulsewidth and then apply various corrections to it such as
49  * injector dead time, transient fuel correction, engine temperature enrichment
50  * and per cylinder trims. The ignition timing and fuel injection timing are
51  * also determined here, as are the various limiters and cuts.
52  */
54  unsigned short airInletTemp = CoreVars->IAT; /* All except MAF use this. */
55  /* Determine the type of air flow data */
57  /* Look up VE with RPM and MAP */
59  /* This won't overflow until 512kPa or about 60psi of boost with 128% VE. */
60  DerivedVars->AirFlow = ((unsigned long)CoreVars->MAP * DerivedVars->VEMain) / VE(100);
61  /* Result is 450 - 65535 always. */
63  /* Look up Airflow with RPM and TPS */
64  DerivedVars->AirFlow = lookupMainTable(CoreVars->RPM, CoreVars->TPS, AirflowTableLocationID); /* Tuned air flow without density information */
66  DerivedVars->AirFlow = CoreVars->MAF; /* Just fix temperature at appropriate level to provide correct Lambda */
67  /// @todo TODO figure out what the correct "temperature" is to make MAF work correctly!
68  airInletTemp = DEGREES_C(20); // Room temperature?
70  /* Look up VE with RPM and MAP */
72  /* This won't overflow until 512kPa or about 60psi of boost with 128% VE. */
73  KeyUserDebugs.speedDensityAirFlow = ((unsigned long)CoreVars->MAP * DerivedVars->VEMain) / VE(100);
74 
75  /* Look up Airflow with RPM and TPS */
76  KeyUserDebugs.alphaNAirFlow = lookupMainTable(CoreVars->RPM, CoreVars->TPS, AirflowTableLocationID); /* Tuned air flow without density information */
77 
78  KeyUserDebugs.blendAlphaNPercent = lookupTwoDTableUS((twoDTableUS*)&TablesA.SmallTablesA.blendVersusRPMTable, CoreVars->RPM);
79 
82 
83  DerivedVars->AirFlow = safeAdd(airflowSD, airflowAN);
84  }else{ /* Default to no fuel delivery and error */
85  DerivedVars->AirFlow = 0;
86  }
87 
88 
89  /* This won't overflow until well past 125C inlet, 1.5 Lambda and fuel as dense as water */
91  /* Result is 7500 - 60000 always. TODO clean up the last item on the above line */
92 
93  /* Divisors for air inlet temp and pressure :
94  * #define airInletTempDivisor 100
95  * #define airPressureDivisor 100
96  * cancel each other out! all others are used. */
97 
99 
100  /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
101 
102 
103 
104 
105  /*&&&&&&&&&&&&&&&&&&&&&&&&&&&& Apply All Corrections PCFC, ETE, IDT, TFC etc &&&&&&&&&&&&&&&&&&&&&&&&&&&*/
106 
107  /* Apply the corrections after calculating */
110 
111 
112 // unsigned char channel; // the declaration of this variable is used in multiple loops below.
113 //
114 // /* "Calculate" the individual fuel pulse widths */
115 // for(channel = 0; channel < INJECTION_CHANNELS; channel++){ /// @todo TODO make injector channels come from config, not defines.
116 // /* Add or subtract the per cylinder fuel trims */
117 // unsigned short channelPW;
118 // channelPW = safeScale(DerivedVars->EffectivePW, TablesB.SmallTablesB.perCylinderFuelTrims[channel]);
119 //
120 // /* Add on the IDT to get the final value and put it into the array */
121 // //outputEventPulseWidthsMath[channel] = safeAdd(channelPW, DerivedVars->IDT); do not re-enable this without fixing it properly...
122 // }
123 
124  // Make sure we don't have a PW if PW is supposed to be zero, ie, zero the IDT as well.
125  if(!(DerivedVars->EffectivePW)){
126  DerivedVars->IDT = 0; // This also makes fuel and electrical duty work consistently in external apps.
127  }
128 
129  /* Reference PW for comparisons etc */
131  /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
132 
133 /// @todo accumulate errors such that we know what sort of PW WOULD have been requested and enable a "over duty cut" to protect boosted users with insufficient injector size on cold nights
134 
135 /// TODO @todo FIXME part of to schedule or not to schedule should be : (masterPulseWidth > injectorMinimumPulseWidth)
136 // IE, NOT in the decoders... KISS in the decoders. This is a hangover from (very) early decoder dev
137 
138 // for(channel = 0;channel < INJECTION_CHANNELS;channel++){ /// @todo TODO make injector channels come from config, not defines.
139  //injectorMainAdvances[channel] = IDT blah blah.
140 // }
141 
142  /* "Calculate" the nominal total pulse width before per channel corrections */
143  masterPulseWidth = safeAdd((DerivedVars->EffectivePW / fixedConfigs1.schedulingSettings.numberOfInjectionsPerEngineCycle), DerivedVars->IDT); // div by number of injections per cycle, configured above
144  // but requires to know how big a cycle is, 1/4 1, 1/2, etc
145 
146  // Note, conversions to address and then pointer are necessary to avoid error on direct cast
147  // Cuts and limiters TODO move these to their own special place?
148  // TODO Make source of threshold either struct or temp based curve for these
149 
151  unsigned short confirmedReenableThreshold = fixedConfigs1.cutAndLimiterSettings.IgnitionRPM.reenableThreshold;
152  if(confirmedReenableThreshold >= fixedConfigs1.cutAndLimiterSettings.IgnitionRPM.disableThreshold){
153  confirmedReenableThreshold = fixedConfigs1.cutAndLimiterSettings.IgnitionRPM.disableThreshold / 2;
154  }
156  ((ignitionCutFlags *)&KeyUserDebugs.ignitionCuts)->IgnitionRPM = 1;
157  }else if(CoreVars->RPM < confirmedReenableThreshold){
158  ((ignitionCutFlags *)&KeyUserDebugs.ignitionCuts)->IgnitionRPM = 0;
159  }
160  }
161 
163  unsigned short confirmedReenableThreshold = fixedConfigs1.cutAndLimiterSettings.InjectionRPM.reenableThreshold;
164  if(confirmedReenableThreshold >= fixedConfigs1.cutAndLimiterSettings.InjectionRPM.disableThreshold){
165  confirmedReenableThreshold = fixedConfigs1.cutAndLimiterSettings.InjectionRPM.disableThreshold / 2;
166  }
168  ((injectionCutFlags *)&KeyUserDebugs.injectionCuts)->InjectionRPM = 1;
169  }else if(CoreVars->RPM < confirmedReenableThreshold){
170  ((injectionCutFlags *)&KeyUserDebugs.injectionCuts)->InjectionRPM = 0;
171  }
172  }
173 
174  // TODO add time based lock out as well as threshold based as threshold could re-enable too quickly
176  unsigned short confirmedReenableThreshold = fixedConfigs1.cutAndLimiterSettings.OverBoost.reenableThreshold;
177  if(confirmedReenableThreshold >= fixedConfigs1.cutAndLimiterSettings.OverBoost.disableThreshold){
178  confirmedReenableThreshold = fixedConfigs1.cutAndLimiterSettings.OverBoost.disableThreshold / 2;
179  }
183  }else if(CoreVars->MAP < confirmedReenableThreshold){
184  ((injectionCutFlags *)&KeyUserDebugs.injectionCuts)->InjOverBoost = 0;
185  ((ignitionCutFlags *)&KeyUserDebugs.ignitionCuts)->IgnOverBoost = 0;
186  }
187  }
188 }