Added Eigen dependency, so now QtRocket Vectors (and matrices and quaternions) are backed by Eigen. Cleaned up unused files also

This commit is contained in:
Travis Hunter 2023-05-06 08:53:56 -06:00
parent 821df8905a
commit 8e620cf0c1
27 changed files with 113 additions and 349 deletions

View File

@ -36,6 +36,11 @@ if(WIN32)
endif()
FetchContent_MakeAvailable(CURL)
# eigen dependency
FetchContent_Declare(eigen
GIT_REPOSITORY https://gitlab.com/libeigen/eigen
GIT_TAG 3.4.0)
FetchContent_MakeAvailable(eigen)
set(CMAKE_AUTOUIC ON)
@ -84,8 +89,6 @@ set(PROJECT_SOURCES
gui/ThrustCurveMotorSelector.ui
gui/qcustomplot.cpp
gui/qcustomplot.h
model/MotorCase.cpp
model/MotorCase.h
model/MotorModel.cpp
model/MotorModel.h
model/MotorModelDatabase.cpp
@ -96,12 +99,10 @@ set(PROJECT_SOURCES
model/ThrustCurve.h
sim/AtmosphericModel.h
sim/ConstantAtmosphere.h
sim/ConstantGravityModel.cpp
sim/ConstantGravityModel.h
sim/DESolver.h
sim/Environment.h
sim/GeoidModel.h
sim/GravityModel.cpp
sim/GravityModel.h
sim/Propagator.cpp
sim/Propagator.h
@ -110,7 +111,6 @@ set(PROJECT_SOURCES
sim/SphericalGeoidModel.h
sim/SphericalGravityModel.cpp
sim/SphericalGravityModel.h
sim/StateData.cpp
sim/StateData.h
sim/USStandardAtmosphere.cpp
sim/USStandardAtmosphere.h
@ -130,15 +130,10 @@ set(PROJECT_SOURCES
utils/ThreadPool.h
utils/ThrustCurveAPI.cpp
utils/ThrustCurveAPI.h
utils/Triplet.h
utils/TSQueue.h
utils/math/Constants.h
utils/math/Quaternion.cpp
utils/math/Quaternion.h
utils/math/UtilityMathFunctions.cpp
utils/math/MathTypes.h
utils/math/UtilityMathFunctions.h
utils/math/Vector3.cpp
utils/math/Vector3.h
${TS_FILES}
)
@ -171,7 +166,7 @@ else()
endif()
#target_link_libraries(qtrocket PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${Qt_VERSION_MAJOR}::PrintSupport libcurl jsoncpp_static fmt::fmt-header-only)
target_link_libraries(qtrocket PRIVATE Qt6::Widgets Qt6::PrintSupport libcurl jsoncpp_static fmt::fmt-header-only)
target_link_libraries(qtrocket PRIVATE Qt6::Widgets Qt6::PrintSupport libcurl jsoncpp_static fmt::fmt-header-only eigen)
set_target_properties(qtrocket PROPERTIES
MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com

View File

@ -83,6 +83,7 @@ MainWindow::MainWindow(QtRocket* _qtRocket, QWidget *parent)
this,
SLOT(onButton_getTCMotorData_clicked()));
ui->calculateTrajectory_btn->setDisabled(true);
}
MainWindow::~MainWindow()
@ -186,7 +187,13 @@ void MainWindow::onButton_setMotor_clicked()
QString motorName = ui->engineSelectorComboBox->currentText();
model::MotorModel mm = rseDatabase->getMotorModelByName(motorName.toStdString());
QtRocket::getInstance()->getRocket()->setMotorModel(mm);
QtRocket::getInstance()->addMotorModels(rseDatabase->getMotors());
// Now that we have a motor selected, we can enable the calculateTrajectory button
ui->calculateTrajectory_btn->setDisabled(false);
/// TODO: Figure out if this is the right place to populate the motor database
/// or from RSEDatabaseLoader where it currently is populated.
//QtRocket::getInstance()->addMotorModels(rseDatabase->getMotors());
}

View File

@ -1 +0,0 @@
#include "MotorCase.h"

View File

@ -1,17 +0,0 @@
#ifndef MODEL_MOTORCASE_H
#define MODEL_MOTORCASE_H
namespace model
{
class MotorCase
{
public:
MotorCase();
~MotorCase();
private:
};
} // namespace model
#endif // MODEL_MOTORCASE_H

View File

@ -1,10 +0,0 @@
#include "ConstantGravityModel.h"
namespace sim {
ConstantGravityModel::ConstantGravityModel()
{
}
} // namespace sim

View File

@ -3,18 +3,21 @@
// qtrocket headers
#include "sim/GravityModel.h"
#include "utils/Triplet.h"
#include "utils/math/MathTypes.h"
namespace sim {
class ConstantGravityModel : public GravityModel
{
public:
ConstantGravityModel();
ConstantGravityModel() {}
virtual ~ConstantGravityModel() {}
TripletD getAccel(double, double, double) override { return TripletD(0.0, 0.0, -9.8); }
Vector3 getAccel(double, double, double) override
{
return Vector3(0.0, 0.0, -9.8);
}
};
} // namespace sim

View File

@ -19,7 +19,17 @@ public:
virtual ~DESolver() {}
virtual void setTimeStep(double ts) = 0;
virtual void step(double t, const std::vector<double>& curVal, std::vector<double>& res ) = 0;
/**
* @brief
*
* @param curVal
* @param res
* @param t Optional parameter, but not used in QtRocket. Some generic solvers take time as
* a parameter to ODEs, but QtRocket's kinematic equations don't. Since I wrote
* the RK4 solver independently as a general tool, this interface is needed
* here unfortunately.
*/
virtual void step(const std::vector<double>& curVal, std::vector<double>& res, double t = 0.0) = 0;
};
} // namespace sim

