From 8d663f858bbd422a72e6a47da8576fa0be0e9c8d Mon Sep 17 00:00:00 2001 From: Travis Hunter Date: Wed, 15 Mar 2023 19:30:56 -0600 Subject: [PATCH] Added RK4 solver --- QtRocket.ui | 4 +++ main.cpp | 6 ++-- qtrocket.pro | 13 ++++++-- resources/qtrocket.png | Bin 0 -> 31670 bytes sim/DESolver.h | 18 +++++++++++ sim/Propagator.cpp | 10 ++++++ sim/Propagator.h | 18 +++++++++++ sim/RK4Solver.cpp | 19 +++++++++++ sim/RK4Solver.h | 27 ++++++++++++++++ utils/math/Quaternion.cpp | 11 +++++++ utils/math/Quaternion.h | 32 ++++++++++++++++++ utils/math/Vector3.cpp | 66 ++++++++++++++++++++++++++++++++++++++ utils/math/Vector3.h | 40 +++++++++++++++++++++++ 13 files changed, 260 insertions(+), 4 deletions(-) create mode 100644 resources/qtrocket.png create mode 100644 sim/DESolver.h create mode 100644 sim/Propagator.cpp create mode 100644 sim/Propagator.h create mode 100644 sim/RK4Solver.cpp create mode 100644 sim/RK4Solver.h create mode 100644 utils/math/Quaternion.cpp create mode 100644 utils/math/Quaternion.h create mode 100644 utils/math/Vector3.cpp create mode 100644 utils/math/Vector3.h diff --git a/QtRocket.ui b/QtRocket.ui index 91751eb..9cfd349 100644 --- a/QtRocket.ui +++ b/QtRocket.ui @@ -13,6 +13,10 @@ QtRocket + + + resources/qtrocket.pngresources/qtrocket.png + diff --git a/main.cpp b/main.cpp index ed45820..845cef4 100644 --- a/main.cpp +++ b/main.cpp @@ -12,9 +12,11 @@ int main(int argc, char *argv[]) // TODO: Only support US English at the moment. Anyone want to help translate? QTranslator translator; const QStringList uiLanguages = QLocale::system().uiLanguages(); - for (const QString &locale : uiLanguages) { + for (const QString &locale : uiLanguages) + { const QString baseName = "qtrocket_" + QLocale(locale).name(); - if (translator.load(":/i18n/" + baseName)) { + if (translator.load(":/i18n/" + baseName)) + { a.installTranslator(&translator); break; } diff --git a/qtrocket.pro b/qtrocket.pro index 5ec3737..c3c5d16 100644 --- a/qtrocket.pro +++ b/qtrocket.pro @@ -17,13 +17,17 @@ SOURCES += \ qcustomplot.cpp \ sim/AtmosphericModel.cpp \ sim/GravityModel.cpp \ + sim/Propagator.cpp \ + sim/RK4Solver.cpp \ sim/SphericalGeoidModel.cpp \ sim/SphericalGravityModel.cpp \ sim/USStandardAtmosphere.cpp \ sim/WindModel.cpp \ utils/BinMap.cpp \ utils/CurlConnection.cpp \ - utils/ThrustCurveAPI.cpp + utils/ThrustCurveAPI.cpp \ + utils/math/Quaternion.cpp \ + utils/math/Vector3.cpp HEADERS += \ QtRocket.h \ @@ -32,8 +36,11 @@ HEADERS += \ model/Thrustcurve.h \ qcustomplot.h \ sim/AtmosphericModel.h \ + sim/DESolver.h \ sim/GeoidModel.h \ sim/GravityModel.h \ + sim/Propagator.h \ + sim/RK4Solver.h \ sim/SphericalGeoidModel.h \ sim/SphericalGravityModel.h \ sim/USStandardAtmosphere.h \ @@ -41,7 +48,9 @@ HEADERS += \ utils/BinMap.h \ utils/CurlConnection.h \ utils/ThrustCurveAPI.h \ - utils/math/Constants.h + utils/math/Constants.h \ + utils/math/Quaternion.h \ + utils/math/Vector3.h FORMS += \ QtRocket.ui diff --git a/resources/qtrocket.png b/resources/qtrocket.png new file mode 100644 index 0000000000000000000000000000000000000000..b41bf2bd5d2dcd5bd8501a42fa8c3ca29f6ad98c GIT binary patch literal 31670 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≺_{`m-s4Kr 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 J=9@Sj{$DOO$Aka? literal 0 HcmV?d00001 diff --git a/sim/DESolver.h b/sim/DESolver.h new file mode 100644 index 0000000..46b979d --- /dev/null +++ b/sim/DESolver.h @@ -0,0 +1,18 @@ +#ifndef SIM_DESOLVER_H +#define SIM_DESOLVER_H + +namespace sim +{ + +class DESolver +{ +public: + DESolver() {} + virtual ~DESolver() {} + + virtual double step(double curVal, double t, double dt) = 0; +}; + +} // namespace sim + +#endif // SIM_DESOLVER_H diff --git a/sim/Propagator.cpp b/sim/Propagator.cpp new file mode 100644 index 0000000..43cdaef --- /dev/null +++ b/sim/Propagator.cpp @@ -0,0 +1,10 @@ +#include "Propagator.h" + +namespace sim { + +Propagator::Propagator() +{ + +} + +} // namespace sim diff --git a/sim/Propagator.h b/sim/Propagator.h new file mode 100644 index 0000000..0662b0b --- /dev/null +++ b/sim/Propagator.h @@ -0,0 +1,18 @@ +#ifndef SIM_PROPAGATOR_H +#define SIM_PROPAGATOR_H + + +namespace sim +{ + +class Propagator +{ +public: + Propagator(); + +private: +}; + +} // namespace sim + +#endif // SIM_PROPAGATOR_H diff --git a/sim/RK4Solver.cpp b/sim/RK4Solver.cpp new file mode 100644 index 0000000..c6ef857 --- /dev/null +++ b/sim/RK4Solver.cpp @@ -0,0 +1,19 @@ +#include "RK4Solver.h" + +namespace sim { + +double RK4Solver::step(double curVal, double t, double dt) +{ + double retVal(0.0); + + k1 = de(t, curVal); + k2 = de(t + dt / 2.0, curVal + (dt * k1 / 2.0)); + k3 = de(t + dt / 2.0, curVal + (dt * k2 / 2.0)); + k4 = de(t + dt, curVal + dt * k3); + retVal = curVal + (1.0 / 6.0)*dt*(k1 + 2.0*k2 + 2.0*k3 + k4); + + return retVal; +} + + +} // namespace sim diff --git a/sim/RK4Solver.h b/sim/RK4Solver.h new file mode 100644 index 0000000..2c89a5e --- /dev/null +++ b/sim/RK4Solver.h @@ -0,0 +1,27 @@ +#ifndef SIM_RK4SOLVER_H +#define SIM_RK4SOLVER_H + +#include "DESolver.h" + +#include + +namespace sim { + +class RK4Solver : public DESolver +{ +public: + RK4Solver(const std::function& d) : de(d) {} + virtual ~RK4Solver() {} + + virtual double step(double curVal, double t, double dt) override; + +private: + std::function de; + + double k1, k2, k3, k4; + +}; + +} // namespace sim + +#endif // SIM_RK4SOLVER_H diff --git a/utils/math/Quaternion.cpp b/utils/math/Quaternion.cpp new file mode 100644 index 0000000..4c23d11 --- /dev/null +++ b/utils/math/Quaternion.cpp @@ -0,0 +1,11 @@ +#include "Quaternion.h" + +namespace math +{ + +Quaternion::Quaternion() +{ + +} + +} // namespace math diff --git a/utils/math/Quaternion.h b/utils/math/Quaternion.h new file mode 100644 index 0000000..25fd934 --- /dev/null +++ b/utils/math/Quaternion.h @@ -0,0 +1,32 @@ +#ifndef MATH_QUATERNION_H +#define MATH_QUATERNION_H + +#include "Vector3.h" + +namespace math +{ + +class Quaternion +{ +public: + Quaternion(); + + Quaternion(double r, const Vector3& i); + Quaternion(double r, double i1, double i2, double i3); + + ~Quaternion(); + + Quaternion operator-(); + Quaternion operator-(const Quaternion& rhs); + Quaternion operator+(const Quaternion& rhs); + Quaternion operator*(double s); + Quaternion operator*(const Quaternion& rhs); + +private: + double real; + Vector3 imag; +}; + +} // namespace math + +#endif // MATH_QUATERNION_H diff --git a/utils/math/Vector3.cpp b/utils/math/Vector3.cpp new file mode 100644 index 0000000..05282ad --- /dev/null +++ b/utils/math/Vector3.cpp @@ -0,0 +1,66 @@ +#include "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 diff --git a/utils/math/Vector3.h b/utils/math/Vector3.h new file mode 100644 index 0000000..5dc7f39 --- /dev/null +++ b/utils/math/Vector3.h @@ -0,0 +1,40 @@ +#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