Pulse Width Calculations and Variable/Table/Function analysi

Official FreeEMS vanilla firmware development, the heart and soul of the system!
User avatar
Fred
Moderator
Posts: 15431
Joined: Tue Jan 15, 2008 2:31 pm
Location: Home sweet home!
Contact:

Pulse Width Calculations and Variable/Table/Function analysi

Post by Fred »

OK, I'm going to try to break it down a bit :
  1. Reading and averaging ADCs intelligently (one function with parameters for all inputs and possibly all vars to ensure minimal duplication)
  2. Use of transfer functions and tables to convert raw ADC readings to actual temperatures and pressures etc
  3. Ranges of inputs and outputs as it relates to maths and intermediate values etc
  4. Which correction tables are going to be included from the start and how they will be included
  5. How to do a master fuel trim setting
  6. How to combine the things we know about flow and combustion volume (rotaries/etc also, hence not cylinder) into fuel demand
  7. Other things?
ADCs :
  • The ADCs are all to be read for each and every combustion event, and also on a timeout for when the engine isn't running.
  • Some smoothing of the raw readings would be good to be consistent across all inputs (the smoothing should be tunable per input though)
  • Should the smoothing be done in the ISR where the readings are taken or later in the fuel calcs section. If the former, needs to be fast, if the latter, we will lose data points inconsistently with RPM.
  • Transfer functions should be in the form of a free table with appropriate ranges for each type of sensor and at an appropriate size to create a smooth enough curve
  • OR should some of them be done with mathematic formulas with appropriate coefficients to manipulate the shape?
  • The variables we need should emerge from this step appropriately scaled to make best use of the range they have and bit space they have
Variable ranges :

