Experimental 1st deriv crank angle estimator
This commit is contained in:
parent
83efa84621
commit
d992eb405a
|
@ -13,6 +13,7 @@ volatile unsigned long toothOneTime = 0; //The time (micros()) that tooth 1 last
|
|||
volatile unsigned long toothOneMinusOneTime = 0; //The 2nd to last time (micros()) that tooth 1 last triggered
|
||||
volatile unsigned int toothHistory[TOOTH_LOG_BUFFER];
|
||||
volatile unsigned int toothHistoryIndex = 0;
|
||||
volatile long toothDeltaV; //Represents the change in time taken between the last 2 teeth compared to the previous 2. Positive value represents accleration, negative = deccleration
|
||||
|
||||
volatile byte secondaryToothCount; //Used for identifying the current secondary (Usually cam) tooth for patterns with multiple secondary teeth
|
||||
volatile unsigned long secondaryLastToothTime = 0; //The time (micros()) that the last tooth was registered (Cam input)
|
||||
|
|
50
decoders.ino
50
decoders.ino
|
@ -43,6 +43,20 @@ inline int stdGetRPM()
|
|||
return (US_IN_MINUTE / revolutionTime); //Calc RPM based on last full revolution time (Faster as /)
|
||||
}
|
||||
|
||||
/*
|
||||
This is a special case of RPM measure that is based on the time between the last 2 teeth rather than the time of the last full revolution
|
||||
This gives much more volatile reading, but is quite useful during cranking, particularly on low resolution patterns.
|
||||
It can only be used on patterns where the teeth are evently spaced
|
||||
It takes an argument of the full (COMPLETE) number of teeth per revolution. For a missing tooth wheel, this is the number if the tooth had NOT been missing (Eg 36-1 = 36)
|
||||
*/
|
||||
inline int crankingGetRPM(byte totalTeeth)
|
||||
{
|
||||
noInterrupts();
|
||||
revolutionTime = (toothLastToothTime - toothLastMinusOneToothTime) * totalTeeth;
|
||||
interrupts();
|
||||
return (US_IN_MINUTE / revolutionTime);
|
||||
}
|
||||
|
||||
/*
|
||||
Name: Missing tooth wheel
|
||||
Desc: A multi-tooth wheel with one of more 'missing' teeth. The first tooth after the missing one is considered number 1 and isthe basis for the trigger angle
|
||||
|
@ -82,6 +96,7 @@ void triggerPri_missingTooth()
|
|||
startRevolutions++; //Counter
|
||||
}
|
||||
|
||||
toothDeltaV = (toothLastToothTime - toothLastMinusOneToothTime) - (curTime - toothLastToothTime); //Positive value = accleration, Negative = decceleration
|
||||
toothLastMinusOneToothTime = toothLastToothTime;
|
||||
toothLastToothTime = curTime;
|
||||
}
|
||||
|
@ -139,11 +154,13 @@ void triggerPri_DualWheel()
|
|||
toothOneMinusOneTime = toothOneTime;
|
||||
toothOneTime = curTime;
|
||||
startRevolutions++; //Counter
|
||||
if ((startRevolutions & 63) == 1) { currentStatus.hasSync = false; } //Every 64 revolutions, force a resync with the cam
|
||||
currentStatus.hasSync = true;
|
||||
//if ((startRevolutions & 63) == 1) { currentStatus.hasSync = false; } //Every 64 revolutions, force a resync with the cam
|
||||
}
|
||||
|
||||
addToothLogEntry(curGap);
|
||||
|
||||
toothDeltaV = (toothLastToothTime - toothLastMinusOneToothTime) - (curTime - toothLastToothTime); //Positive value = accleration, Negative = decceleration
|
||||
toothLastMinusOneToothTime = toothLastToothTime;
|
||||
toothLastToothTime = curTime;
|
||||
}
|
||||
|
@ -183,8 +200,10 @@ int getCrankAngle_DualWheel(int timePerDegree)
|
|||
|
||||
int crankAngle = (tempToothCurrentCount - 1) * triggerToothAngle + configPage2.triggerAngle; //Number of teeth that have passed since tooth 1, multiplied by the angle each tooth represents, plus the angle that tooth 1 is ATDC. This gives accuracy only to the nearest tooth.
|
||||
crankAngle += ( (micros() - tempToothLastToothTime) / timePerDegree); //Estimate the number of degrees travelled since the last tooth
|
||||
|
||||
|
||||
if (crankAngle >= 720) { crankAngle -= 720; }
|
||||
if (crankAngle > 360) { crankAngle -= 360; }
|
||||
if (crankAngle < 0) { crankAngle += 360; }
|
||||
|
||||
return crankAngle;
|
||||
}
|
||||
|
@ -219,14 +238,16 @@ void triggerPri_BasicDistributor()
|
|||
else { toothCurrentCount++; } //Increment the tooth counter
|
||||
|
||||
addToothLogEntry(curGap);
|
||||
|
||||
|
||||
toothDeltaV = (toothLastToothTime - toothLastMinusOneToothTime) - (curTime -toothLastToothTime); //Positive value = accleration, Negative = decceleration
|
||||
toothLastMinusOneToothTime = toothLastToothTime;
|
||||
toothLastToothTime = curTime;
|
||||
}
|
||||
void triggerSec_BasicDistributor() { return; } //Not required
|
||||
int getRPM_BasicDistributor()
|
||||
{
|
||||
return stdGetRPM();
|
||||
if(currentStatus.RPM < configPage2.crankRPM) { crankingGetRPM((configPage1.nCylinders >> 1)); }
|
||||
else { return stdGetRPM(); }
|
||||
}
|
||||
int getCrankAngle_BasicDistributor(int timePerDegree)
|
||||
{
|
||||
|
@ -241,7 +262,9 @@ int getCrankAngle_BasicDistributor(int timePerDegree)
|
|||
|
||||
int crankAngle = (tempToothCurrentCount - 1) * triggerToothAngle + configPage2.triggerAngle; //Number of teeth that have passed since tooth 1, multiplied by the angle each tooth represents, plus the angle that tooth 1 is ATDC. This gives accuracy only to the nearest tooth.
|
||||
crankAngle += ldiv( (micros() - tempToothLastToothTime), timePerDegree).quot; //Estimate the number of degrees travelled since the last tooth
|
||||
if (crankAngle >= 720) { crankAngle -= 720; }
|
||||
if (crankAngle > 360) { crankAngle -= 360; }
|
||||
if (crankAngle < 0) { crankAngle += 360; }
|
||||
|
||||
return crankAngle;
|
||||
}
|
||||
|
@ -283,6 +306,7 @@ void triggerPri_GM7X()
|
|||
}
|
||||
}
|
||||
|
||||
toothDeltaV = (toothLastToothTime - toothLastMinusOneToothTime) - (curTime - toothLastToothTime); //Positive value = accleration, Negative = decceleration
|
||||
toothLastMinusOneToothTime = toothLastToothTime;
|
||||
toothLastToothTime = curTime;
|
||||
}
|
||||
|
@ -374,6 +398,7 @@ void triggerPri_4G63()
|
|||
|
||||
addToothLogEntry(curGap);
|
||||
|
||||
toothDeltaV = (toothLastToothTime - toothLastMinusOneToothTime) - (curTime - toothLastToothTime); //Positive value = accleration, Negative = decceleration
|
||||
toothLastMinusOneToothTime = toothLastToothTime;
|
||||
toothLastToothTime = curTime;
|
||||
}
|
||||
|
@ -401,14 +426,12 @@ void triggerSec_4G63()
|
|||
|
||||
int getRPM_4G63()
|
||||
{
|
||||
noInterrupts();
|
||||
revolutionTime = (toothOneTime - toothOneMinusOneTime); //The time in uS that one revolution would take at current speed (The time tooth 1 was last seen, minus the time it was seen prior to that)
|
||||
interrupts();
|
||||
//triggerFilterTime = revolutionTime >> 5; PROBLEMATIC!!!
|
||||
return ldiv(US_IN_MINUTE, revolutionTime).quot; //Calc RPM based on last full revolution time (uses ldiv rather than div as US_IN_MINUTE is a long)
|
||||
if(currentStatus.RPM < configPage2.crankRPM) { crankingGetRPM(2); }
|
||||
else { return stdGetRPM(); }
|
||||
}
|
||||
int getCrankAngle_4G63(int timePerDegree)
|
||||
int getCrankAngle_4G63(int timePerDegree)
|
||||
{
|
||||
if(!currentStatus.hasSync) { return 0;}
|
||||
//This is the current angle ATDC the engine is at. This is the last known position based on what tooth was last 'seen'. It is only accurate to the resolution of the trigger wheel (Eg 36-1 is 10 degrees)
|
||||
unsigned long tempToothLastToothTime;
|
||||
int tempToothCurrentCount;
|
||||
|
@ -420,6 +443,7 @@ int getCrankAngle_4G63(int timePerDegree)
|
|||
|
||||
int crankAngle = toothAngles[(tempToothCurrentCount - 1)] + configPage2.triggerAngle; //Perform a lookup of the fixed toothAngles array to find what the angle of the last tooth passed was.
|
||||
crankAngle += ldiv( (micros() - tempToothLastToothTime), timePerDegree).quot; //Estimate the number of degrees travelled since the last tooth
|
||||
if (crankAngle >= 720) { crankAngle -= 720; }
|
||||
if (crankAngle > 360) { crankAngle -= 360; }
|
||||
if (crankAngle < 0) { crankAngle += 360; }
|
||||
|
||||
|
@ -562,9 +586,11 @@ void triggerPri_Jeep2000()
|
|||
toothCurrentCount++; //Increment the tooth counter
|
||||
}
|
||||
|
||||
addToothLogEntry(curGap);
|
||||
addToothLogEntry(curGap);
|
||||
|
||||
toothLastToothTime = curTime;
|
||||
toothDeltaV = (toothLastToothTime - toothLastMinusOneToothTime) - (curTime - toothLastToothTime); //Positive value = accleration, Negative = decceleration
|
||||
toothLastMinusOneToothTime = toothLastToothTime;
|
||||
toothLastToothTime = curTime;
|
||||
}
|
||||
void triggerSec_Jeep2000()
|
||||
{
|
||||
|
|
|
@ -726,7 +726,9 @@ void loop()
|
|||
int tempStartAngle;
|
||||
|
||||
//How fast are we going? Need to know how long (uS) it will take to get from one tooth to the next. We then use that to estimate how far we are between the last tooth and the next one
|
||||
timePerDegree = ldiv( 166666L, currentStatus.RPM ).quot; //There is a small amount of rounding in this calculation, however it is less than 0.001 of a uS (Faster as ldiv than / )
|
||||
long toothAccel = toothDeltaV / triggerToothAngle; //An amount represengint the current acceleration or decceleration of the crank in degrees per uS per uS
|
||||
timePerDegree = ldiv( 166666L, currentStatus.RPM ).quot + (toothAccel * (micros() - toothLastToothTime)); //There is a small amount of rounding in this calculation, however it is less than 0.001 of a uS (Faster as ldiv than / )
|
||||
//timePerDegree = ldiv( 166666L, currentStatus.RPM ).quot; //There is a small amount of rounding in this calculation, however it is less than 0.001 of a uS (Faster as ldiv than / )
|
||||
|
||||
//Check that the duty cycle of the chosen pulsewidth isn't too high. This is disabled at cranking
|
||||
if( !BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) )
|
||||
|
@ -741,7 +743,7 @@ void loop()
|
|||
//Determine next firing angles
|
||||
//1
|
||||
int PWdivTimerPerDegree = div(currentStatus.PW, timePerDegree).quot; //How many crank degrees the calculated PW will take at the current speed
|
||||
injector1StartAngle = configPage1.inj1Ang - ( PWdivTimerPerDegree ); //This is a little primitive, but is based on the idea that all fuel needs to be delivered before the inlet valve opens. I am using 355 as the point at which the injector MUST be closed by. See http://www.extraefi.co.uk/sequential_fuel.html for more detail
|
||||
injector1StartAngle = configPage1.inj1Ang - ( PWdivTimerPerDegree ); //This is a little primitive, but is based on the idea that all fuel needs to be delivered before the inlet valve opens. See http://www.extraefi.co.uk/sequential_fuel.html for more detail
|
||||
if(injector1StartAngle < 0) {injector1StartAngle += 360;}
|
||||
//Repeat the above for each cylinder
|
||||
switch (configPage1.nCylinders)
|
||||
|
@ -820,7 +822,7 @@ void loop()
|
|||
break;
|
||||
//4 cylinders
|
||||
case 4:
|
||||
ignition2StartAngle = channel2IgnDegrees + 360 - currentStatus.advance - dwellAngle; //(div((configPage2.dwellRun*100), timePerDegree).quot ));
|
||||
ignition2StartAngle = channel2IgnDegrees + 360 - currentStatus.advance - dwellAngle;
|
||||
if(ignition2StartAngle > 360) {ignition2StartAngle -= 360;}
|
||||
if(ignition2StartAngle < 0) {ignition2StartAngle += 360;}
|
||||
break;
|
||||
|
@ -946,9 +948,13 @@ void loop()
|
|||
crankAngle = getCrankAngle(timePerDegree); //Refresh with the latest crank angle
|
||||
if(ignitionOn && (currentStatus.RPM < ((unsigned int)(configPage2.HardRevLim) * 100) ))
|
||||
{
|
||||
//if ( (ignition1StartAngle > crankAngle) && ign1LastRev != startRevolutions)
|
||||
if ( (ignition1StartAngle > crankAngle) && ign1LastRev != startRevolutions)
|
||||
//if (ign1LastRev != startRevolutions)
|
||||
{
|
||||
unsigned long ignition1StartTime;
|
||||
if(ignition1StartAngle > crankAngle) { ignition1StartTime = ((unsigned long)(ignition1StartAngle - crankAngle) * (unsigned long)timePerDegree); }
|
||||
else { ignition1StartTime = ((unsigned long)(360 - crankAngle + ignition1StartAngle) * (unsigned long)timePerDegree); }
|
||||
|
||||
setIgnitionSchedule1(ign1StartFunction,
|
||||
((unsigned long)(ignition1StartAngle - crankAngle) * (unsigned long)timePerDegree),
|
||||
currentStatus.dwell,
|
||||
|
@ -961,7 +967,12 @@ void loop()
|
|||
tempStartAngle = ignition2StartAngle - channel2IgnDegrees;
|
||||
if ( tempStartAngle < 0) { tempStartAngle += 360; }
|
||||
if ( (tempStartAngle > tempCrankAngle) && ign2LastRev != startRevolutions)
|
||||
//if ( ign2LastRev != startRevolutions )
|
||||
{
|
||||
unsigned long ignition2StartTime;
|
||||
if(tempStartAngle > tempCrankAngle) { ignition2StartTime = ((unsigned long)(tempStartAngle - tempCrankAngle) * (unsigned long)timePerDegree); }
|
||||
else { ignition2StartTime = ((unsigned long)(360 - tempCrankAngle + tempStartAngle) * (unsigned long)timePerDegree); }
|
||||
|
||||
setIgnitionSchedule2(ign2StartFunction,
|
||||
((unsigned long)(tempStartAngle - tempCrankAngle) * (unsigned long)timePerDegree),
|
||||
currentStatus.dwell,
|
||||
|
|
Loading…
Reference in New Issue