speeduino/speeduino/table3d_interpolate.cpp

214 lines
8.6 KiB
C++
Raw Normal View History

Reduce 3d table memory usage (>500 bytes) (#662) * Use table_row_iterator_t to adjust ignitionTable * Separate 2d & 3d table code, abstract page to table iterator conversion. This is just moving code around in preparation for future changes. * Reduce table RAM (.bss) usage Generate a separate type for each possible 3d axis & size combination. This turns what was runtime information into compile time data. * Save 1 byte per table. Use a flag value (INT16_MAX) instead of a separate boolean flag * File renaming table_iterator -> table3d_iterator.h table3d.h -> table3d_interpolate.h table3d.cpp -> table3d_interpolate.cpp table3d_types.h -> table3d.h * Optimize page.cpp: reduce code clutter, maintain performance * Reduce flash usage * Encapsulate table metadata * Performance - hoist if statement * Replace function with macro * Use a packed enum as a type identifier Use a packed enum as a type identifier Slimmer data types * Use table iterators for random access to table values and axis. * Centralize write buffer check * Encapsulate 16-bit reference concept * Performance: make table iterators proper classes This allows us to chain calls on temporaries - not possible with regular function calls. * Performance: encapsulate EEPROM update & address increment * Save flash - don't duplicate function * Performance: directly invalidate table cache * Separate out iterator reversal * Separate out entity mapping & per-byte access Much faster, smaller code footprint & easier to understand * Code quality fixes * Separate out axis metadata * Doxygen comments * Separate int16_ref into separate file * Separate out table axies & values into separate types No need for metadata types & more localised code. E.g. creating iterators is now alongside the data over which they iterate. * Doxygen
2021-11-17 16:30:29 -08:00
#include "table3d_interpolate.h"
Performance: optimize division (#1082) * Add udiv_32_16 * Apply udiv_32_16() where possible * Convert udiv_32_16 to assembler It's worth 20 loop/s * Remove unused functions * Remove degreesPeruSx2048 - unused * Remove angleToTime - replace with direct calls 1. Drop angleToTime() It's slow, only partially implemented and adds zero value (and has MISRA violations) 2. Consistent function naming 3. Doxygen * triggerPri_Nissan360 shouldn't set timePerDegree. It will be overwritten every loop by doCrankSpeedCalcs() * Use angleToTimeMicroSecPerDegree() instead of timePerDegree No loss in performance Increased injection open/close time accuracy (so unit test values must change) Can remove timePerDegree global. * Hide (encapsulate) crank math globals. * Base all angle to time conversions on decoder computed variables. This is within 2us of the revolution based method and is much faster - which is essentially zero percent change. * Performance: move calculation of degreesPeruSx32768 into decoders. Remove doCrankSpeedCalcs() - it's doing nothing at the moment. * Apply libdivide to triggerSetEndTeeth functions. Since triggerToothAngle is set once at initialization time, we can generate the libdivide struct once and reuse it many times. * Remove lastToothCalcAdvance - unused * Replace 16-bit division with shift * Replace 32-bit divison with 16-bit division * Avoid 32-bit division; use div100() * inline percentage() * Optimize div100() * MISRA fixes * Replace magic numbers with #defs * Replace libdivide structs with inline constants No perf or memory changes * Use fixed types for PWM max count variables * Accurate rounded integer division * Formalise rounding behavior (DIV_ROUND_CORRECT) * Apply DIV_ROUND_CORRECT to DIV_ROUND_CLOSEST(), UDIV_ROUND_CLOSEST(), div100(), div360(), percentage() & halfPercentage() * Add, fix & improve unit tests * Add udiv_32_16_closest() * Perf: Limit percentage calculations to 16-bits * MISRA fixes * Add compare_executiontime() to encapsulate common perf testing code * Signed to unsigned division * Convert ignitionLimits() to an inline function. Slight speed up, probably due to removing multiple evaluations of macro arguments. * Split unit tests up. * udiv_32_16 - check for valid parameters
2023-11-05 14:10:08 -08:00
#include "maths.h"
Reduce 3d table memory usage (>500 bytes) (#662) * Use table_row_iterator_t to adjust ignitionTable * Separate 2d & 3d table code, abstract page to table iterator conversion. This is just moving code around in preparation for future changes. * Reduce table RAM (.bss) usage Generate a separate type for each possible 3d axis & size combination. This turns what was runtime information into compile time data. * Save 1 byte per table. Use a flag value (INT16_MAX) instead of a separate boolean flag * File renaming table_iterator -> table3d_iterator.h table3d.h -> table3d_interpolate.h table3d.cpp -> table3d_interpolate.cpp table3d_types.h -> table3d.h * Optimize page.cpp: reduce code clutter, maintain performance * Reduce flash usage * Encapsulate table metadata * Performance - hoist if statement * Replace function with macro * Use a packed enum as a type identifier Use a packed enum as a type identifier Slimmer data types * Use table iterators for random access to table values and axis. * Centralize write buffer check * Encapsulate 16-bit reference concept * Performance: make table iterators proper classes This allows us to chain calls on temporaries - not possible with regular function calls. * Performance: encapsulate EEPROM update & address increment * Save flash - don't duplicate function * Performance: directly invalidate table cache * Separate out iterator reversal * Separate out entity mapping & per-byte access Much faster, smaller code footprint & easier to understand * Code quality fixes * Separate out axis metadata * Doxygen comments * Separate int16_ref into separate file * Separate out table axies & values into separate types No need for metadata types & more localised code. E.g. creating iterators is now alongside the data over which they iterate. * Doxygen
2021-11-17 16:30:29 -08:00
// ============================= Axis Bin Searching =========================
static inline bool is_in_bin(const table3d_axis_t &testValue, const table3d_axis_t &min, const table3d_axis_t &max)
{
return testValue > min && testValue <= max;
}
// Find the axis index for the top of the bin that covers the test value.
// E.g. 4 in { 1, 3, 5, 7, 9 } would be 2
// We assume the axis is in order.
static inline table3d_dim_t find_bin_max(
table3d_axis_t &value, // Value to search for
const table3d_axis_t *pAxis, // The axis to search
table3d_dim_t minElement, // Axis index of the element with the lowest value (at one end of the array)
table3d_dim_t maxElement, // Axis index of the element with the highest value (at the other end of the array)
table3d_dim_t lastBinMax) // The last result from this call - used to speed up searches
{
// It's quicker to increment/adjust this pointer than to repeatedly
// index the array - minimum 2%, often >5%
const table3d_axis_t *pMax = nullptr;
// minElement is at one end of the array, so the "lowest" bin
// is [minElement, minElement+stride]. Since we're working with the upper
// index of the bin pair, we can't go below minElement + stride.
table3d_dim_t minBinIndex = minElement - 1U;
// Check the cached last bin and either side first - it's likely that this will give a hit under
// real world conditions
// Check if we're still in the same bin as last time
pMax = pAxis + lastBinMax;
if (is_in_bin(value, *(pMax + 1U), *pMax))
Reduce 3d table memory usage (>500 bytes) (#662) * Use table_row_iterator_t to adjust ignitionTable * Separate 2d & 3d table code, abstract page to table iterator conversion. This is just moving code around in preparation for future changes. * Reduce table RAM (.bss) usage Generate a separate type for each possible 3d axis & size combination. This turns what was runtime information into compile time data. * Save 1 byte per table. Use a flag value (INT16_MAX) instead of a separate boolean flag * File renaming table_iterator -> table3d_iterator.h table3d.h -> table3d_interpolate.h table3d.cpp -> table3d_interpolate.cpp table3d_types.h -> table3d.h * Optimize page.cpp: reduce code clutter, maintain performance * Reduce flash usage * Encapsulate table metadata * Performance - hoist if statement * Replace function with macro * Use a packed enum as a type identifier Use a packed enum as a type identifier Slimmer data types * Use table iterators for random access to table values and axis. * Centralize write buffer check * Encapsulate 16-bit reference concept * Performance: make table iterators proper classes This allows us to chain calls on temporaries - not possible with regular function calls. * Performance: encapsulate EEPROM update & address increment * Save flash - don't duplicate function * Performance: directly invalidate table cache * Separate out iterator reversal * Separate out entity mapping & per-byte access Much faster, smaller code footprint & easier to understand * Code quality fixes * Separate out axis metadata * Doxygen comments * Separate int16_ref into separate file * Separate out table axies & values into separate types No need for metadata types & more localised code. E.g. creating iterators is now alongside the data over which they iterate. * Doxygen
2021-11-17 16:30:29 -08:00
{
return lastBinMax;
}
// Check the bin above the last one
pMax = pMax + 1U;
if (lastBinMax!=minBinIndex && is_in_bin(value, *(pMax + 1U), *pMax))
{
return lastBinMax + 1U;
}
// Check the bin below the last one
pMax -= 2U;
if (lastBinMax!=maxElement && is_in_bin(value, *(pMax + 1U), *pMax))
{
return lastBinMax - 1U;
}
Reduce 3d table memory usage (>500 bytes) (#662) * Use table_row_iterator_t to adjust ignitionTable * Separate 2d & 3d table code, abstract page to table iterator conversion. This is just moving code around in preparation for future changes. * Reduce table RAM (.bss) usage Generate a separate type for each possible 3d axis & size combination. This turns what was runtime information into compile time data. * Save 1 byte per table. Use a flag value (INT16_MAX) instead of a separate boolean flag * File renaming table_iterator -> table3d_iterator.h table3d.h -> table3d_interpolate.h table3d.cpp -> table3d_interpolate.cpp table3d_types.h -> table3d.h * Optimize page.cpp: reduce code clutter, maintain performance * Reduce flash usage * Encapsulate table metadata * Performance - hoist if statement * Replace function with macro * Use a packed enum as a type identifier Use a packed enum as a type identifier Slimmer data types * Use table iterators for random access to table values and axis. * Centralize write buffer check * Encapsulate 16-bit reference concept * Performance: make table iterators proper classes This allows us to chain calls on temporaries - not possible with regular function calls. * Performance: encapsulate EEPROM update & address increment * Save flash - don't duplicate function * Performance: directly invalidate table cache * Separate out iterator reversal * Separate out entity mapping & per-byte access Much faster, smaller code footprint & easier to understand * Code quality fixes * Separate out axis metadata * Doxygen comments * Separate int16_ref into separate file * Separate out table axies & values into separate types No need for metadata types & more localised code. E.g. creating iterators is now alongside the data over which they iterate. * Doxygen
2021-11-17 16:30:29 -08:00
// Check if outside array limits - won't happen often in the real world
// so check after the cache check
// At or above maximum - clamp to final value
if (value>=pAxis[maxElement])
{
value = pAxis[maxElement];
return maxElement;
}
// At or below minimum - clamp to lowest value
if (value<=pAxis[minElement])
{
value = pAxis[minElement];
return minElement - 1U;
}
// No hits above, so run a linear search.
// We start at the maximum & work down, rather than looping from [0] up to [max]
// 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)
lastBinMax = maxElement;
pMax = pAxis + lastBinMax;
while (lastBinMax!=minBinIndex && !is_in_bin(value, *(pMax + 1U), *pMax))
{
++lastBinMax;
++pMax;
}
return lastBinMax;
}
Reduce 3d table memory usage (>500 bytes) (#662) * Use table_row_iterator_t to adjust ignitionTable * Separate 2d & 3d table code, abstract page to table iterator conversion. This is just moving code around in preparation for future changes. * Reduce table RAM (.bss) usage Generate a separate type for each possible 3d axis & size combination. This turns what was runtime information into compile time data. * Save 1 byte per table. Use a flag value (INT16_MAX) instead of a separate boolean flag * File renaming table_iterator -> table3d_iterator.h table3d.h -> table3d_interpolate.h table3d.cpp -> table3d_interpolate.cpp table3d_types.h -> table3d.h * Optimize page.cpp: reduce code clutter, maintain performance * Reduce flash usage * Encapsulate table metadata * Performance - hoist if statement * Replace function with macro * Use a packed enum as a type identifier Use a packed enum as a type identifier Slimmer data types * Use table iterators for random access to table values and axis. * Centralize write buffer check * Encapsulate 16-bit reference concept * Performance: make table iterators proper classes This allows us to chain calls on temporaries - not possible with regular function calls. * Performance: encapsulate EEPROM update & address increment * Save flash - don't duplicate function * Performance: directly invalidate table cache * Separate out iterator reversal * Separate out entity mapping & per-byte access Much faster, smaller code footprint & easier to understand * Code quality fixes * Separate out axis metadata * Doxygen comments * Separate int16_ref into separate file * Separate out table axies & values into separate types No need for metadata types & more localised code. E.g. creating iterators is now alongside the data over which they iterate. * Doxygen
2021-11-17 16:30:29 -08:00
table3d_dim_t find_xbin(table3d_axis_t &value, const table3d_axis_t *pAxis, table3d_dim_t size, table3d_dim_t lastBin)
{
return find_bin_max(value, pAxis, size-1U, 0U, lastBin);
}
table3d_dim_t find_ybin(table3d_axis_t &value, const table3d_axis_t *pAxis, table3d_dim_t size, table3d_dim_t lastBin)
{
// Y axis is stored in reverse for performance purposes (not sure that's still valid).
// The minimum value is at the end & max at the start. So need to adjust for that.
return find_bin_max(value, pAxis, size-1U, 0U, lastBin);
}
// ========================= Fixed point math =========================
// An unsigned fixed point number type with 1 integer bit & 8 fractional bits.
// See https://en.wikipedia.org/wiki/Q_(number_format).
// This is specialised for the number range 0..1 - a generic fixed point
// class would miss some important optimisations. Specifically, we can avoid
// type promotion during multiplication.
typedef uint16_t QU1X8_t;
static constexpr QU1X8_t QU1X8_INTEGER_SHIFT = 8;
static constexpr QU1X8_t QU1X8_ONE = (QU1X8_t)1U << QU1X8_INTEGER_SHIFT;
static constexpr QU1X8_t QU1X8_HALF = (QU1X8_t)1U << (QU1X8_INTEGER_SHIFT-1U);
static inline QU1X8_t mulQU1X8(QU1X8_t a, QU1X8_t b)
{
// 1x1 == 1....but the real reason for this is to avoid 16-bit multiplication overflow.
//
// We are using uint16_t as our underlying fixed point type. If we follow the regular
// code path, we'd need to promote to uint32_t to avoid overflow.
//
// The overflow can only happen when *both* the X & Y inputs
// are at the edge of a bin.
//
// This is a rare condition, so most of the time we can use 16-bit multiplication and gain performance
if (a==QU1X8_ONE && b==QU1X8_ONE)
Reduce 3d table memory usage (>500 bytes) (#662) * Use table_row_iterator_t to adjust ignitionTable * Separate 2d & 3d table code, abstract page to table iterator conversion. This is just moving code around in preparation for future changes. * Reduce table RAM (.bss) usage Generate a separate type for each possible 3d axis & size combination. This turns what was runtime information into compile time data. * Save 1 byte per table. Use a flag value (INT16_MAX) instead of a separate boolean flag * File renaming table_iterator -> table3d_iterator.h table3d.h -> table3d_interpolate.h table3d.cpp -> table3d_interpolate.cpp table3d_types.h -> table3d.h * Optimize page.cpp: reduce code clutter, maintain performance * Reduce flash usage * Encapsulate table metadata * Performance - hoist if statement * Replace function with macro * Use a packed enum as a type identifier Use a packed enum as a type identifier Slimmer data types * Use table iterators for random access to table values and axis. * Centralize write buffer check * Encapsulate 16-bit reference concept * Performance: make table iterators proper classes This allows us to chain calls on temporaries - not possible with regular function calls. * Performance: encapsulate EEPROM update & address increment * Save flash - don't duplicate function * Performance: directly invalidate table cache * Separate out iterator reversal * Separate out entity mapping & per-byte access Much faster, smaller code footprint & easier to understand * Code quality fixes * Separate out axis metadata * Doxygen comments * Separate int16_ref into separate file * Separate out table axies & values into separate types No need for metadata types & more localised code. E.g. creating iterators is now alongside the data over which they iterate. * Doxygen
2021-11-17 16:30:29 -08:00
{
return QU1X8_ONE;
Reduce 3d table memory usage (>500 bytes) (#662) * Use table_row_iterator_t to adjust ignitionTable * Separate 2d & 3d table code, abstract page to table iterator conversion. This is just moving code around in preparation for future changes. * Reduce table RAM (.bss) usage Generate a separate type for each possible 3d axis & size combination. This turns what was runtime information into compile time data. * Save 1 byte per table. Use a flag value (INT16_MAX) instead of a separate boolean flag * File renaming table_iterator -> table3d_iterator.h table3d.h -> table3d_interpolate.h table3d.cpp -> table3d_interpolate.cpp table3d_types.h -> table3d.h * Optimize page.cpp: reduce code clutter, maintain performance * Reduce flash usage * Encapsulate table metadata * Performance - hoist if statement * Replace function with macro * Use a packed enum as a type identifier Use a packed enum as a type identifier Slimmer data types * Use table iterators for random access to table values and axis. * Centralize write buffer check * Encapsulate 16-bit reference concept * Performance: make table iterators proper classes This allows us to chain calls on temporaries - not possible with regular function calls. * Performance: encapsulate EEPROM update & address increment * Save flash - don't duplicate function * Performance: directly invalidate table cache * Separate out iterator reversal * Separate out entity mapping & per-byte access Much faster, smaller code footprint & easier to understand * Code quality fixes * Separate out axis metadata * Doxygen comments * Separate int16_ref into separate file * Separate out table axies & values into separate types No need for metadata types & more localised code. E.g. creating iterators is now alongside the data over which they iterate. * Doxygen
2021-11-17 16:30:29 -08:00
}
// Add the equivalent of 0.5 to the final calculation pre-rounding.
// This will have the effect of rounding to the nearest integer, rather
// than always rounding down.
return ((a * b) + QU1X8_HALF) >> QU1X8_INTEGER_SHIFT;
}
Reduce 3d table memory usage (>500 bytes) (#662) * Use table_row_iterator_t to adjust ignitionTable * Separate 2d & 3d table code, abstract page to table iterator conversion. This is just moving code around in preparation for future changes. * Reduce table RAM (.bss) usage Generate a separate type for each possible 3d axis & size combination. This turns what was runtime information into compile time data. * Save 1 byte per table. Use a flag value (INT16_MAX) instead of a separate boolean flag * File renaming table_iterator -> table3d_iterator.h table3d.h -> table3d_interpolate.h table3d.cpp -> table3d_interpolate.cpp table3d_types.h -> table3d.h * Optimize page.cpp: reduce code clutter, maintain performance * Reduce flash usage * Encapsulate table metadata * Performance - hoist if statement * Replace function with macro * Use a packed enum as a type identifier Use a packed enum as a type identifier Slimmer data types * Use table iterators for random access to table values and axis. * Centralize write buffer check * Encapsulate 16-bit reference concept * Performance: make table iterators proper classes This allows us to chain calls on temporaries - not possible with regular function calls. * Performance: encapsulate EEPROM update & address increment * Save flash - don't duplicate function * Performance: directly invalidate table cache * Separate out iterator reversal * Separate out entity mapping & per-byte access Much faster, smaller code footprint & easier to understand * Code quality fixes * Separate out axis metadata * Doxygen comments * Separate int16_ref into separate file * Separate out table axies & values into separate types No need for metadata types & more localised code. E.g. creating iterators is now alongside the data over which they iterate. * Doxygen
2021-11-17 16:30:29 -08:00
// ============================= Axis value to bin % =========================
static inline QU1X8_t compute_bin_position(table3d_axis_t value, const table3d_dim_t &bin, const table3d_axis_t *pAxis)
{
table3d_axis_t binMinValue = pAxis[bin+1U];
if (value==binMinValue) { return 0; }
table3d_axis_t binMaxValue = pAxis[bin];
if (value==binMaxValue) { return QU1X8_ONE; }
table3d_axis_t binWidth = binMaxValue-binMinValue;
// Since we can have bins of any width, we need to use
// 24.8 fixed point to avoid overflow
table3d_axis_t binPosition = value - binMinValue;
uint32_t p = (uint32_t)binPosition << QU1X8_INTEGER_SHIFT;
// But since we are computing the ratio (0 to 1), p is guaranteed to be
// less than binWidth and thus the division below will result in a value
// <=1. So we can reduce the data type from 24.8 (uint32_t) to 1.8 (uint16_t)
Performance: optimize division (#1082) * Add udiv_32_16 * Apply udiv_32_16() where possible * Convert udiv_32_16 to assembler It's worth 20 loop/s * Remove unused functions * Remove degreesPeruSx2048 - unused * Remove angleToTime - replace with direct calls 1. Drop angleToTime() It's slow, only partially implemented and adds zero value (and has MISRA violations) 2. Consistent function naming 3. Doxygen * triggerPri_Nissan360 shouldn't set timePerDegree. It will be overwritten every loop by doCrankSpeedCalcs() * Use angleToTimeMicroSecPerDegree() instead of timePerDegree No loss in performance Increased injection open/close time accuracy (so unit test values must change) Can remove timePerDegree global. * Hide (encapsulate) crank math globals. * Base all angle to time conversions on decoder computed variables. This is within 2us of the revolution based method and is much faster - which is essentially zero percent change. * Performance: move calculation of degreesPeruSx32768 into decoders. Remove doCrankSpeedCalcs() - it's doing nothing at the moment. * Apply libdivide to triggerSetEndTeeth functions. Since triggerToothAngle is set once at initialization time, we can generate the libdivide struct once and reuse it many times. * Remove lastToothCalcAdvance - unused * Replace 16-bit division with shift * Replace 32-bit divison with 16-bit division * Avoid 32-bit division; use div100() * inline percentage() * Optimize div100() * MISRA fixes * Replace magic numbers with #defs * Replace libdivide structs with inline constants No perf or memory changes * Use fixed types for PWM max count variables * Accurate rounded integer division * Formalise rounding behavior (DIV_ROUND_CORRECT) * Apply DIV_ROUND_CORRECT to DIV_ROUND_CLOSEST(), UDIV_ROUND_CLOSEST(), div100(), div360(), percentage() & halfPercentage() * Add, fix & improve unit tests * Add udiv_32_16_closest() * Perf: Limit percentage calculations to 16-bits * MISRA fixes * Add compare_executiontime() to encapsulate common perf testing code * Signed to unsigned division * Convert ignitionLimits() to an inline function. Slight speed up, probably due to removing multiple evaluations of macro arguments. * Split unit tests up. * udiv_32_16 - check for valid parameters
2023-11-05 14:10:08 -08:00
return udiv_32_16(p, (uint16_t)binWidth);
}
Reduce 3d table memory usage (>500 bytes) (#662) * Use table_row_iterator_t to adjust ignitionTable * Separate 2d & 3d table code, abstract page to table iterator conversion. This is just moving code around in preparation for future changes. * Reduce table RAM (.bss) usage Generate a separate type for each possible 3d axis & size combination. This turns what was runtime information into compile time data. * Save 1 byte per table. Use a flag value (INT16_MAX) instead of a separate boolean flag * File renaming table_iterator -> table3d_iterator.h table3d.h -> table3d_interpolate.h table3d.cpp -> table3d_interpolate.cpp table3d_types.h -> table3d.h * Optimize page.cpp: reduce code clutter, maintain performance * Reduce flash usage * Encapsulate table metadata * Performance - hoist if statement * Replace function with macro * Use a packed enum as a type identifier Use a packed enum as a type identifier Slimmer data types * Use table iterators for random access to table values and axis. * Centralize write buffer check * Encapsulate 16-bit reference concept * Performance: make table iterators proper classes This allows us to chain calls on temporaries - not possible with regular function calls. * Performance: encapsulate EEPROM update & address increment * Save flash - don't duplicate function * Performance: directly invalidate table cache * Separate out iterator reversal * Separate out entity mapping & per-byte access Much faster, smaller code footprint & easier to understand * Code quality fixes * Separate out axis metadata * Doxygen comments * Separate int16_ref into separate file * Separate out table axies & values into separate types No need for metadata types & more localised code. E.g. creating iterators is now alongside the data over which they iterate. * Doxygen
2021-11-17 16:30:29 -08:00
// ============================= End internal support functions =========================
//This function pulls a value from a 3D table given a target for X and Y coordinates.
//It performs a 2D linear interpolation as described in: www.megamanual.com/v22manual/ve_tuner.pdf
table3d_value_t __attribute__((noclone)) get3DTableValue(struct table3DGetValueCache *pValueCache,
table3d_dim_t axisSize,
const table3d_value_t *pValues,
const table3d_axis_t *pXAxis,
const table3d_axis_t *pYAxis,
table3d_axis_t Y_in, table3d_axis_t X_in)
{
//0th check is whether the same X and Y values are being sent as last time.
// If they are, this not only prevents a lookup of the axis, but prevents the
//interpolation calcs being performed
if( X_in == pValueCache->last_lookup.x &&
Y_in == pValueCache->last_lookup.y)
Reduce 3d table memory usage (>500 bytes) (#662) * Use table_row_iterator_t to adjust ignitionTable * Separate 2d & 3d table code, abstract page to table iterator conversion. This is just moving code around in preparation for future changes. * Reduce table RAM (.bss) usage Generate a separate type for each possible 3d axis & size combination. This turns what was runtime information into compile time data. * Save 1 byte per table. Use a flag value (INT16_MAX) instead of a separate boolean flag * File renaming table_iterator -> table3d_iterator.h table3d.h -> table3d_interpolate.h table3d.cpp -> table3d_interpolate.cpp table3d_types.h -> table3d.h * Optimize page.cpp: reduce code clutter, maintain performance * Reduce flash usage * Encapsulate table metadata * Performance - hoist if statement * Replace function with macro * Use a packed enum as a type identifier Use a packed enum as a type identifier Slimmer data types * Use table iterators for random access to table values and axis. * Centralize write buffer check * Encapsulate 16-bit reference concept * Performance: make table iterators proper classes This allows us to chain calls on temporaries - not possible with regular function calls. * Performance: encapsulate EEPROM update & address increment * Save flash - don't duplicate function * Performance: directly invalidate table cache * Separate out iterator reversal * Separate out entity mapping & per-byte access Much faster, smaller code footprint & easier to understand * Code quality fixes * Separate out axis metadata * Doxygen comments * Separate int16_ref into separate file * Separate out table axies & values into separate types No need for metadata types & more localised code. E.g. creating iterators is now alongside the data over which they iterate. * Doxygen
2021-11-17 16:30:29 -08:00
{
return pValueCache->lastOutput;
Reduce 3d table memory usage (>500 bytes) (#662) * Use table_row_iterator_t to adjust ignitionTable * Separate 2d & 3d table code, abstract page to table iterator conversion. This is just moving code around in preparation for future changes. * Reduce table RAM (.bss) usage Generate a separate type for each possible 3d axis & size combination. This turns what was runtime information into compile time data. * Save 1 byte per table. Use a flag value (INT16_MAX) instead of a separate boolean flag * File renaming table_iterator -> table3d_iterator.h table3d.h -> table3d_interpolate.h table3d.cpp -> table3d_interpolate.cpp table3d_types.h -> table3d.h * Optimize page.cpp: reduce code clutter, maintain performance * Reduce flash usage * Encapsulate table metadata * Performance - hoist if statement * Replace function with macro * Use a packed enum as a type identifier Use a packed enum as a type identifier Slimmer data types * Use table iterators for random access to table values and axis. * Centralize write buffer check * Encapsulate 16-bit reference concept * Performance: make table iterators proper classes This allows us to chain calls on temporaries - not possible with regular function calls. * Performance: encapsulate EEPROM update & address increment * Save flash - don't duplicate function * Performance: directly invalidate table cache * Separate out iterator reversal * Separate out entity mapping & per-byte access Much faster, smaller code footprint & easier to understand * Code quality fixes * Separate out axis metadata * Doxygen comments * Separate int16_ref into separate file * Separate out table axies & values into separate types No need for metadata types & more localised code. E.g. creating iterators is now alongside the data over which they iterate. * Doxygen
2021-11-17 16:30:29 -08:00
}
// Assign this here, as we might modify coords below.
pValueCache->last_lookup.x = X_in;
pValueCache->last_lookup.y = Y_in;
Reduce 3d table memory usage (>500 bytes) (#662) * Use table_row_iterator_t to adjust ignitionTable * Separate 2d & 3d table code, abstract page to table iterator conversion. This is just moving code around in preparation for future changes. * Reduce table RAM (.bss) usage Generate a separate type for each possible 3d axis & size combination. This turns what was runtime information into compile time data. * Save 1 byte per table. Use a flag value (INT16_MAX) instead of a separate boolean flag * File renaming table_iterator -> table3d_iterator.h table3d.h -> table3d_interpolate.h table3d.cpp -> table3d_interpolate.cpp table3d_types.h -> table3d.h * Optimize page.cpp: reduce code clutter, maintain performance * Reduce flash usage * Encapsulate table metadata * Performance - hoist if statement * Replace function with macro * Use a packed enum as a type identifier Use a packed enum as a type identifier Slimmer data types * Use table iterators for random access to table values and axis. * Centralize write buffer check * Encapsulate 16-bit reference concept * Performance: make table iterators proper classes This allows us to chain calls on temporaries - not possible with regular function calls. * Performance: encapsulate EEPROM update & address increment * Save flash - don't duplicate function * Performance: directly invalidate table cache * Separate out iterator reversal * Separate out entity mapping & per-byte access Much faster, smaller code footprint & easier to understand * Code quality fixes * Separate out axis metadata * Doxygen comments * Separate int16_ref into separate file * Separate out table axies & values into separate types No need for metadata types & more localised code. E.g. creating iterators is now alongside the data over which they iterate. * Doxygen
2021-11-17 16:30:29 -08:00
// Figure out where on the axes the incoming coord are
pValueCache->lastXBinMax = find_xbin(X_in, pXAxis, axisSize, pValueCache->lastXBinMax);
pValueCache->lastYBinMax = find_ybin(Y_in, pYAxis, axisSize, pValueCache->lastYBinMax);
Reduce 3d table memory usage (>500 bytes) (#662) * Use table_row_iterator_t to adjust ignitionTable * Separate 2d & 3d table code, abstract page to table iterator conversion. This is just moving code around in preparation for future changes. * Reduce table RAM (.bss) usage Generate a separate type for each possible 3d axis & size combination. This turns what was runtime information into compile time data. * Save 1 byte per table. Use a flag value (INT16_MAX) instead of a separate boolean flag * File renaming table_iterator -> table3d_iterator.h table3d.h -> table3d_interpolate.h table3d.cpp -> table3d_interpolate.cpp table3d_types.h -> table3d.h * Optimize page.cpp: reduce code clutter, maintain performance * Reduce flash usage * Encapsulate table metadata * Performance - hoist if statement * Replace function with macro * Use a packed enum as a type identifier Use a packed enum as a type identifier Slimmer data types * Use table iterators for random access to table values and axis. * Centralize write buffer check * Encapsulate 16-bit reference concept * Performance: make table iterators proper classes This allows us to chain calls on temporaries - not possible with regular function calls. * Performance: encapsulate EEPROM update & address increment * Save flash - don't duplicate function * Performance: directly invalidate table cache * Separate out iterator reversal * Separate out entity mapping & per-byte access Much faster, smaller code footprint & easier to understand * Code quality fixes * Separate out axis metadata * Doxygen comments * Separate int16_ref into separate file * Separate out table axies & values into separate types No need for metadata types & more localised code. E.g. creating iterators is now alongside the data over which they iterate. * Doxygen
2021-11-17 16:30:29 -08:00
/*
At this point we have the 4 corners of the map where the interpolated value will fall in
Eg: (yMax,xMin) (yMax,xMax)
Reduce 3d table memory usage (>500 bytes) (#662) * Use table_row_iterator_t to adjust ignitionTable * Separate 2d & 3d table code, abstract page to table iterator conversion. This is just moving code around in preparation for future changes. * Reduce table RAM (.bss) usage Generate a separate type for each possible 3d axis & size combination. This turns what was runtime information into compile time data. * Save 1 byte per table. Use a flag value (INT16_MAX) instead of a separate boolean flag * File renaming table_iterator -> table3d_iterator.h table3d.h -> table3d_interpolate.h table3d.cpp -> table3d_interpolate.cpp table3d_types.h -> table3d.h * Optimize page.cpp: reduce code clutter, maintain performance * Reduce flash usage * Encapsulate table metadata * Performance - hoist if statement * Replace function with macro * Use a packed enum as a type identifier Use a packed enum as a type identifier Slimmer data types * Use table iterators for random access to table values and axis. * Centralize write buffer check * Encapsulate 16-bit reference concept * Performance: make table iterators proper classes This allows us to chain calls on temporaries - not possible with regular function calls. * Performance: encapsulate EEPROM update & address increment * Save flash - don't duplicate function * Performance: directly invalidate table cache * Separate out iterator reversal * Separate out entity mapping & per-byte access Much faster, smaller code footprint & easier to understand * Code quality fixes * Separate out axis metadata * Doxygen comments * Separate int16_ref into separate file * Separate out table axies & values into separate types No need for metadata types & more localised code. E.g. creating iterators is now alongside the data over which they iterate. * Doxygen
2021-11-17 16:30:29 -08:00
(yMin,xMin) (yMin,xMax)
Reduce 3d table memory usage (>500 bytes) (#662) * Use table_row_iterator_t to adjust ignitionTable * Separate 2d & 3d table code, abstract page to table iterator conversion. This is just moving code around in preparation for future changes. * Reduce table RAM (.bss) usage Generate a separate type for each possible 3d axis & size combination. This turns what was runtime information into compile time data. * Save 1 byte per table. Use a flag value (INT16_MAX) instead of a separate boolean flag * File renaming table_iterator -> table3d_iterator.h table3d.h -> table3d_interpolate.h table3d.cpp -> table3d_interpolate.cpp table3d_types.h -> table3d.h * Optimize page.cpp: reduce code clutter, maintain performance * Reduce flash usage * Encapsulate table metadata * Performance - hoist if statement * Replace function with macro * Use a packed enum as a type identifier Use a packed enum as a type identifier Slimmer data types * Use table iterators for random access to table values and axis. * Centralize write buffer check * Encapsulate 16-bit reference concept * Performance: make table iterators proper classes This allows us to chain calls on temporaries - not possible with regular function calls. * Performance: encapsulate EEPROM update & address increment * Save flash - don't duplicate function * Performance: directly invalidate table cache * Separate out iterator reversal * Separate out entity mapping & per-byte access Much faster, smaller code footprint & easier to understand * Code quality fixes * Separate out axis metadata * Doxygen comments * Separate int16_ref into separate file * Separate out table axies & values into separate types No need for metadata types & more localised code. E.g. creating iterators is now alongside the data over which they iterate. * Doxygen
2021-11-17 16:30:29 -08:00
In the following calculation the table values are referred to by the following variables:
A B
C D
*/
table3d_dim_t rowMax = pValueCache->lastYBinMax * axisSize;
table3d_dim_t rowMin = rowMax + axisSize;
table3d_dim_t colMax = axisSize - pValueCache->lastXBinMax - 1U;
table3d_dim_t colMin = colMax - 1U;
table3d_value_t A = pValues[rowMax + colMin];
table3d_value_t B = pValues[rowMax + colMax];
table3d_value_t C = pValues[rowMin + colMin];
table3d_value_t D = pValues[rowMin + colMax];
Reduce 3d table memory usage (>500 bytes) (#662) * Use table_row_iterator_t to adjust ignitionTable * Separate 2d & 3d table code, abstract page to table iterator conversion. This is just moving code around in preparation for future changes. * Reduce table RAM (.bss) usage Generate a separate type for each possible 3d axis & size combination. This turns what was runtime information into compile time data. * Save 1 byte per table. Use a flag value (INT16_MAX) instead of a separate boolean flag * File renaming table_iterator -> table3d_iterator.h table3d.h -> table3d_interpolate.h table3d.cpp -> table3d_interpolate.cpp table3d_types.h -> table3d.h * Optimize page.cpp: reduce code clutter, maintain performance * Reduce flash usage * Encapsulate table metadata * Performance - hoist if statement * Replace function with macro * Use a packed enum as a type identifier Use a packed enum as a type identifier Slimmer data types * Use table iterators for random access to table values and axis. * Centralize write buffer check * Encapsulate 16-bit reference concept * Performance: make table iterators proper classes This allows us to chain calls on temporaries - not possible with regular function calls. * Performance: encapsulate EEPROM update & address increment * Save flash - don't duplicate function * Performance: directly invalidate table cache * Separate out iterator reversal * Separate out entity mapping & per-byte access Much faster, smaller code footprint & easier to understand * Code quality fixes * Separate out axis metadata * Doxygen comments * Separate int16_ref into separate file * Separate out table axies & values into separate types No need for metadata types & more localised code. E.g. creating iterators is now alongside the data over which they iterate. * Doxygen
2021-11-17 16:30:29 -08:00
//Check that all values aren't just the same (This regularly happens with things like the fuel trim maps)
if( (A == B) && (A == C) && (A == D) ) { pValueCache->lastOutput = A; }
Reduce 3d table memory usage (>500 bytes) (#662) * Use table_row_iterator_t to adjust ignitionTable * Separate 2d & 3d table code, abstract page to table iterator conversion. This is just moving code around in preparation for future changes. * Reduce table RAM (.bss) usage Generate a separate type for each possible 3d axis & size combination. This turns what was runtime information into compile time data. * Save 1 byte per table. Use a flag value (INT16_MAX) instead of a separate boolean flag * File renaming table_iterator -> table3d_iterator.h table3d.h -> table3d_interpolate.h table3d.cpp -> table3d_interpolate.cpp table3d_types.h -> table3d.h * Optimize page.cpp: reduce code clutter, maintain performance * Reduce flash usage * Encapsulate table metadata * Performance - hoist if statement * Replace function with macro * Use a packed enum as a type identifier Use a packed enum as a type identifier Slimmer data types * Use table iterators for random access to table values and axis. * Centralize write buffer check * Encapsulate 16-bit reference concept * Performance: make table iterators proper classes This allows us to chain calls on temporaries - not possible with regular function calls. * Performance: encapsulate EEPROM update & address increment * Save flash - don't duplicate function * Performance: directly invalidate table cache * Separate out iterator reversal * Separate out entity mapping & per-byte access Much faster, smaller code footprint & easier to understand * Code quality fixes * Separate out axis metadata * Doxygen comments * Separate int16_ref into separate file * Separate out table axies & values into separate types No need for metadata types & more localised code. E.g. creating iterators is now alongside the data over which they iterate. * Doxygen
2021-11-17 16:30:29 -08: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
const QU1X8_t p = compute_bin_position(X_in, pValueCache->lastXBinMax, pXAxis);
const QU1X8_t q = compute_bin_position(Y_in, pValueCache->lastYBinMax, pYAxis);
const QU1X8_t m = mulQU1X8(QU1X8_ONE-p, q);
const QU1X8_t n = mulQU1X8(p, q);
const QU1X8_t o = mulQU1X8(QU1X8_ONE-p, QU1X8_ONE-q);
const QU1X8_t r = mulQU1X8(p, QU1X8_ONE-q);
pValueCache->lastOutput = ( (A * m) + (B * n) + (C * o) + (D * r) ) >> QU1X8_INTEGER_SHIFT;
Reduce 3d table memory usage (>500 bytes) (#662) * Use table_row_iterator_t to adjust ignitionTable * Separate 2d & 3d table code, abstract page to table iterator conversion. This is just moving code around in preparation for future changes. * Reduce table RAM (.bss) usage Generate a separate type for each possible 3d axis & size combination. This turns what was runtime information into compile time data. * Save 1 byte per table. Use a flag value (INT16_MAX) instead of a separate boolean flag * File renaming table_iterator -> table3d_iterator.h table3d.h -> table3d_interpolate.h table3d.cpp -> table3d_interpolate.cpp table3d_types.h -> table3d.h * Optimize page.cpp: reduce code clutter, maintain performance * Reduce flash usage * Encapsulate table metadata * Performance - hoist if statement * Replace function with macro * Use a packed enum as a type identifier Use a packed enum as a type identifier Slimmer data types * Use table iterators for random access to table values and axis. * Centralize write buffer check * Encapsulate 16-bit reference concept * Performance: make table iterators proper classes This allows us to chain calls on temporaries - not possible with regular function calls. * Performance: encapsulate EEPROM update & address increment * Save flash - don't duplicate function * Performance: directly invalidate table cache * Separate out iterator reversal * Separate out entity mapping & per-byte access Much faster, smaller code footprint & easier to understand * Code quality fixes * Separate out axis metadata * Doxygen comments * Separate int16_ref into separate file * Separate out table axies & values into separate types No need for metadata types & more localised code. E.g. creating iterators is now alongside the data over which they iterate. * Doxygen
2021-11-17 16:30:29 -08:00
}
return pValueCache->lastOutput;
}