2015-07-10 06:01:56 -07:00
|
|
|
/**
|
2022-09-01 08:35:35 -07:00
|
|
|
* @file efi_interpolation.h
|
|
|
|
* See also libfirmware interpolation.h
|
2015-07-10 06:01:56 -07:00
|
|
|
*
|
|
|
|
* @date Oct 17, 2013
|
2020-01-13 18:57:43 -08:00
|
|
|
* @author Andrey Belomutskiy, (c) 2012-2020
|
2015-07-10 06:01:56 -07:00
|
|
|
*/
|
|
|
|
|
2020-04-01 18:32:21 -07:00
|
|
|
#pragma once
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2022-09-01 08:35:35 -07:00
|
|
|
#include <rusefi/isnan.h>
|
2016-06-29 20:01:53 -07:00
|
|
|
#include <math.h>
|
2015-07-10 06:01:56 -07:00
|
|
|
#include "datalogging.h"
|
2016-06-29 20:01:53 -07:00
|
|
|
#include "obd_error_codes.h"
|
2022-09-05 01:00:24 -07:00
|
|
|
#include "error_handling.h"
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2021-01-11 05:00:15 -08:00
|
|
|
#include <type_traits>
|
|
|
|
|
2017-03-27 19:55:22 -07:00
|
|
|
#ifndef DEBUG_INTERPOLATION
|
2018-03-04 19:55:24 -08:00
|
|
|
#define DEBUG_INTERPOLATION FALSE
|
2017-03-27 19:55:22 -07:00
|
|
|
#endif
|
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
#define INTERPOLATION_A(x1, y1, x2, y2) ((y1 - y2) / (x1 - x2))
|
|
|
|
|
|
|
|
int findIndex(const float array[], int size, float value);
|
|
|
|
int findIndex2(const float array[], unsigned size, float value);
|
2017-08-01 13:27:16 -07:00
|
|
|
float interpolateClamped(float x1, float y1, float x2, float y2, float x);
|
2016-01-09 12:01:41 -08:00
|
|
|
float interpolateMsg(const char *msg, float x1, float y1, float x2, float y2, float x);
|
2019-07-09 11:16:36 -07:00
|
|
|
|
2022-01-22 19:17:38 -08:00
|
|
|
// _technically_ and _theoretically_ we can support flat line for both bins and values but I am not sure if
|
|
|
|
// such a rare case is something we want to support
|
2021-06-26 12:02:25 -07:00
|
|
|
template<typename TValue, int TSize>
|
|
|
|
void ensureArrayIsAscending(const char* msg, const TValue (&values)[TSize]) {
|
|
|
|
for (size_t i = 0; i < TSize - 1; i++) {
|
2022-06-29 15:48:30 -07:00
|
|
|
float cur = values[i];
|
|
|
|
float next = values[i + 1];
|
2021-08-16 01:20:32 -07:00
|
|
|
if (next <= cur) {
|
2021-08-16 06:11:22 -07:00
|
|
|
firmwareError(CUSTOM_ERR_AXIS_ORDER, "Invalid table axis (must be ascending!): %s %f %f at %d", msg, cur, next, i);
|
2021-06-26 12:02:25 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-13 12:21:31 -07:00
|
|
|
template<typename TValue, int TSize>
|
|
|
|
void ensureArrayIsAscendingOrDefault(const char* msg, const TValue (&values)[TSize]) {
|
|
|
|
if (values[1] == 0) {
|
|
|
|
return; // looks like default empty array, do not check
|
|
|
|
}
|
|
|
|
ensureArrayIsAscending(msg, values);
|
|
|
|
}
|
|
|
|
|
2019-06-15 11:33:41 -07:00
|
|
|
/** @brief Binary search
|
|
|
|
* @returns the highest index within sorted array such that array[i] is greater than or equal to the parameter
|
|
|
|
* @note If the parameter is smaller than the first element of the array, -1 is returned.
|
|
|
|
*
|
|
|
|
* See also ensureArrayIsAscending
|
|
|
|
*/
|
|
|
|
template<typename kType>
|
|
|
|
int findIndexMsgExt(const char *msg, const kType array[], int size, kType value) {
|
2019-11-17 05:08:57 -08:00
|
|
|
float fvalue = (float)value;
|
|
|
|
if (cisnan(fvalue)) {
|
2019-06-15 11:33:41 -07:00
|
|
|
firmwareError(ERROR_NAN_FIND_INDEX, "NaN in findIndex%s", msg);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (value < array[0])
|
|
|
|
return -1;
|
|
|
|
int middle;
|
|
|
|
|
|
|
|
int left = 0;
|
|
|
|
int right = size;
|
|
|
|
|
|
|
|
// todo: extract binary search as template method?
|
|
|
|
while (true) {
|
|
|
|
#if 0
|
|
|
|
// that's an assertion to make sure we do not loop here
|
|
|
|
size--;
|
|
|
|
efiAssert(CUSTOM_ERR_ASSERT, size > 0, "Unexpected state in binary search", 0);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// todo: compare current implementation with
|
|
|
|
// http://eigenjoy.com/2011/01/21/worlds-fastest-binary-search/
|
|
|
|
// ?
|
|
|
|
middle = (left + right) / 2;
|
|
|
|
|
|
|
|
// print("left=%d middle=%d right=%d: %.2f\r\n", left, middle, right, array[middle]);
|
|
|
|
|
|
|
|
if (middle == left)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (middle != 0 && array[middle - 1] > array[middle]) {
|
|
|
|
#if EFI_UNIT_TEST
|
|
|
|
firmwareError(CUSTOM_ERR_6610, "%s: out of order %.2f %.2f", msg, array[middle - 1], array[middle]);
|
|
|
|
#else
|
|
|
|
warning(CUSTOM_ERR_OUT_OF_ORDER, "%s: out of order %.2f %.2f", msg, array[middle - 1], array[middle]);
|
|
|
|
|
|
|
|
#endif /* EFI_UNIT_TEST */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (value < array[middle]) {
|
|
|
|
right = middle;
|
|
|
|
} else if (value > array[middle]) {
|
|
|
|
left = middle;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return middle;
|
|
|
|
}
|
|
|
|
|
2021-12-20 18:58:53 -08:00
|
|
|
#define findIndexMsg(msg, array, size, value) findIndexMsgExt(msg, array, size, value)
|
2021-12-19 22:23:10 -08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets specified value for specified key in a correction curve
|
|
|
|
* see also setLinearCurve()
|
|
|
|
*/
|
|
|
|
template<typename VType, typename kType>
|
|
|
|
void setCurveValue(const kType bins[], VType values[], int size, float key, float value) {
|
|
|
|
int index = findIndexMsg("tbVl", bins, size, key);
|
|
|
|
if (index == -1)
|
|
|
|
index = 0;
|
|
|
|
values[index] = value;
|
|
|
|
}
|
|
|
|
|
2021-04-21 09:53:13 -07:00
|
|
|
void initInterpolation();
|