Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decimal Type determined at Compile Time (#26) #126

Merged
merged 30 commits into from
Dec 2, 2023
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
e170ee7
feat: add compile time decimal type
mookums Nov 24, 2023
3cdcd31
feat: add -D when passed LOST_DATABASE_DOUBLE
mookums Nov 24, 2023
7fadedf
feat: switch from float to decimal
mookums Nov 24, 2023
c1c0fd4
feat: add db flagging & checking
mookums Nov 24, 2023
4a70b3a
fix: cpplint
mookums Nov 24, 2023
9ae2b85
refactor: change all float endianness to decimal endianness
mookums Nov 24, 2023
dff0155
feat: make double mode default
mookums Nov 28, 2023
83e66a6
feat: eigen3 with float/double accordingly
mookums Nov 28, 2023
92b143e
feat: optimize dbFlags
mookums Nov 28, 2023
09ff6d9
fix: prevent double promotion
mookums Nov 28, 2023
6195ddd
fix: cpplint again
mookums Nov 28, 2023
3378aa4
fix: tests with decimal type
mookums Nov 28, 2023
3c4f908
test: add test with float mode
mookums Nov 28, 2023
2128c9e
fix: remove debug logging
mookums Nov 28, 2023
c42076e
feat: add decimal support to kvector test
mookums Nov 28, 2023
46392c8
fix: rebuild with LOST_FLOAT_MODE on test
mookums Nov 28, 2023
08a5bd5
fix: gitlab actions syntax
mookums Nov 28, 2023
8044f6e
fix: split into independent double and float builds
mookums Nov 28, 2023
1328d9f
fix: switch all math functions to decimal wrapped ones
mookums Nov 28, 2023
4511cc3
fix: use math macros instead of redefining them
mookums Nov 28, 2023
bf183b1
fix: cpplint again again
mookums Nov 28, 2023
380cdd6
fix: findpairsexact instead of findpairsliberal
mookums Nov 29, 2023
53259c9
refactor: apply conditional only to format string
mookums Nov 29, 2023
a55c216
feat: error on double promotion when in float mode
mookums Nov 29, 2023
f9c1d80
fix: double promotion in test
mookums Nov 29, 2023
321a4ab
fix: use DECIMAL macro instead of typecast
mookums Nov 29, 2023
1e49367
refactor: return to uint32_t for dbFlags
mookums Nov 29, 2023
e36e1ec
fix: double promotion in kvector test
mookums Nov 29, 2023
debaa0f
fix: cpplint wins again
mookums Nov 29, 2023
aace162
fix: wrap all decimal macros in parenthesis
mookums Dec 2, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .github/workflows/build-test-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,14 @@ jobs:

steps:
- uses: actions/checkout@v3
- name: Build
- name: Build Double
run: CXXFLAGS=-Werror make -j$(($(nproc)+1))
- name: Test
- name: Test Double
run: CXXFLAGS=-Werror make test -j$(($(nproc)+1))
- name: Build Float
run: CXXFLAGS=-Werror make clean all LOST_FLOAT_MODE=1 -j$(($(nproc)+1))
- name: Test Float
run: CXXFLAGS=-Werror make test LOST_FLOAT_MODE=1 -j$(($(nproc)+1))

lint:
runs-on: ubuntu-latest
Expand Down
8 changes: 7 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2020 Mark Polyakov, Karen Haining (If you edit the file, add your name here!)
# Copyright (c) 2020 Mark Polyakov, Karen Haining, Muki Kiboigo (If you edit the file, add your name here!)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
Expand Down Expand Up @@ -51,6 +51,12 @@ ifndef LOST_DISABLE_ASAN
LDFLAGS := $(LDFLAGS) -fsanitize=address
endif

# Use Double Mode by default.
# If compiled with LOST_FLOAT_MODE=1, we will use floats.
ifdef LOST_FLOAT_MODE
CXXFLAGS := $(CXXFLAGS) -Wdouble-promotion -Werror=double-promotion -D LOST_FLOAT_MODE
endif

all: $(BIN) $(BSC)

release: CXXFLAGS := $(RELEASE_CXXFLAGS)
Expand Down
105 changes: 74 additions & 31 deletions src/attitude-estimators.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
#include "attitude-estimators.hpp"

#include <eigen3/Eigen/Dense>
#include <eigen3/Eigen/Eigenvalues>

#include "decimal.hpp"

namespace lost {

#define EPSILON 0.0001 // threshold for 0 for Newton-Raphson method
#define EPSILON DECIMAL(0.0001) // threshold for 0 for Newton-Raphson method

Attitude DavenportQAlgorithm::Go(const Camera &camera,
const Stars &stars,
Expand All @@ -16,47 +19,82 @@ Attitude DavenportQAlgorithm::Go(const Camera &camera,
assert(stars.size() >= 2);

// attitude profile matrix
Eigen::Matrix3f B;
#ifdef LOST_FLOAT_MODE
Eigen::Matrix3f B;
#else
Eigen::Matrix3d B;
#endif


B.setZero();
for (const StarIdentifier &s : starIdentifiers) {
Star bStar = stars[s.starIndex];
Vec3 bStarSpatial = camera.CameraToSpatial(bStar.position);
Eigen::Vector3f bi;

#ifdef LOST_FLOAT_MODE
Eigen::Vector3f bi;
Eigen::Vector3f ri;
#else
Eigen::Vector3d bi;
Eigen::Vector3d ri;
#endif

bi << bStarSpatial.x, bStarSpatial.y, bStarSpatial.z;

CatalogStar rStar = catalog[s.catalogIndex];
Eigen::Vector3f ri;
ri << rStar.spatial.x, rStar.spatial.y, rStar.spatial.z;

//Weight = 1 (can be changed later, in which case we want to make a vector to hold all weights {ai})
// Calculate matrix B = sum({ai}{bi}{ri}T)
B += ri * bi.transpose() * s.weight;
}

// S = B + Transpose(B)
Eigen::Matrix3f S = B + B.transpose();
#ifdef LOST_FLOAT_MODE
Eigen::Matrix3f S = B + B.transpose();
#else
Eigen::Matrix3d S = B + B.transpose();
#endif

//sigma = B[0][0] + B[1][1] + B[2][2]
float sigma = B.trace();
decimal sigma = B.trace();

//Z = [[B[1][2] - B[2][1]], [B[2][0] - B[0][2]], [B[0][1] - B[1][0]]]
Eigen::Vector3f Z;
#ifdef LOST_FLOAT_MODE
Eigen::Vector3f Z;
#else
Eigen::Vector3d Z;
#endif

Z << B(1,2) - B(2,1),
B(2,0) - B(0,2),
B(0,1) - B(1,0);

// K = [[[sigma], [Z[0]], [Z[1]], [Z[2]]], [[Z[0]], [S[0][0] - sigma], [S[0][1]], [S[0][2]]], [[Z[1]], [S[1][0]], [S[1][1] - sigma], [S[1][2]]], [[Z[2]], [S[2][0]], [S[2][1]], [S[2][2] - sigma]]]
Eigen::Matrix4f K;
#ifdef LOST_FLOAT_MODE
Eigen::Matrix4f K;
#else
Eigen::Matrix4d K;
#endif

K << sigma, Z(0), Z(1), Z(2),
Z(0), S(0,0) - sigma, S(0,1), S(0,2),
Z(1), S(1,0), S(1,1) - sigma, S(1,2),
Z(2), S(2,0), S(2,1), S(2,2) - sigma;

//Find eigenvalues of K, store the largest one as lambda
//find the maximum index
Eigen::EigenSolver<Eigen::Matrix4f> solver(K);
Eigen::Vector4cf values = solver.eigenvalues();
Eigen::Matrix4cf vectors = solver.eigenvectors();
#ifdef LOST_FLOAT_MODE
Eigen::EigenSolver<Eigen::Matrix4f> solver(K);
Eigen::Vector4cf values = solver.eigenvalues();
Eigen::Matrix4cf vectors = solver.eigenvectors();
#else
Eigen::EigenSolver<Eigen::Matrix4d> solver(K);
Eigen::Vector4cd values = solver.eigenvalues();
Eigen::Matrix4cd vectors = solver.eigenvectors();
#endif

int maxIndex = 0;
float maxEigenvalue = values(0).real();
decimal maxEigenvalue = values(0).real();
for (int i = 1; i < values.size(); i++) {
if (values(i).real() > maxEigenvalue) {
maxIndex = i;
Expand All @@ -65,7 +103,12 @@ Attitude DavenportQAlgorithm::Go(const Camera &camera,
}

//The return quaternion components = eigenvector assocaited with lambda
Eigen::Vector4cf maxEigenvector = vectors.col(maxIndex);
#ifdef LOST_FLOAT_MODE
Eigen::Vector4cf maxEigenvector = vectors.col(maxIndex);
#else
Eigen::Vector4cd maxEigenvector = vectors.col(maxIndex);
#endif

// IMPORTANT: The matrix K is symmetric -- clearly first row and first column are equal.
// Furthermore, S is symmetric because s_i,j = b_i,j + b_j,i and s_j,i=b_j,i + b_i,j, so the
// bottom right 3x3 block of K is symmetric too. Thus all its eigenvalues and eigenvectors
Expand Down Expand Up @@ -117,19 +160,19 @@ Attitude TriadAlgorithm::Go(const Camera &camera,
* Characteristic polynomial of the quest K-matrix
* @see equation 19b of https://arc.aiaa.org/doi/pdf/10.2514/1.62549
*/
float QuestCharPoly(float x, float a, float b, float c, float d, float s) {return (pow(x,2)-a) * (pow(x,2)-b) - (c*x) + (c*s) - d;}
decimal QuestCharPoly(decimal x, decimal a, decimal b, decimal c, decimal d, decimal s) {return (DECIMAL_POW(x,2)-a) * (DECIMAL_POW(x,2)-b) - (c*x) + (c*s) - d;}

/**
* Derivitive of the characteristic polynomial of the quest K-matrix
*/
float QuestCharPolyPrime(float x, float a, float b, float c) {return 4*pow(x,3) - 2*(a+b)*x - c;}
decimal QuestCharPolyPrime(decimal x, decimal a, decimal b, decimal c) {return 4*DECIMAL_POW(x,3) - 2*(a+b)*x - c;}

/**
* Approximates roots of a real function using the Newton-Raphson algorithm
* @see https://www.geeksforgeeks.org/program-for-newton-raphson-method/
*/
float QuestEigenvalueEstimator(float guess, float a, float b, float c, float d, float s) {
float height;
decimal QuestEigenvalueEstimator(decimal guess, decimal a, decimal b, decimal c, decimal d, decimal s) {
decimal height;
do {
height = QuestCharPoly(guess, a, b, c, d, s) / QuestCharPolyPrime(guess, a, b, c);
guess -= height;
Expand All @@ -149,7 +192,7 @@ Attitude QuestAlgorithm::Go(const Camera &camera,
assert(stars.size() >= 2);

// initial guess for eigenvalue (sum of the weights)
float guess = 0;
decimal guess = 0;

// attitude profile matrix
Mat3 B = {0, 0, 0, 0, 0, 0, 0, 0, 0};
Expand All @@ -171,7 +214,7 @@ Attitude QuestAlgorithm::Go(const Camera &camera,
// S = B + Transpose(B)
Mat3 S = B + B.Transpose();
//sigma = B[0][0] + B[1][1] + B[2][2]
float sigma = B.Trace();
decimal sigma = B.Trace();
//Z = [[B[1][2] - B[2][1]], [B[2][0] - B[0][2]], [B[0][1] - B[1][0]]]
Vec3 Z = {
B.At(1,2) - B.At(2,1),
Expand All @@ -180,23 +223,23 @@ Attitude QuestAlgorithm::Go(const Camera &camera,
};

// calculate coefficients for characteristic polynomial
float delta = S.Det();
float kappa = (S.Inverse() * delta).Trace();
float a = pow(sigma,2) - kappa;
float b = pow(sigma,2) + (Z * Z);
float c = delta + (Z * S * Z);
float d = Z * (S * S) * Z;
decimal delta = S.Det();
decimal kappa = (S.Inverse() * delta).Trace();
decimal a = DECIMAL_POW(sigma,2) - kappa;
decimal b = DECIMAL_POW(sigma,2) + (Z * Z);
decimal c = delta + (Z * S * Z);
decimal d = Z * (S * S) * Z;

// Newton-Raphson method for estimating the largest eigenvalue
float eig = QuestEigenvalueEstimator(guess, a, b, c, d, sigma);
decimal eig = QuestEigenvalueEstimator(guess, a, b, c, d, sigma);

// solve for the optimal quaternion: from https://ahrs.readthedocs.io/en/latest/filters/quest.html
float alpha = pow(eig,2) - pow(sigma, 2) + kappa;
float beta = eig - sigma;
float gamma = (eig + sigma) * alpha - delta;
decimal alpha = DECIMAL_POW(eig,2) - DECIMAL_POW(sigma, 2) + kappa;
decimal beta = eig - sigma;
decimal gamma = (eig + sigma) * alpha - delta;

Vec3 X = ((kIdentityMat3 * alpha) + (S * beta) + (S * S)) * Z;
float scalar = 1 / sqrt(pow(gamma,2) + X.MagnitudeSq());
decimal scalar = 1 / DECIMAL_SQRT(DECIMAL_POW(gamma,2) + X.MagnitudeSq());
X = X * scalar;
gamma *= scalar;

Expand Down
Loading
Loading