/** * @file table_helper.h * * @date Jul 6, 2014 * @author Andrey Belomutskiy, (c) 2012-2020 */ #pragma once #include #include "error_handling.h" #include "interpolation.h" #include "efilib.h" #include "efi_ratio.h" // popular left edge of CLT-based correction curves #define CLT_CURVE_RANGE_FROM -40 class ValueProvider3D { public: virtual float getValue(float xRpm, float y) const = 0; }; /** * this helper class brings together 3D table with two 2D axis curves */ template> class Map3D : public ValueProvider3D { public: explicit Map3D(const char*name) { create(name); } void init(vType table[RPM_BIN_SIZE][LOAD_BIN_SIZE], const kType loadBins[LOAD_BIN_SIZE], const kType rpmBins[RPM_BIN_SIZE]) { // this method cannot use logger because it's invoked before everything // that's because this method needs to be invoked before initial configuration processing // and initial configuration load is done prior to logging initialization for (int k = 0; k < LOAD_BIN_SIZE; k++) { pointers[k] = table[k]; } this->loadBins = loadBins; this->rpmBins = rpmBins; } float getValue(float xRpm, float y) const override { efiAssert(CUSTOM_ERR_ASSERT, loadBins, "map not initialized", NAN); if (cisnan(y)) { warning(CUSTOM_PARAM_RANGE, "%s: y is NaN", name); return NAN; } // todo: we have a bit of a mess: in TunerStudio, RPM is X-axis return interpolate3d(y, loadBins, LOAD_BIN_SIZE, xRpm, rpmBins, RPM_BIN_SIZE, pointers) * TValueMultiplier::asFloat(); } void setAll(vType value) { efiAssertVoid(CUSTOM_ERR_6573, loadBins, "map not initialized"); for (int l = 0; l < LOAD_BIN_SIZE; l++) { for (int r = 0; r < RPM_BIN_SIZE; r++) { pointers[l][r] = value / TValueMultiplier::asFloat(); } } } vType *pointers[LOAD_BIN_SIZE]; private: void create(const char* name) { this->name = name; memset(&pointers, 0, sizeof(pointers)); } const kType *loadBins = NULL; const kType *rpmBins = NULL; const char *name; }; template> void copy2DTable(const vType source[LOAD_BIN_SIZE][RPM_BIN_SIZE], vType destination[LOAD_BIN_SIZE][RPM_BIN_SIZE]) { for (int k = 0; k < LOAD_BIN_SIZE; k++) { for (int rpmIndex = 0; rpmIndex < RPM_BIN_SIZE; rpmIndex++) { destination[k][rpmIndex] = source[k][rpmIndex]; } } } typedef Map3D> lambda_Map3D_t; typedef Map3D ign_Map3D_t; typedef Map3D fuel_Map3D_t; typedef Map3D baroCorr_Map3D_t; typedef Map3D pedal2tps_t; typedef Map3D> boostOpenLoop_Map3D_t; typedef Map3D boostClosedLoop_Map3D_t; typedef Map3D iacPidMultiplier_t; typedef Map3D gppwm_Map3D_t; typedef Map3D> mapEstimate_Map3D_t; void setRpmBin(float array[], int size, float idleRpm, float topRpm); /** * @param precision for example '0.1' for one digit fractional part. Default to 0.01, two digits. */ template void setLinearCurve(TValue (&array)[TSize], float from, float to, float precision = 0.01f) { for (int i = 0; i < TSize; i++) { float value = interpolateMsg("setLinearCurve", 0, from, TSize - 1, to, i); /** * rounded values look nicer, also we want to avoid precision mismatch with Tuner Studio */ array[i] = efiRound(value, precision); } } template void setArrayValues(TValue (&array)[TSize], TValue value) { for (int i = 0; i < TSize; i++) { array[i] = value; } } template constexpr void setTable(TElement (&dest)[N][M], const TElement value) { for (size_t n = 0; n < N; n++) { for (size_t m = 0; m < M; m++) { dest[n][m] = value; } } } void setRpmTableBin(float array[], int size);