math module
This commit is contained in:
parent
5c871dac13
commit
8fcca4c0ce
|
@ -1,6 +1,8 @@
|
|||
Modules:
|
||||
## Modules:
|
||||
- `util`: General purpose math functions, interpolation, array handling, etc.
|
||||
|
||||
## Including modules in your project:
|
||||
|
||||
Set variable `$(RUSEFI_LIB)` to the path to the folder that contains this readme.
|
||||
|
||||
Include the mk files of the modules that you want, then add:
|
||||
|
@ -8,3 +10,7 @@ Include the mk files of the modules that you want, then add:
|
|||
- `$(RUSEFI_LIB_CPP)` to your list of c++ input files
|
||||
|
||||
Currently, C++17 is required to compile these libraries.
|
||||
|
||||
## Unit tests:
|
||||
|
||||
TODO
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
// Various math utility functions, implemented in microcontroller friendly ways.
|
||||
|
||||
#pragma once
|
||||
|
||||
// absolute value
|
||||
int absI(int value);
|
||||
float absF(float value);
|
||||
|
||||
// Min/max
|
||||
int maxI(int i1, int i2);
|
||||
int minI(int i1, int i2);
|
||||
float maxF(float i1, float i2);
|
||||
float minF(float i1, float i2);
|
||||
|
||||
// Clamping
|
||||
float clampF(float min, float clamp, float max);
|
||||
|
||||
// Returns if two floats are within 0.0001
|
||||
bool isSameF(float a, float b);
|
||||
|
||||
// @brief Compute e^x using a 4th order taylor expansion centered at x=-1. Provides
|
||||
// bogus results outside the range -2 < x < 0.
|
||||
float expf_taylor(float x);
|
||||
|
||||
// @brief Compute tan(theta) using a ratio of the Taylor series for sin and cos
|
||||
// Valid for the range [0, pi/2 - 0.01]
|
||||
float tanf_taylor(float theta);
|
|
@ -0,0 +1,95 @@
|
|||
#include <rusefi/math.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
float absF(float value) {
|
||||
return value > 0 ? value : -value;
|
||||
}
|
||||
|
||||
int absI(int value) {
|
||||
return value >= 0 ? value : -value;
|
||||
}
|
||||
|
||||
int maxI(int i1, int i2) {
|
||||
return i1 > i2 ? i1 : i2;
|
||||
}
|
||||
|
||||
int minI(int i1, int i2) {
|
||||
return i1 < i2 ? i1 : i2;
|
||||
}
|
||||
|
||||
float maxF(float i1, float i2) {
|
||||
return i1 > i2 ? i1 : i2;
|
||||
}
|
||||
|
||||
float minF(float i1, float i2) {
|
||||
return i1 < i2 ? i1 : i2;
|
||||
}
|
||||
|
||||
float clampF(float min, float clamp, float max) {
|
||||
return maxF(min, minF(clamp, max));
|
||||
}
|
||||
|
||||
bool isSameF(float a, float b) {
|
||||
return absF(a - b) < 0.0001;
|
||||
}
|
||||
|
||||
constexpr float expf_taylor_impl(float x, uint8_t n)
|
||||
{
|
||||
if (x < -2)
|
||||
{
|
||||
return 0.818f;
|
||||
}
|
||||
else if (x > 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
x = x + 1;
|
||||
|
||||
float x_power = x;
|
||||
int fac = 1;
|
||||
float sum = 1;
|
||||
|
||||
for (int i = 1; i <= n; i++)
|
||||
{
|
||||
fac *= i;
|
||||
sum += x_power / fac;
|
||||
|
||||
x_power *= x;
|
||||
}
|
||||
|
||||
constexpr const float constant_e = 2.71828f;
|
||||
return sum / constant_e;
|
||||
}
|
||||
|
||||
float expf_taylor(float x)
|
||||
{
|
||||
return expf_taylor_impl(x, 4);
|
||||
}
|
||||
|
||||
float tanf_taylor(float x) {
|
||||
// This exists because the "normal" implementation, tanf, pulls in like 6kb of
|
||||
// code and loookup tables
|
||||
|
||||
// This is only specified from [0, pi/2 - 0.01)
|
||||
// Inside that range it has an error of less than 0.1%, and it gets worse as theta -> pi/2
|
||||
|
||||
// Precompute some exponents of x
|
||||
float x2 = x * x;
|
||||
float x3 = x2 * x;
|
||||
float x4 = x3 * x;
|
||||
float x5 = x4 * x;
|
||||
float x6 = x5 * x;
|
||||
// x7 not used
|
||||
float x8 = x6 * x2;
|
||||
|
||||
// 3-term Taylor Series for sin(theta)
|
||||
float sin_val = x - (x3 / 6) + (x5 / 120);
|
||||
|
||||
// 5-term Taylor Series for cos(theta)
|
||||
float cos_val = 1 - (x2 / 2) + (x4 / 24) - (x6 / 720) + (x8 / 40320);
|
||||
|
||||
// tan = sin / cos
|
||||
return sin_val / cos_val;
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
#include <rusefi/math.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <math.h>
|
||||
|
||||
TEST(Util_Math, ExpTaylor)
|
||||
{
|
||||
float x = -2;
|
||||
|
||||
// test from -2 < x < 0
|
||||
for(float x = -2; x < 0; x += 0.05)
|
||||
{
|
||||
// Compare taylor to libc implementation
|
||||
EXPECT_NEAR(expf_taylor(x), expf(x), 0.01f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Util_Math, clampf) {
|
||||
// off scale low
|
||||
EXPECT_EQ(clampF(10, 5, 20), 10);
|
||||
EXPECT_EQ(clampF(-10, -50, 10), -10);
|
||||
|
||||
// in range (unclamped)
|
||||
EXPECT_EQ(clampF(10, 15, 20), 15);
|
||||
EXPECT_EQ(clampF(-10, -5, 10), -5);
|
||||
|
||||
// off scale high
|
||||
EXPECT_EQ(clampF(10, 25, 20), 20);
|
||||
EXPECT_EQ(clampF(-10, 50, 10), 10);
|
||||
}
|
||||
|
||||
TEST(Util_Math, tanf_taylor) {
|
||||
// Function is only specified from [0, pi/2) ish, so test that range
|
||||
for (float i = 0; i < 1.5; i += 0.1f)
|
||||
{
|
||||
// Compare to libc implementation
|
||||
EXPECT_NEAR(tanf_taylor(i), tanf(i), 0.05f) << "I = " << i;
|
||||
}
|
||||
}
|
|
@ -3,4 +3,8 @@ RUSEFI_LIB_INC += $(RUSEFI_LIB)/util/include
|
|||
RUSEFI_LIB_CPP += \
|
||||
$(RUSEFI_LIB)/util/src/util_dummy.cpp \
|
||||
$(RUSEFI_LIB)/util/src/crc.cpp \
|
||||
$(RUSEFI_LIB)/util/src/math.cpp \
|
||||
|
||||
RUSEFI_LIB_CPP_TEST += \
|
||||
$(RUSEFI_LIB)/util/test/test_math.cpp \
|
||||
|
||||
|
|
Loading…
Reference in New Issue