Advanced fuel control options
This summarizes my efforts to flush out all the remaining key tables associated with fuel control. My original intent was simply to work out the tables that affect IPW during startup, but it turned out that I had to work out everything to understand the startup IPW stuff. So as usual, this effort morphed from a few day effort into a month long effort. Some of this has already been covered by jcsbanks, Bez, and Mattjin. I've put it all in one place, added detail, and made some corrections to what appear to be a few inaccuracies in the interpretation of the code.
Before going into the gory detail, I'll briefly describe the four different fuel pulse widths (FPWs) that are generated in the ROM code.
1) Cranking primer pulse - This is a single async pulse that is generated when the starter is engaged.
2) Cranking fuel pulse width - This is fuel pulse width that controls sync IPW while the starter is cranking
3) Main sync fuel pulse width - It is made up of four components. The two important ones are the base sync fuel pulse width contribution previously described by jcsbanks and a sync accel fuel pulse with contribution. The sync accel contribution keys off of an increasing load.
4) Async accel fuel pulse width - This is the async accel fuel pulse width previously described by Bez. It is a tip-in enrichment that keys off of a change in TPS.
I intend to write a patch that allows each of these contributions to be logged. This will allow a much better understanding of how all these contributions affect the final calculated IPW. In the mean time, each of the fuel pulse widths are described below. I have also included the tables for all these items for the 88590015 ROM. As usual, I hope people can help in getting these translated to other ROMs. (Note that some of these tables are listed in other threads and may or may not be accurately represented in the other threads.) Eventually, I will see to it that these tables get incorporated into a future version of ECUFlash.
Lastly, there are a few aspects of the fuel control routines that I want to study further that may result in the interpretation of a few of these tables changing a bit. It should be nothing drastic though.
1) Cranking primer pulse
This is a single pulse that is generated when the starter is engaged. The value is calculated from a 2D table vs coolant temperature and is the "Startup Enrichment IPW Adder" that I posted on EvoM a while ago. The value from this table is added to the injector latency and then sent to the injectors. For completeness, I'll list the table and scaling here, but with an updated name:
Code:
<scaling name="TimeInjCranking" units="ms" toexpr="x*0.008" frexpr="x/0.008" format="%.1f" min="0" max="500" inc="1" storagetype="uint16" endian="big"/>
<table name="Cranking Primer Initial Pulse" category="Fuel" type="2D" level="2" scaling="TimeInjCranking" address="52b2">
<table name="Coolant Temperature" type="Y Axis" elements="9" scaling="Temp" address="6ff8"/>
</table>
2) Cranking fuel pulse width
Two different cranking FPWs are calculated. One is used while the starter is engaged, and the other appears to be momentarily used just after the starter is disengaged. I will only cover the value that is used while the starter is engaged. The formula for the cranking FPW while the starter is engaged is:
CFPW = constant*(TCOMP/128)*(CRANKINGTIMECOMP/128)*(UCOMP/128)*Baro + InjectorLatency
TCOMP = 2D compensation table vs coolant temp
CRANKINGTIMECOMP = 2D compensation table vs the length of time that the starter has been engaged
UCOMP = 2D compensation vs an unknown time interval. A measure of the number of times a specific subroutine has been called. Probably shouldn't be adjusted, so I am not including a definition for this table.
Baro = barometric pressure.
The coolant temp compensation and cranking time compensation for the 88590015 ROM are:
Code:
<scaling name="TimeTCOMPCrankingHack" units="Approximate ms" toexpr="x*0.9" frexpr="x/0.9" format="%.1f" min="0" max="500" inc="1" storagetype="uint8" endian="big"/>
<table name="Initial Cranking IPW vs Coolant Temp" category="Fuel" address="6040" type="2D" level="2" scaling="TimeTCOMPCrankingHack">
<table name="Engine Temp" address="7014" type="Y Axis" elements="11" scaling="Temp"/>
</table>
<scaling name="Percent (128)" units="Percent (%)" toexpr="x/1.28" frexpr="x*1.28" format="%.0f" min="0" max="100" inc="1" storagetype="uint8" endian="big"/>
<table name="Cranking IPW Compensation vs Time" category="Fuel" type="2D" level="2" scaling="Percent (128)" address="323E">
<table name="Time Since Engaging Starter (sec)" type="Static Y Axis" elements="20">
<data>0.000</data>
<data>0.022</data>
<data>0.044</data>
<data>0.066</data>
<data>0.088</data>
<data>0.110</data>
<data>0.132</data>
<data>0.154</data>
<data>0.176</data>
<data>0.198</data>
<data>0.220</data>
<data>0.242</data>
<data>0.264</data>
<data>0.286</data>
<data>0.308</data>
<data>0.330</data>
<data>0.352</data>
<data>0.374</data>
<data>0.396</data>
<data>0.418</data>
</table>
</table>
3) Main synchronous fuel pulse width
This is the main fuel pulse. There are four contributions to this FPW (plus injector latency). The main fuel pulse is calculated from:
MFPW = BFPW + SyncLoadAccel - SyncLoadDecel + SyncLoadChangeIdle + InjectorLatency
Each of the four contributions are calculated from a base value that I call "injector flow per Hz". This is given by:
IFPHz = MAFScale*MAFComp*AirDensTweak*InjScale*InjMult
MAFScale = the 2D MAF scaling table that everyone knows.
MAFComp = the 2D MAF compensation table that everyone knows. Its just another multiplier based on MAF Hz (like the MAF scaling table).
AirDensTweak = 3D table vs MAF Hz and relative air volume. Mislabeled in early versions of ECUFlash. It appears to be there to handle potential MAF misbehavior at low airflow rates.
InjScale = the 1D injector scaling table that everyone knows
InjMult = a 1D table that Mitsubishi probably intended to be used to compensate for fuels that have different AFR requirements (e.g. gasoline vs E85). The built-in map switching code can select between an array of different values.
The tables associated with this base value are all listed in ECUFlash for the 88590015 ROM, but for completeness, I'll include them here again:
Code:
<table name="Airflow/Hz Raw Scaling" category="Fuel" type="2D" level="2" scaling="uint8" address="2d06">
<table name="MAF Hz" type="Y Axis" elements="21" scaling="MAFHz" address="6da4"/>
</table>
<table name="Airflow/Hz Offset Raw" category="Fuel" type="1D" level="2" scaling="uint16" address="1112"/>
<table name="MAF Compensation" category="Fuel" type="2D" level="2" scaling="uint8" address="2d22">
<table name="MAF Hz" type="Y Axis" elements="21" scaling="MAFHz" address="6da4"/>
</table>
<scaling name="AirTempBaroFactor" units="Fraction" toexpr="x/48" frexpr="x*48" format="%.2f" min="0" max="2" inc="0.02" storagetype="uint16" endian="big"/>
<scaling name="AirTempBaroCorrection" units="Fraction" toexpr="x/128" frexpr="x*128" format="%.2f" min="0" max="2" inc="0.02" storagetype="uint8" endian="big"/>
<table name="Airflow/Hz Baro and Air Temp Compensation" category="Fuel" type="3D" level="2" swapxy="true" scaling="AirTempBaroCorrection" address="2d51">
<table name="Rel Air Volume (20C, 1 bar)" type="X Axis" elements="4" scaling="AirTempBaroFactor" address="6d92"/>
<table name="MAF Hz" type="Y Axis" elements="9" scaling="MAFHz" address="6dd8"/>
</table>
<table name="Injector Size Scaling" category="Fuel" type="1D" scaling="InjectorScaling" address="1106"/>
The four contributions
A) Base fuel pulse - This is the contribution that jcsbanks has described. It takes over after the starter has been disengaged. The equation for this contribution is given by:
BFPW = constant*[(STFT/256 + X + Y + 128)/512]*(MAFCompW/128)*
[(MasterLoad {+/- K*DeltaMasterLoad})/2048]*(AFRMAP/128)*(CAM/128)*
[(FFFF6F32+384)/512]*[(2*Startup_Mult+128)/128]*
(Z/128)*Baro*AirDensityFactor*(BFPW_Mult/128)*IFPHz
STFT = STFT, 0 during open loop driving
X = to be worked out, related to LTFT low, may be non-zero during open loop driving
Y = to be worked out, 0 during open loop driving
AFRMAP = AFRMAP from fuel table lookup routine
MAFCompW = MAF signal compensation vs coolant temp, 128 at normal operating temperature.
MasterLoad = master load variable, calculated from MAF signal
DeltaMasterLoad = absolute value of the change in master load, only used when load < 70, +/- based on accel/decel.
K is either 2 or 3 depending on a flag.
CAM = some factor related to camshaft timing, probably 128 during normal conditions, needs to be worked out.
FFFF6F32 = Have yet to work it out. Logging shows it to mostly be 128, but can vary between ~100 and ~150.
Startup_Mult = an average of two BFPW startup enrichment tables. These add a bit of enrichment for the first few moments after the engine has fired up. Decays to zero over a period of a few seconds after starter is disengaged.
Z = to be worked out, always 128.
Baro = barometric pressure
AirDensityFactor = 2D relative air density vs IAT table
BFPW_Mult = 128 under normal conditions, details to be worked out
IFPHz = see equation above
The additional tables for the BFPW contribution for the 88590015 ROM are:
Code:
<scaling name="Percent64(8-bit)" units="%" toexpr="100*x/64" frexpr="64*x/100" format="%.0f" min="0" max="400" inc="1" storagetype="uint8" endian="big"/>
<table name="BFPW Startup Comp vs Coolant Temp #1" category="Fuel" address="3146" type="2D" level="2" scaling="Percent64(8-bit)">
<table name="Coolant Temp" address="6ff8" type="Y Axis" elements="9" scaling="Temp"/>
</table>
<table name="BFPW Startup Comp vs Coolant Temp #2" category="Fuel" address="3156" type="2D" level="2" scaling="Percent64(8-bit)">
<table name="Coolant Temp" address="6ff8" type="Y Axis" elements="9" scaling="Temp"/>
</table>
<table name="MAF Comp vs Coolant Temp #1" category="Fuel" address="3136" type="2D" level="1" scaling="uint8">
<table name="Coolant Temp" address="6ff8" type="Y Axis" elements="9" scaling="Temp"/>
</table>
<table name="MAF Comp vs Coolant Temp #2" category="Fuel" address="3126" type="2D" level="1" scaling="uint8">
<table name="Coolant Temp" address="6ff8" type="Y Axis" elements="9" scaling="Temp"/>
</table>
<scaling name="AirDensComp" units="Air Density Correction" toexpr="x/129" frexpr="x/129" format="%.3f" min="0" max="2" inc="0.01" storagetype="uint8" endian="big"/>
<table name="Air Density Compensation for Load And IPW" category="Misc" type="2D" level="2" scaling="AirDensComp" address="30fe">
<table name="MAF Air Temp" type="Y Axis" elements="8" scaling="Temp" address="714a"/>
</table>
B) Sync Load Accel - This is a synchronous acceleration enrichment adder that is driven by an increasing load. The contribution is designed to rapidly decay out after load is no longer increasing. The equation for this contribution is:
SyncLoadAccel = constant*(DeltaMasterLoadPos/2048)*(TCOMP/128)*(RPMCOMP/128)*Baro*IFPHz
DeltaMasterLoadPos = increase in master load, zero when load is steady
TCOMP = 2D table vs coolant temp, scaling is x/128. There are two tables. Factors that control when each table is used have not been determined.
RPMCOMP = 2D table vs RPM, scaling is x/128
Baro = barometric pressure
IFPHz = see description above
The tables for the SyncLoadAccel adder for the 88590015 ROM are:
Code:
<scaling name="Mult128" units="Factor" toexpr="x/128" frexpr="x/128" format="%.2f" min="0" max="5" inc="0.02" storagetype="uint8" endian="big"/>
<table name="Sync Load Accel Compensation vs RPM" category="Fuel" type="2D" scaling="Mult128" level="2" address="3278">
<table name="RPM" type="Y Axis" elements="15" scaling="RPM" address="6c26"/>
</table>
<table name="Sync Load Accel Compensation vs Coolant Temp Table #1" category="Fuel" type="2D" level="2" scaling="Mult128" address="6566">
<table name="Coolant Temp" type="Y Axis" elements="8" scaling="Temp" address="6fde"/>
</table>
<table name="Sync Load Accel Compensation vs Coolant Temp Table #2" category="Fuel" type="2D" level="2" scaling="Mult128" address="326a">
<table name="Coolant Temp" type="Y Axis" elements="8" scaling="Temp" address="6fde"/>
</table>
C) Sync Load Decel Subtractor - Subtracts fuel during rapid load reduction. I believe that its purpose is to transition to a fuel cut mode. The equation for this contribution is:
SyncLoadDecel = constant*DeltaMasterLoadNeg/2048)*LCOMP*TCOMP*(RPMCOMP/128)*Baro*IFPHz
DeltaLoadMasterNeg = decrease in master load, zero when load is steady
LCOMP = 2D table vs load
TCOMP = 2D table vs coolant temp
RPMCOMP = 2D table vs RPM,
Baro = barometric pressure
IFPHz = see description above
The tables for the SyncLoadDecel subtractor for the 88590015 ROM are:
Code:
<table name="Decel IPW Subtraction Comp vs RPM" category="Fuel" address="3350" type="2D" level="2" scaling="Mult128">
<table name="RPM" address="6b7a" type="Y Axis" elements="10" scaling="RPM"/>
</table>
<table name="Decel IPW Subtraction Comp vs Load" category="Fuel" address="3360" type="2D" level="2" scaling="Mult128">
<table name="Load" address="6cba" type="Y Axis" elements="14" scaling="Load"/>
</table>
<table name="Decel IPW Subtraction Comp vs Coolant Temp" category="Fuel" address="3342" type="2D" level="2" scaling="Mult128">
<table name="Coolant Temp" address="6fde" type="Y Axis" elements="8" scaling="Temp"/>
</table>
D) Sync Load Change Idle - It appears that the purpose of this contribution is to transition from a fuel cut mode to the target IPW when rpms drop below 1000 rpm. Increasing and decreasing load can affect the contribution and after a set period of time, the contribution goes away regardless of whether load is changing. The contribution appears to be very small and is definitely not important for performance tuning. The equation for it is:
SyncLoadChangeIdle = constant*(DeltaMasterLoad/2048)*UCOMP*TCOMP*IFPHz
DeltaMasterLoad = Different than other DeltaLoad variables. Don't fully understand this yet
UCOMP = 2D table vs a RAM variable that I do not yet understand
TCOMP = 2D table vs coolant temp, scaling is x/128
IFPHz = see description above
The tables for these items in the 88590015 ROM are:
Code:
<table name="Sync Load Change Idle Compensation vs Time Below 1000 rpm" category="Fuel" type="2D" level="2" scaling="Mult128" address="6b3e">
<table name="Unknown" type="Y Axis" elements="21" scaling="uint16" address="8246"/>
</table>
<table name="Sync Load Change Idle Compensation vs Coolant Temp" category="Fuel" type="2D" level="2" scaling="Mult128" address="6b30">
<table name="Coolant Temp" type="Y Axis" elements="8" scaling="Temp" address="6fde"/>
</table>
4) Async TPS accel enrichment
This is the async accel that Bez and jcsbanks have mentioned many times, and as most people know, it is an async throttle tip-in enrichment adder to the fuel contribution. After finding a few inaccuracies in what Bez had posted, I decided to also work out some scalings. The equation for the async accel contribution is:
AsyncAccel = constant*TPSDeltaMULT*(AAStartupMult*TCOMP + RPMCOMP) + InjectorLatency
TPSDeltaMULT = 2D table vs TPSDelta
TCOMP = 2D table vs coolant temp compensation. There are two tables.
RPMCOMP = 2D table vs RPM compensation.
The definitions for these tables plus the other items that control async accel for the 88590015 ROM are listed below.
Code:
<table name="Async Accel Pause Period" category="Fuel" address="1254" type="1D" level="2" scaling="uint16"/>
<table name="Async Accel Min TPS Delta" category="Fuel" address="1256" type="1D" level="2" scaling="ThrottlePercentage"/>
<scaling name="AsyncAccelMaxFPW" units="ms" toexpr="x*32*0.008" frexpr="x/(32*0.008)" format="%.2f" min="0" max="20" inc="0.02" storagetype="uint16" endian="big"/>
<table name="Async Accel Max Pulsewidth" category="Fuel" address="1258" type="1D" level="2" scaling="AsyncAccelMaxFPW"/>
<scaling name="Mult128-16" units="Multiplication Factor" toexpr="x/128" frexpr="x/128" format="%.2f" min="0" max="5" inc="0.02" storagetype="uint16" endian="big"/>
<table name="Async Accel Max Total Contribution During Accel Period" category="Fuel" address="125A" type="1D" level="2" scaling="Mult128-16"/>
<table name="Async Accel Mult to Coolant Temp Adder During 5 Sec After Startup" category="Fuel" address="125c" type="1D" level="2" scaling="Mult128-16"/>
<table name="Async Accel Above TPS Enrichment Cutoff vs RPM" category="Fuel" address="32c6" type="2D" level="2" scaling="ThrottlePercentage8">
<table name="X" address="6c26" type="Y Axis" elements="10" scaling="RPM"/>
</table>
<table name="Async Accel Multiplier vs TPS Delta" category="Fuel" address="32b6" type="2D" level="2" scaling="Mult128">
<table name="TPS Delta" type="Static Y Axis" elements="9">
<data>0.0%</data>
<data>1.6%</data>
<data>3.1%</data>
<data>4.7%</data>
<data>6.3%</data>
<data>7.8%</data>
<data>9.4%</data>
<data>11.0%</data>
<data>12.5%</data>
</table>
</table>
<table name="Async Accel vs RPM Adder" category="Fuel" address="32e4" type="2D" level="2" scaling="uint8">
<table name="RPM" address="6c26" type="Y Axis" elements="15" scaling="RPM"/>
</table>
<table name="Async Accel vs Coolant Temp Adder (Main)" category="Fuel" address="32d6" type="2D" level="2" scaling="uint8">
<table name="Coolant Temp" address="6fde" type="Y Axis" elements="8" scaling="Temp"/>
</table>
<table name="Async Accel vs Coolant Temp Adder (Alt)" category="Fuel" address="6558" type="2D" level="2" scaling="uint8">
<table name="Coolant Temp" address="6fde" type="Y Axis" elements="8" scaling="Temp"/>
</table>