I've approached this from the perspective of minimising the range of sensor to realistic figures for all engines, and maximising that range inside the 16 bit variable. This approach could be wrong in that it means you can only put two 16 bit vars together before you need to divide back down again to avoid 32bit overflow. Thoughts?
  • RPM = Revolutions Per Minute : 0 - 32768 RPM (0.5 RPM (/2)) [Will going with half rpm increments and 32k complicate the maths?]
  • CHT = Coolant / Head Temperature : 0.0 - 655.35 K (0.01 Kelvin (/100)) [No one ever gets their engine hotter or colder than that, including air cooled guys. We are better off in degrees K so that we don't have negative numbers. Air coolers say 600F is the max they want to be able to watch.]
  • MAP = Manifold Absolute Pressure : 0.0 - 655.35 (0.01 kPa (/100)) [Up to ~80psi of boost. Going with a /2 as well would limit max boost to 33psi which is marginal for a serious setup.]
  • AAP = Atmospheric Absolute Barometric Pressure : 0.0 - 655.35 kPa (0.01 kPa (/100)) [Use same range as normal MAP despite not needing it.]
  • IAT= Inlet Air Temperature : 0.0 - 655.35 K (0.01 Kelvin (/100)) [Be consistent with CHT despite never needing those figures.]
  • MAT = Manifold Air Temperature : 0.0 - 655.35 K (0.01 Kelvin (/100)) [Corrected IAT, calculated from other values and used in the actual calculation.]
  • TPS = Throttle Position Sensor : 0.0 - 102.398438 % (0.0015625 % (/640)) [This is equivalent to dividing the raw reading by 10. IE, bit shifted 6 places to the right and divided by 10 for the value.]
  • EGO = Exhaust Gas Oxygen : 0.0 - 1.99996948 Lambda (0.0000305175781 Lambda (/32768)) [Not using AFR keeps it compatible with all fuel types.]
  • LT = Lambda Target : 0.0 - 1.99996948 lambda (0.0000305175781 (/32768)) [Not using AFR keeps it compatible with all fuel types.]
  • VE = Volumetric Efficiency : 0.0 - 127.998047 % (0.001953125 % (/512) [We want this close to 100% for the maximum range, but with some headroom.]
  • PL = Percent Load : 0.0 - 655.35 % (0.01% (/100)) [Needs to match largest load type (MAP, TPS, MAF, etc)]
  • MFT = Master Fuel Trim : -12.8 - 12.7 % (0.1% (/10)) [The range here doesn't need to be particularly large, perhaps +/- 10% or so and 8 bits of resolution. Is this enough?]
  • PCFT = Per Cylinder Fuel Trim : -12.8 - 12.7 % (0.1% (/10)) [The range here doesn't need to be particularly large, perhaps +/- 10% or so and 8 bits of resolution. This is enough.]
  • FPW = Fuel Pulse Width : 0.0 OR Minimum - Maximum OR 52428us (0.8us (*0.8)) [This one is fixed for now, though we COULD reduce or increase the resolution and the opposite for range if we wanted, though it should never ever be needed. It is OK for the calculation to output something between 0 and min and it will be pushed back to either end of that scale, probably requested = min, not zero, and same at the top end, obviously to max though as you can't have more than max!]
  • EPW = Electrical Pulse Width : 0.0 OR Minimum - Maximum OR 52428us (0.8us (*0.8)) [Ditto]
  • IDT = Injector Dead Time : 0.0 - 52428us (0.8us (*0.8)) [This needs to be in the region of 2000us/2ms max at normal operating voltage, but perhaps 3x larger at lower voltages. It will only be a small table, so 16bits per entry is fine.]
  • BRV = Battery Reference Voltage : 0.0 - 65.535 V (0.001V (/1000)) [Measurement range will probably be 0 - 30v or so but the variable should be tweakable to handle a 24V system with ease and appropriate hardware. We don't want to cap the measurement such that real high figures with a failed alternator or something are outside it's range, BUT, we do want to keep the range minimal to maximise resolution from the ADC. 0-5V = 0 - 1023 raw ADC scaled externally with resistors : the half is not enough, 1/3 is enough for perfect conditions, 1/4 = 20v which is marginal for surge type conditions, but might be the best option. Double this for a 24v system.]
  • ETE/CHE = Engine Temperature Enrichment / Coolant/Head Enrichment : (+) 0 - 655 % (enough?) [I'm not sure how much extra fuel the engine needs when it is cold worst case, help me out. I know that maybe 10% would be enough for over temp enrichment, and 0% for in range (maybe 80 - 100C for a water cooler)]
  • PSE = Post Start Enrichment : 0 - 655 % (enough?) [How much extra fuel do your engines need post start?]
  • TFC/DFC = Transient/Delta Fuel Correction : +/- 327 % (enough?) [This will be a single value having a source of many potential algorithms. This is only necessary for slow readings and inaccurate calculations of readings. In a perfect system (which we are aiming to approximate) it wouldn't be required at all]
  • PCV = Per Cylinder Volume : 2.0 max = 32768 divisor and nothing will come close : http://en.wikipedia.org/wiki/List_of_au ... splacement and http://en.wikipedia.org/wiki/Single_cyl ... der_engine
  • IFPC = Injector Flow Per Cylinder : biggest I could find was 1.6l/min so that could be a goer, THOUGH, we should be using mass it is fairly approximate anyway. 2.0 should be fine so divisor of 32768 is good here too
  • etc. (what have I forgotten?)
Tables and functions to generate the needed variables :
  • RPM : Calculated directly by the engine position/rpm interpretter/decoder.
  • CHT : Transfer from raw ADC required. Options are : 8x2 table of user tunable conversion values OR mathematical formula with coefficients OR ?
  • MAP : Linear with Max and Min ADC > kPa pairs.
  • AAP : Linear with Max and Min ADC > kPa pairs. Obtained from separate sensor, or turn on time/rpm = zero /tps = open etc.
  • IAT : Transfer from raw ADC required. Options are : 8x2 table of user tunable conversion values OR mathematical formula with coefficients OR ?
  • MAT : Transfer might be just (MAT = IAT) or involve something more complex such as deriving from time after start and coolant temp at start and current airflow (rpm/load) etc.
  • TPS : Linear with Max and Min ADC > % pairs.
  • EGO : Linear with Max and Min ADC > Lambda pairs.
  • LT : From lookup table of some size or other (probably lower res and size than the main tables 8x8x8bit perhaps)
  • VE : From lookup function of some size and sort or other (possibly 24x24 for good boost resolution and mapping to zero RPM.
  • PL : Taken straight from one of several load sources : MAP, TPS, MAF, ABP x MAP, etc
  • MFT : From single cell value of 8 bits signed.
  • PCFT : From single cell values of 8 bits signed.
  • FPW : The single output of all the fueling calculations!
  • IDT : From a lookup table of perhaps 8x2x16bits such that the user specifies the normal voltage point and behaviour on both sides themselves.
  • BRV : Linear with Max and Min ADC > Voltage pairs. (min will usually be zero, but leave it open to be changed anyway)
  • CHE : This should be a U shaped curve such that at low temps the engine runs rich (because it needs to), and at high temps it runs rich (to cool things off) and not affect things at all in the middle, so perhaps flat in the middle. It should be a user trimable table. Possibly with a % effectiveness table on rpm/load too? (non linear through load/rpm space?) OR alternatively two 8x8 tables, one for coolant vs rpm, and one for coolant vs load. Each has it's advantage, hard to know which is better.
  • PSE : From lookup table of perhaps 8x2x16bit to allow curve over time of the users choice.
  • TFC/DFC : From output of some algorithm or other. Many possible options, delta TPS, delta MAP, wall wetting, delta RPM etc.
Mathematics/Equations and flow of them from ADC > PW and all things in between :
  • Read ADCs
  • Average/smooth ADCs
  • Transfer ADCs to usable values via various methods
  • Look up the VE from the load and RPM
  • Calculate the basic PW from all variables
  • Calculate corrections and apply them one by one
  • Add the opening time
  • Schedule the start of INJECTION (not the start of the electrical pulse) for the angle specified by the tuner.
  • What have I forgotten?
For each item, details here :
  • ADCs will be read once for each combustion event syncronously (all of them). This does not mean we are stuck with this, switching sampling methods for different sensors should be simple. All of them can also be sampled at various other frequencies and a particular variable can be generated from any source.
  • ADCs should probably be averaged right there and then in the ISR where they are read in otherwise samples will be taken and lost.
  • When ADCs are read, a "do calcs now" flag is set. This is picked up by the calc section which only runs when the flag is set and clears the flag once it starts to run. The effect of this is that if a new sample comes in while calculating the calculation will be run again on the next iteration. If new vars don't come in, other things can be done instead and the latency to doing the calcs again will be lower for it.
  • Generate the variables from ADCs with lookups etc
    • For CHT and IAT we will get a 0 - 1023 10 bit number representing the voltage at the ADC. The ADC pin will be connected to a pull up and one side of a thermistor sensor. The other side will be connected to ground. In the case of the common ND sensor running temperature means a very low resistance across the sensor : 80C = 340 Ohms. At cold temps the resistance is very high : -10C = 10k Ohm. The middle of the curve rests at around the 2k region, so if we use that we will get 4.1666V and around 800ADC reading for -10C and 0.73V and 150ADC reading for 80C. Now, if we are to use my suggested scale of degrees K then our temps are actually 263K and 353K at each end of our range. 26300 / 150 = 175 coefficient for one end of the transfer scale and 35300 / 800 = 44 coefficient for the other. This indicates to me that the tuning table for transfer would have much worse resolution if we reduced the used range of the output vars. Using degrees K makes this better, not worse. This will be looked up from an array of values that are pre calculated on a PC with FreeTherm or similar.
    • AAP/MAP/BRV/EGO : Linear interpolation from max reading and max adc to min reading and min adc
    • TPS : Similar to above, but boxed between max and min readings first.
  • etc
  • etc, help me fill in the blanks.
Fred.
DIYEFI.org - where Open Source means Open Source, and Free means Freedom
FreeEMS.org - the open source engine management system
FreeEMS dev diary and its comments thread and my turbo truck!
n00bs, do NOT PM or email tech questions! Use the forum!
The ever growing list of FreeEMS success stories!
User avatar
Fred
Moderator
Posts: 15431
Joined: Tue Jan 15, 2008 2:31 pm
Location: Home sweet home!
Contact:

Re: Pulse Width Calculations and Variable/Table/Function analysi

Post by Fred »

Bump, it may not be perfect, but its a pretty good start. I thought because the other thread had gone a bit wayward, I'd split this post out of it and start again here. Stay focused here please. I'll copy some of the mathematics posted in the other thread across here as I have a chance to think about it. The above post can be a collection of thoughts and decisions from this thread.

Get discussing :-)

Fred.
DIYEFI.org - where Open Source means Open Source, and Free means Freedom
FreeEMS.org - the open source engine management system
FreeEMS dev diary and its comments thread and my turbo truck!
n00bs, do NOT PM or email tech questions! Use the forum!
The ever growing list of FreeEMS success stories!
User avatar
Fred
Moderator
Posts: 15431
Joined: Tue Jan 15, 2008 2:31 pm
Location: Home sweet home!
Contact:

Re: Pulse Width Calculations and Variable/Table/Function analysi

Post by Fred »

It occurred to me that if we average the ADC values and then transfer them to final values we may/will lose intermediate accuracy. IE If we have the raw ADC at 0 - 1023 and it is creeping up from 567 to 568 slowly, we have the same granularity in our average so it will step up. If on the other hand we have much larger output after the transfer and average there, then we end up with a gap of say 20 between two ADC transfered values then the average will slowly move between them rather than stepping from one to the other. It will be prudent to pay this some attention as we work on the critical math part of the code :-)

Fred.
DIYEFI.org - where Open Source means Open Source, and Free means Freedom
FreeEMS.org - the open source engine management system
FreeEMS dev diary and its comments thread and my turbo truck!
n00bs, do NOT PM or email tech questions! Use the forum!
The ever growing list of FreeEMS success stories!
User avatar
Fred
Moderator
Posts: 15431
Joined: Tue Jan 15, 2008 2:31 pm
Location: Home sweet home!
Contact:

Re: Pulse Width Calculations and Variable/Table/Function analysi

Post by Fred »

It occurred to me this arvo that maximising the values in their variables IS the best thing to do at least from a smoothing during averaging point of view. If a value is mapped from 10 bits to 16 bits (or close to it) then there will be rougly 64 steps between values. The implication of that is that when the output variable is averaged the result can fall anywhere in the middle of that. The larger the more granular and therefore the smoother the result. At the very least it should be stored and averaged like that. It can always be transformed prior to calculation if necessary.

Fred.
DIYEFI.org - where Open Source means Open Source, and Free means Freedom
FreeEMS.org - the open source engine management system
FreeEMS dev diary and its comments thread and my turbo truck!
n00bs, do NOT PM or email tech questions! Use the forum!
The ever growing list of FreeEMS success stories!
User avatar
Fred
Moderator
Posts: 15431
Joined: Tue Jan 15, 2008 2:31 pm
Location: Home sweet home!
Contact:

Re: Pulse Width Calculations and Variable/Table/Function analysi

Post by Fred »

I thought I would post up the current variable transfer functions as they are in 0.0.14 for your viewing pleasure :

Code: Select all

	/*&&&&&&& Calculate and obtain the basic variables with which we will perform the calculations &&&&&&&*/
	
	// get IAT from ADC
	localIAT = IATTransferTable[ADCArrays.IAT[localInputBank]];
	
	// get CHT from ADC
	localCHT = CHTTransferTable[ADCArrays.CHT[localInputBank]];
	
	// get MAP from ADC
	localMAP = (((unsigned long)ADCArrays.MAP[localInputBank] * MAPRange) / ADC_DIVISIONS) + MAPMinimum;

	// get AAP from ADC
	localAAP = (((unsigned long)ADCArrays.AAP[localInputBank] * AAPRange) / ADC_DIVISIONS) + AAPMinimum;

	// get EGO from ADC
	localEGO = (((unsigned long)ADCArrays.EGO[localInputBank] * EGORange) / ADC_DIVISIONS) + EGOMinimum;
	
	// get BRV from ADC
	localBRV = (((unsigned long)ADCArrays.BRV[localInputBank] * BRVRange) / ADC_DIVISIONS) + BRVMinimum;
	
	/* Bound the TPS ADC reading and shift it to start at zero */
	unsigned short localTPSADC = ADCArrays.TPS[localInputBank];
	if(localTPSADC < TPSMinimumADC){
		localTPSADC = 0;
	}else if(localTPSADC > TPSMaximumADC){
		localTPSADC = TPSRangeADC;
	}else{
		localTPSADC -= TPSMinimumADC;
	}
	
	// get TPS from ADC
	localTPS = ((unsigned long)localTPSADC * TPS_RANGE) / TPSRangeADC;
	// No need to add TPS min as  we know it is 0 by definition.
	
	// get spare ADC
	localSP = ADCArrays.SpareADC[localInputBank] << 6;
	/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
More will be added shortly along with the rest of the math etc :-)

Fred.
DIYEFI.org - where Open Source means Open Source, and Free means Freedom
FreeEMS.org - the open source engine management system
FreeEMS dev diary and its comments thread and my turbo truck!
n00bs, do NOT PM or email tech questions! Use the forum!
The ever growing list of FreeEMS success stories!
User avatar
Fred
Moderator
Posts: 15431
Joined: Tue Jan 15, 2008 2:31 pm
Location: Home sweet home!
Contact:

Re: Pulse Width Calculations and Variable/Table/Function analysi

Post by Fred »

Based on some of the earlier calculations that I did (wrongly) here : http://www.diyefi.org/forum/viewtopic.php?p=2785#p2785

I've written some broken code (easier to visualise) to do the math. There is no way it would work, but the items in it are all correct and scale properly. The next step is to break it down into chunks that are calced in a specific order such that constants are done once at boot up from config and it is possible to adjust certain parts of the equation based on sensor input etc.

Here is the pseudo code :

Code: Select all

finalMasterPulseWidth = ((msToTicks * (molarMassOfAir/ molarMassOfAirDivisor) * (airPressure / airPressureDivisor) * (lookedUpVE / (lookedUpVEDivisor * VEpercentageDivisor)) * (perCylinderVolume / perCylinderVolumeDivisor)) / ((universalGasConstant / universalGasConstantDivisor) * (airInletTemp / airInletTempDivisor) * (stoichiometricAFR / stoichiometricAFRDivisor) * (desiredLambda / desiredLambdaDivisor) * (densityOfFuel / (densityOfFuelDivisor * densityOfFuelUnitDivisor)) * (injectorFlow / (injectorFlowUnitDivisor * injectorFlowDivisor))));
Lovely. Now, to break it down into manageable chunks!

Fred. (beware, this is a serious thread, do post if you have something ON topic to say, do not post for any other reason. Except Abe who is special and needs love.)
DIYEFI.org - where Open Source means Open Source, and Free means Freedom
FreeEMS.org - the open source engine management system
FreeEMS dev diary and its comments thread and my turbo truck!
n00bs, do NOT PM or email tech questions! Use the forum!
The ever growing list of FreeEMS success stories!
User avatar
Fred
Moderator
Posts: 15431
Joined: Tue Jan 15, 2008 2:31 pm
Location: Home sweet home!
Contact:

Re: Pulse Width Calculations and Variable/Table/Function analysi

Post by Fred »

BTW, this is sort of tested. I created some defines with the same names as the variables and populated them all with the same numbers as the variables, let the C pre processor do it's thing and then copied the equation with values into google calc and got some answers out. Then I checked each defines for the same value, and scaling as I replaced it with the variable. It works and gives a solid number that looks spot on. My mistakes earlier were having fuel density on the wrong side of the divide and dividing flow by the whole thing instead of the whole thing by flow.

Fred.
DIYEFI.org - where Open Source means Open Source, and Free means Freedom
FreeEMS.org - the open source engine management system
FreeEMS dev diary and its comments thread and my turbo truck!
n00bs, do NOT PM or email tech questions! Use the forum!
The ever growing list of FreeEMS success stories!
User avatar
Fred
Moderator
Posts: 15431
Joined: Tue Jan 15, 2008 2:31 pm
Location: Home sweet home!
Contact:

Re: Pulse Width Calculations and Variable/Table/Function analysi

Post by Fred »

Well, after MUCH thought and many rearrangements of equations and constants and scalers and factors and divisors etc etc etc, I have a result!

Basic code to produce a real world pulse width based on the variables available. All variables are local fakes at the moment (to keep it simple for me later).

In the end it came down to the following :
  • A single constant fuel value of 139371764 stored in an unsigned long
  • A run time fuel constant that is calculated from injector flow, cylinder volume and stoichiometric AFR for the fuel used. (all of these three are tunable values that must be calculated at each restart/reboot)
  • The top half of the equation (things in front of/above the divide by sign)
  • The bottom half of the equation (things after/below the divide by sign)
Poor googles servers. They just make such a great calculator though, you can dump a massive equation in all at once and just get an answer. Then you can edit etc etc. I've made great use of that today, that's for sure!

So, the final equation to get the base pulse width of a single fuel is this (the naming is temporary as stated above) :

Code: Select all

finalMasterTotalEndPW = (bootTimeConst * topHalf) / bottomHalf;
Nice and readable and clear.... and... NO GAY "req fuel" variables that are meaningless and obtuse!! All real variables with appropriate ranges and values. Awesome.

It is possible to overflow the final variable with strange settings, so I should probably load it into an unsigned long and check it to ensure it is less than 65535 and if not, set it to that before using it further along.

There is still substantial work to do on the fuel calcs section, but the hard part is done. Just labour intensive now.

Fred.
DIYEFI.org - where Open Source means Open Source, and Free means Freedom
FreeEMS.org - the open source engine management system
FreeEMS dev diary and its comments thread and my turbo truck!
n00bs, do NOT PM or email tech questions! Use the forum!
The ever growing list of FreeEMS success stories!
User avatar
Fred
Moderator
Posts: 15431
Joined: Tue Jan 15, 2008 2:31 pm
Location: Home sweet home!
Contact:

Re: Pulse Width Calculations and Variable/Table/Function analysi

Post by Fred »

A list of complications (don't attach any meaning to that statement except that they are non simple) :
  • Staged injection
  • Dual fuel on staged injection
  • MAF support
  • Atmospheric pressure correction
  • More than one injection per event
  • Multiple simultaneous load options
  • etc.
I'll be working on them and integrating them all in an intelligent way for the release after next. The next release will have partial mathematics and config structure in it.

Fred.
DIYEFI.org - where Open Source means Open Source, and Free means Freedom
FreeEMS.org - the open source engine management system
FreeEMS dev diary and its comments thread and my turbo truck!
n00bs, do NOT PM or email tech questions! Use the forum!
The ever growing list of FreeEMS success stories!
johnd
DIP8 - Involved
Posts: 23
Joined: Tue Jun 24, 2008 8:21 pm

Re: Pulse Width Calculations and Variable/Table/Function analysi

Post by johnd »

BRV-- what happens if upper limit is breached by alternator regulator fault
I have seen 40v+ from a 12v system -yes it damaged things on car --but what over voltage protection are you considering or for that matter what under voltage protection --low volts means high amperage draw

EGO-- why go down to zero and up so high
anything less than 0.6 will probably give rich misfire and can damage probes very quickly
surley there should be lower and upper fault configurable trigger value which will disconnect the lambda function
when mapping you are not within these values ,

Battery correction Voltage table -- to stop engine dying when any larger power drain happens and dips voltage to ecu /injectors when engine is idling
Post Reply