rusEFI
The most advanced open source ECU
interpolation.cpp
Go to the documentation of this file.
1 /**
2  * @file interpolation.cpp
3  * @brief Linear interpolation algorithms
4  *
5  * See test_interpolation_3d.cpp
6  *
7  *
8  * @date Oct 17, 2013
9  * @author Andrey Belomutskiy, (c) 2012-2020
10  * @author Dmitry Sidin, (c) 2015
11  */
12 
13 #include "pch.h"
14 
15 #include "efi_interpolation.h"
16 
17 #define BINARY_PERF true
18 
19 #if BINARY_PERF && ! EFI_UNIT_TEST
20 
21 #define COUNT 10000
22 
23 float array16[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
24 
25 static void testBinary() {
26  const int size16 = 16;
27 
28  uint32_t totalOld = 0;
29  uint32_t totalNew = 0;
30 
31  for (int v = 0; v <= 16; v++) {
32  uint32_t timeOld;
33  {
34  uint32_t start = getTimeNowLowerNt();
35  int temp = 0;
36  for (int i = 0; i < COUNT; i++) {
37  temp += findIndex(array16, size16, v);
38  }
39  timeOld = getTimeNowLowerNt() - start;
40  }
41  uint32_t timeNew;
42  {
43  uint32_t start = getTimeNowLowerNt();
44  int temp = 0;
45  for (int i = 0; i < COUNT; i++) {
46  temp += findIndex2(array16, size16, v);
47  }
48  timeNew = getTimeNowLowerNt() - start;
49  }
50  efiPrintf("for v=%d old=%d ticks", v, timeOld);
51  efiPrintf("for v=%d new=%d ticks", v, timeNew);
52 
53  totalOld += timeOld;
54  totalNew += timeNew;
55  }
56  efiPrintf("totalOld=%d ticks", totalOld);
57  efiPrintf("totalNew=%d ticks", totalNew);
58 
59 }
60 
61 #endif
62 
63 /** @brief Linear interpolation by two points
64  *
65  * @param x1 key of the first point
66  * @param y1 value of the first point
67  * @param x2 key of the second point
68  * @param y2 value of the second point
69  * @param X key to be interpolated
70  *
71  * @note For example, "interpolateMsg("", engineConfiguration.tpsMin, 0, engineConfiguration.tpsMax, 100, adc);"
72  * @see interpolateClamped
73  */
74 float interpolateMsg(const char *msg, float x1, float y1, float x2, float y2, float x) {
75  if (cisnan(x1) || cisnan(x2) || cisnan(y1) || cisnan(y2)) {
76  warning(ObdCode::CUSTOM_ERR_INTERPOLATE_1, "interpolate%s: why param", msg);
77  return NAN;
78  }
79  if (cisnan(x)) {
80  warning(ObdCode::CUSTOM_ERR_INTERPOLATE_2, "interpolate%s: why X", msg);
81  return NAN;
82  }
83  // todo: double comparison using EPS
84  if (x1 == x2) {
85  /**
86  * we could end up here for example while resetting bins while changing engine type
87  */
88  warning(ObdCode::CUSTOM_ERR_INTERPOLATE_3, "interpolate%s: Same x1 and x2 in interpolate: %.2f/%.2f", msg, x1, x2);
89  return NAN;
90  }
91 
92  // a*x1 + b = y1
93  // a*x2 + b = y2
94 // efiAssertVoid(ObdCode::CUSTOM_ERR_ASSERT_VOID, x1 != x2, "no way we can interpolate");
95  float a = INTERPOLATION_A(x1, y1, x2, y2);
96  if (cisnan(a)) {
97  warning(ObdCode::CUSTOM_ERR_INTERPOLATE_4, "interpolate%s: why a", msg);
98  return NAN;
99  }
100  float b = y1 - a * x1;
101  return a * x + b;
102 }
103 
104 float interpolateClampedWithValidation(float x1, float y1, float x2, float y2, float x) {
105  if (x1 >= x2) {
106  criticalError("interpolateClamped %f has to be smaller than %f", x1, x2);
107  }
108  return interpolateClamped(x1, y1, x2, y2, x);
109 }
110 
111 /**
112  * todo: use 'interpolateClampedWithValidation' wider?
113  * @see interpolateMsg
114  */
115 float interpolateClamped(float x1, float y1, float x2, float y2, float x) {
116  // note how we assume order of x1 and x2 here! see also interpolateClampedWithValidation
117  if (x <= x1)
118  return y1;
119  if (x >= x2)
120  return y2;
121 
122  // todo: do we care with code duplication with interpolateMsg above?
123  float a = INTERPOLATION_A(x1, y1, x2, y2);
124  float b = y1 - a * x1;
125  return a * x + b;
126 }
127 
128 /**
129  * Another implementation, which one is faster?
130  */
131 int findIndex2(const float array[], unsigned size, float value) {
132  efiAssert(ObdCode::CUSTOM_ERR_ASSERT, !cisnan(value), "NaN in findIndex2", 0);
133  efiAssert(ObdCode::CUSTOM_ERR_ASSERT, size > 1, "size in findIndex", 0);
134 // if (size <= 1)
135 // return size && *array <= value ? 0 : -1;
136 
137  signed i = 0;
138  //unsigned b = 1 << int(log(float(size) - 1) / 0.69314718055994530942);
139  unsigned b = size >> 1; // in our case size is always a power of 2
140  efiAssert(ObdCode::CUSTOM_ERR_ASSERT, b + b == size, "Size not power of 2", -1);
141  for (; b; b >>= 1) {
142  unsigned j = i | b;
143  /**
144  * it should be
145  * "if (j < size && array[j] <= value)"
146  * but in our case size is always power of 2 thus size is always more then j
147  */
148  // efiAssert(ObdCode::CUSTOM_ERR_ASSERT, j < size, "size", 0);
149  if (array[j] <= value)
150  i = j;
151  }
152  return i || *array <= value ? i : -1;
153 }
154 
155 int findIndex(const float array[], int size, float value) {
156  return findIndexMsg("", array, size, value);
157 }
158 
160 #if BINARY_PERF && ! EFI_UNIT_TEST
161  addConsoleAction("binarytest", testBinary);
162 #endif
163 }
void addConsoleAction(const char *token, Void callback)
Register console action without parameters.
int findIndexMsg(const char *msg, const kType array[], int size, kType value)
Binary search.
bool warning(ObdCode code, const char *fmt,...)
void initInterpolation()
int findIndex(const float array[], int size, float value)
float interpolateMsg(const char *msg, float x1, float y1, float x2, float y2, float x)
Linear interpolation by two points.
float interpolateClampedWithValidation(float x1, float y1, float x2, float y2, float x)
static void testBinary()
float interpolateClamped(float x1, float y1, float x2, float y2, float x)
int findIndex2(const float array[], unsigned size, float value)
float array16[]
uint32_t getTimeNowLowerNt()
@ CUSTOM_ERR_INTERPOLATE_3
@ CUSTOM_ERR_INTERPOLATE_4
@ CUSTOM_ERR_INTERPOLATE_2
@ CUSTOM_ERR_ASSERT
@ CUSTOM_ERR_INTERPOLATE_1
composite packet size