WIP. Added templated RK4 solver and some more framework code
This commit is contained in:
parent
6e00f22ce4
commit
39920e2777
@ -82,15 +82,27 @@ void MainWindow::on_testButton2_clicked()
|
||||
|
||||
double ts = 0.01;
|
||||
|
||||
sim::RK4Solver velXSolver([=](double x, double t) -> double { return 0.0; });
|
||||
velXSolver.setTimeStep(ts);
|
||||
sim::RK4Solver velYSolver([=](double y, double t) -> double { return -9.8; });
|
||||
velYSolver.setTimeStep(ts);
|
||||
// X position/velocity. x[0] is X position, x[1] is X velocity
|
||||
double x[2] = {0.0, initialVelocityX};
|
||||
|
||||
sim::RK4Solver posXSolver([=](double x, double t) -> double { return velXSolver.step(x, t); });
|
||||
posXSolver.setTimeStep(ts);
|
||||
sim::RK4Solver posYSolver([=](double y, double t) -> double { return velYSolver.step(x, t); });
|
||||
posYSolver.setTimeStep(ts);
|
||||
// Y position/velocity. y[0] is Y position, y[1] is Y velocity
|
||||
double y[2] = {0.0, initialVelocityY};
|
||||
|
||||
auto xvelODE = [mass, dragCoeff](double, double* x) -> double
|
||||
{
|
||||
|
||||
return -dragCoeff * 1.225 * 0.00774192 / (2.0 * mass) * x[1]*x[1]; };
|
||||
auto xposODE = [](double, double* x) -> double { return x[1]; };
|
||||
sim::RK4Solver xSolver(xposODE, xvelODE);
|
||||
xSolver.setTimeStep(0.01);
|
||||
|
||||
auto yvelODE = [mass, dragCoeff](double, double* y) -> double
|
||||
{
|
||||
|
||||
return -dragCoeff * 1.225 * 0.00774192 / (2.0 * mass) * y[1]*y[1] - 9.8; };
|
||||
auto yposODE = [](double, double* y) -> double { return y[1]; };
|
||||
sim::RK4Solver ySolver(yposODE, yvelODE);
|
||||
ySolver.setTimeStep(0.01);
|
||||
|
||||
|
||||
// These can be solved independently for now. Maybe figure out how to merge them later
|
||||
@ -98,33 +110,42 @@ void MainWindow::on_testButton2_clicked()
|
||||
QTextStream cout(stdout);
|
||||
cout << "Initial X velocity: " << initialVelocityX << "\n";
|
||||
cout << "Initial Y velocity: " << initialVelocityY << "\n";
|
||||
double resX[2];
|
||||
double resY[2];
|
||||
for(size_t i = 0; i < maxTs; ++i)
|
||||
{
|
||||
position.emplace_back(posXSolver.step(position[i].getX1(), i * ts),
|
||||
posYSolver.step(position[i].getX2(), i * ts),
|
||||
0.0);
|
||||
xSolver.step(i * ts, x, resX);
|
||||
ySolver.step(i * ts, y, resY);
|
||||
position.emplace_back(resX[0], resY[0], 0.0);
|
||||
|
||||
x[0] = resX[0];
|
||||
x[1] = resX[1];
|
||||
y[0] = resY[0];
|
||||
y[1] = resY[1];
|
||||
|
||||
cout << "(" << position[i].getX1() << ", " << position[i].getX2() << ")\n";
|
||||
if(y[0] < 0.0)
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
auto& plot = ui->plotWindow;
|
||||
// generate some data:
|
||||
QVector<double> x(position.size()), y(position.size());
|
||||
for (int i = 0; i < x.size(); ++i)
|
||||
QVector<double> xData(position.size()), yData(position.size());
|
||||
for (int i = 0; i < xData.size(); ++i)
|
||||
{
|
||||
x[i] = position[i].getX1();
|
||||
y[i] = position[i].getX2();
|
||||
xData[i] = position[i].getX1();
|
||||
yData[i] = position[i].getX2();
|
||||
}
|
||||
// create graph and assign data to it:
|
||||
plot->addGraph();
|
||||
plot->graph(0)->setData(x, y);
|
||||
plot->graph(0)->setData(xData, yData);
|
||||
// give the axes some labels:
|
||||
plot->xAxis->setLabel("x");
|
||||
plot->yAxis->setLabel("y");
|
||||
// set axes ranges, so we see all data:
|
||||
plot->xAxis->setRange(*std::min_element(std::begin(x), std::end(x)), *std::max_element(std::begin(x), std::end(x)));
|
||||
plot->yAxis->setRange(*std::min_element(std::begin(y), std::end(y)), *std::max_element(std::begin(y), std::end(y)));
|
||||
plot->xAxis->setRange(*std::min_element(std::begin(xData), std::end(xData)), *std::max_element(std::begin(xData), std::end(xData)));
|
||||
plot->yAxis->setRange(*std::min_element(std::begin(yData), std::end(yData)), *std::max_element(std::begin(yData), std::end(yData)));
|
||||
plot->replot();
|
||||
|
||||
}
|
||||
|
||||
|
@ -99,7 +99,7 @@
|
||||
<string>Calculate Ballistic Trajectory</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QWidget" name="">
|
||||
<widget class="QWidget" name="layoutWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>260</x>
|
||||
@ -117,7 +117,11 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="initialVelocity"/>
|
||||
<widget class="QLineEdit" name="initialVelocity">
|
||||
<property name="text">
|
||||
<string>500.0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
@ -127,7 +131,11 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="initialAngle"/>
|
||||
<widget class="QLineEdit" name="initialAngle">
|
||||
<property name="text">
|
||||
<string>45.0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
@ -137,7 +145,11 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="mass"/>
|
||||
<widget class="QLineEdit" name="mass">
|
||||
<property name="text">
|
||||
<string>1.0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
@ -147,7 +159,11 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLineEdit" name="dragCoeff"/>
|
||||
<widget class="QLineEdit" name="dragCoeff">
|
||||
<property name="text">
|
||||
<string>0.5</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
6
model/Rocket.cpp
Normal file
6
model/Rocket.cpp
Normal file
@ -0,0 +1,6 @@
|
||||
#include "Rocket.h"
|
||||
|
||||
Rocket::Rocket()
|
||||
{
|
||||
|
||||
}
|
43
model/Rocket.h
Normal file
43
model/Rocket.h
Normal file
@ -0,0 +1,43 @@
|
||||
#ifndef ROCKET_H
|
||||
#define ROCKET_H
|
||||
|
||||
#include "utils/math/Vector3.h"
|
||||
#include "utils/math/Quaternion.h"
|
||||
|
||||
#include "sim/Propagator.h"
|
||||
|
||||
#include <utility> // std::move
|
||||
#include <memory>
|
||||
|
||||
class Rocket
|
||||
{
|
||||
public:
|
||||
Rocket();
|
||||
|
||||
void setPosition(const math::Vector3& pos) { *position = pos; }
|
||||
void setPosition(math::Vector3&& pos) { *position = std::move(pos); }
|
||||
|
||||
void setVelocity(const math::Vector3& vel) { *velocity = vel; }
|
||||
void setVelocity(math::Vector3&& vel) { *velocity = std::move(vel); }
|
||||
|
||||
void setOrientation(const math::Quaternion& ori) { *orientation = ori; }
|
||||
void setOrientation(math::Quaternion&& ori) { *orientation = std::move(ori); }
|
||||
|
||||
void setOrientationRate(const math::Quaternion& ori) { *orientationRate = ori; }
|
||||
void setOrientationRate(math::Quaternion&& ori) { *orientationRate = std::move(ori); }
|
||||
|
||||
const math::Vector3& getPosition() const { return *position; }
|
||||
const math::Vector3& getVelocity() const { return *velocity; }
|
||||
const math::Quaternion& getOrientation() const { return *orientation; }
|
||||
const math::Quaternion& getOrientationRate() const { return *orientation; }
|
||||
private:
|
||||
|
||||
std::shared_ptr<math::Vector3> position;
|
||||
std::shared_ptr<math::Vector3> velocity;
|
||||
std::shared_ptr<math::Quaternion> orientation;
|
||||
std::shared_ptr<math::Quaternion> orientationRate;
|
||||
|
||||
sim::Propagator propagator;
|
||||
};
|
||||
|
||||
#endif // ROCKET_H
|
@ -17,11 +17,11 @@ SOURCES += \
|
||||
gui/MainWindow.cpp \
|
||||
model/Motor.cpp \
|
||||
model/MotorCase.cpp \
|
||||
model/Rocket.cpp \
|
||||
model/Thrustcurve.cpp \
|
||||
sim/AtmosphericModel.cpp \
|
||||
sim/GravityModel.cpp \
|
||||
sim/Propagator.cpp \
|
||||
sim/RK4Solver.cpp \
|
||||
sim/SphericalGeoidModel.cpp \
|
||||
sim/SphericalGravityModel.cpp \
|
||||
sim/StateData.cpp \
|
||||
@ -43,6 +43,7 @@ HEADERS += \
|
||||
gui/qcustomplot.h \
|
||||
model/Motor.h \
|
||||
model/MotorCase.h \
|
||||
model/Rocket.h \
|
||||
model/Thrustcurve.h \
|
||||
sim/AtmosphericModel.h \
|
||||
sim/DESolver.h \
|
||||
|
@ -11,7 +11,7 @@ public:
|
||||
virtual ~DESolver() {}
|
||||
|
||||
virtual void setTimeStep(double ts) = 0;
|
||||
virtual double step(double curVal, double t) const = 0;
|
||||
virtual void step(double t, double* curVal, double* res ) = 0;
|
||||
};
|
||||
|
||||
} // namespace sim
|
||||
|
@ -1,6 +1,9 @@
|
||||
#ifndef SIM_PROPAGATOR_H
|
||||
#define SIM_PROPAGATOR_H
|
||||
|
||||
#include "sim/DESolver.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace sim
|
||||
{
|
||||
@ -11,6 +14,8 @@ public:
|
||||
Propagator();
|
||||
|
||||
private:
|
||||
|
||||
std::unique_ptr<sim::DESolver> solver;
|
||||
};
|
||||
|
||||
} // namespace sim
|
||||
|
@ -1,19 +0,0 @@
|
||||
#include "RK4Solver.h"
|
||||
|
||||
namespace sim {
|
||||
|
||||
double RK4Solver::step(double curVal, double t) const
|
||||
{
|
||||
double retVal(0.0);
|
||||
|
||||
double k1 = de(curVal, t);
|
||||
double k2 = de(curVal + (dt * k1 / 2.0), t + dt / 2.0);
|
||||
double k3 = de(curVal + (dt * k2 / 2.0), t + dt / 2.0);
|
||||
double k4 = de(curVal + dt * k3, t + dt);
|
||||
retVal = curVal + (1.0 / 6.0)*dt*(k1 + 2.0*k2 + 2.0*k3 + k4);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
} // namespace sim
|
@ -1,27 +1,93 @@
|
||||
#ifndef SIM_RK4SOLVER_H
|
||||
#define SIM_RK4SOLVER_H
|
||||
|
||||
#include "DESolver.h"
|
||||
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
#include <cmath>
|
||||
|
||||
#include "utils/Logger.h"
|
||||
#include "sim/DESolver.h"
|
||||
|
||||
namespace sim {
|
||||
|
||||
template<typename... Ts>
|
||||
class RK4Solver : public DESolver
|
||||
{
|
||||
public:
|
||||
RK4Solver(std::function<double(double, double)> d) : de(d) {}
|
||||
|
||||
RK4Solver(Ts... funcs)
|
||||
{
|
||||
(odes.push_back(funcs), ...);
|
||||
|
||||
}
|
||||
virtual ~RK4Solver() {}
|
||||
|
||||
void setTimeStep(double inTs) override { dt = inTs; }
|
||||
double step(double curVal, double t) const override;
|
||||
void setTimeStep(double inTs) override { dt = inTs; halfDT = dt / 2.0; }
|
||||
|
||||
void step(double t, double* curVal, double* res) override
|
||||
{
|
||||
if(dt == std::numeric_limits<double>::quiet_NaN())
|
||||
{
|
||||
utils::Logger::getInstance()->error("Calling RK4Solver without setting dt first is an error");
|
||||
res[0] = std::numeric_limits<double>::quiet_NaN();
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < len; ++i)
|
||||
{
|
||||
k1[i] = odes[i](t, curVal);
|
||||
}
|
||||
// compute k2 values. This involves stepping the current values forward a half-step
|
||||
// based on k1, so we do the stepping first
|
||||
for(size_t i = 0; i < len; ++i)
|
||||
{
|
||||
temp[i] = curVal[i] + k1[i]*dt / 2.0;
|
||||
}
|
||||
for(size_t i = 0; i < len; ++i)
|
||||
{
|
||||
k2[i] = odes[i](t + halfDT, temp);
|
||||
}
|
||||
// repeat for k3
|
||||
for(size_t i = 0; i < len; ++i)
|
||||
{
|
||||
temp[i] = curVal[i] + k2[i]*dt / 2.0;
|
||||
}
|
||||
for(size_t i = 0; i < len; ++i)
|
||||
{
|
||||
k3[i] = odes[i](t + halfDT, temp);
|
||||
}
|
||||
|
||||
// now k4
|
||||
for(size_t i = 0; i < len; ++i)
|
||||
{
|
||||
temp[i] = curVal[i] + k3[i]*dt;
|
||||
}
|
||||
for(size_t i = 0; i < len; ++i)
|
||||
{
|
||||
k4[i] = odes[i](t + dt, temp);
|
||||
}
|
||||
|
||||
// now compute the result
|
||||
for(size_t i = 0; i < len; ++i)
|
||||
{
|
||||
res[i] = curVal[i] + (dt / 6.0)*(k1[i] + 2.0*k2[i] + 2.0*k3[i] + k4[i]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
std::function<double(double, double)> de;
|
||||
std::vector<std::function<double(double, double*)>> odes;
|
||||
|
||||
//double k1, k2, k3, k4;
|
||||
static constexpr size_t len = sizeof...(Ts);
|
||||
double k1[len];
|
||||
double k2[len];
|
||||
double k3[len];
|
||||
double k4[len];
|
||||
|
||||
double dt;
|
||||
double temp[len];
|
||||
|
||||
double dt = std::numeric_limits<double>::quiet_NaN();
|
||||
double halfDT = 0.0;
|
||||
|
||||
};
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define STATEDATA_H
|
||||
|
||||
#include "utils/math/Vector3.h"
|
||||
#include "utils/math/Quaternion.h"
|
||||
|
||||
/**
|
||||
* @brief The StateData class holds physical state data. Things such as position, velocity,
|
||||
@ -14,12 +15,11 @@ public:
|
||||
StateData();
|
||||
|
||||
private:
|
||||
math::Vector3 position;
|
||||
math::Vector3 velocity;
|
||||
math::Vector3 acceleration;
|
||||
math::Vector3 position{0.0, 0.0, 0.0};
|
||||
math::Vector3 velocity{0.0, 0.0, 0.0};
|
||||
|
||||
math::Vector3 orientation; // roll, pitch, yaw
|
||||
math::Vector3 orientationVelocity; // roll-rate, pitch-rate, yaw-rate
|
||||
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;
|
||||
|
||||
|
@ -8,4 +8,16 @@ 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
|
||||
|
@ -3,6 +3,8 @@
|
||||
|
||||
#include "Vector3.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace math
|
||||
{
|
||||
|
||||
@ -10,17 +12,38 @@ class Quaternion
|
||||
{
|
||||
public:
|
||||
Quaternion();
|
||||
~Quaternion() {}
|
||||
|
||||
Quaternion(double r, const Vector3& i);
|
||||
Quaternion(double r, double i1, double i2, double i3);
|
||||
|
||||
~Quaternion();
|
||||
Quaternion(const Quaternion&) = default;
|
||||
Quaternion(Quaternion&&) = default;
|
||||
|
||||
Quaternion operator-();
|
||||
Quaternion operator-(const Quaternion& rhs);
|
||||
Quaternion operator+(const Quaternion& rhs);
|
||||
Quaternion operator*(double s);
|
||||
Quaternion operator*(const Quaternion& rhs);
|
||||
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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user