math module

This commit is contained in:
Matthew Kennedy 2022-07-16 19:37:27 -07:00
parent 5c871dac13
commit 8fcca4c0ce
5 changed files with 172 additions and 1 deletions

View File

@ -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

View File

@ -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);

95
util/src/math.cpp Normal file
View File

@ -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;
}

39
util/test/test_math.cpp Normal file
View File

@ -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;
}
}

View File

@ -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 \