2015-05-28 16:49:44 -07:00
/*
Speeduino - Simple engine management for the Arduino Mega 2560 platform
Copyright ( C ) Josh Stewart
A full copy of the license may be found in the projects root directory
*/
2014-02-26 18:26:04 -08:00
/*
Because the size of the table is dynamic , this functino is required to reallocate the array sizes
2014-02-26 20:17:14 -08:00
Note that this may clear some of the existing values of the table
2014-02-26 18:26:04 -08:00
*/
2015-02-14 09:04:00 -08:00
# include "table.h"
2018-07-19 06:26:31 -07:00
# include "globals.h"
2015-02-14 09:04:00 -08:00
2014-02-26 20:17:14 -08:00
void table2D_setSize ( struct table2D * targetTable , byte newSize )
2014-02-26 18:26:04 -08:00
{
2017-08-02 18:46:48 -07:00
//Table resize is ONLY permitted during system initialisation.
//if(initialisationComplete == false)
2014-05-12 04:27:22 -07:00
{
2017-08-02 18:46:48 -07:00
//2D tables can contain either bytes or ints, depending on the value of the valueSize field
if ( targetTable - > valueSize = = SIZE_BYTE )
{
2019-08-01 17:14:25 -07:00
//The following lines have MISRA suppressions as realloc is otherwise forbidden. These calls have been verified as unable to be executed from anywhere but controlled areas.
//cppcheck-suppress misra-21.3
targetTable - > values = ( byte * ) realloc ( targetTable - > values , newSize * sizeof ( byte ) ) ; //cppcheck-suppress misra_21.3
2017-08-02 18:46:48 -07:00
targetTable - > axisX = ( byte * ) realloc ( targetTable - > axisX , newSize * sizeof ( byte ) ) ;
targetTable - > xSize = newSize ;
}
else
{
2018-01-27 03:14:11 -08:00
targetTable - > values16 = ( int16_t * ) realloc ( targetTable - > values16 , newSize * sizeof ( int16_t ) ) ;
targetTable - > axisX16 = ( int16_t * ) realloc ( targetTable - > axisX16 , newSize * sizeof ( int16_t ) ) ;
2017-08-02 18:46:48 -07:00
targetTable - > xSize = newSize ;
} //Byte or int
} //initialisationComplete
2014-02-26 18:26:04 -08:00
}
2015-09-17 22:06:21 -07:00
void table3D_setSize ( struct table3D * targetTable , byte newSize )
{
2017-08-02 18:46:48 -07:00
if ( initialisationComplete = = false )
{
2015-09-17 22:06:21 -07:00
targetTable - > values = ( byte * * ) malloc ( newSize * sizeof ( byte * ) ) ;
for ( byte i = 0 ; i < newSize ; i + + ) { targetTable - > values [ i ] = ( byte * ) malloc ( newSize * sizeof ( byte ) ) ; }
2017-08-02 18:46:48 -07:00
2018-01-27 03:14:11 -08:00
targetTable - > axisX = ( int16_t * ) malloc ( newSize * sizeof ( int16_t ) ) ;
targetTable - > axisY = ( int16_t * ) malloc ( newSize * sizeof ( int16_t ) ) ;
2015-09-17 22:06:21 -07:00
targetTable - > xSize = newSize ;
targetTable - > ySize = newSize ;
2017-08-02 18:46:48 -07:00
} //initialisationComplete
2015-09-17 22:06:21 -07:00
}
2014-02-26 18:26:04 -08:00
/*
This function simply pulls a 1 D linear interpolated ( ie averaged ) value from a 2 D table
ie : Given a value on the X axis , it returns a Y value that coresponds to the point on the curve between the nearest two defined X values
2014-05-12 04:27:22 -07:00
2017-08-02 18:46:48 -07:00
This function must take into account whether a table contains 8 - bit or 16 - bit values .
2014-05-12 04:27:22 -07:00
Unfortunately this means many of the lines are duplicated depending on this
2014-02-26 18:26:04 -08:00
*/
2017-08-02 18:46:48 -07:00
int table2D_getValue ( struct table2D * fromTable , int X_in )
2014-01-07 00:01:14 -08:00
{
2017-08-02 18:46:48 -07:00
int returnValue ;
bool valueFound = false ;
int X = X_in ;
2014-05-12 04:27:22 -07:00
int xMinValue , xMaxValue ;
2018-02-04 17:44:24 -08:00
int xMin = 0 ;
int xMax = 0 ;
//Check whether the X input is the same as last time this ran
2018-02-11 15:45:02 -08:00
if ( ( X_in = = fromTable - > lastInput ) & & ( fromTable - > cacheTime = = currentStatus . secl ) )
2014-05-12 04:27:22 -07:00
{
2018-02-04 17:44:24 -08:00
returnValue = fromTable - > lastOutput ;
valueFound = true ;
2014-05-12 04:27:22 -07:00
}
else
{
2018-02-04 22:31:22 -08:00
fromTable - > cacheTime = currentStatus . secl ; //As we're not using the cache value, set the current secl value to track when this new value was calc'd
2018-02-04 17:44:24 -08:00
if ( fromTable - > valueSize = = SIZE_BYTE )
{
//Byte version
xMinValue = fromTable - > axisX [ 0 ] ;
xMaxValue = fromTable - > axisX [ fromTable - > xSize - 1 ] ;
}
else
{
//int version
xMinValue = fromTable - > axisX16 [ 0 ] ;
xMaxValue = fromTable - > axisX16 [ fromTable - > xSize - 1 ] ;
}
2017-08-02 18:46:48 -07:00
2018-02-04 17:44:24 -08:00
//If the requested X value is greater/small than the maximum/minimum bin, reset X to be that value
if ( X > xMaxValue ) { X = xMaxValue ; }
if ( X < xMinValue ) { X = xMinValue ; }
2014-01-07 00:01:14 -08:00
2016-01-04 13:01:31 -08:00
2018-02-04 17:44:24 -08:00
if ( fromTable - > valueSize = = SIZE_BYTE )
{
//**** Byte version ****
//1st check is whether we're still in the same X bin as last time
if ( ( X < = fromTable - > axisX [ fromTable - > lastXMax ] ) & & ( X > fromTable - > axisX [ fromTable - > lastXMin ] ) )
{
xMaxValue = fromTable - > axisX [ fromTable - > lastXMax ] ;
xMinValue = fromTable - > axisX [ fromTable - > lastXMin ] ;
xMax = fromTable - > lastXMax ;
xMin = fromTable - > lastXMin ;
}
else
{
//If we're not in the same bin, loop through to find where we are
for ( int x = fromTable - > xSize - 1 ; x > = 0 ; x - - )
{
//Checks the case where the X value is exactly what was requested
if ( ( X = = fromTable - > axisX [ x ] ) | | ( x = = 0 ) )
2017-08-02 18:46:48 -07:00
{
2018-02-04 17:44:24 -08:00
returnValue = fromTable - > values [ x ] ; //Simply return the coresponding value
valueFound = true ;
2017-08-02 18:46:48 -07:00
break ;
}
2018-02-04 17:44:24 -08:00
else
{
//Normal case
if ( ( X < = fromTable - > axisX [ x ] ) & & ( X > fromTable - > axisX [ x - 1 ] ) )
{
xMaxValue = fromTable - > axisX [ x ] ;
xMinValue = fromTable - > axisX [ x - 1 ] ;
xMax = x ;
fromTable - > lastXMax = xMax ;
xMin = x - 1 ;
fromTable - > lastXMin = xMin ;
break ;
}
}
}
}
}
else
{
// **** INT VERSION ****
//1st check is whether we're still in the same X bin as last time
if ( ( X < = fromTable - > axisX16 [ fromTable - > lastXMax ] ) & & ( X > fromTable - > axisX16 [ fromTable - > lastXMin ] ) )
{
xMaxValue = fromTable - > axisX16 [ fromTable - > lastXMax ] ;
xMinValue = fromTable - > axisX16 [ fromTable - > lastXMin ] ;
xMax = fromTable - > lastXMax ;
xMin = fromTable - > lastXMin ;
}
else
{
//If we're not in the same bin, loop through to find where we are
for ( int x = fromTable - > xSize - 1 ; x > = 0 ; x - - )
{
//Checks the case where the X value is exactly what was requested
if ( ( X = = fromTable - > axisX16 [ x ] ) | | ( x = = 0 ) )
2017-08-02 18:46:48 -07:00
{
2018-02-04 17:44:24 -08:00
returnValue = fromTable - > values16 [ x ] ; //Simply return the coresponding value
valueFound = true ;
2017-08-02 18:46:48 -07:00
break ;
2018-02-04 17:44:24 -08:00
}
else
{
//Normal case
if ( ( X < = fromTable - > axisX16 [ x ] ) & & ( X > fromTable - > axisX16 [ x - 1 ] ) )
{
xMaxValue = fromTable - > axisX16 [ x ] ;
xMinValue = fromTable - > axisX16 [ x - 1 ] ;
xMax = x ;
fromTable - > lastXMax = xMax ;
xMin = x - 1 ;
fromTable - > lastXMin = xMin ;
break ;
} //Found in loop
} //Exact hit
} //For loop
} //In cache or not
} //byte or int values
} //X_in same as last time
2016-01-04 13:01:31 -08:00
2017-08-02 18:46:48 -07:00
if ( valueFound = = false )
2014-01-07 00:01:14 -08:00
{
2017-08-02 18:46:48 -07:00
unsigned int m = X - xMinValue ;
unsigned int n = xMaxValue - xMinValue ;
//Float version
/*
int yVal = ( m / n ) * ( abs ( fromTable . values [ xMax ] - fromTable . values [ xMin ] ) ) ;
*/
//Non-Float version
2019-08-01 17:14:25 -07:00
uint16_t yVal ;
2017-08-02 18:46:48 -07:00
if ( fromTable - > valueSize = = SIZE_BYTE )
{
//Byte version
yVal = ( ( long ) ( m < < 6 ) / n ) * ( abs ( fromTable - > values [ xMax ] - fromTable - > values [ xMin ] ) ) ;
yVal = ( yVal > > 6 ) ;
if ( fromTable - > values [ xMax ] > fromTable - > values [ xMin ] ) { yVal = fromTable - > values [ xMin ] + yVal ; }
else { yVal = fromTable - > values [ xMin ] - yVal ; }
}
else
{
2014-05-12 04:27:22 -07:00
//int version
2017-08-02 18:46:48 -07:00
yVal = ( ( long ) ( m < < 6 ) / n ) * ( abs ( fromTable - > values16 [ xMax ] - fromTable - > values16 [ xMin ] ) ) ;
yVal = ( yVal > > 6 ) ;
if ( fromTable - > values [ xMax ] > fromTable - > values16 [ xMin ] ) { yVal = fromTable - > values16 [ xMin ] + yVal ; }
else { yVal = fromTable - > values16 [ xMin ] - yVal ; }
}
returnValue = yVal ;
2014-05-12 04:27:22 -07:00
}
2017-08-02 18:46:48 -07:00
2018-01-23 17:05:50 -08:00
fromTable - > lastInput = X_in ;
fromTable - > lastOutput = returnValue ;
2017-08-02 18:46:48 -07:00
return returnValue ;
2014-01-07 00:01:14 -08:00
}
//This function pulls a value from a 3D table given a target for X and Y coordinates.
2019-08-01 17:14:25 -07:00
//It performs a 2D linear interpolation as descibred in: www.megamanual.com/v22manual/ve_tuner.pdf
2017-08-02 18:46:48 -07:00
int get3DTableValue ( struct table3D * fromTable , int Y_in , int X_in )
2014-01-07 00:01:14 -08:00
{
2017-08-02 18:46:48 -07:00
int X = X_in ;
int Y = Y_in ;
int tableResult = 0 ;
2014-01-07 00:01:14 -08:00
//Loop through the X axis bins for the min/max pair
2017-08-02 18:46:48 -07:00
//Note: For the X axis specifically, rather than looping from tableAxisX[0] up to tableAxisX[max], we start at tableAxisX[Max] and go down.
2014-01-07 00:01:14 -08:00
// This is because the important tables (fuel and injection) will have the highest RPM at the top of the X axis, so starting there will mean the best case occurs when the RPM is highest (And hence the CPU is needed most)
2015-06-04 04:54:11 -07:00
int xMinValue = fromTable - > axisX [ 0 ] ;
int xMaxValue = fromTable - > axisX [ fromTable - > xSize - 1 ] ;
2015-06-03 07:31:02 -07:00
byte xMin = 0 ;
byte xMax = 0 ;
2017-08-02 18:46:48 -07:00
2014-01-07 00:01:14 -08:00
//If the requested X value is greater/small than the maximum/minimum bin, reset X to be that value
if ( X > xMaxValue ) { X = xMaxValue ; }
if ( X < xMinValue ) { X = xMinValue ; }
2017-08-02 18:46:48 -07:00
2015-06-04 04:54:11 -07:00
//1st check is whether we're still in the same X bin as last time
if ( ( X < = fromTable - > axisX [ fromTable - > lastXMax ] ) & & ( X > fromTable - > axisX [ fromTable - > lastXMin ] ) )
2014-01-07 00:01:14 -08:00
{
2015-06-04 04:54:11 -07:00
xMaxValue = fromTable - > axisX [ fromTable - > lastXMax ] ;
xMinValue = fromTable - > axisX [ fromTable - > lastXMin ] ;
xMax = fromTable - > lastXMax ;
xMin = fromTable - > lastXMin ;
}
//2nd check is whether we're in the next RPM bin (To the right)
else if ( ( ( fromTable - > lastXMax + 1 ) < fromTable - > xSize ) & & ( X < = fromTable - > axisX [ fromTable - > lastXMax + 1 ] ) & & ( X > fromTable - > axisX [ fromTable - > lastXMin + 1 ] ) ) //First make sure we're not already at the last X bin
{
2017-08-02 18:46:48 -07:00
xMax = fromTable - > lastXMax + 1 ;
fromTable - > lastXMax = xMax ;
xMin = fromTable - > lastXMin + 1 ;
fromTable - > lastXMin = xMin ;
2015-06-04 04:54:11 -07:00
xMaxValue = fromTable - > axisX [ fromTable - > lastXMax ] ;
xMinValue = fromTable - > axisX [ fromTable - > lastXMin ] ;
}
//3rd check is to look at the previous bin (to the left)
else if ( ( fromTable - > lastXMin > 0 ) & & ( X < = fromTable - > axisX [ fromTable - > lastXMax - 1 ] ) & & ( X > fromTable - > axisX [ fromTable - > lastXMin - 1 ] ) ) //First make sure we're not already at the first X bin
{
2017-08-02 18:46:48 -07:00
xMax = fromTable - > lastXMax - 1 ;
fromTable - > lastXMax = xMax ;
xMin = fromTable - > lastXMin - 1 ;
fromTable - > lastXMin = xMin ;
2015-06-04 04:54:11 -07:00
xMaxValue = fromTable - > axisX [ fromTable - > lastXMax ] ;
2017-08-02 18:46:48 -07:00
xMinValue = fromTable - > axisX [ fromTable - > lastXMin ] ;
2015-06-04 04:54:11 -07:00
}
else
//If it's not caught by one of the above scenarios, give up and just run the loop
{
2019-08-01 17:14:25 -07:00
for ( int8_t x = fromTable - > xSize - 1 ; x > = 0 ; x - - )
2014-01-07 00:01:14 -08:00
{
2015-06-04 04:54:11 -07:00
//Checks the case where the X value is exactly what was requested
if ( ( X = = fromTable - > axisX [ x ] ) | | ( x = = 0 ) )
{
xMaxValue = fromTable - > axisX [ x ] ;
xMinValue = fromTable - > axisX [ x ] ;
2017-08-02 18:46:48 -07:00
xMax = x ;
fromTable - > lastXMax = xMax ;
xMin = x ;
fromTable - > lastXMin = xMin ;
2015-06-04 04:54:11 -07:00
break ;
}
//Normal case
if ( ( X < = fromTable - > axisX [ x ] ) & & ( X > fromTable - > axisX [ x - 1 ] ) )
{
xMaxValue = fromTable - > axisX [ x ] ;
xMinValue = fromTable - > axisX [ x - 1 ] ;
2017-08-02 18:46:48 -07:00
xMax = x ;
fromTable - > lastXMax = xMax ;
xMin = x - 1 ;
fromTable - > lastXMin = xMin ;
2015-06-04 04:54:11 -07:00
break ;
2017-08-02 18:46:48 -07:00
}
2014-01-07 00:01:14 -08:00
}
}
2017-08-02 18:46:48 -07:00
2014-01-07 00:01:14 -08:00
//Loop through the Y axis bins for the min/max pair
2015-06-04 04:54:11 -07:00
int yMaxValue = fromTable - > axisY [ 0 ] ;
int yMinValue = fromTable - > axisY [ fromTable - > ySize - 1 ] ;
2015-06-03 07:31:02 -07:00
byte yMin = 0 ;
byte yMax = 0 ;
2017-08-02 18:46:48 -07:00
2014-01-07 00:01:14 -08:00
//If the requested Y value is greater/small than the maximum/minimum bin, reset Y to be that value
if ( Y > yMaxValue ) { Y = yMaxValue ; }
if ( Y < yMinValue ) { Y = yMinValue ; }
2017-08-02 18:46:48 -07:00
2015-06-04 04:54:11 -07:00
//1st check is whether we're still in the same Y bin as last time
if ( ( Y > = fromTable - > axisY [ fromTable - > lastYMax ] ) & & ( Y < fromTable - > axisY [ fromTable - > lastYMin ] ) )
2014-01-07 00:01:14 -08:00
{
2015-06-04 04:54:11 -07:00
yMaxValue = fromTable - > axisY [ fromTable - > lastYMax ] ;
yMinValue = fromTable - > axisY [ fromTable - > lastYMin ] ;
yMax = fromTable - > lastYMax ;
yMin = fromTable - > lastYMin ;
}
//2nd check is whether we're in the next MAP/TPS bin (Next one up)
else if ( ( fromTable - > lastYMin > 0 ) & & ( Y < = fromTable - > axisY [ fromTable - > lastYMin - 1 ] ) & & ( Y > fromTable - > axisY [ fromTable - > lastYMax - 1 ] ) ) //First make sure we're not already at the top Y bin
{
2017-08-02 18:46:48 -07:00
yMax = fromTable - > lastYMax - 1 ;
fromTable - > lastYMax = yMax ;
yMin = fromTable - > lastYMin - 1 ;
fromTable - > lastYMin = yMin ;
2015-06-04 04:54:11 -07:00
yMaxValue = fromTable - > axisY [ fromTable - > lastYMax ] ;
yMinValue = fromTable - > axisY [ fromTable - > lastYMin ] ;
}
//3rd check is to look at the previous bin (Next one down)
else if ( ( ( fromTable - > lastYMax + 1 ) < fromTable - > ySize ) & & ( Y < = fromTable - > axisY [ fromTable - > lastYMin + 1 ] ) & & ( Y > fromTable - > axisY [ fromTable - > lastYMax + 1 ] ) ) //First make sure we're not already at the bottom Y bin
{
2017-08-02 18:46:48 -07:00
yMax = fromTable - > lastYMax + 1 ;
fromTable - > lastYMax = yMax ;
yMin = fromTable - > lastYMin + 1 ;
fromTable - > lastYMin = yMin ;
2015-06-04 04:54:11 -07:00
yMaxValue = fromTable - > axisY [ fromTable - > lastYMax ] ;
2017-08-02 18:46:48 -07:00
yMinValue = fromTable - > axisY [ fromTable - > lastYMin ] ;
2015-06-04 04:54:11 -07:00
}
else
//If it's not caught by one of the above scenarios, give up and just run the loop
{
2017-08-02 18:46:48 -07:00
2019-08-01 17:14:25 -07:00
for ( int8_t y = fromTable - > ySize - 1 ; y > = 0 ; y - - )
2014-01-07 00:01:14 -08:00
{
2015-06-04 04:54:11 -07:00
//Checks the case where the Y value is exactly what was requested
if ( ( Y = = fromTable - > axisY [ y ] ) | | ( y = = 0 ) )
{
yMaxValue = fromTable - > axisY [ y ] ;
yMinValue = fromTable - > axisY [ y ] ;
2017-08-02 18:46:48 -07:00
yMax = y ;
fromTable - > lastYMax = yMax ;
yMin = y ;
fromTable - > lastYMin = yMin ;
2015-06-04 04:54:11 -07:00
break ;
}
//Normal case
if ( ( Y > = fromTable - > axisY [ y ] ) & & ( Y < fromTable - > axisY [ y - 1 ] ) )
{
yMaxValue = fromTable - > axisY [ y ] ;
yMinValue = fromTable - > axisY [ y - 1 ] ;
2017-08-02 18:46:48 -07:00
yMax = y ;
fromTable - > lastYMax = yMax ;
yMin = y - 1 ;
fromTable - > lastYMin = yMin ;
2015-06-04 04:54:11 -07:00
break ;
2017-08-02 18:46:48 -07:00
}
2014-01-07 00:01:14 -08:00
}
}
2017-08-02 18:46:48 -07:00
/*
2014-01-07 00:01:14 -08:00
At this point we have the 4 corners of the map where the interpolated value will fall in
Eg : ( yMin , xMin ) ( yMin , xMax )
2017-08-02 18:46:48 -07:00
2014-01-07 00:01:14 -08:00
( yMax , xMin ) ( yMax , xMax )
2017-08-02 18:46:48 -07:00
2014-01-07 00:01:14 -08:00
In the following calculation the table values are referred to by the following variables :
A B
2017-08-02 18:46:48 -07:00
2014-01-07 00:01:14 -08:00
C D
2017-08-02 18:46:48 -07:00
2014-01-07 00:01:14 -08:00
*/
2015-06-04 04:54:11 -07:00
int A = fromTable - > values [ yMin ] [ xMin ] ;
int B = fromTable - > values [ yMin ] [ xMax ] ;
int C = fromTable - > values [ yMax ] [ xMin ] ;
int D = fromTable - > values [ yMax ] [ xMax ] ;
2016-11-07 22:04:34 -08:00
//Check that all values aren't just the same (This regularly happens with things like the fuel trim maps)
2017-08-02 18:51:07 -07:00
if ( ( A = = B ) & & ( A = = C ) & & ( A = = D ) ) { tableResult = A ; }
2017-08-02 18:46:48 -07:00
else
{
//Create some normalised position values
//These are essentially percentages (between 0 and 1) of where the desired value falls between the nearest bins on each axis
2016-10-22 04:17:56 -07:00
2017-06-02 14:09:36 -07:00
2017-08-02 18:46:48 -07:00
//Initial check incase the values were hit straight on
2017-08-02 18:51:07 -07:00
2019-08-01 17:14:25 -07:00
unsigned long p = ( long ) X - xMinValue ;
2017-08-02 18:46:48 -07:00
if ( xMaxValue = = xMinValue ) { p = ( p < < 8 ) ; } //This only occurs if the requested X value was equal to one of the X axis bins
else { p = ( ( p < < 8 ) / ( xMaxValue - xMinValue ) ) ; } //This is the standard case
2019-08-01 17:14:25 -07:00
unsigned long q ;
2017-08-02 18:51:07 -07:00
if ( yMaxValue = = yMinValue )
{
q = ( long ) Y - yMinValue ;
q = ( q < < 8 ) ;
}
//Standard case
else
{
q = long ( Y ) - yMaxValue ;
q = 256 - ( ( q < < 8 ) / ( yMinValue - yMaxValue ) ) ;
}
/*
long q ;
if ( yMaxValue = = yMinValue ) { q = ( ( long ) ( Y - yMinValue ) < < 8 ) ; }
else { q = 256 - ( ( ( long ) ( Y - yMaxValue ) < < 8 ) / ( yMinValue - yMaxValue ) ) ; }
*/
2017-08-02 18:46:48 -07:00
int m = ( ( 256 - p ) * ( 256 - q ) ) > > 8 ;
int n = ( p * ( 256 - q ) ) > > 8 ;
int o = ( ( 256 - p ) * q ) > > 8 ;
int r = ( p * q ) > > 8 ;
tableResult = ( ( A * m ) + ( B * n ) + ( C * o ) + ( D * r ) ) > > 8 ;
}
return tableResult ;
}