Experimental 1st deriv crank angle estimator

This commit is contained in:
Josh Stewart 2015-11-03 21:22:33 +11:00
parent 83efa84621
commit d992eb405a
3 changed files with 54 additions and 16 deletions

View File

@ -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)

View File

@ -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()
{

View File

@ -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,