From dc6f53bda5bc94cba393011fd48f21b8e35d2ddd Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Tue, 7 Mar 2023 05:45:17 -0800 Subject: [PATCH] extract newton's method implementation (#5157) * move expected, update libfirmware * hellen ID solver uses shared Newton's method * comment shouldn't have been moved --- .../config/boards/hellen/hellen_board_id.cpp | 24 ++---- .../config/boards/hellen/hellen_board_id.h | 6 +- firmware/console/binary/tooth_logger.h | 2 +- .../actuators/gppwm/gppwm_channel.cpp | 2 +- .../controllers/algo/fuel/injector_model.h | 2 +- firmware/controllers/closed_loop_controller.h | 2 +- firmware/controllers/core/state_sequence.h | 2 +- firmware/controllers/lua/rusefi_lua.h | 2 +- firmware/controllers/lua/script_impl.h | 2 +- firmware/controllers/sensors/core/sensor.h | 2 +- .../controllers/system/timer/event_queue.h | 2 +- .../hw_layer/ports/stm32/stm32_common.cpp | 2 +- firmware/libfirmware | 2 +- firmware/util/expected.h | 83 ------------------- 14 files changed, 21 insertions(+), 114 deletions(-) delete mode 100644 firmware/util/expected.h diff --git a/firmware/config/boards/hellen/hellen_board_id.cpp b/firmware/config/boards/hellen/hellen_board_id.cpp index 3c648c271d..40d28c5bbc 100644 --- a/firmware/config/boards/hellen/hellen_board_id.cpp +++ b/firmware/config/boards/hellen/hellen_board_id.cpp @@ -85,28 +85,18 @@ float HellenBoardIdSolver::solve(float Tc1, float Tc2, float x0, float y, float k1 = iC * Td; k2 = iC * (Tc1 + Td); k3 = iC * (Tc1 - Tc2); - + // the same method works for R (if C is known) or C (if R is known) - float Xcur, Xnext; - Xnext = x0; + auto result = NewtonsMethodSolver::solve(x0, deltaX, 20); // 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. - int safetyLimit = 20; - do { - if (safetyLimit-- < 0) { - firmwareError(OBD_PCM_Processor_Fault, "hellen boardID is broken"); - break; - } - Xcur = Xnext; - Xnext = Xcur - fx(Xcur) / dfx(Xcur); + if (!result) { + firmwareError(OBD_PCM_Processor_Fault, "hellen boardID is broken"); + return 0; + } -#ifdef HELLEN_BOARD_ID_DEBUG - efiPrintf ("* %f", Xnext); -#endif /* HELLEN_BOARD_ID_DEBUG */ - } while (absF(Xnext - Xcur) > deltaX); - - return Xnext; + return result.Value; } float HellenBoardIdFinderBase::findClosestResistor(float R, bool testOnlyMajorSeries, int *rIdx) { diff --git a/firmware/config/boards/hellen/hellen_board_id.h b/firmware/config/boards/hellen/hellen_board_id.h index d27c55e03d..c6e39ab0b8 100644 --- a/firmware/config/boards/hellen/hellen_board_id.h +++ b/firmware/config/boards/hellen/hellen_board_id.h @@ -27,15 +27,15 @@ public: // We need to solve the following equation for R or C: // X^Td - X^(Tc1+Td) + X^(Tc2-Tc1) - 1 = 0 // where: X = exp(-1/(RC)) -class HellenBoardIdSolver +class HellenBoardIdSolver : public NewtonsMethodSolver { public: - float fx(float x) { + float fx(float x) override { return exp(k1 / x) - exp(k2 / x) + exp(k3 / x) - 1.0; } // 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)); } diff --git a/firmware/console/binary/tooth_logger.h b/firmware/console/binary/tooth_logger.h index 746fa92e33..22c599d518 100644 --- a/firmware/console/binary/tooth_logger.h +++ b/firmware/console/binary/tooth_logger.h @@ -8,7 +8,7 @@ #pragma once #include "rusefi_enums.h" -#include "expected.h" +#include #include "trigger_structure.h" #if EFI_UNIT_TEST diff --git a/firmware/controllers/actuators/gppwm/gppwm_channel.cpp b/firmware/controllers/actuators/gppwm/gppwm_channel.cpp index 7d394de45e..ce28373447 100644 --- a/firmware/controllers/actuators/gppwm/gppwm_channel.cpp +++ b/firmware/controllers/actuators/gppwm/gppwm_channel.cpp @@ -4,7 +4,7 @@ #include "gppwm_channel.h" #include "table_helper.h" -#include "expected.h" +#include expected readGppwmChannel(gppwm_channel_e channel) { switch (channel) { diff --git a/firmware/controllers/algo/fuel/injector_model.h b/firmware/controllers/algo/fuel/injector_model.h index 29a075e4a3..3c37b7deaa 100644 --- a/firmware/controllers/algo/fuel/injector_model.h +++ b/firmware/controllers/algo/fuel/injector_model.h @@ -1,6 +1,6 @@ #pragma once -#include "expected.h" +#include #include "injector_model_generated.h" #include "engine_module.h" diff --git a/firmware/controllers/closed_loop_controller.h b/firmware/controllers/closed_loop_controller.h index b73e57fbfa..a12a6667f3 100644 --- a/firmware/controllers/closed_loop_controller.h +++ b/firmware/controllers/closed_loop_controller.h @@ -4,7 +4,7 @@ #pragma once -#include "expected.h" +#include template class ClosedLoopController { diff --git a/firmware/controllers/core/state_sequence.h b/firmware/controllers/core/state_sequence.h index 685a95f479..8c5039882c 100644 --- a/firmware/controllers/core/state_sequence.h +++ b/firmware/controllers/core/state_sequence.h @@ -9,7 +9,7 @@ #include #include "rusefi_enums.h" -#include "expected.h" +#include enum class TriggerValue : uint8_t { FALL = 0, diff --git a/firmware/controllers/lua/rusefi_lua.h b/firmware/controllers/lua/rusefi_lua.h index 23d4778015..322b1655b2 100644 --- a/firmware/controllers/lua/rusefi_lua.h +++ b/firmware/controllers/lua/rusefi_lua.h @@ -44,7 +44,7 @@ private: void startLua(); #if EFI_UNIT_TEST -#include "expected.h" +#include expected testLuaReturnsNumberOrNil(const char* script); float testLuaReturnsNumber(const char* script); diff --git a/firmware/controllers/lua/script_impl.h b/firmware/controllers/lua/script_impl.h index 6e15eb9b12..3ee396eca2 100644 --- a/firmware/controllers/lua/script_impl.h +++ b/firmware/controllers/lua/script_impl.h @@ -7,7 +7,7 @@ #pragma once -#include "expected.h" +#include typedef Map3D fsio8_Map3D_f32t; typedef Map3D fsio8_Map3D_u8t; diff --git a/firmware/controllers/sensors/core/sensor.h b/firmware/controllers/sensors/core/sensor.h index 31ebd7a646..570324d458 100644 --- a/firmware/controllers/sensors/core/sensor.h +++ b/firmware/controllers/sensors/core/sensor.h @@ -48,7 +48,7 @@ #pragma once #include "sensor_type.h" -#include "expected.h" +#include #include diff --git a/firmware/controllers/system/timer/event_queue.h b/firmware/controllers/system/timer/event_queue.h index 6017a2416c..5f91ce6b25 100644 --- a/firmware/controllers/system/timer/event_queue.h +++ b/firmware/controllers/system/timer/event_queue.h @@ -7,7 +7,7 @@ #include "scheduler.h" #include "utlist.h" -#include "expected.h" +#include #pragma once diff --git a/firmware/hw_layer/ports/stm32/stm32_common.cpp b/firmware/hw_layer/ports/stm32/stm32_common.cpp index 4e16765278..e6ee589414 100644 --- a/firmware/hw_layer/ports/stm32/stm32_common.cpp +++ b/firmware/hw_layer/ports/stm32/stm32_common.cpp @@ -8,7 +8,7 @@ #include "pch.h" -#include "expected.h" +#include #include "hardware.h" #ifdef STM32F4XX diff --git a/firmware/libfirmware b/firmware/libfirmware index 16a8e0b636..163cee4279 160000 --- a/firmware/libfirmware +++ b/firmware/libfirmware @@ -1 +1 @@ -Subproject commit 16a8e0b636f0a8d5f88dfdd6a1a4639ad90da936 +Subproject commit 163cee4279c83f46efccd279ce22006d039fb2bb diff --git a/firmware/util/expected.h b/firmware/util/expected.h deleted file mode 100644 index ac05d2fd9d..0000000000 --- a/firmware/util/expected.h +++ /dev/null @@ -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 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 -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 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& 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{};