/** * @file table_helper.h * * @date Jul 6, 2014 * @author Andrey Belomutskiy, (c) 2012-2020 */ #pragma once #include #include "interpolation.h" #include "efilib.h" #include "efi_ratio.h" #include "scaled_channel.h" // popular left edge of CLT-based correction curves #define CLT_CURVE_RANGE_FROM -40 class ValueProvider3D { public: virtual float getValue(float xColumn, float yRow) const = 0; }; /** * this helper class brings together 3D table with two 2D axis curves */ template> class Map3D : public ValueProvider3D { public: template void init(scaled_channel table[TRowNum][TColNum], const kType rowBins[TRowNum], const kType columnBins[TColNum]) { static_assert(TValueMultiplier::den == mult); static_assert(TValueMultiplier::num == 1); m_values = reinterpret_cast(&table[0][0]); 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 { if (!m_values) { // not initialized, return 0 return 0; } auto row = priv::getBinPtr(yRow, m_rowBins); auto col = priv::getBinPtr(xColumn, m_columnBins); // Orient the table such that (0, 0) is the bottom left corner, // then the following variable names will make sense float lowerLeft = getValueAtPosition(row.Idx, col.Idx); float upperLeft = getValueAtPosition(row.Idx + 1, col.Idx); float lowerRight = getValueAtPosition(row.Idx, col.Idx + 1); float upperRight = getValueAtPosition(row.Idx + 1, col.Idx + 1); // Interpolate each side by itself float left = priv::linterp(lowerLeft, upperLeft, row.Frac); float right = priv::linterp(lowerRight, upperRight, row.Frac); // Then interpolate between those float tableValue = priv::linterp(left, right, col.Frac); // Correct by the ratio of table units to "world" units return tableValue * TValueMultiplier::asFloat(); } void setAll(vType value) { efiAssertVoid(CUSTOM_ERR_6573, m_values, "map not initialized"); for (size_t i = 0; i < TRowNum * TColNum; i++) { m_values[i] = value / TValueMultiplier::asFloat(); } } private: static size_t getIndexForCoordinates(size_t row, size_t column) { // Index 0 is bottom left corner // Index TColNum - 1 is bottom right corner // indicies count right, then up return row * TColNum + column; } vType getValueAtPosition(size_t row, size_t column) const { auto idx = getIndexForCoordinates(row, column); return m_values[idx]; } // TODO: should be const /*const*/ vType* m_values = nullptr; const kType *m_rowBins = nullptr; const kType *m_columnBins = nullptr; }; 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; } } } template constexpr void setTable(scaled_channel (&dest)[N][M], float value) { for (size_t n = 0; n < N; n++) { for (size_t m = 0; m < M; m++) { dest[n][m] = value; } } } template constexpr void copyTable(TDest (&dest)[N][M], const TSource (&source)[N][M], float multiply = 1.0f) { for (size_t n = 0; n < N; n++) { for (size_t m = 0; m < M; m++) { dest[n][m] = source[n][m] * multiply; } } } void setRpmTableBin(float array[], int size);