support autoscale on table axes (#3452)
* scale map Y axis * allow different row/col types * scaled channel detector * interpolation * looks like this actually works * tests, no manual scaling * comment
This commit is contained in:
parent
e1b085cf32
commit
24224729a3
|
@ -14,7 +14,7 @@
|
||||||
#include "wall_fuel_state_generated.h"
|
#include "wall_fuel_state_generated.h"
|
||||||
#include "tps_accel_state_generated.h"
|
#include "tps_accel_state_generated.h"
|
||||||
|
|
||||||
typedef Map3D<TPS_TPS_ACCEL_TABLE, TPS_TPS_ACCEL_TABLE, float, float> tps_tps_Map3D_t;
|
typedef Map3D<TPS_TPS_ACCEL_TABLE, TPS_TPS_ACCEL_TABLE, float, float, float> tps_tps_Map3D_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* this object is used for MAP rate-of-change and TPS rate-of-change corrections
|
* this object is used for MAP rate-of-change and TPS rate-of-change corrections
|
||||||
|
|
|
@ -41,7 +41,7 @@ float SpeedDensityAirmass::getMap(int rpm) const {
|
||||||
float fallbackMap;
|
float fallbackMap;
|
||||||
if (CONFIG(enableMapEstimationTableFallback)) {
|
if (CONFIG(enableMapEstimationTableFallback)) {
|
||||||
// if the map estimation table is enabled, estimate map based on the TPS and RPM
|
// if the map estimation table is enabled, estimate map based on the TPS and RPM
|
||||||
fallbackMap = m_mapEstimationTable->getValue(rpm, TPS_2_BYTE_PACKING_MULT * Sensor::getOrZero(SensorType::Tps1));
|
fallbackMap = m_mapEstimationTable->getValue(rpm, Sensor::getOrZero(SensorType::Tps1));
|
||||||
} else {
|
} else {
|
||||||
fallbackMap = CONFIG(failedMapFallback);
|
fallbackMap = CONFIG(failedMapFallback);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
// see useFSIO5ForCriticalIssueEngineStop
|
// see useFSIO5ForCriticalIssueEngineStop
|
||||||
#define MAGIC_OFFSET_FOR_CRITICAL_ENGINE 5
|
#define MAGIC_OFFSET_FOR_CRITICAL_ENGINE 5
|
||||||
|
|
||||||
typedef Map3D<FSIO_TABLE_8, FSIO_TABLE_8, float, float> fsio8_Map3D_f32t;
|
typedef Map3D<FSIO_TABLE_8, FSIO_TABLE_8, float, float, float> fsio8_Map3D_f32t;
|
||||||
typedef Map3D<FSIO_TABLE_8, FSIO_TABLE_8, uint8_t, float> fsio8_Map3D_u8t;
|
typedef Map3D<FSIO_TABLE_8, FSIO_TABLE_8, uint8_t, float, float> fsio8_Map3D_u8t;
|
||||||
|
|
||||||
expected<float> getEngineValue(le_action_e action DECLARE_ENGINE_PARAMETER_SUFFIX);
|
expected<float> getEngineValue(le_action_e action DECLARE_ENGINE_PARAMETER_SUFFIX);
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
#include "interpolation.h"
|
#include "interpolation.h"
|
||||||
#include "efi_ratio.h"
|
#include "efi_ratio.h"
|
||||||
|
|
||||||
template <class TBin, class TValue, int TSize, typename TInputScale = efi::ratio<1>, typename TOutputScale = efi::ratio<1>>
|
template <class TBin, class TValue, int TSize, typename TOutputScale = efi::ratio<1>>
|
||||||
class TableFunc final : public SensorConverter {
|
class TableFunc final : public SensorConverter {
|
||||||
public:
|
public:
|
||||||
TableFunc(TBin (&bins)[TSize], TValue (&values)[TSize])
|
TableFunc(TBin (&bins)[TSize], TValue (&values)[TSize])
|
||||||
|
@ -20,9 +20,6 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
SensorResult convert(float inputValue) const override {
|
SensorResult convert(float inputValue) const override {
|
||||||
// Multiply by the reciprocal instead of dividing
|
|
||||||
inputValue = inputValue * TInputScale::recip::asFloat();
|
|
||||||
|
|
||||||
return interpolate2d(inputValue, m_bins, m_values) * TOutputScale::asFloat();
|
return interpolate2d(inputValue, m_bins, m_values) * TOutputScale::asFloat();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,8 +14,6 @@ using ValueType = std::remove_extent_t<decltype(CONFIG(fuelLevelValues))>;
|
||||||
|
|
||||||
static TableFunc
|
static TableFunc
|
||||||
<BinType, ValueType, FUEL_LEVEL_TABLE_COUNT,
|
<BinType, ValueType, FUEL_LEVEL_TABLE_COUNT,
|
||||||
// Bins are stored in millivolts
|
|
||||||
efi::ratio<1, PACK_MULT_VOLTAGE>,
|
|
||||||
// Values are stored in percent
|
// Values are stored in percent
|
||||||
efi::ratio<1>>
|
efi::ratio<1>>
|
||||||
fuelCurve(CONFIG(fuelLevelBins), CONFIG(fuelLevelValues));
|
fuelCurve(CONFIG(fuelLevelBins), CONFIG(fuelLevelValues));
|
||||||
|
|
|
@ -13,9 +13,7 @@ using BinType = std::remove_extent_t<decltype(config->mafDecodingBins)>;
|
||||||
using ValueType = std::remove_extent_t<decltype(config->mafDecoding)>;
|
using ValueType = std::remove_extent_t<decltype(config->mafDecoding)>;
|
||||||
|
|
||||||
// This function converts volts -> kg/h
|
// This function converts volts -> kg/h
|
||||||
static TableFunc
|
static TableFunc mafCurve(config->mafDecodingBins, config->mafDecoding);
|
||||||
<BinType, ValueType, MAF_DECODING_COUNT>
|
|
||||||
mafCurve(config->mafDecodingBins, config->mafDecoding);
|
|
||||||
|
|
||||||
void initMaf(DECLARE_CONFIG_PARAMETER_SIGNATURE) {
|
void initMaf(DECLARE_CONFIG_PARAMETER_SIGNATURE) {
|
||||||
adc_channel_e channel = CONFIG(mafAdcChannel);
|
adc_channel_e channel = CONFIG(mafAdcChannel);
|
||||||
|
|
|
@ -977,7 +977,7 @@ custom maf_sensor_type_e 4 bits, S32, @OFFSET@, [0:1], @@maf_sensor_type_e_enum@
|
||||||
pin_output_mode_e drv8860_csPinMode;
|
pin_output_mode_e drv8860_csPinMode;
|
||||||
brain_pin_e drv8860_miso;
|
brain_pin_e drv8860_miso;
|
||||||
|
|
||||||
uint16_t[FUEL_LEVEL_TABLE_COUNT] fuelLevelBins;;"volt", {1/@@PACK_MULT_VOLTAGE@@}, 0, 0, 5, 3
|
uint16_t[FUEL_LEVEL_TABLE_COUNT] autoscale<PACK_MULT_VOLTAGE> fuelLevelBins;;"volt", {1/@@PACK_MULT_VOLTAGE@@}, 0, 0, 5, 3
|
||||||
|
|
||||||
output_pin_e[LUA_PWM_COUNT iterate] luaOutputPins
|
output_pin_e[LUA_PWM_COUNT iterate] luaOutputPins
|
||||||
|
|
||||||
|
@ -1558,7 +1558,7 @@ tcubinary_table_t tcuSolenoidTable;
|
||||||
float vssFilterReciprocal;+Good example: number of tooth on wheel, For Can 10 is a good number.;"Hz", 1, 0, 2, 20, 2
|
float vssFilterReciprocal;+Good example: number of tooth on wheel, For Can 10 is a good number.;"Hz", 1, 0, 2, 20, 2
|
||||||
|
|
||||||
map_estimate_table_t mapEstimateTable;
|
map_estimate_table_t mapEstimateTable;
|
||||||
uint16_t[FUEL_LOAD_COUNT] mapEstimateTpsBins;;"% TPS", {1/@@TPS_2_BYTE_PACKING_MULT@@}, 0, 0, 100, 1
|
uint16_t[FUEL_LOAD_COUNT] autoscale<TPS_2_BYTE_PACKING_MULT> mapEstimateTpsBins;;"% TPS", {1/@@TPS_2_BYTE_PACKING_MULT@@}, 0, 0, 100, 1
|
||||||
uint16_t[FUEL_RPM_COUNT] mapEstimateRpmBins;;"RPM", 1, 0, 0, 18000, 0
|
uint16_t[FUEL_RPM_COUNT] mapEstimateRpmBins;;"RPM", 1, 0, 0, 18000, 0
|
||||||
|
|
||||||
fsio_table_8x8_u8t vvtTable1;
|
fsio_table_8x8_u8t vvtTable1;
|
||||||
|
|
|
@ -25,25 +25,16 @@ public:
|
||||||
/**
|
/**
|
||||||
* this helper class brings together 3D table with two 2D axis curves
|
* this helper class brings together 3D table with two 2D axis curves
|
||||||
*/
|
*/
|
||||||
template<int TColNum, int TRowNum, typename vType, typename kType, typename TValueMultiplier = efi::ratio<1>>
|
template<int TColNum, int TRowNum, typename TValue, typename TColumn, typename TRow, typename TValueMultiplier = efi::ratio<1>>
|
||||||
class Map3D : public ValueProvider3D {
|
class Map3D : public ValueProvider3D {
|
||||||
public:
|
public:
|
||||||
template<int mult>
|
template <typename TValueInit, typename TRowInit, typename TColumnInit>
|
||||||
void init(scaled_channel<vType, mult> table[TRowNum][TColNum], const kType rowBins[TRowNum], const kType columnBins[TColNum]) {
|
void init(TValueInit table[TRowNum][TColNum], const TRowInit rowBins[TRowNum], const TColumnInit columnBins[TColNum]) {
|
||||||
static_assert(TValueMultiplier::den == mult);
|
// This splits out here so that we don't need one overload of init per possible combination of table/rows/columns types/dimensions
|
||||||
static_assert(TValueMultiplier::num == 1);
|
// Overload resolution figures out the correct versions of the functions below to call, some of which have assertions about what's allowed
|
||||||
|
initValues(table);
|
||||||
m_values = reinterpret_cast<vType*>(&table[0][0]);
|
initRows(rowBins);
|
||||||
|
initCols(columnBins);
|
||||||
m_rowBins = rowBins;
|
|
||||||
m_columnBins = columnBins;
|
|
||||||
}
|
|
||||||
|
|
||||||
void init(vType table[TRowNum][TColNum], const kType rowBins[TRowNum], const kType columnBins[TColNum]) {
|
|
||||||
m_values = &table[0][0];
|
|
||||||
|
|
||||||
m_rowBins = rowBins;
|
|
||||||
m_columnBins = columnBins;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float getValue(float xColumn, float yRow) const override {
|
float getValue(float xColumn, float yRow) const override {
|
||||||
|
@ -52,8 +43,8 @@ public:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto row = priv::getBinPtr<kType, TRowNum>(yRow, m_rowBins);
|
auto row = priv::getBinPtr<TRow, TRowNum>(yRow * m_rowMult, m_rowBins);
|
||||||
auto col = priv::getBinPtr<kType, TColNum>(xColumn, m_columnBins);
|
auto col = priv::getBinPtr<TColumn, TColNum>(xColumn * m_colMult, m_columnBins);
|
||||||
|
|
||||||
// Orient the table such that (0, 0) is the bottom left corner,
|
// Orient the table such that (0, 0) is the bottom left corner,
|
||||||
// then the following variable names will make sense
|
// then the following variable names will make sense
|
||||||
|
@ -73,7 +64,7 @@ public:
|
||||||
return tableValue * TValueMultiplier::asFloat();
|
return tableValue * TValueMultiplier::asFloat();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setAll(vType value) {
|
void setAll(TValue value) {
|
||||||
efiAssertVoid(CUSTOM_ERR_6573, m_values, "map not initialized");
|
efiAssertVoid(CUSTOM_ERR_6573, m_values, "map not initialized");
|
||||||
|
|
||||||
for (size_t i = 0; i < TRowNum * TColNum; i++) {
|
for (size_t i = 0; i < TRowNum * TColNum; i++) {
|
||||||
|
@ -82,6 +73,40 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
template <int TMult>
|
||||||
|
void initValues(scaled_channel<TValue, TMult> table[TRowNum][TColNum]) {
|
||||||
|
static_assert(TValueMultiplier::den == TMult);
|
||||||
|
static_assert(TValueMultiplier::num == 1);
|
||||||
|
|
||||||
|
m_values = reinterpret_cast<TValue*>(&table[0][0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void initValues(TValue table[TRowNum][TColNum]) {
|
||||||
|
m_values = &table[0][0];
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int TRowMult>
|
||||||
|
void initRows(const scaled_channel<TRow, TRowMult> rowBins[TRowNum]) {
|
||||||
|
m_rowBins = reinterpret_cast<const TRow*>(&rowBins[0]);
|
||||||
|
m_rowMult = TRowMult;
|
||||||
|
}
|
||||||
|
|
||||||
|
void initRows(const TRow rowBins[TRowNum]) {
|
||||||
|
m_rowBins = &rowBins[0];
|
||||||
|
m_rowMult = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int TColMult>
|
||||||
|
void initCols(const scaled_channel<TColumn, TColMult> columnBins[TColNum]) {
|
||||||
|
m_columnBins = reinterpret_cast<const TColumn*>(&columnBins[0]);
|
||||||
|
m_colMult = TColMult;
|
||||||
|
}
|
||||||
|
|
||||||
|
void initCols(const TColumn columnBins[TColNum]) {
|
||||||
|
m_columnBins = &columnBins[0];
|
||||||
|
m_colMult = 1;
|
||||||
|
}
|
||||||
|
|
||||||
static size_t getIndexForCoordinates(size_t row, size_t column) {
|
static size_t getIndexForCoordinates(size_t row, size_t column) {
|
||||||
// Index 0 is bottom left corner
|
// Index 0 is bottom left corner
|
||||||
// Index TColNum - 1 is bottom right corner
|
// Index TColNum - 1 is bottom right corner
|
||||||
|
@ -89,28 +114,31 @@ private:
|
||||||
return row * TColNum + column;
|
return row * TColNum + column;
|
||||||
}
|
}
|
||||||
|
|
||||||
vType getValueAtPosition(size_t row, size_t column) const {
|
TValue getValueAtPosition(size_t row, size_t column) const {
|
||||||
auto idx = getIndexForCoordinates(row, column);
|
auto idx = getIndexForCoordinates(row, column);
|
||||||
return m_values[idx];
|
return m_values[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: should be const
|
// TODO: should be const
|
||||||
/*const*/ vType* m_values = nullptr;
|
/*const*/ TValue* m_values = nullptr;
|
||||||
|
|
||||||
const kType *m_rowBins = nullptr;
|
const TRow *m_rowBins = nullptr;
|
||||||
const kType *m_columnBins = nullptr;
|
const TColumn *m_columnBins = nullptr;
|
||||||
|
|
||||||
|
float m_rowMult = 1;
|
||||||
|
float m_colMult = 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef Map3D<FUEL_RPM_COUNT, FUEL_LOAD_COUNT, uint8_t, float, efi::ratio<1, PACK_MULT_LAMBDA_CFG>> lambda_Map3D_t;
|
typedef Map3D<FUEL_RPM_COUNT, FUEL_LOAD_COUNT, uint8_t, float, float, efi::ratio<1, PACK_MULT_LAMBDA_CFG>> lambda_Map3D_t;
|
||||||
typedef Map3D<IGN_RPM_COUNT, IGN_LOAD_COUNT, float, float> ign_Map3D_t;
|
typedef Map3D<IGN_RPM_COUNT, IGN_LOAD_COUNT, float, float, float> ign_Map3D_t;
|
||||||
typedef Map3D<FUEL_RPM_COUNT, FUEL_LOAD_COUNT, float, float> fuel_Map3D_t;
|
typedef Map3D<FUEL_RPM_COUNT, FUEL_LOAD_COUNT, float, float, float> fuel_Map3D_t;
|
||||||
typedef Map3D<BARO_CORR_SIZE, BARO_CORR_SIZE, float, float> baroCorr_Map3D_t;
|
typedef Map3D<BARO_CORR_SIZE, BARO_CORR_SIZE, float, float, float> baroCorr_Map3D_t;
|
||||||
typedef Map3D<PEDAL_TO_TPS_SIZE, PEDAL_TO_TPS_SIZE, uint8_t, uint8_t> pedal2tps_t;
|
typedef Map3D<PEDAL_TO_TPS_SIZE, PEDAL_TO_TPS_SIZE, uint8_t, uint8_t, uint8_t> pedal2tps_t;
|
||||||
typedef Map3D<BOOST_RPM_COUNT, BOOST_LOAD_COUNT, uint8_t, uint8_t, efi::ratio<LOAD_1_BYTE_PACKING_MULT>> boostOpenLoop_Map3D_t;
|
typedef Map3D<BOOST_RPM_COUNT, BOOST_LOAD_COUNT, uint8_t, uint8_t, uint8_t, efi::ratio<LOAD_1_BYTE_PACKING_MULT>> boostOpenLoop_Map3D_t;
|
||||||
typedef Map3D<BOOST_RPM_COUNT, BOOST_LOAD_COUNT, uint8_t, uint8_t> boostClosedLoop_Map3D_t;
|
typedef Map3D<BOOST_RPM_COUNT, BOOST_LOAD_COUNT, uint8_t, uint8_t, uint8_t> boostClosedLoop_Map3D_t;
|
||||||
typedef Map3D<IAC_PID_MULT_SIZE, IAC_PID_MULT_SIZE, uint8_t, uint8_t> iacPidMultiplier_t;
|
typedef Map3D<IAC_PID_MULT_SIZE, IAC_PID_MULT_SIZE, uint8_t, uint8_t, uint8_t> iacPidMultiplier_t;
|
||||||
typedef Map3D<GPPWM_RPM_COUNT, GPPWM_LOAD_COUNT, uint8_t, uint8_t> gppwm_Map3D_t;
|
typedef Map3D<GPPWM_RPM_COUNT, GPPWM_LOAD_COUNT, uint8_t, uint8_t, uint8_t> gppwm_Map3D_t;
|
||||||
typedef Map3D<FUEL_RPM_COUNT, FUEL_LOAD_COUNT, uint16_t, uint16_t, efi::ratio<1, PACK_MULT_MAP_ESTIMATE>> mapEstimate_Map3D_t;
|
typedef Map3D<FUEL_RPM_COUNT, FUEL_LOAD_COUNT, uint16_t, uint16_t, uint16_t, efi::ratio<1, PACK_MULT_MAP_ESTIMATE>> mapEstimate_Map3D_t;
|
||||||
|
|
||||||
void setRpmBin(float array[], int size, float idleRpm, float topRpm);
|
void setRpmBin(float array[], int size, float idleRpm, float topRpm);
|
||||||
|
|
||||||
|
|
|
@ -94,11 +94,23 @@ BinResult getBinPtr(float value, const TBin* bins) {
|
||||||
return { idx, fraction };
|
return { idx, fraction };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class TBin, int TSize, int TMult>
|
||||||
|
BinResult getBinPtr(float value, const scaled_channel<TBin, TMult>* bins) {
|
||||||
|
// Strip off the scaled_channel, and perform the scaling before searching the array
|
||||||
|
auto binPtrRaw = reinterpret_cast<const TBin*>(bins);
|
||||||
|
return getBinPtr<TBin, TSize>(value * TMult, binPtrRaw);
|
||||||
|
}
|
||||||
|
|
||||||
template<class TBin, int TSize>
|
template<class TBin, int TSize>
|
||||||
BinResult getBin(float value, const TBin (&bins)[TSize]) {
|
BinResult getBin(float value, const TBin (&bins)[TSize]) {
|
||||||
return getBinPtr<TBin, TSize>(value, &bins[0]);
|
return getBinPtr<TBin, TSize>(value, &bins[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class TBin, int TSize, int TMult>
|
||||||
|
BinResult getBin(float value, const scaled_channel<TBin, TMult> (&bins)[TSize]) {
|
||||||
|
return getBinPtr<TBin, TSize, TMult>(value, &bins[0]);
|
||||||
|
}
|
||||||
|
|
||||||
static float linterp(float low, float high, float frac)
|
static float linterp(float low, float high, float frac)
|
||||||
{
|
{
|
||||||
return high * frac + low * (1 - frac);
|
return high * frac + low * (1 - frac);
|
||||||
|
@ -108,7 +120,7 @@ static float linterp(float low, float high, float frac)
|
||||||
template <class TBin, class TValue, int TSize>
|
template <class TBin, class TValue, int TSize>
|
||||||
float interpolate2d(const float value, const TBin (&bin)[TSize], const TValue (&values)[TSize]) {
|
float interpolate2d(const float value, const TBin (&bin)[TSize], const TValue (&values)[TSize]) {
|
||||||
// Enforce numeric only (int, float, uintx_t, etc)
|
// Enforce numeric only (int, float, uintx_t, etc)
|
||||||
static_assert(std::is_arithmetic_v<TBin>, "Table values must be an arithmetic type");
|
static_assert(std::is_arithmetic_v<TBin> || is_scaled_channel<TBin>, "Table values must be an arithmetic type or scaled channel");
|
||||||
|
|
||||||
auto b = priv::getBin(value, bin);
|
auto b = priv::getBin(value, bin);
|
||||||
|
|
||||||
|
|
|
@ -16,13 +16,18 @@
|
||||||
|
|
||||||
#include "rusefi_generated.h"
|
#include "rusefi_generated.h"
|
||||||
|
|
||||||
|
struct scaled_channel_base { };
|
||||||
|
|
||||||
|
template <typename TTest>
|
||||||
|
static constexpr bool is_scaled_channel = std::is_base_of_v<scaled_channel_base, TTest>;
|
||||||
|
|
||||||
// This class lets us transparently store something at a ratio inside an integer type
|
// This class lets us transparently store something at a ratio inside an integer type
|
||||||
// Just use it like a float - you can read and write to it, like this:
|
// Just use it like a float - you can read and write to it, like this:
|
||||||
// scaled_channel<uint8_t, 10> myVar;
|
// scaled_channel<uint8_t, 10> myVar;
|
||||||
// myVar = 2.4f; // converts to an int, stores 24
|
// myVar = 2.4f; // converts to an int, stores 24
|
||||||
// float x = myVar; // converts back to float, returns 2.4f
|
// float x = myVar; // converts back to float, returns 2.4f
|
||||||
template <typename T, int mult = 1>
|
template <typename T, int mult = 1>
|
||||||
class scaled_channel {
|
class scaled_channel : scaled_channel_base {
|
||||||
using TSelf = scaled_channel<T, mult>;
|
using TSelf = scaled_channel<T, mult>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -78,3 +83,7 @@ using scaled_voltage = scaled_channel<uint16_t, PACK_MULT_VOLTAGE>; // 0-65v at
|
||||||
using scaled_afr = scaled_channel<uint16_t, PACK_MULT_AFR>; // 0-65afr at 0.001 resolution
|
using scaled_afr = scaled_channel<uint16_t, PACK_MULT_AFR>; // 0-65afr at 0.001 resolution
|
||||||
using scaled_lambda = scaled_channel<uint16_t, PACK_MULT_LAMBDA>; // 0-6.5 lambda at 0.0001 resolution
|
using scaled_lambda = scaled_channel<uint16_t, PACK_MULT_LAMBDA>; // 0-6.5 lambda at 0.0001 resolution
|
||||||
using scaled_fuel_mass_mg = scaled_channel<uint16_t, PACK_MULT_FUEL_MASS>; // 0 - 655.35 milligrams, 0.01mg resolution
|
using scaled_fuel_mass_mg = scaled_channel<uint16_t, PACK_MULT_FUEL_MASS>; // 0 - 655.35 milligrams, 0.01mg resolution
|
||||||
|
|
||||||
|
// make sure the scaled channel detector works
|
||||||
|
static_assert(!is_scaled_channel<int>);
|
||||||
|
static_assert(is_scaled_channel<scaled_channel<int, 5>>);
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
float rpmBins[5] = { 100, 200, 300, 400, 500 };
|
float rpmBins[5] = { 100, 200, 300, 400, 500 };
|
||||||
float mafBins[4] = { 1, 2, 3, 4 };
|
float mafBins[4] = { 1, 2, 3, 4 };
|
||||||
|
|
||||||
|
scaled_channel<int, 10> mafBins2[4] = { 1, 2, 3, 4 };
|
||||||
|
|
||||||
float map[4][5] = {
|
float map[4][5] = {
|
||||||
{ 1, 2, 3, 4, 4},
|
{ 1, 2, 3, 4, 4},
|
||||||
{ 2, 3, 4, 200, 200 },
|
{ 2, 3, 4, 200, 200 },
|
||||||
|
@ -21,15 +23,27 @@ float map[4][5] = {
|
||||||
{ 4, 5, 300, 600, 600 },
|
{ 4, 5, 300, 600, 600 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static float getValue(float rpm, float maf) {
|
|
||||||
Map3D<5, 4, float, float> x;
|
|
||||||
x.init(map, mafBins, rpmBins);
|
|
||||||
|
|
||||||
return x.getValue(rpm, maf);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define EXPECT_NEAR_M4(a, b) EXPECT_NEAR(a, b, 1e-4)
|
#define EXPECT_NEAR_M4(a, b) EXPECT_NEAR(a, b, 1e-4)
|
||||||
|
|
||||||
|
static float getValue(float rpm, float maf) {
|
||||||
|
float result1, result2;
|
||||||
|
|
||||||
|
Map3D<5, 4, float, float, float> x1;
|
||||||
|
x1.init(map, mafBins, rpmBins);
|
||||||
|
|
||||||
|
result1 = x1.getValue(rpm, maf);
|
||||||
|
|
||||||
|
|
||||||
|
Map3D<5, 4, float, float, int> x2;
|
||||||
|
x2.init(map, mafBins2, rpmBins);
|
||||||
|
|
||||||
|
result2 = x2.getValue(rpm, maf);
|
||||||
|
|
||||||
|
EXPECT_NEAR_M4(result1, result2);
|
||||||
|
|
||||||
|
return result1;
|
||||||
|
}
|
||||||
|
|
||||||
static void newTestToComfirmInterpolation() {
|
static void newTestToComfirmInterpolation() {
|
||||||
// here's how the table loos like:
|
// here's how the table loos like:
|
||||||
//
|
//
|
||||||
|
|
|
@ -16,12 +16,12 @@ TEST(TableFuncTest, basic) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TableFuncTest, scaled) {
|
TEST(TableFuncTest, scaled) {
|
||||||
uint16_t in[] = { 0, 1000, 2000 };
|
scaled_channel<uint16_t, 1000> in[] = { 0, 1, 2 };
|
||||||
uint8_t out[] = { 70, 60, 50 };
|
uint8_t out[] = { 70, 60, 50 };
|
||||||
|
|
||||||
TableFunc<uint16_t, uint8_t, 3,
|
using BinType = std::remove_extent_t<decltype(in)>;
|
||||||
// Input units are 1/1000
|
|
||||||
efi::ratio<1, 1000>,
|
TableFunc<BinType, uint8_t, 3,
|
||||||
// output units are 1/100
|
// output units are 1/100
|
||||||
efi::ratio<1, 100>>
|
efi::ratio<1, 100>>
|
||||||
dut(in, out);
|
dut(in, out);
|
||||||
|
|
Loading…
Reference in New Issue