Move a chunk of the prediction code out of speeduino.ino into crankMaths

This commit is contained in:
Josh Stewart 2018-08-31 17:35:29 +10:00
parent bc94053f10
commit 765e52fce5
3 changed files with 83 additions and 64 deletions

View File

@ -15,9 +15,14 @@
unsigned long angleToTime(int16_t, byte);
uint16_t timeToAngle(unsigned long, byte);
void doCrankSpeedCalcs();
volatile uint16_t timePerDegree;
volatile uint16_t timePerDegreex16;
volatile uint16_t degreesPeruSx2048;
//These are only part of the experimental 2nd deriv calcs
byte deltaToothCount = 0; //The last tooth that was used with the deltaV calc
int rpmDelta;
#endif

View File

@ -1,6 +1,7 @@
#include "globals.h"
#include "crankMaths.h"
#include "decoders.h"
#include "timers.h"
/*
* Converts a crank angle into a time from or since that angle occurred.
@ -76,4 +77,71 @@ uint16_t timeToAngle(unsigned long time, byte method)
return returnAngle;
}
void doCrankSpeedCalcs()
{
//********************************************************
//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
//We use a 1st Deriv accleration prediction, but only when there is an even spacing between primary sensor teeth
//Any decoder that has uneven spacing has its triggerToothAngle set to 0
if( (secondDerivEnabled > 0) && (toothHistoryIndex >= 3) && (currentStatus.RPM < 2000) ) //toothHistoryIndex must be greater than or equal to 3 as we need the last 3 entries. Currently this mode only runs below 3000 rpm
//if(true)
{
//Only recalculate deltaV if the tooth has changed since last time (DeltaV stays the same until the next tooth)
//if (deltaToothCount != toothCurrentCount)
{
deltaToothCount = toothCurrentCount;
int angle1, angle2; //These represent the crank angles that are travelled for the last 2 pulses
if(configPage4.TrigPattern == 4)
{
//Special case for 70/110 pattern on 4g63
angle2 = triggerToothAngle; //Angle 2 is the most recent
if (angle2 == 70) { angle1 = 110; }
else { angle1 = 70; }
}
else if(configPage4.TrigPattern == 0)
{
//Special case for missing tooth decoder where the missing tooth was one of the last 2 seen
if(toothCurrentCount == 1) { angle2 = 2*triggerToothAngle; angle1 = triggerToothAngle; }
else if(toothCurrentCount == 2) { angle1 = 2*triggerToothAngle; angle2 = triggerToothAngle; }
else { angle1 = triggerToothAngle; angle2 = triggerToothAngle; }
}
else { angle1 = triggerToothAngle; angle2 = triggerToothAngle; }
long toothDeltaV = (1000000L * angle2 / toothHistory[toothHistoryIndex]) - (1000000L * angle1 / toothHistory[toothHistoryIndex-1]);
long toothDeltaT = toothHistory[toothHistoryIndex];
//long timeToLastTooth = micros() - toothLastToothTime;
rpmDelta = (toothDeltaV << 10) / (6 * toothDeltaT);
}
timePerDegreex16 = ldiv( 2666656L, currentStatus.RPM + rpmDelta).quot; //This give accuracy down to 0.1 of a degree and can provide noticably better timing results on low res triggers
timePerDegree = timePerDegreex16 / 16;
}
else
{
//If we can, attempt to get the timePerDegree by comparing the times of the last two teeth seen. This is only possible for evenly spaced teeth
noInterrupts();
if( (triggerToothAngleIsCorrect == true) && (toothLastToothTime > toothLastMinusOneToothTime) )
{
//noInterrupts();
unsigned long tempToothLastToothTime = toothLastToothTime;
unsigned long tempToothLastMinusOneToothTime = toothLastMinusOneToothTime;
uint16_t tempTriggerToothAngle = triggerToothAngle;
interrupts();
timePerDegreex16 = (unsigned long)( (tempToothLastToothTime - tempToothLastMinusOneToothTime)*16) / tempTriggerToothAngle;
timePerDegree = timePerDegreex16 / 16;
}
else
{
//long timeThisRevolution = (micros_safe() - toothOneTime); //micros() is no longer interrupt safe
interrupts();
//long rpm_adjust = (timeThisRevolution * (long)currentStatus.rpmDOT) / 1000000; //Take into account any likely accleration that has occurred since the last full revolution completed
long rpm_adjust = 0;
timePerDegreex16 = ldiv( 2666656L, currentStatus.RPM + rpm_adjust).quot; //The use of a x16 value gives accuracy down to 0.1 of a degree and can provide noticably better timing results on low res triggers
timePerDegree = timePerDegreex16 / 16;
}
}
degreesPeruSx2048 = 2048 / timePerDegree;
}

View File

@ -74,8 +74,6 @@ unsigned long counter;
unsigned long currentLoopTime; //The time the current loop started (uS)
unsigned long previousLoopTime; //The time the previous loop started (uS)
byte deltaToothCount = 0; //The last tooth that was used with the deltaV calc
int rpmDelta;
byte maxIgnOutputs = 1; //Used for rolling rev limiter
byte curRollingCut = 0; //Rolling rev limiter, current ignition channel being cut
byte rollingCutCounter = 0; //how many times (revolutions) the ignition has been cut in a row
@ -209,6 +207,15 @@ void setup()
flexBoostTable.values16 = configPage10.flexBoostAdj;
flexBoostTable.axisX = configPage10.flexBoostBins;
knockWindowStartTable.valueSize = SIZE_BYTE;
knockWindowStartTable.xSize = 6;
knockWindowStartTable.values = configPage10.knock_window_angle;
knockWindowStartTable.axisX = configPage10.knock_window_rpms;
knockWindowDurationTable.valueSize = SIZE_BYTE;
knockWindowDurationTable.xSize = 6;
knockWindowDurationTable.values = configPage10.knock_window_dur;
knockWindowDurationTable.axisX = configPage10.knock_window_rpms;
//Setup the calibration tables
loadCalibration();
@ -1119,68 +1126,7 @@ void loop()
int tempCrankAngle;
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
//We use a 1st Deriv accleration prediction, but only when there is an even spacing between primary sensor teeth
//Any decoder that has uneven spacing has its triggerToothAngle set to 0
if( (secondDerivEnabled > 0) && (toothHistoryIndex >= 3) && (currentStatus.RPM < 2000) ) //toothHistoryIndex must be greater than or equal to 3 as we need the last 3 entries. Currently this mode only runs below 3000 rpm
//if(true)
{
//Only recalculate deltaV if the tooth has changed since last time (DeltaV stays the same until the next tooth)
//if (deltaToothCount != toothCurrentCount)
{
deltaToothCount = toothCurrentCount;
int angle1, angle2; //These represent the crank angles that are travelled for the last 2 pulses
if(configPage4.TrigPattern == 4)
{
//Special case for 70/110 pattern on 4g63
angle2 = triggerToothAngle; //Angle 2 is the most recent
if (angle2 == 70) { angle1 = 110; }
else { angle1 = 70; }
}
else if(configPage4.TrigPattern == 0)
{
//Special case for missing tooth decoder where the missing tooth was one of the last 2 seen
if(toothCurrentCount == 1) { angle2 = 2*triggerToothAngle; angle1 = triggerToothAngle; }
else if(toothCurrentCount == 2) { angle1 = 2*triggerToothAngle; angle2 = triggerToothAngle; }
else { angle1 = triggerToothAngle; angle2 = triggerToothAngle; }
}
else { angle1 = triggerToothAngle; angle2 = triggerToothAngle; }
long toothDeltaV = (1000000L * angle2 / toothHistory[toothHistoryIndex]) - (1000000L * angle1 / toothHistory[toothHistoryIndex-1]);
long toothDeltaT = toothHistory[toothHistoryIndex];
//long timeToLastTooth = micros() - toothLastToothTime;
rpmDelta = (toothDeltaV << 10) / (6 * toothDeltaT);
}
timePerDegreex16 = ldiv( 2666656L, currentStatus.RPM + rpmDelta).quot; //This give accuracy down to 0.1 of a degree and can provide noticably better timing results on low res triggers
timePerDegree = timePerDegreex16 / 16;
}
else
{
//If we can, attempt to get the timePerDegree by comparing the times of the last two teeth seen. This is only possible for evenly spaced teeth
if( (triggerToothAngleIsCorrect == true) && (toothLastToothTime > toothLastMinusOneToothTime) && false ) //This is currently NOT working. Don't know why yet
{
noInterrupts();
unsigned long tempToothLastToothTime = toothLastToothTime;
unsigned long tempToothLastMinusOneToothTime = toothLastMinusOneToothTime;
uint16_t tempTriggerToothAngle = triggerToothAngle;
interrupts();
timePerDegreex16 = (unsigned long)( (tempToothLastToothTime - tempToothLastMinusOneToothTime)*16) / tempTriggerToothAngle;
timePerDegree = timePerDegreex16 / 16;
}
else
{
long timeThisRevolution = (micros_safe() - toothOneTime); //micros() is no longer interrupt safe
long rpm_adjust = (timeThisRevolution * (long)currentStatus.rpmDOT) / 1000000; //Take into account any likely accleration that has occurred since the last full revolution completed
rpm_adjust = 0;
timePerDegreex16 = ldiv( 2666656L, currentStatus.RPM + rpm_adjust).quot; //The use of a x16 value gives accuracy down to 0.1 of a degree and can provide noticably better timing results on low res triggers
timePerDegree = timePerDegreex16 / 16;
}
}
degreesPeruSx2048 = 2048 / timePerDegree;
doCrankSpeedCalcs(); //In crankMaths.ino
//Check that the duty cycle of the chosen pulsewidth isn't too high.
unsigned long pwLimit = percentage(configPage2.dutyLim, revolutionTime); //The pulsewidth limit is determined to be the duty cycle limit (Eg 85%) by the total time it takes to perform 1 revolution