View File

@ -1,14 +0,0 @@
#include "GravityModel.h"
namespace sim
{
GravityModel::GravityModel()
{
}
GravityModel::~GravityModel()
{
}
} // namespace sim

View File

@ -2,7 +2,7 @@
#define SIM_GRAVITYMODEL_H
// qtrocket headers
#include "utils/Triplet.h"
#include "utils/math/MathTypes.h"
namespace sim
{
@ -10,11 +10,11 @@ namespace sim
class GravityModel
{
public:
GravityModel();
virtual ~GravityModel();
GravityModel() {}
virtual ~GravityModel() {}
virtual TripletD getAccel(double x, double y, double z) = 0;
TripletD getAccel(const TripletD& t) { return this->getAccel(t.x1, t.x2, t.x3); }
virtual Vector3 getAccel(double x, double y, double z) = 0;
Vector3 getAccel(const Vector3& t) { return this->getAccel(t[0], t[1], t[2]); }
};
} // namespace sim

View File

@ -23,7 +23,8 @@
namespace sim {
Propagator::Propagator(Rocket* r)
: integrator(),
: linearIntegrator(),
//orientationIntegrator(),
rocket(r)
{
@ -37,23 +38,25 @@ Propagator::Propagator(Rocket* r)
// and pass it a freshly allocated RK4Solver pointer
// The state vector has components of the form:
// (x, y, z, xdot, ydot, zdot, pitch, yaw, roll, pitchRate, yawRate, rollRate)
integrator.reset(new RK4Solver(
/* dx/dt */ [](double, const std::vector<double>& s) -> double {return s[3]; },
/* dy/dt */ [](double, const std::vector<double>& s) -> double {return s[4]; },
/* dz/dt */ [](double, const std::vector<double>& s) -> double {return s[5]; },
/* dvx/dt */ [this](double, const std::vector<double>& ) -> double { return getForceX() / getMass(); },
/* dvy/dt */ [this](double, const std::vector<double>& ) -> double { return getForceY() / getMass(); },
/* dvz/dt */ [this](double, const std::vector<double>& ) -> double { return getForceZ() / getMass(); },
/* dpitch/dt */ [](double, const std::vector<double>& s) -> double { return s[9]; },
/* dyaw/dt */ [](double, const std::vector<double>& s) -> double { return s[10]; },
/* droll/dt */ [](double, const std::vector<double>& s) -> double { return s[11]; },
/* dpitchRate/dt */ [this](double, const std::vector<double>& s) -> double { return (getTorqueP() - s[7] * s[8] * (getIroll() - getIyaw())) / getIpitch(); },
/* dyawRate/dt */ [this](double, const std::vector<double>& s) -> double { return (getTorqueQ() - s[6] * s[9] * (getIpitch() - getIroll())) / getIyaw(); },
/* drollRate/dt */ [this](double, const std::vector<double>& s) -> double { return (getTorqueR() - s[6] * s[7] * (getIyaw() - getIpitch())) / getIroll(); }));
linearIntegrator.reset(new RK4Solver(
/* dx/dt */ [](const std::vector<double>& s, double) -> double {return s[3]; },
/* dy/dt */ [](const std::vector<double>& s, double) -> double {return s[4]; },
/* dz/dt */ [](const std::vector<double>& s, double) -> double {return s[5]; },
/* dvx/dt */ [this](const std::vector<double>&, double ) -> double { return getForceX() / getMass(); },
/* dvy/dt */ [this](const std::vector<double>&, double ) -> double { return getForceY() / getMass(); },
/* dvz/dt */ [this](const std::vector<double>&, double ) -> double { return getForceZ() / getMass(); }));
linearIntegrator->setTimeStep(timeStep);
// orientationIntegrator.reset(new RK4Solver(
// /* dpitch/dt */ [](double, const std::vector<double>& s) -> double { return s[3]; },
// /* dyaw/dt */ [](double, const std::vector<double>& s) -> double { return s[4]; },
// /* droll/dt */ [](double, const std::vector<double>& s) -> double { return s[5]; },
// /* dpitchRate/dt */ [this](double, const std::vector<double>& s) -> double { return (getTorqueP() - s[1] * s[2] * (getIroll() - getIyaw())) / getIpitch(); },
// /* dyawRate/dt */ [this](double, const std::vector<double>& s) -> double { return (getTorqueQ() - s[0] * s[2] * (getIpitch() - getIroll())) / getIyaw(); },
// /* drollRate/dt */ [this](double, const std::vector<double>& s) -> double { return (getTorqueR() - s[0] * s[1] * (getIyaw() - getIpitch())) / getIroll(); }));
// orientationIntegrator->setTimeStep(timeStep);
integrator->setTimeStep(timeStep);
saveStates = true;
}
@ -69,7 +72,7 @@ void Propagator::runUntilTerminate()
while(true)
{
// tempRes gets overwritten
integrator->step(currentTime, currentState, tempRes);
linearIntegrator->step(currentState, tempRes);
std::swap(currentState, tempRes);
if(saveStates)
@ -110,7 +113,7 @@ double Propagator::getForceY()
double Propagator::getForceZ()
{
QtRocket* qtrocket = QtRocket::getInstance();
double gravity = (qtrocket->getEnvironment()->getGravityModel()->getAccel(currentState[0], currentState[1], currentState[2])).x3;
double gravity = (qtrocket->getEnvironment()->getGravityModel()->getAccel(currentState[0], currentState[1], currentState[2]))[2];
double airDrag = (currentState[5] >= 0 ? -1.0 : 1.0) * qtrocket->getEnvironment()->getAtmosphericModel()->getDensity(currentState[2]) / 2.0 * 0.008107 * rocket->getDragCoefficient() * currentState[5]* currentState[5];
double thrust = rocket->getThrust(currentTime);
return gravity + airDrag + thrust;

View File

@ -74,12 +74,13 @@ private:
//private:
std::unique_ptr<sim::DESolver> integrator;
std::unique_ptr<sim::DESolver> linearIntegrator;
//std::unique_ptr<sim::DESolver> orientationIntegrator;
Rocket* rocket;
std::vector<double> currentState{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
std::vector<double> tempRes{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
std::vector<double> currentState{0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
std::vector<double> tempRes{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
bool saveStates{true};
double currentTime{0.0};
double timeStep{0.01};

View File

@ -19,6 +19,15 @@
namespace sim {
/**
* @brief Runge-Kutta 4th order coupled ODE solver.
* @note This was written outside of the context of QtRocket, and it is very generic. There are
* some features of this solver that are note used by QtRocket, for example, it can solve
* and arbitrarily large system of coupled ODEs, but QtRocket only makes use of a system
* of size 6 (x, y, z, xDot, yDot, zDot) at a time.
*
* @tparam Ts
*/
template<typename... Ts>
class RK4Solver : public DESolver
{
@ -34,7 +43,7 @@ public:
void setTimeStep(double inTs) override { dt = inTs; halfDT = dt / 2.0; }
void step(double t, const std::vector<double>& curVal, std::vector<double>& res) override
void step(const std::vector<double>& curVal, std::vector<double>& res, double t = 0.0) override
{
if(dt == std::numeric_limits<double>::quiet_NaN())
{
@ -44,7 +53,7 @@ public:
for(size_t i = 0; i < len; ++i)
{
k1[i] = odes[i](t, curVal);
k1[i] = odes[i](curVal, t);
}
// compute k2 values. This involves stepping the current values forward a half-step
// based on k1, so we do the stepping first
@ -54,7 +63,7 @@ public:
}
for(size_t i = 0; i < len; ++i)
{
k2[i] = odes[i](t + halfDT, temp);
k2[i] = odes[i](temp, t + halfDT);
}
// repeat for k3
for(size_t i = 0; i < len; ++i)
@ -63,7 +72,7 @@ public:
}
for(size_t i = 0; i < len; ++i)
{
k3[i] = odes[i](t + halfDT, temp);
k3[i] = odes[i](temp, t + halfDT);
}
// now k4
@ -73,7 +82,7 @@ public:
}
for(size_t i = 0; i < len; ++i)
{
k4[i] = odes[i](t + dt, temp);
k4[i] = odes[i](temp, t + dt);
}
// now compute the result
@ -85,7 +94,7 @@ public:
}
private:
std::vector<std::function<double(double, const std::vector<double>&)>> odes;
std::vector<std::function<double(const std::vector<double>&, double)>> odes;
static constexpr size_t len = sizeof...(Ts);
double k1[len];

View File

@ -25,7 +25,7 @@ SphericalGravityModel::~SphericalGravityModel()
}
TripletD SphericalGravityModel::getAccel(double x, double y, double z)
Vector3 SphericalGravityModel::getAccel(double x, double y, double z)
{
// Convert x, y, z from meters to km. This is to avoid potential precision losses
// with using the earth's gravitation parameter in meters (14 digit number).
@ -43,7 +43,7 @@ TripletD SphericalGravityModel::getAccel(double x, double y, double z)
double ay = accelFactor * y_km * 1000.0;
double az = accelFactor * z_km * 1000.0;
return TripletD(ax, ay, az);
return Vector3(ax, ay, az);
}

View File

@ -2,7 +2,7 @@
#define SIM_SPHERICALGRAVITYMODEL_H
// qtrocket headers
#include "GravityModel.h"
#include "sim/GravityModel.h"
namespace sim
{
@ -13,7 +13,7 @@ public:
SphericalGravityModel();
virtual ~SphericalGravityModel();
TripletD getAccel(double x, double y, double z) override;
Vector3 getAccel(double x, double y, double z) override;
};
} // namespace sim

View File

@ -1,6 +0,0 @@
#include "StateData.h"
StateData::StateData()
{
}

View File

@ -2,8 +2,7 @@
#define STATEDATA_H
// qtrocket headers
#include "utils/math/Vector3.h"
#include "utils/math/Quaternion.h"
#include "utils/math/MathTypes.h"
/**
* @brief The StateData class holds physical state data. Things such as position, velocity,
@ -13,17 +12,18 @@
class StateData
{
public:
StateData();
StateData() {}
~StateData() {}
/// TODO: Put these behind an interface
// private:
Vector3 position{0.0, 0.0, 0.0};
Vector3 velocity{0.0, 0.0, 0.0};
private:
math::Vector3 position{0.0, 0.0, 0.0};
math::Vector3 velocity{0.0, 0.0, 0.0};
Quaternion orientation{0.0, 0.0, 0.0, 0.0}; /// (scalar, vector)
Quaternion orientationRate{0.0, 0.0, 0.0, 0.0}; /// (scalar, vector)
math::Quaternion orientation{0.0, 0.0, 0.0, 0.0}; // roll, pitch, yaw
math::Quaternion orientationRate{0.0, 0.0, 0.0, 0.0}; // roll-rate, pitch-rate, yaw-rate
// Necessary?
//math::Vector3 orientationAccel;
Matrix3 dcm{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
// This is an array because the integrator expects it
double data[6];

View File

@ -13,9 +13,9 @@ WindModel::~WindModel()
{
}
TripletD WindModel::getWindSpeed(double /* x */, double /* y */ , double /* z */)
Vector3 WindModel::getWindSpeed(double /* x */, double /* y */ , double /* z */)
{
return TripletD(0.0, 0.0, 0.0);
return Vector3(0.0, 0.0, 0.0);
}
} // namespace sim

View File

@ -2,7 +2,7 @@
#define SIM_WINDMODEL_H
// qtrocket headers
#include "utils/Triplet.h"
#include "utils/math/MathTypes.h"
namespace sim
{
@ -13,7 +13,7 @@ public:
WindModel();
virtual ~WindModel();
virtual TripletD getWindSpeed(double x, double y, double z);
virtual Vector3 getWindSpeed(double x, double y, double z);
};

View File

@ -98,6 +98,7 @@ void MotorModelDatabase::saveMotorDatabase(const std::string& filename)
motor.put("type", m.data.type.str());
motor.put("lastUpdated", m.data.lastUpdated);
// delays tag is in the form of a csv string
std::stringstream delays;
for (std::size_t i = 0; i < m.data.delays.size() - 1; ++i)
{

View File

@ -1,21 +0,0 @@
#ifndef TRIPLET_H
#define TRIPLET_H
/**
* The purpose of this class is to get rid of using std::tuple for coordinate triplets.
*/
template<typename T>
struct Triplet
{
Triplet(const T& a, const T& b, const T& c)
: x1(a), x2(b), x3(c)
{}
T x1;
T x2;
T x3;
};
using TripletD = Triplet<double>;
#endif // TRIPLET_H

15
utils/math/MathTypes.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef UTILS_MATH_MATHTYPES_H
#define UTILS_MATH_MATHTYPES_H
#include <Eigen/Dense>
/// This is not in any namespace. These typedefs are intended to be used throughout QtRocket,
/// so keeping them in the global namespace seems to make sense.
typedef Eigen::Matrix3d Matrix3;
typedef Eigen::Matrix4d Matrix4;
typedef Eigen::Vector3d Vector3;
typedef Eigen::Quaterniond Quaternion;
#endif // UTILS_MATH_MATHTYPES_H

View File

@ -1,25 +0,0 @@
// qtrocket headers
#include "utils/math/Quaternion.h"
namespace math
{
Quaternion::Quaternion()
{
}
Quaternion::Quaternion(double r, const Vector3& i)
: real(r),
imag(i)
{
}
Quaternion::Quaternion(double r, double i1, double i2, double i3)
: real(r),
imag(i1, i2, i3)
{
}
} // namespace math

View File

@ -1,63 +0,0 @@
#ifndef MATH_QUATERNION_H
#define MATH_QUATERNION_H
/// \cond
// C headers
// C++ headers
#include <utility>
// 3rd party headers
/// \endcond
// qtrocket headers
#include "Vector3.h"
namespace math
{
class Quaternion
{
public:
Quaternion();
~Quaternion() {}
Quaternion(double r, const Vector3& i);
Quaternion(double r, double i1, double i2, double i3);
Quaternion(const Quaternion&) = default;
Quaternion(Quaternion&&) = default;
Quaternion& operator=(const Quaternion& rhs)
{
if(this == &rhs)
return *this;
real = rhs.real;
imag = rhs.imag;
return *this;
}
Quaternion& operator=(Quaternion&& rhs)
{
if(this == &rhs)
return *this;
real = std::move(rhs.real);
imag = std::move(rhs.imag);
return *this;
}
/*
Quaternion operator-() {}
Quaternion operator-(const Quaternion& ) {}
Quaternion operator+(const Quaternion& ) {}
Quaternion operator*(double ) {}
Quaternion operator*(const Quaternion& ) {}
*/
private:
double real;
Vector3 imag;
};
} // namespace math
#endif // MATH_QUATERNION_H

View File

@ -1,15 +0,0 @@
/// \cond
// C headers
// C++ headers
// 3rd party headers
/// \endcond
namespace utils
{
namespace math
{
} // namespace math
} // namespace utils

View File

@ -1,68 +0,0 @@
// qtrocket headers
#include "utils/math/Vector3.h"
namespace math
{
Vector3::Vector3()
: x1(0.0),
x2(0.0),
x3(0.0)
{
}
Vector3::Vector3(const double& inX1,
const double& inX2,
const double& inX3)
: x1(inX1),
x2(inX2),
x3(inX3)
{
}
Vector3::Vector3(const Vector3& o)
: x1(o.x1),
x2(o.x2),
x3(o.x3)
{
}
Vector3::~Vector3()
{}
Vector3 Vector3::operator=(const Vector3& rhs)
{
return Vector3(rhs.x1, rhs.x2, rhs.x3);
}
Vector3 Vector3::operator-()
{
return Vector3(-x1, -x2, -x3);
}
Vector3 Vector3::operator-(const Vector3& rhs)
{
return Vector3(x1 - rhs.x1,
x2 - rhs.x2,
x3 - rhs.x3);
}
Vector3 Vector3::operator+(const Vector3& rhs)
{
return Vector3(x1 + rhs.x1,
x2 + rhs.x2,
x3 + rhs.x3);
}
Vector3 Vector3::operator*(const double& s)
{
return Vector3(x1 * s,
x2 * s,
x3 * s);
}
} // namespace math

View File

@ -1,40 +0,0 @@
#ifndef MATH_VECTOR3_H
#define MATH_VECTOR3_H
namespace math
{
class Vector3
{
public:
Vector3();
Vector3(const double& inX1,
const double& inX2,
const double& inX3);
Vector3(const Vector3& o);
~Vector3();
Vector3 operator=(const Vector3& rhs);
Vector3 operator-();
Vector3 operator-(const Vector3& rhs);
Vector3 operator+(const Vector3& rhs);
Vector3 operator*(const double& s);
double getX1() { return x1; }
double getX2() { return x2; }
double getX3() { return x3; }
//private:
double x1;
double x2;
double x3;
};
} // namespace math
#endif // MATH_VECTOR3_H