Speeduino
Loading...
Searching...
No Matches
table2d.h
Go to the documentation of this file.
1/*
2This file is used for everything related to maps/tables including their definition, functions etc
3*/
4#ifndef TABLE_H
5#define TABLE_H
6
7#include <stdint.h>
8#include <Arduino.h>
9
11// private to table2D implementation
12
13namespace _table2d_detail {
14
15// The 2D table cache
16template <typename axis_t, typename value_t>
17struct Table2DCache
18{
19 // Store the upper index of the bin we last found. This is used to make the next check faster
20 // Since this is the *upper* index, it can never be 0.
21 uint8_t lastBinUpperIndex = 1U; // The axis bin search algo relies on this being 1 initially
22
23 //Store the last input and output for caching
24 axis_t lastInput = 0;
25 value_t lastOutput = 0;
26 uint8_t cacheTime = 0U; //Tracks when the last cache value was set so it can expire after x seconds. A timeout is required to pickup when a tuning value is changed, otherwise the old cached value will continue to be returned as the X value isn't changing.
27
28 constexpr Table2DCache(void) = default;
29};
30
31extern uint8_t getCacheTime(void);
32
33// LCOV_EXCL_START
34template <typename axis_t, typename value_t>
35static inline bool cacheExpired(const Table2DCache<axis_t, value_t> &cache) {
36 return (cache.cacheTime != getCacheTime());
37}
38// LCOV_EXCL_STOP
39
40template <typename T>
41struct Bin {
42 constexpr Bin(const T *array, uint8_t binUpperIndex)
46 {
47 }
48 constexpr Bin(uint8_t binUpperIndex, const T upperValue, const T lowerValue)
52 {
53 }
54
55 const T upperValue(void) const noexcept { return _upperValue; }
56 const T lowerValue(void) const noexcept { return _lowerValue; }
57
58 static bool withinBin(const T &value, const T &min, const T&max) noexcept {
59 return (value <= max) && (value > min);
60 }
61 bool withinBin(const T value) const noexcept {
63 }
64
68};
69
70template <typename T, uint8_t sizeT>
71static inline Bin<T> findBin(const T *const array, const T value)
72{
73 // Loop from the upper end of the axis back down to the 1st bin [0,1]
74 // Assume array is ordered [min...max]
75 const T *binLower = array+sizeT-2U;
76 while ( (*binLower >= value) && (binLower != array) ) { --binLower; }
77 return Bin<T>(binLower-array+1U, *(binLower+1U), *binLower);
78}
79
80// Generic interpolation
81// Exclude from code coverage - it's just a wrapper around map()
82// LCOV_EXCL_START
83template <typename axis_t, typename value_t>
84static inline value_t interpolate(const axis_t axisValue, const Bin<axis_t> &axisBin, const Bin<value_t> &valueBin)
85{
86 return map(axisValue, axisBin.lowerValue(), axisBin.upperValue(), valueBin.lowerValue(), valueBin.upperValue());
87}
88// LCOV_EXCL_STOP
89
90// Specialized interpolation of uint8_t for performance
92
93} // _table2d_detail
95
107template <typename axis_t, typename value_t, uint8_t sizeT>
109{
111
114
115 mutable _table2d_detail::Table2DCache<axis_t, value_t> cache;
116
118 : values(*pCurve) //cppcheck-suppress misra-c2012-10.4
119 , axis(*pAxisBin)
120 {
121 }
122
123 static constexpr size_type size(void) { return sizeT; }
124
126// Turn off caching during unit tests
127#if !defined(UNIT_TEST)
128 // LCOV_EXCL_START
129 // Check whether the X input is the same as last time this ran
130 if( (axisValue == cache.lastInput) && (!cacheExpired(cache)) )
131 {
132 return cache.lastOutput;
133 }
134 // LCOV_EXCL_STOP
135#endif
136
137 // Test if above the max axis value, clip to max data value
138 if(axisValue >= axis[sizeT-1U])
139 {
140 cache.lastOutput = values[sizeT-1U];
141 cache.lastBinUpperIndex = sizeT-1U;
142 }
143 // Test if below the min axis value, clip to min data value
144 else if (axisValue <= axis[0])
145 {
146 cache.lastOutput = values[0];
147 cache.lastBinUpperIndex = 1U;
148 }
149 else
150 {
151 // None of the cached or last values match, so we need to find the new value
152 // 1st check is whether we're still in the same X bin as last time
153 _table2d_detail::Bin<axis_t> xBin = _table2d_detail::Bin<axis_t>(axis, cache.lastBinUpperIndex);
154 if (!xBin.withinBin(axisValue))
155 {
156 // LCOV_EXCL_BR_START
157 //If we're not in the same bin, search
158 xBin = _table2d_detail::findBin<axis_t, sizeT>(axis, axisValue);
159 // LCOV_EXCL_BR_STOP
160 }
161
162 // We are exactly at the bin upper bound, so no need to interpolate
163 if (axisValue==xBin.upperValue())
164 {
165 cache.lastOutput = values[xBin.upperIndex];
166 cache.lastBinUpperIndex = xBin.upperIndex;
167 }
168 else // Must be within the bin, interpolate
169 {
170 // LCOV_EXCL_BR_START
171 cache.lastOutput = _table2d_detail::interpolate(axisValue, xBin, _table2d_detail::Bin<value_t>(values, xBin.upperIndex));
172 // LCOV_EXCL_BR_STOP
173 cache.lastBinUpperIndex = xBin.upperIndex;
174 }
175 // Note: we cannot be at the bin lower bound here, as that would violate the bin definition of a non-inclusive lower bound
176 }
177 cache.cacheTime = _table2d_detail::getCacheTime(); //As we're not using the cache value, set the current secl value to track when this new value was calculated
178 cache.lastInput = axisValue;
179
180 return cache.lastOutput;
181 }
182};
183
194template <typename axis_t, typename value_t, uint8_t sizeT>
196{
197 // LCOV_EXCL_START
198 return fromTable->getValue(axisValue);
199 // LCOV_EXCL_STOP
200}
201
202// Hide use of template in the header file
213
214#endif // TABLE_H
static TIntegral readSerialIntegralTimeout(void)
Reads an integral type, timing out if necessary.
Definition comms.cpp:175
A 2D table.
Definition table2d.h:109
_table2d_detail::Table2DCache< axis_t, value_t > cache
Definition table2d.h:115
static constexpr size_type size(void)
Definition table2d.h:123
constexpr table2D(axis_t(*pAxisBin)[sizeT], value_t(*pCurve)[sizeT])
Definition table2d.h:117
axis_t(& axis)[sizeT]
Definition table2d.h:113
uint8_t size_type
Definition table2d.h:110
value_t(& values)[sizeT]
Definition table2d.h:112
value_t getValue(const axis_t axisValue) const
Definition table2d.h:125
static value_t table2D_getValue(const table2D< axis_t, value_t, sizeT > *fromTable, const axis_t axisValue)
Interpolate a value from a 2d table.
Definition table2d.h:195