WIP. Added Stage objects, and made Stage and Rocket a Propagatable. Changed Propagator to propagate a Propagatable instead of a Rocket. This is to allow for propagating dropped stages
This commit is contained in:
parent
9b807d53a4
commit
41183b8397
@ -81,7 +81,7 @@ QtRocket::QtRocket()
|
||||
setEnvironment(std::make_shared<sim::Environment>());
|
||||
|
||||
rocket.first =
|
||||
std::make_shared<Rocket>();
|
||||
std::make_shared<model::Rocket>();
|
||||
|
||||
rocket.second =
|
||||
std::make_shared<sim::Propagator>(rocket.first);
|
||||
|
@ -44,13 +44,13 @@ public:
|
||||
|
||||
std::shared_ptr<sim::Environment> getEnvironment() { return environment; }
|
||||
void setTimeStep(double t) { rocket.second->setTimeStep(t); }
|
||||
std::shared_ptr<Rocket> getRocket() { return rocket.first; }
|
||||
std::shared_ptr<model::Rocket> getRocket() { return rocket.first; }
|
||||
|
||||
std::shared_ptr<utils::MotorModelDatabase> getMotorDatabase() { return motorDatabase; }
|
||||
|
||||
void addMotorModels(std::vector<model::MotorModel>& m);
|
||||
|
||||
void addRocket(std::shared_ptr<Rocket> r) { rocket.first = r; }
|
||||
void addRocket(std::shared_ptr<model::Rocket> r) { rocket.first = r; }
|
||||
|
||||
void setEnvironment(std::shared_ptr<sim::Environment> e) { environment = e; }
|
||||
|
||||
@ -79,7 +79,7 @@ private:
|
||||
|
||||
utils::Logger* logger;
|
||||
|
||||
std::pair<std::shared_ptr<Rocket>, std::shared_ptr<sim::Propagator>> rocket;
|
||||
std::pair<std::shared_ptr<model::Rocket>, std::shared_ptr<sim::Propagator>> rocket;
|
||||
|
||||
std::shared_ptr<sim::Environment> environment;
|
||||
std::shared_ptr<utils::MotorModelDatabase> motorDatabase;
|
||||
|
@ -91,8 +91,8 @@ void AnalysisWindow::onButton_plotVelocity_clicked()
|
||||
|
||||
void AnalysisWindow::onButton_plotMotorCurve_clicked()
|
||||
{
|
||||
std::shared_ptr<Rocket> rocket = QtRocket::getInstance()->getRocket();
|
||||
model::MotorModel motor = rocket->getCurrentMotorModel();
|
||||
std::shared_ptr<model::Rocket> rocket = QtRocket::getInstance()->getRocket();
|
||||
model::MotorModel& motor = rocket->getCurrentStage()->getMotorModel();
|
||||
ThrustCurve tc = motor.getThrustCurve();
|
||||
|
||||
|
||||
|
@ -5,8 +5,12 @@ add_library(model
|
||||
MotorModelDatabase.h
|
||||
Part.cpp
|
||||
Part.h
|
||||
Propagatable.cpp
|
||||
Propagatable.h
|
||||
Rocket.cpp
|
||||
Rocket.h
|
||||
Stage.cpp
|
||||
Stage.h
|
||||
ThrustCurve.cpp
|
||||
ThrustCurve.h)
|
||||
|
||||
|
@ -1,6 +1,103 @@
|
||||
#include "Part.h"
|
||||
#include "utils/Logger.h"
|
||||
|
||||
namespace model
|
||||
{
|
||||
|
||||
Part::Part()
|
||||
{}
|
||||
|
||||
Part::~Part()
|
||||
{}
|
||||
|
||||
Part::Part(const Part& orig)
|
||||
: parent(orig.parent),
|
||||
name(orig.name),
|
||||
inertiaTensor(orig.inertiaTensor),
|
||||
compositeInertiaTensor(orig.compositeInertiaTensor),
|
||||
mass(orig.mass),
|
||||
compositeMass(orig.compositeMass),
|
||||
cm(orig.cm),
|
||||
length(orig.length),
|
||||
innerRadiusTop(orig.innerRadiusTop),
|
||||
outerRadiusTop(orig.outerRadiusTop),
|
||||
innerRadiusBottom(orig.innerRadiusBottom),
|
||||
outerRadiusBottom(orig.outerRadiusBottom),
|
||||
needsRecomputing(orig.needsRecomputing),
|
||||
childParts()
|
||||
{
|
||||
|
||||
// We are copying the whole tree. If the part we're copying itself has child
|
||||
// parts, we are also copying all of them! This may be inefficient and not what
|
||||
// is desired, but it is less likely to lead to weird bugs with the same part
|
||||
// appearing in multiple locations of the rocket
|
||||
utils::Logger::getInstance()->debug("Calling model::Part copy constructor. Recursively copying all child parts. Check Part names for uniqueness");
|
||||
|
||||
|
||||
for(const auto& i : orig.childParts)
|
||||
{
|
||||
Part& x = *std::get<0>(i);
|
||||
std::shared_ptr<Part> tempPart = std::make_shared<Part>(x);
|
||||
childParts.emplace_back(tempPart, std::get<1>(i));;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
double Part::getChildMasses(double t)
|
||||
{
|
||||
double childMasses{0.0};
|
||||
for(const auto& i : childParts)
|
||||
{
|
||||
childMasses += std::get<0>(i)->getMass(t);
|
||||
}
|
||||
return childMasses;
|
||||
|
||||
}
|
||||
|
||||
void Part::addChildPart(const Part& childPart, Vector3 position)
|
||||
{
|
||||
|
||||
double childMass = childPart.compositeMass;
|
||||
Matrix3 childInertiaTensor = childPart.compositeInertiaTensor;
|
||||
std::shared_ptr<Part> newChild = std::make_shared<Part>(childPart);
|
||||
// Set the parent pointer
|
||||
newChild->parent = this;
|
||||
|
||||
// Recompute inertia tensor
|
||||
|
||||
childInertiaTensor += childMass * ( position.dot(position) * Matrix3::Identity() - position*position.transpose());
|
||||
|
||||
compositeInertiaTensor += childInertiaTensor;
|
||||
compositeMass += childMass;
|
||||
|
||||
childParts.emplace_back(std::move(newChild), std::move(position));
|
||||
|
||||
if(parent)
|
||||
{
|
||||
parent->markAsNeedsRecomputing();
|
||||
parent->recomputeInertiaTensor();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Part::recomputeInertiaTensor()
|
||||
{
|
||||
if(!needsRecomputing)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// recompute the whole composite inertia tensor
|
||||
// Reset the composite inertia tensor
|
||||
compositeInertiaTensor = inertiaTensor;
|
||||
compositeMass = mass;
|
||||
for(auto& [child, pos] : childParts)
|
||||
{
|
||||
child->recomputeInertiaTensor();
|
||||
compositeInertiaTensor += child->compositeInertiaTensor + child->compositeMass * ( pos.dot(pos) * Matrix3::Identity() - pos*pos.transpose());
|
||||
compositeMass += child->compositeMass;
|
||||
}
|
||||
needsRecomputing = false;
|
||||
}
|
||||
|
||||
} // namespace model
|
63
model/Part.h
63
model/Part.h
@ -4,16 +4,16 @@
|
||||
/// \cond
|
||||
// C headers
|
||||
// C++ headers
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
|
||||
// 3rd party headers
|
||||
/// \endcond
|
||||
|
||||
// qtrocket headers
|
||||
#include "utils/math/MathTypes.h"
|
||||
#include "model/Part.h"
|
||||
|
||||
namespace model
|
||||
{
|
||||
@ -24,8 +24,10 @@ public:
|
||||
Part();
|
||||
virtual ~Part();
|
||||
|
||||
Part(const Part&);
|
||||
|
||||
void setMass(double m) { mass = m; }
|
||||
|
||||
|
||||
// Set the inertia tensor
|
||||
void setI(const Matrix3& I) { inertiaTensor = I; }
|
||||
|
||||
@ -37,11 +39,58 @@ public:
|
||||
|
||||
void setInnerRadius(double r) { innerRadiusTop = r; innerRadiusBottom = r; }
|
||||
void setOuterRadius(double r) { outerRadiusTop = r; outerRadiusBottom = r; }
|
||||
|
||||
double getMass(double t)
|
||||
{
|
||||
return mass;
|
||||
}
|
||||
|
||||
double getCompositeMass(double t)
|
||||
{
|
||||
return compositeMass;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Add a child part to this part.
|
||||
*
|
||||
* @param childPart Child part to add
|
||||
* @param position Relative position of the child part's center-of-mass w.r.t the
|
||||
* parent's center of mass
|
||||
*/
|
||||
void addChildPart(const Part& childPart, Vector3 position);
|
||||
|
||||
/**
|
||||
* @brief Recomputes the inertia tensor. If the change is due to the change in inertia
|
||||
* of a child part, an optional name of the child part can be given to
|
||||
* only recompute that change rather than recompute all child inertia
|
||||
* tensors
|
||||
*
|
||||
* @param name Optional name of the child part to recompute. If empty, it will
|
||||
* recompute all child inertia tensors
|
||||
*/
|
||||
//void recomputeInertiaTensor(std::string name = "");
|
||||
void recomputeInertiaTensor();
|
||||
private:
|
||||
|
||||
// This is a pointer to the parent Part, if it has one. Purpose is to be able to
|
||||
// tell the parent if it needs to recompute anything if this part changes. e.g.
|
||||
// if a change to this part's inertia tensor occurs, the parent needs to recompute
|
||||
// it's total inertia tensor.
|
||||
Part* parent{nullptr};
|
||||
|
||||
std::string name;
|
||||
|
||||
double getChildMasses(double t);
|
||||
void markAsNeedsRecomputing()
|
||||
{ needsRecomputing = true; if(parent) { parent->markAsNeedsRecomputing(); }}
|
||||
|
||||
// Because a part is both a simple part and the composite of itself with all of it's children,
|
||||
// we will keep track of this object's inertia tensor (without children), and the composite
|
||||
// one with all of it's children attached
|
||||
Matrix3 inertiaTensor; // moment of inertia tensor with respect to the part's center of mass and
|
||||
//
|
||||
Matrix3 compositeInertiaTensor;
|
||||
double mass; // The moment of inertia tensor also has this, so don't double compute
|
||||
double compositeMass; // The mass of this part along with all attached parts
|
||||
|
||||
Vector3 cm; // center of mass wrt middle of component
|
||||
|
||||
@ -53,7 +102,11 @@ private:
|
||||
double innerRadiusBottom;
|
||||
double outerRadiusBottom;
|
||||
|
||||
bool needsRecomputing{false};
|
||||
|
||||
/// @brief child parts and the relative positions of their center of mass w.r.t.
|
||||
/// the center of mass of this part
|
||||
std::vector<std::tuple<std::shared_ptr<Part>, Vector3>> childParts;
|
||||
};
|
||||
|
||||
}
|
||||
|
0
model/Propagatable.cpp
Normal file
0
model/Propagatable.cpp
Normal file
40
model/Propagatable.h
Normal file
40
model/Propagatable.h
Normal file
@ -0,0 +1,40 @@
|
||||
#ifndef MODEL_PROPAGATABLE_H
|
||||
#define MODEL_PROPAGATABLE_H
|
||||
|
||||
/// \cond
|
||||
// C headers
|
||||
// C++ headers
|
||||
#include <utility>
|
||||
// 3rd party headers
|
||||
/// \endcond
|
||||
|
||||
// qtrocket headers
|
||||
#include "sim/Aero.h"
|
||||
#include "sim/StateData.h"
|
||||
|
||||
namespace model
|
||||
{
|
||||
|
||||
class Propagatable
|
||||
{
|
||||
public:
|
||||
Propagatable() {}
|
||||
virtual ~Propagatable() {}
|
||||
|
||||
virtual double getDragCoefficient() = 0;
|
||||
virtual void setDragCoefficient(double d) = 0;
|
||||
|
||||
virtual bool terminateCondition(const std::pair<double, StateData>&) = 0;
|
||||
|
||||
virtual double getMass(double t) = 0;
|
||||
virtual double getThrust(double t) = 0;
|
||||
private:
|
||||
|
||||
sim::Aero aeroData;
|
||||
|
||||
StateData state;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // MODEL_PROPAGATABLE_H
|
@ -3,6 +3,9 @@
|
||||
#include "Rocket.h"
|
||||
#include "QtRocket.h"
|
||||
|
||||
namespace model
|
||||
{
|
||||
|
||||
Rocket::Rocket()
|
||||
{
|
||||
|
||||
@ -10,12 +13,12 @@ Rocket::Rocket()
|
||||
|
||||
void Rocket::launch()
|
||||
{
|
||||
mm.startMotor(0.0);
|
||||
currentStage->getMotorModel().startMotor(0.0);
|
||||
}
|
||||
|
||||
void Rocket::setMotorModel(const model::MotorModel& motor)
|
||||
{
|
||||
mm = motor;
|
||||
currentStage->setMotorModel(motor);
|
||||
}
|
||||
|
||||
bool Rocket::terminateCondition(const std::pair<double, StateData>& cond)
|
||||
@ -29,5 +32,17 @@ bool Rocket::terminateCondition(const std::pair<double, StateData>& cond)
|
||||
|
||||
double Rocket::getThrust(double t)
|
||||
{
|
||||
return mm.getThrust(t);
|
||||
return currentStage->getMotorModel().getThrust(t);
|
||||
}
|
||||
|
||||
double Rocket::getMass(double t)
|
||||
{
|
||||
double totalMass = 0.0;
|
||||
for(const auto& stage : stages)
|
||||
{
|
||||
totalMass += stage.second->getMass(t);
|
||||
}
|
||||
return totalMass;
|
||||
}
|
||||
|
||||
} // namespace model
|
@ -4,6 +4,7 @@
|
||||
/// \cond
|
||||
// C headers
|
||||
// C++ headers
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility> // std::move
|
||||
@ -13,15 +14,20 @@
|
||||
|
||||
// qtrocket headers
|
||||
#include "model/ThrustCurve.h"
|
||||
#include "model/MotorModel.h"
|
||||
#include "sim/Propagator.h"
|
||||
#include "utils/math/MathTypes.h"
|
||||
|
||||
#include "model/Stage.h"
|
||||
#include "model/Propagatable.h"
|
||||
|
||||
namespace model
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief The Rocket class holds all rocket components
|
||||
*
|
||||
*/
|
||||
class Rocket
|
||||
class Rocket : public Propagatable
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@ -29,40 +35,18 @@ public:
|
||||
*/
|
||||
Rocket();
|
||||
|
||||
/**
|
||||
* @brief Rocket class destructor
|
||||
*
|
||||
*/
|
||||
virtual ~Rocket() {}
|
||||
|
||||
/**
|
||||
* @brief launch Propagates the Rocket object until termination,
|
||||
* normally when altitude crosses from positive to negative
|
||||
*/
|
||||
void launch();
|
||||
|
||||
/**
|
||||
* @brief getMass returns the current mass of the rocket. This is the sum of all components' masses
|
||||
* @return total current mass of the Rocket
|
||||
*/
|
||||
double getMass(double simTime) const { return mass + mm.getMass(simTime); }
|
||||
|
||||
/**
|
||||
* @brief setMass sets the current total mass of the Rocket
|
||||
* @param m total Rocket mass
|
||||
* @todo This should be dynamically computed, not set. Fix this
|
||||
*/
|
||||
void setMass(double m) { mass = m;}
|
||||
|
||||
/**
|
||||
* @brief setDragCoefficient sets the current total drag coefficient of the Rocket
|
||||
* @param d drag coefficient
|
||||
* @todo This should be dynamically computed, not set. Fix this
|
||||
*/
|
||||
void setDragCoefficient(double d) { dragCoeff = d; }
|
||||
|
||||
/**
|
||||
* @brief getDragCoefficient returns the current drag coefficient
|
||||
*
|
||||
* This is intended to be called by the propagator during propagation.
|
||||
* @return the coefficient of drag
|
||||
*/
|
||||
double getDragCoefficient() const { return dragCoeff; }
|
||||
|
||||
/**
|
||||
* @brief getThrust returns current motor thrust
|
||||
* @param t current simulation time
|
||||
@ -70,6 +54,13 @@ public:
|
||||
*/
|
||||
double getThrust(double t);
|
||||
|
||||
/**
|
||||
* @brief getMass returns current rocket
|
||||
* @param t current simulation time
|
||||
* @return mass in kg
|
||||
*/
|
||||
virtual double getMass(double t) override;
|
||||
|
||||
/**
|
||||
* @brief setMotorModel
|
||||
* @param motor
|
||||
@ -80,14 +71,14 @@ public:
|
||||
* @brief Returns the current motor model.
|
||||
* @return The current motor model
|
||||
*/
|
||||
const model::MotorModel& getCurrentMotorModel() const { return mm; }
|
||||
//const model::MotorModel& getCurrentMotorModel() const { return mm; }
|
||||
|
||||
/**
|
||||
* @brief terminateCondition returns true or false, whether the passed-in time/state matches the terminate condition
|
||||
* @param cond time/state pair
|
||||
* @return true if the passed-in time/state satisfies the terminate condition
|
||||
*/
|
||||
bool terminateCondition(const std::pair<double, StateData>& cond);
|
||||
virtual bool terminateCondition(const std::pair<double, StateData>& cond) override;
|
||||
|
||||
/**
|
||||
* @brief setName sets the rocket name
|
||||
@ -95,16 +86,22 @@ public:
|
||||
*/
|
||||
void setName(const std::string& n) { name = n; }
|
||||
|
||||
virtual double getDragCoefficient() override { return 1.0; }
|
||||
virtual void setDragCoefficient(double d) override { }
|
||||
void setMass(double m) { }
|
||||
|
||||
std::shared_ptr<Stage> getCurrentStage() { return currentStage; }
|
||||
|
||||
private:
|
||||
|
||||
std::string name; /// Rocket name
|
||||
double dragCoeff; /// @todo get rid of this, should be dynamically calculated
|
||||
double mass; /// @todo get rid of this, should be dynamically computed, but is the current rocket mass
|
||||
|
||||
model::MotorModel mm; /// Current Motor Model
|
||||
std::map<unsigned int, std::shared_ptr<Stage>> stages;
|
||||
std::shared_ptr<Stage> currentStage;
|
||||
//model::MotorModel mm; /// Current Motor Model
|
||||
|
||||
|
||||
};
|
||||
|
||||
} // namespace model
|
||||
#endif // ROCKET_H
|
||||
|
27
model/Stage.cpp
Normal file
27
model/Stage.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
/// \cond
|
||||
// C headers
|
||||
// C++ headers
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
// 3rd party headers
|
||||
/// \endcond
|
||||
|
||||
// qtrocket headers
|
||||
#include "Stage.h"
|
||||
|
||||
namespace model
|
||||
{
|
||||
|
||||
Stage::Stage()
|
||||
{}
|
||||
|
||||
Stage::~Stage()
|
||||
{}
|
||||
|
||||
void Stage::setMotorModel(const model::MotorModel& motor)
|
||||
{
|
||||
mm = motor;
|
||||
}
|
||||
|
||||
} // namespace model
|
69
model/Stage.h
Normal file
69
model/Stage.h
Normal file
@ -0,0 +1,69 @@
|
||||
#ifndef SIM_STAGE_H
|
||||
#define SIM_STAGE_H
|
||||
|
||||
/// \cond
|
||||
// C headers
|
||||
// C++ headers
|
||||
#include <string>
|
||||
|
||||
// 3rd party headers
|
||||
/// \endcond
|
||||
|
||||
// qtrocket headers
|
||||
#include "model/MotorModel.h"
|
||||
#include "model/Part.h"
|
||||
#include "model/Propagatable.h"
|
||||
|
||||
namespace model
|
||||
{
|
||||
|
||||
class Stage : public Propagatable
|
||||
{
|
||||
public:
|
||||
Stage();
|
||||
virtual ~Stage();
|
||||
|
||||
/**
|
||||
* @brief setMotorModel
|
||||
* @param motor
|
||||
*/
|
||||
void setMotorModel(const model::MotorModel& motor);
|
||||
|
||||
/**
|
||||
* @brief Returns the current motor model.
|
||||
* @return The current motor model
|
||||
*/
|
||||
model::MotorModel& getMotorModel() { return mm; }
|
||||
|
||||
virtual double getMass(double t) override
|
||||
{
|
||||
return topPart.getCompositeMass(t) + mm.getMass(t);
|
||||
}
|
||||
|
||||
virtual double getDragCoefficient() override { return 1.0 ;}
|
||||
virtual void setDragCoefficient(double d) override {}
|
||||
|
||||
virtual bool terminateCondition(const std::pair<double, StateData>& cond) override
|
||||
{
|
||||
// Terminate propagation when the z coordinate drops below zero
|
||||
if(cond.second.position[2] < 0)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual double getThrust(double t) override { return mm.getThrust(t); }
|
||||
|
||||
|
||||
private:
|
||||
std::string name;
|
||||
|
||||
Part topPart;
|
||||
|
||||
model::MotorModel mm;
|
||||
Vector3 motorModelPosition; // position of motor cg w.r.t. the stage c.g.
|
||||
};
|
||||
|
||||
} // namespace model
|
||||
|
||||
#endif // SIM_STAGE_H
|
0
sim/Aero.cpp
Normal file
0
sim/Aero.cpp
Normal file
41
sim/Aero.h
Normal file
41
sim/Aero.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef SIM_AERO_H
|
||||
#define SIM_AERO_H
|
||||
|
||||
/// \cond
|
||||
// C headers
|
||||
// C++ headers
|
||||
#include <string>
|
||||
|
||||
// 3rd party headers
|
||||
/// \endcond
|
||||
|
||||
// qtrocket headers
|
||||
#include "utils/math/MathTypes.h"
|
||||
|
||||
namespace sim
|
||||
{
|
||||
|
||||
class Aero
|
||||
{
|
||||
public:
|
||||
|
||||
private:
|
||||
|
||||
Vector3 cp; /// center of pressure
|
||||
|
||||
double Cx; /// longitudinal coefficient
|
||||
double Cy; /// These are probably the same for axial symmetric
|
||||
double Cz; /// rockets. The coeffients in the y and z body directions
|
||||
|
||||
double Cl; // roll moment coefficient
|
||||
double Cm; // pitch moment coefficient
|
||||
double Cn; // yaw moment coefficient
|
||||
|
||||
double baseCd; // coefficient of drag due to base drag
|
||||
double Cd; // total coeffient of drag
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif // SIM_AERO_H
|
@ -13,6 +13,10 @@ public:
|
||||
virtual double getDensity(double altitude) = 0;
|
||||
virtual double getPressure(double altitude) = 0;
|
||||
virtual double getTemperature(double altitude) = 0;
|
||||
|
||||
virtual double getSpeedOfSound(double altitude) = 0;
|
||||
virtual double getDynamicViscosity(double altitude) = 0;
|
||||
|
||||
};
|
||||
|
||||
} // namespace sim
|
||||
|
@ -1,4 +1,6 @@
|
||||
add_library(sim
|
||||
Aero.cpp
|
||||
Aero.h
|
||||
AtmosphericModel.h
|
||||
ConstantAtmosphere.h
|
||||
ConstantGravityModel.h
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
// qtrocket headers
|
||||
#include "AtmosphericModel.h"
|
||||
#include "utils/math/Constants.h"
|
||||
|
||||
namespace sim {
|
||||
|
||||
@ -15,6 +16,10 @@ public:
|
||||
double getDensity(double) override { return 1.225; }
|
||||
double getPressure(double) override { return 101325.0; }
|
||||
double getTemperature(double) override { return 288.15; }
|
||||
|
||||
double getSpeedOfSound(double) override { return 340.294; }
|
||||
|
||||
double getDynamicViscosity(double) override { return 1.78938e-5; }
|
||||
};
|
||||
|
||||
} // namespace sim
|
||||
|
@ -22,10 +22,10 @@
|
||||
|
||||
namespace sim {
|
||||
|
||||
Propagator::Propagator(std::shared_ptr<Rocket> r)
|
||||
Propagator::Propagator(std::shared_ptr<model::Rocket> r)
|
||||
: linearIntegrator(),
|
||||
//orientationIntegrator(),
|
||||
rocket(r),
|
||||
object(r),
|
||||
currentState(),
|
||||
nextState(),
|
||||
currentGravity(),
|
||||
@ -154,7 +154,7 @@ void Propagator::runUntilTerminate()
|
||||
{
|
||||
states.push_back(std::make_pair(currentTime, nextState));
|
||||
}
|
||||
if(rocket->terminateCondition(std::make_pair(currentTime, currentState)))
|
||||
if(object->terminateCondition(std::make_pair(currentTime, currentState)))
|
||||
break;
|
||||
|
||||
currentTime += timeStep;
|
||||
@ -171,27 +171,27 @@ void Propagator::runUntilTerminate()
|
||||
|
||||
double Propagator::getMass()
|
||||
{
|
||||
return rocket->getMass(currentTime);
|
||||
return object->getMass(currentTime);
|
||||
}
|
||||
|
||||
double Propagator::getForceX()
|
||||
{
|
||||
QtRocket* qtrocket = QtRocket::getInstance();
|
||||
return (currentState.velocity[0] >= 0 ? -1.0 : 1.0) * qtrocket->getEnvironment()->getAtmosphericModel()->getDensity(currentState.position[2])/ 2.0 * 0.008107 * rocket->getDragCoefficient() * currentState.velocity[0]* currentState.velocity[0];
|
||||
return (currentState.velocity[0] >= 0 ? -1.0 : 1.0) * qtrocket->getEnvironment()->getAtmosphericModel()->getDensity(currentState.position[2])/ 2.0 * 0.008107 * object->getDragCoefficient() * currentState.velocity[0]* currentState.velocity[0];
|
||||
}
|
||||
|
||||
double Propagator::getForceY()
|
||||
{
|
||||
QtRocket* qtrocket = QtRocket::getInstance();
|
||||
return (currentState.velocity[1] >= 0 ? -1.0 : 1.0) * qtrocket->getEnvironment()->getAtmosphericModel()->getDensity(currentState.position[2]) / 2.0 * 0.008107 * rocket->getDragCoefficient() * currentState.velocity[1]* currentState.velocity[1];
|
||||
return (currentState.velocity[1] >= 0 ? -1.0 : 1.0) * qtrocket->getEnvironment()->getAtmosphericModel()->getDensity(currentState.position[2]) / 2.0 * 0.008107 * object->getDragCoefficient() * currentState.velocity[1]* currentState.velocity[1];
|
||||
}
|
||||
|
||||
double Propagator::getForceZ()
|
||||
{
|
||||
QtRocket* qtrocket = QtRocket::getInstance();
|
||||
double gravity = (qtrocket->getEnvironment()->getGravityModel()->getAccel(currentState.position[0], currentState.position[1], currentState.position[2]))[2];
|
||||
double airDrag = (currentState.velocity[2] >= 0 ? -1.0 : 1.0) * qtrocket->getEnvironment()->getAtmosphericModel()->getDensity(currentState.position[2]) / 2.0 * 0.008107 * rocket->getDragCoefficient() * currentState.velocity[2]* currentState.velocity[2];
|
||||
double thrust = rocket->getThrust(currentTime);
|
||||
double airDrag = (currentState.velocity[2] >= 0 ? -1.0 : 1.0) * qtrocket->getEnvironment()->getAtmosphericModel()->getDensity(currentState.position[2]) / 2.0 * 0.008107 * object->getDragCoefficient() * currentState.velocity[2]* currentState.velocity[2];
|
||||
double thrust = object->getThrust(currentTime);
|
||||
return gravity + airDrag + thrust;
|
||||
}
|
||||
|
||||
|
@ -14,10 +14,14 @@
|
||||
#include "sim/RK4Solver.h"
|
||||
#include "utils/math/MathTypes.h"
|
||||
#include "sim/StateData.h"
|
||||
#include "model/Propagatable.h"
|
||||
|
||||
|
||||
// Forward declare
|
||||
namespace model
|
||||
{
|
||||
class Rocket;
|
||||
}
|
||||
class QtRocket;
|
||||
|
||||
namespace sim
|
||||
@ -26,7 +30,7 @@ namespace sim
|
||||
class Propagator
|
||||
{
|
||||
public:
|
||||
Propagator(std::shared_ptr<Rocket> r);
|
||||
Propagator(std::shared_ptr<model::Rocket> r);
|
||||
~Propagator();
|
||||
|
||||
void setInitialState(const StateData& initialState)
|
||||
@ -70,7 +74,7 @@ private:
|
||||
std::unique_ptr<sim::RK4Solver<Vector3>> linearIntegrator;
|
||||
// std::unique_ptr<sim::RK4Solver<Quaternion>> orientationIntegrator;
|
||||
|
||||
std::shared_ptr<Rocket> rocket;
|
||||
std::shared_ptr<model::Propagatable> object;
|
||||
|
||||
StateData currentState;
|
||||
StateData nextState;
|
||||
|
@ -74,12 +74,11 @@ public:
|
||||
//}
|
||||
// private:
|
||||
|
||||
// These are 4-vectors so quaternion multiplication works out. The last term (scalar) is always
|
||||
// zero. I could just use quaternions here, but I want to make it clear that these aren't
|
||||
// rotations, they're vectors
|
||||
// Intended to be used as world state data
|
||||
Vector3 position{0.0, 0.0, 0.0};
|
||||
Vector3 velocity{0.0, 0.0, 0.0};
|
||||
|
||||
// Orientation of body coordinates w.r.t. world coordinates
|
||||
Quaternion orientation{0.0, 0.0, 0.0, 0.0}; /// (vector, scalar)
|
||||
Quaternion orientationRate{0.0, 0.0, 0.0, 0.0}; /// (vector, scalar)
|
||||
|
||||
|
@ -80,8 +80,6 @@ utils::BinMap USStandardAtmosphere::standardTemperature(initTemps());
|
||||
utils::BinMap USStandardAtmosphere::standardDensity(initDensities());
|
||||
utils::BinMap USStandardAtmosphere::standardPressure(initPressures());
|
||||
|
||||
|
||||
|
||||
USStandardAtmosphere::USStandardAtmosphere()
|
||||
{
|
||||
|
||||
@ -119,7 +117,6 @@ double USStandardAtmosphere::getTemperature(double altitude)
|
||||
double baseAltitude = standardTemperature.getBinBase(altitude);
|
||||
return baseTemp - (altitude - baseAltitude) * temperatureLapseRate[altitude];
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
double USStandardAtmosphere::getPressure(double altitude)
|
||||
{
|
||||
@ -142,4 +139,17 @@ double USStandardAtmosphere::getPressure(double altitude)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
double USStandardAtmosphere::getSpeedOfSound(double altitude)
|
||||
{
|
||||
return std::sqrt( (Constants::gamma * Constants::Rstar * getTemperature(altitude))
|
||||
/
|
||||
Constants::airMolarMass);
|
||||
}
|
||||
|
||||
double USStandardAtmosphere::getDynamicViscosity(double altitude)
|
||||
{
|
||||
double temperature = getTemperature(altitude);
|
||||
return (Constants::beta * std::pow(temperature, 1.5)) / ( temperature + Constants::S);
|
||||
}
|
||||
} // namespace sim
|
||||
|
@ -28,6 +28,10 @@ public:
|
||||
double getPressure(double altitude) override;
|
||||
double getTemperature(double altitude) override;
|
||||
|
||||
double getSpeedOfSound(double altitude) override;
|
||||
|
||||
double getDynamicViscosity(double altitude) override;
|
||||
|
||||
private:
|
||||
static utils::BinMap temperatureLapseRate;
|
||||
static utils::BinMap standardTemperature;
|
||||
|
@ -6,26 +6,85 @@ TEST(USStandardAtmosphereTests, DensityTests)
|
||||
{
|
||||
sim::USStandardAtmosphere atmosphere;
|
||||
|
||||
// Test that the calucated values are with 1% of the published values in the NOAA report
|
||||
EXPECT_NEAR(atmosphere.getDensity(0.0) / 1.225, 1.0, 0.01);
|
||||
EXPECT_NEAR(atmosphere.getDensity(1000.0) / 1.112, 1.0, 0.01);
|
||||
EXPECT_NEAR(atmosphere.getDensity(2000.0) / 1.007, 1.0, 0.01);
|
||||
EXPECT_NEAR(atmosphere.getDensity(3000.0) / 0.9093, 1.0, 0.01);
|
||||
EXPECT_NEAR(atmosphere.getDensity(4000.0) / 0.8194, 1.0, 0.01);
|
||||
EXPECT_NEAR(atmosphere.getDensity(5000.0) / 0.7364, 1.0, 0.01);
|
||||
EXPECT_NEAR(atmosphere.getDensity(6000.0) / 0.6601, 1.0, 0.01);
|
||||
EXPECT_NEAR(atmosphere.getDensity(7000.0) / 0.5900, 1.0, 0.01);
|
||||
EXPECT_NEAR(atmosphere.getDensity(8000.0) / 0.5258, 1.0, 0.01);
|
||||
EXPECT_NEAR(atmosphere.getDensity(9000.0) / 0.4647, 1.0, 0.01);
|
||||
EXPECT_NEAR(atmosphere.getDensity(10000.0) / 0.4135, 1.0, 0.01);
|
||||
EXPECT_NEAR(atmosphere.getDensity(15000.0) / 0.1948, 1.0, 0.01);
|
||||
EXPECT_NEAR(atmosphere.getDensity(20000.0) / 0.08891, 1.0, 0.01);
|
||||
EXPECT_NEAR(atmosphere.getDensity(25000.0) / 0.039466, 1.0, 0.01);
|
||||
EXPECT_NEAR(atmosphere.getDensity(30000.0) / 0.018012, 1.0, 0.01);
|
||||
EXPECT_NEAR(atmosphere.getDensity(40000.0) / 0.0038510, 1.0, 0.01);
|
||||
EXPECT_NEAR(atmosphere.getDensity(50000.0) / 0.00097752, 1.0, 0.01);
|
||||
EXPECT_NEAR(atmosphere.getDensity(60000.0) / 0.00028832, 1.0, 0.01);
|
||||
EXPECT_NEAR(atmosphere.getDensity(70000.0) / 0.000074243, 1.0, 0.01);
|
||||
EXPECT_NEAR(atmosphere.getDensity(80000.0) / 0.000015701, 1.0, 0.01);
|
||||
// Test that the calucated values are with 0.1% of the published values in the NOAA report
|
||||
EXPECT_NEAR(atmosphere.getDensity(0.0) / 1.225, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getDensity(1000.0) / 1.112, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getDensity(2000.0) / 1.007, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getDensity(3000.0) / 0.9093, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getDensity(4000.0) / 0.8194, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getDensity(5000.0) / 0.7364, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getDensity(6000.0) / 0.6601, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getDensity(7000.0) / 0.5900, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getDensity(15000.0) / 0.19367, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getDensity(20000.0) / 0.088035, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getDensity(25000.0) / 0.039466, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getDensity(30000.0) / 0.018012, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getDensity(40000.0) / 0.0038510, 1.0, 0.001);
|
||||
|
||||
// These are generally accurate to ~0.5%. Slight deviation of calculated
|
||||
// density from the given density in the report table
|
||||
EXPECT_NEAR(atmosphere.getDensity(8000.0) / 0.52579, 1.0, 0.005);
|
||||
EXPECT_NEAR(atmosphere.getDensity(9000.0) / 0.46706, 1.0, 0.005);
|
||||
EXPECT_NEAR(atmosphere.getDensity(10000.0) / 0.41351, 1.0, 0.005);
|
||||
EXPECT_NEAR(atmosphere.getDensity(50000.0) / 0.00097752, 1.0, 0.005);
|
||||
EXPECT_NEAR(atmosphere.getDensity(60000.0) / 0.00028832, 1.0, 0.005);
|
||||
EXPECT_NEAR(atmosphere.getDensity(70000.0) / 0.000074243, 1.0, 0.005);
|
||||
EXPECT_NEAR(atmosphere.getDensity(80000.0) / 0.000015701, 1.0, 0.005);
|
||||
|
||||
}
|
||||
|
||||
TEST(USStandardAtmosphereTests, PressureTests)
|
||||
{
|
||||
sim::USStandardAtmosphere atmosphere;
|
||||
|
||||
// Test that the calucated values are with 0.1% of the published values in the NOAA report
|
||||
EXPECT_NEAR(atmosphere.getPressure(0.0) / 101325.0, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getPressure(1000.0) / 89876.0, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getPressure(2000.0) / 79501.0, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getPressure(3000.0) / 70108.0, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getPressure(4000.0) / 61640.0, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getPressure(5000.0) / 54019.0, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getPressure(6000.0) / 47181.0, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getPressure(7000.0) / 41060.0, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getPressure(8000.0) / 35599.0, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getPressure(9000.0) / 30742.0, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getPressure(10000.0) / 26436.0, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getPressure(15000.0) / 12044.0, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getPressure(20000.0) / 5474.8, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getPressure(25000.0) / 2511.0, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getPressure(30000.0) / 1171.8, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getPressure(40000.0) / 277.52, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getPressure(50000.0) / 75.944, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getPressure(60000.0) / 20.314, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getPressure(70000.0) / 4.6342, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getPressure(80000.0) / 0.88627, 1.0, 0.001);
|
||||
|
||||
}
|
||||
|
||||
TEST(USStandardAtmosphereTests, TemperatureTests)
|
||||
{
|
||||
sim::USStandardAtmosphere atmosphere;
|
||||
|
||||
// Test that the calucated values are with 0.1% of the published values in the NOAA report
|
||||
EXPECT_NEAR(atmosphere.getTemperature(0.0) / 288.15, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getTemperature(1000.0) / 281.651, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getTemperature(2000.0) / 275.154, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getTemperature(3000.0) / 268.659, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getTemperature(4000.0) / 262.166, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getTemperature(5000.0) / 255.676, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getTemperature(6000.0) / 249.187, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getTemperature(7000.0) / 242.7, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getTemperature(8000.0) / 236.215, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getTemperature(9000.0) / 229.733, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getTemperature(10000.0) / 223.252, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getTemperature(15000.0) / 216.65, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getTemperature(20000.0) / 216.65, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getTemperature(25000.0) / 221.552, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getTemperature(30000.0) / 226.509, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getTemperature(40000.0) / 251.05, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getTemperature(50000.0) / 270.65, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getTemperature(60000.0) / 245.45, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getTemperature(70000.0) / 217.450, 1.0, 0.001);
|
||||
EXPECT_NEAR(atmosphere.getTemperature(80000.0) / 196.650, 1.0, 0.001);
|
||||
|
||||
}
|
@ -6,9 +6,19 @@ namespace utils::math
|
||||
|
||||
namespace Constants
|
||||
{
|
||||
constexpr double Rstar = 8.3144598;
|
||||
constexpr double Rstar = 8.31432;
|
||||
constexpr const double g0 = 9.80665;
|
||||
constexpr const double airMolarMass = 0.0289644;
|
||||
|
||||
// gamma is the ratio of the specific heat of air at constant pressure to that at
|
||||
// constant volume. Used in computing the speed of sound
|
||||
constexpr const double gamma = 1.4;
|
||||
|
||||
// beta is used in calculating the dynamic viscosity of air. Based on the 1976 US Standard
|
||||
// Atmosphere report, it is empirically measured to be:
|
||||
constexpr const double beta = 1.458e-6;
|
||||
// Sutherland's constant
|
||||
constexpr const double S = 110.4;
|
||||
constexpr const double standardTemperature = 288.15;
|
||||
constexpr const double standardDensity = 1.2250;
|
||||
constexpr const double meanEarthRadiusWGS84 = 6371008.8;
|
||||
|
Loading…
x
Reference in New Issue
Block a user