extract newton's method implementation (#5157)
* move expected, update libfirmware * hellen ID solver uses shared Newton's method * comment shouldn't have been moved
This commit is contained in:
parent
f29307f55d
commit
dc6f53bda5
|
@ -87,26 +87,16 @@ float HellenBoardIdSolver::solve(float Tc1, float Tc2, float x0, float y, float
|
||||||
k3 = iC * (Tc1 - Tc2);
|
k3 = iC * (Tc1 - Tc2);
|
||||||
|
|
||||||
// the same method works for R (if C is known) or C (if R is known)
|
// the same method works for R (if C is known) or C (if R is known)
|
||||||
float Xcur, Xnext;
|
auto result = NewtonsMethodSolver::solve(x0, deltaX, 20);
|
||||||
Xnext = x0;
|
|
||||||
|
|
||||||
// since we had https://github.com/rusefi/rusefi/issues/4084 let's add paranoia check
|
// since we had https://github.com/rusefi/rusefi/issues/4084 let's add paranoia check
|
||||||
// All real cases seem to converge in <= 5 iterations, so we don't need to try more than 20.
|
// All real cases seem to converge in <= 5 iterations, so we don't need to try more than 20.
|
||||||
int safetyLimit = 20;
|
if (!result) {
|
||||||
do {
|
|
||||||
if (safetyLimit-- < 0) {
|
|
||||||
firmwareError(OBD_PCM_Processor_Fault, "hellen boardID is broken");
|
firmwareError(OBD_PCM_Processor_Fault, "hellen boardID is broken");
|
||||||
break;
|
return 0;
|
||||||
}
|
}
|
||||||
Xcur = Xnext;
|
|
||||||
Xnext = Xcur - fx(Xcur) / dfx(Xcur);
|
|
||||||
|
|
||||||
#ifdef HELLEN_BOARD_ID_DEBUG
|
return result.Value;
|
||||||
efiPrintf ("* %f", Xnext);
|
|
||||||
#endif /* HELLEN_BOARD_ID_DEBUG */
|
|
||||||
} while (absF(Xnext - Xcur) > deltaX);
|
|
||||||
|
|
||||||
return Xnext;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float HellenBoardIdFinderBase::findClosestResistor(float R, bool testOnlyMajorSeries, int *rIdx) {
|
float HellenBoardIdFinderBase::findClosestResistor(float R, bool testOnlyMajorSeries, int *rIdx) {
|
||||||
|
|
|
@ -27,15 +27,15 @@ public:
|
||||||
// We need to solve the following equation for R or C:
|
// We need to solve the following equation for R or C:
|
||||||
// X^Td - X^(Tc1+Td) + X^(Tc2-Tc1) - 1 = 0
|
// X^Td - X^(Tc1+Td) + X^(Tc2-Tc1) - 1 = 0
|
||||||
// where: X = exp(-1/(RC))
|
// where: X = exp(-1/(RC))
|
||||||
class HellenBoardIdSolver
|
class HellenBoardIdSolver : public NewtonsMethodSolver
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
float fx(float x) {
|
float fx(float x) override {
|
||||||
return exp(k1 / x) - exp(k2 / x) + exp(k3 / x) - 1.0;
|
return exp(k1 / x) - exp(k2 / x) + exp(k3 / x) - 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// first-order derivative
|
// first-order derivative
|
||||||
float dfx(float x) {
|
float dfx(float x) override {
|
||||||
return (-1.0f / (x * x)) * (k1 * exp(k1 / x) - k2 * exp(k2 / x) + k3 * exp(k3 / x));
|
return (-1.0f / (x * x)) * (k1 * exp(k1 / x) - k2 * exp(k2 / x) + k3 * exp(k3 / x));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "rusefi_enums.h"
|
#include "rusefi_enums.h"
|
||||||
#include "expected.h"
|
#include <rusefi/expected.h>
|
||||||
#include "trigger_structure.h"
|
#include "trigger_structure.h"
|
||||||
|
|
||||||
#if EFI_UNIT_TEST
|
#if EFI_UNIT_TEST
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#include "gppwm_channel.h"
|
#include "gppwm_channel.h"
|
||||||
|
|
||||||
#include "table_helper.h"
|
#include "table_helper.h"
|
||||||
#include "expected.h"
|
#include <rusefi/expected.h>
|
||||||
|
|
||||||
expected<float> readGppwmChannel(gppwm_channel_e channel) {
|
expected<float> readGppwmChannel(gppwm_channel_e channel) {
|
||||||
switch (channel) {
|
switch (channel) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "expected.h"
|
#include <rusefi/expected.h>
|
||||||
#include "injector_model_generated.h"
|
#include "injector_model_generated.h"
|
||||||
#include "engine_module.h"
|
#include "engine_module.h"
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "expected.h"
|
#include <rusefi/expected.h>
|
||||||
|
|
||||||
template <typename TInput, typename TOutput>
|
template <typename TInput, typename TOutput>
|
||||||
class ClosedLoopController {
|
class ClosedLoopController {
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "rusefi_enums.h"
|
#include "rusefi_enums.h"
|
||||||
#include "expected.h"
|
#include <rusefi/expected.h>
|
||||||
|
|
||||||
enum class TriggerValue : uint8_t {
|
enum class TriggerValue : uint8_t {
|
||||||
FALL = 0,
|
FALL = 0,
|
||||||
|
|
|
@ -44,7 +44,7 @@ private:
|
||||||
void startLua();
|
void startLua();
|
||||||
|
|
||||||
#if EFI_UNIT_TEST
|
#if EFI_UNIT_TEST
|
||||||
#include "expected.h"
|
#include <rusefi/expected.h>
|
||||||
|
|
||||||
expected<float> testLuaReturnsNumberOrNil(const char* script);
|
expected<float> testLuaReturnsNumberOrNil(const char* script);
|
||||||
float testLuaReturnsNumber(const char* script);
|
float testLuaReturnsNumber(const char* script);
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "expected.h"
|
#include <rusefi/expected.h>
|
||||||
|
|
||||||
typedef Map3D<SCRIPT_TABLE_8, SCRIPT_TABLE_8, float, int16_t, int16_t> fsio8_Map3D_f32t;
|
typedef Map3D<SCRIPT_TABLE_8, SCRIPT_TABLE_8, float, int16_t, int16_t> fsio8_Map3D_f32t;
|
||||||
typedef Map3D<SCRIPT_TABLE_8, SCRIPT_TABLE_8, uint8_t, int16_t, int16_t> fsio8_Map3D_u8t;
|
typedef Map3D<SCRIPT_TABLE_8, SCRIPT_TABLE_8, uint8_t, int16_t, int16_t> fsio8_Map3D_u8t;
|
||||||
|
|
|
@ -48,7 +48,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "sensor_type.h"
|
#include "sensor_type.h"
|
||||||
#include "expected.h"
|
#include <rusefi/expected.h>
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
#include "scheduler.h"
|
#include "scheduler.h"
|
||||||
#include "utlist.h"
|
#include "utlist.h"
|
||||||
#include "expected.h"
|
#include <rusefi/expected.h>
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
|
|
||||||
#include "expected.h"
|
#include <rusefi/expected.h>
|
||||||
#include "hardware.h"
|
#include "hardware.h"
|
||||||
|
|
||||||
#ifdef STM32F4XX
|
#ifdef STM32F4XX
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 16a8e0b636f0a8d5f88dfdd6a1a4639ad90da936
|
Subproject commit 163cee4279c83f46efccd279ce22006d039fb2bb
|
|
@ -1,83 +0,0 @@
|
||||||
/**
|
|
||||||
* @file expected.h
|
|
||||||
* @brief This utility class provides a way for a function to accept or return a value that may be invalid.
|
|
||||||
*
|
|
||||||
* For example, suppose there needs to be a solution for prevention of divide by zero. One could write this function:
|
|
||||||
*
|
|
||||||
* expected<int> my_divide(int num, int denom) {
|
|
||||||
* if (denom == 0) return unexpected;
|
|
||||||
* return num / denom;
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* @date April 18, 2020
|
|
||||||
* @author Matthew Kennedy, (c) 2020
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
struct unexpected_t {};
|
|
||||||
|
|
||||||
enum class UnexpectedCode : char {
|
|
||||||
Unknown = 0,
|
|
||||||
|
|
||||||
// Too much time has passed
|
|
||||||
Timeout,
|
|
||||||
|
|
||||||
// The decoded value was impossibly high/low
|
|
||||||
High,
|
|
||||||
Low,
|
|
||||||
|
|
||||||
// An inconsistency was detected using multiple sources of information
|
|
||||||
Inconsistent,
|
|
||||||
|
|
||||||
// A value is unavailable due to configuration
|
|
||||||
Configuration,
|
|
||||||
};
|
|
||||||
template <class TValue>
|
|
||||||
struct expected {
|
|
||||||
bool Valid;
|
|
||||||
|
|
||||||
union {
|
|
||||||
TValue Value;
|
|
||||||
UnexpectedCode Code;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Implicit constructor to construct in the invalid state
|
|
||||||
constexpr expected(const unexpected_t&) : Valid(false), Code{UnexpectedCode::Unknown} {}
|
|
||||||
|
|
||||||
constexpr expected(UnexpectedCode code) : Valid(false), Code{code} {}
|
|
||||||
|
|
||||||
// Implicit constructor to convert from TValue (for valid values, so an expected<T> behaves like a T)
|
|
||||||
constexpr expected(TValue validValue)
|
|
||||||
: Valid(true)
|
|
||||||
, Value(validValue)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implicit conversion operator to bool, so you can do things like if (myResult) { ... }
|
|
||||||
constexpr explicit operator bool() const {
|
|
||||||
return Valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Easy default value handling
|
|
||||||
constexpr TValue value_or(TValue valueIfInvalid) const {
|
|
||||||
return Valid ? Value : valueIfInvalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator ==(const expected<TValue>& other) const {
|
|
||||||
// If validity mismatch, not equal
|
|
||||||
if (Valid != other.Valid) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If both are invalid, they are equal
|
|
||||||
if (!Valid && !other.Valid) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Both are guaranteed valid - simply compare values
|
|
||||||
return Value == other.Value;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr unexpected_t unexpected{};
|
|
Loading…
Reference in New Issue