Updated to YASim-0.1.1
This commit is contained in:
parent
6d077f4127
commit
4c422bbe6d
24 changed files with 348 additions and 149 deletions
|
@ -10,8 +10,6 @@
|
||||||
#include "Airplane.hpp"
|
#include "Airplane.hpp"
|
||||||
namespace yasim {
|
namespace yasim {
|
||||||
|
|
||||||
// FIXME: hook gear extension into the force calculation somehow...
|
|
||||||
|
|
||||||
Airplane::Airplane()
|
Airplane::Airplane()
|
||||||
{
|
{
|
||||||
_emptyWeight = 0;
|
_emptyWeight = 0;
|
||||||
|
@ -19,10 +17,12 @@ Airplane::Airplane()
|
||||||
_wing = 0;
|
_wing = 0;
|
||||||
_tail = 0;
|
_tail = 0;
|
||||||
_ballast = 0;
|
_ballast = 0;
|
||||||
_cruiseRho = 0;
|
_cruiseP = 0;
|
||||||
|
_cruiseT = 0;
|
||||||
_cruiseSpeed = 0;
|
_cruiseSpeed = 0;
|
||||||
_cruiseWeight = 0;
|
_cruiseWeight = 0;
|
||||||
_approachRho = 0;
|
_approachP = 0;
|
||||||
|
_approachT = 0;
|
||||||
_approachSpeed = 0;
|
_approachSpeed = 0;
|
||||||
_approachAoA = 0;
|
_approachAoA = 0;
|
||||||
_approachWeight = 0;
|
_approachWeight = 0;
|
||||||
|
@ -51,8 +51,7 @@ void Airplane::iterate(float dt)
|
||||||
{
|
{
|
||||||
_model.iterate();
|
_model.iterate();
|
||||||
|
|
||||||
// Consume fuel
|
// FIXME: Consume fuel
|
||||||
// FIXME
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ControlMap* Airplane::getControlMap()
|
ControlMap* Airplane::getControlMap()
|
||||||
|
@ -139,14 +138,16 @@ void Airplane::setApproach(float speed, float altitude)
|
||||||
void Airplane::setApproach(float speed, float altitude, float aoa)
|
void Airplane::setApproach(float speed, float altitude, float aoa)
|
||||||
{
|
{
|
||||||
_approachSpeed = speed;
|
_approachSpeed = speed;
|
||||||
_approachRho = Atmosphere::getStdDensity(altitude);
|
_approachP = Atmosphere::getStdPressure(altitude);
|
||||||
|
_approachT = Atmosphere::getStdTemperature(altitude);
|
||||||
_approachAoA = aoa;
|
_approachAoA = aoa;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Airplane::setCruise(float speed, float altitude)
|
void Airplane::setCruise(float speed, float altitude)
|
||||||
{
|
{
|
||||||
_cruiseSpeed = speed;
|
_cruiseSpeed = speed;
|
||||||
_cruiseRho = Atmosphere::getStdDensity(altitude);
|
_cruiseP = Atmosphere::getStdPressure(altitude);
|
||||||
|
_cruiseT = Atmosphere::getStdTemperature(altitude);
|
||||||
_cruiseAoA = 0;
|
_cruiseAoA = 0;
|
||||||
_tailIncidence = 0;
|
_tailIncidence = 0;
|
||||||
}
|
}
|
||||||
|
@ -254,6 +255,7 @@ int Airplane::addWeight(float* pos, float size)
|
||||||
wr->handle = _model.getBody()->addMass(0, pos);
|
wr->handle = _model.getBody()->addMass(0, pos);
|
||||||
|
|
||||||
wr->surf = new Surface();
|
wr->surf = new Surface();
|
||||||
|
wr->surf->setPosition(pos);
|
||||||
wr->surf->setTotalDrag(size*size);
|
wr->surf->setTotalDrag(size*size);
|
||||||
_model.addSurface(wr->surf);
|
_model.addSurface(wr->surf);
|
||||||
_surfs.add(wr->surf);
|
_surfs.add(wr->surf);
|
||||||
|
@ -364,7 +366,7 @@ float Airplane::compileFuselage(Fuselage* f)
|
||||||
float len = Math::mag3(fwd);
|
float len = Math::mag3(fwd);
|
||||||
float wid = f->width;
|
float wid = f->width;
|
||||||
int segs = (int)Math::ceil(len/wid);
|
int segs = (int)Math::ceil(len/wid);
|
||||||
float segWgt = wid*wid/segs;
|
float segWgt = len*wid/segs;
|
||||||
for(int j=0; j<segs; j++) {
|
for(int j=0; j<segs; j++) {
|
||||||
float frac = (j+0.5) / segs;
|
float frac = (j+0.5) / segs;
|
||||||
float pos[3];
|
float pos[3];
|
||||||
|
@ -406,10 +408,11 @@ void Airplane::compileGear(GearRec* gr)
|
||||||
|
|
||||||
// Put the surface at the half-way point on the gear strut, give
|
// Put the surface at the half-way point on the gear strut, give
|
||||||
// it a drag coefficient equal to a square of the same dimension
|
// it a drag coefficient equal to a square of the same dimension
|
||||||
// (gear are really draggy) and make it symmetric.
|
// (gear are really draggy) and make it symmetric. Assume that
|
||||||
|
// the "length" of the gear is 3x the compression distance
|
||||||
float pos[3], cmp[3];
|
float pos[3], cmp[3];
|
||||||
g->getCompression(cmp);
|
g->getCompression(cmp);
|
||||||
float length = Math::mag3(cmp);
|
float length = 3 * Math::mag3(cmp);
|
||||||
g->getPosition(pos);
|
g->getPosition(pos);
|
||||||
Math::mul3(0.5, cmp, cmp);
|
Math::mul3(0.5, cmp, cmp);
|
||||||
Math::add3(pos, cmp, pos);
|
Math::add3(pos, cmp, pos);
|
||||||
|
@ -486,6 +489,11 @@ void Airplane::compile()
|
||||||
tr->handle = _model.addThruster(tr->thruster);
|
tr->handle = _model.addThruster(tr->thruster);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ground effect
|
||||||
|
float gepos[3];
|
||||||
|
float gespan = _wing->getGroundEffect(gepos);
|
||||||
|
_model.setGroundEffect(gepos, gespan, .3);
|
||||||
|
|
||||||
solveGear();
|
solveGear();
|
||||||
solve();
|
solve();
|
||||||
|
|
||||||
|
@ -550,31 +558,15 @@ void Airplane::solveGear()
|
||||||
|
|
||||||
void Airplane::stabilizeThrust()
|
void Airplane::stabilizeThrust()
|
||||||
{
|
{
|
||||||
float thrust[3], tmp[3];
|
for(int i=0; i<_thrusters.size(); i++)
|
||||||
float last = 0;
|
_model.getThruster(i)->stabilize();
|
||||||
while(1) {
|
|
||||||
thrust[0] = thrust[1] = thrust[2] = 0;
|
|
||||||
for(int i=0; i<_thrusters.size(); i++) {
|
|
||||||
Thruster* t = _model.getThruster(i);
|
|
||||||
t->integrate(0.033);
|
|
||||||
t->getThrust(tmp);
|
|
||||||
Math::add3(thrust, tmp, thrust);
|
|
||||||
}
|
|
||||||
|
|
||||||
float t = Math::mag3(thrust);
|
|
||||||
float ratio = (t+0.1)/(last+0.1);
|
|
||||||
if(ratio < 1.00001 && ratio > 0.99999)
|
|
||||||
break;
|
|
||||||
|
|
||||||
last = t;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Airplane::runCruise()
|
void Airplane::runCruise()
|
||||||
{
|
{
|
||||||
setupState(_cruiseAoA, _cruiseSpeed, &_cruiseState);
|
setupState(_cruiseAoA, _cruiseSpeed, &_cruiseState);
|
||||||
_model.setState(&_cruiseState);
|
_model.setState(&_cruiseState);
|
||||||
_model.setAirDensity(_cruiseRho);
|
_model.setAir(_cruiseP, _cruiseT);
|
||||||
|
|
||||||
// The control configuration
|
// The control configuration
|
||||||
_controls.reset();
|
_controls.reset();
|
||||||
|
@ -600,7 +592,7 @@ void Airplane::runCruise()
|
||||||
for(int i=0; i<_thrusters.size(); i++) {
|
for(int i=0; i<_thrusters.size(); i++) {
|
||||||
Thruster* t = ((ThrustRec*)_thrusters.get(i))->thruster;
|
Thruster* t = ((ThrustRec*)_thrusters.get(i))->thruster;
|
||||||
t->setWind(wind);
|
t->setWind(wind);
|
||||||
t->setDensity(_cruiseRho);
|
t->setAir(_cruiseP, _cruiseT);
|
||||||
}
|
}
|
||||||
stabilizeThrust();
|
stabilizeThrust();
|
||||||
|
|
||||||
|
@ -614,7 +606,7 @@ void Airplane::runApproach()
|
||||||
{
|
{
|
||||||
setupState(_approachAoA, _approachSpeed, &_approachState);
|
setupState(_approachAoA, _approachSpeed, &_approachState);
|
||||||
_model.setState(&_approachState);
|
_model.setState(&_approachState);
|
||||||
_model.setAirDensity(_approachRho);
|
_model.setAir(_approachP, _approachT);
|
||||||
|
|
||||||
// The control configuration
|
// The control configuration
|
||||||
_controls.reset();
|
_controls.reset();
|
||||||
|
@ -640,7 +632,7 @@ void Airplane::runApproach()
|
||||||
for(int i=0; i<_thrusters.size(); i++) {
|
for(int i=0; i<_thrusters.size(); i++) {
|
||||||
Thruster* t = ((ThrustRec*)_thrusters.get(i))->thruster;
|
Thruster* t = ((ThrustRec*)_thrusters.get(i))->thruster;
|
||||||
t->setWind(wind);
|
t->setWind(wind);
|
||||||
t->setDensity(_approachRho);
|
t->setAir(_approachP, _approachT);
|
||||||
}
|
}
|
||||||
stabilizeThrust();
|
stabilizeThrust();
|
||||||
|
|
||||||
|
|
|
@ -112,13 +112,15 @@ private:
|
||||||
|
|
||||||
Vector _cruiseControls;
|
Vector _cruiseControls;
|
||||||
State _cruiseState;
|
State _cruiseState;
|
||||||
float _cruiseRho;
|
float _cruiseP;
|
||||||
|
float _cruiseT;
|
||||||
float _cruiseSpeed;
|
float _cruiseSpeed;
|
||||||
float _cruiseWeight;
|
float _cruiseWeight;
|
||||||
|
|
||||||
Vector _approachControls;
|
Vector _approachControls;
|
||||||
State _approachState;
|
State _approachState;
|
||||||
float _approachRho;
|
float _approachP;
|
||||||
|
float _approachT;
|
||||||
float _approachSpeed;
|
float _approachSpeed;
|
||||||
float _approachAoA;
|
float _approachAoA;
|
||||||
float _approachWeight;
|
float _approachWeight;
|
||||||
|
|
|
@ -7,7 +7,7 @@ namespace yasim {
|
||||||
// McCormick lists 299.16/101325/1.22500, but those don't agree with
|
// McCormick lists 299.16/101325/1.22500, but those don't agree with
|
||||||
// R=287. I chose to correct the temperature to 288.20, since 79F is
|
// R=287. I chose to correct the temperature to 288.20, since 79F is
|
||||||
// pretty hot for a "standard" atmosphere.
|
// pretty hot for a "standard" atmosphere.
|
||||||
// meters kelvin kPa kg/m^3
|
// meters kelvin Pa kg/m^3
|
||||||
float Atmosphere::data[][4] = {{ 0, 288.20, 101325, 1.22500 },
|
float Atmosphere::data[][4] = {{ 0, 288.20, 101325, 1.22500 },
|
||||||
{ 900, 282.31, 90971, 1.12260 },
|
{ 900, 282.31, 90971, 1.12260 },
|
||||||
{ 1800, 276.46, 81494, 1.02690 },
|
{ 1800, 276.46, 81494, 1.02690 },
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "Jet.hpp"
|
#include "Jet.hpp"
|
||||||
#include "Thruster.hpp"
|
#include "Thruster.hpp"
|
||||||
|
#include "PropEngine.hpp"
|
||||||
#include "Gear.hpp"
|
#include "Gear.hpp"
|
||||||
#include "Wing.hpp"
|
#include "Wing.hpp"
|
||||||
#include "Math.hpp"
|
#include "Math.hpp"
|
||||||
|
@ -114,7 +115,7 @@ void ControlMap::applyControls()
|
||||||
switch(o->type) {
|
switch(o->type) {
|
||||||
case THROTTLE: ((Thruster*)obj)->setThrottle(lval); break;
|
case THROTTLE: ((Thruster*)obj)->setThrottle(lval); break;
|
||||||
case MIXTURE: ((Thruster*)obj)->setMixture(lval); break;
|
case MIXTURE: ((Thruster*)obj)->setMixture(lval); break;
|
||||||
case PROP: ((Thruster*)obj)->setPropAdvance(lval); break;
|
case ADVANCE: ((PropEngine*)obj)->setAdvance(lval); break;
|
||||||
case REHEAT: ((Jet*)obj)->setReheat(lval); break;
|
case REHEAT: ((Jet*)obj)->setReheat(lval); break;
|
||||||
case BRAKE: ((Gear*)obj)->setBrake(lval); break;
|
case BRAKE: ((Gear*)obj)->setBrake(lval); break;
|
||||||
case STEER: ((Gear*)obj)->setRotation(lval); break;
|
case STEER: ((Gear*)obj)->setRotation(lval); break;
|
||||||
|
|
|
@ -9,7 +9,7 @@ class ControlMap {
|
||||||
public:
|
public:
|
||||||
~ControlMap();
|
~ControlMap();
|
||||||
|
|
||||||
enum OutputType { THROTTLE, MIXTURE, REHEAT, PROP,
|
enum OutputType { THROTTLE, MIXTURE, ADVANCE, REHEAT, PROP,
|
||||||
BRAKE, STEER, EXTEND,
|
BRAKE, STEER, EXTEND,
|
||||||
INCIDENCE, FLAP0, FLAP1, SLAT, SPOILER };
|
INCIDENCE, FLAP0, FLAP1, SLAT, SPOILER };
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ static const float LBS2N = 4.44822;
|
||||||
static const float LBS2KG = 0.45359237;
|
static const float LBS2KG = 0.45359237;
|
||||||
static const float CM2GALS = 264.172037284;
|
static const float CM2GALS = 264.172037284;
|
||||||
static const float HP2W = 745.700;
|
static const float HP2W = 745.700;
|
||||||
|
static const float INHG2PA = 3386.389;
|
||||||
|
|
||||||
// Stubs, so that this can be compiled without the FlightGear
|
// Stubs, so that this can be compiled without the FlightGear
|
||||||
// binary. What's the best way to handle this?
|
// binary. What's the best way to handle this?
|
||||||
|
@ -141,6 +142,7 @@ void FGFDM::startElement(const char* name, const XMLAttributes &atts)
|
||||||
v[2] = attrf(a, "z");
|
v[2] = attrf(a, "z");
|
||||||
float mass = attrf(a, "mass") * LBS2KG;
|
float mass = attrf(a, "mass") * LBS2KG;
|
||||||
j->setDryThrust(attrf(a, "thrust") * LBS2N);
|
j->setDryThrust(attrf(a, "thrust") * LBS2N);
|
||||||
|
j->setReheatThrust(attrf(a, "afterburner", 0) * LBS2N);
|
||||||
j->setPosition(v);
|
j->setPosition(v);
|
||||||
_airplane.addThruster(j, mass, v);
|
_airplane.addThruster(j, mass, v);
|
||||||
sprintf(buf, "/engines/engine[%d]", _nextEngine++);
|
sprintf(buf, "/engines/engine[%d]", _nextEngine++);
|
||||||
|
@ -333,21 +335,36 @@ void FGFDM::parsePropeller(XMLAttributes* a)
|
||||||
float radius = attrf(a, "radius");
|
float radius = attrf(a, "radius");
|
||||||
float speed = attrf(a, "cruise-speed") * KTS2MPS;
|
float speed = attrf(a, "cruise-speed") * KTS2MPS;
|
||||||
float omega = attrf(a, "cruise-rpm") * RPM2RAD;
|
float omega = attrf(a, "cruise-rpm") * RPM2RAD;
|
||||||
float rho = Atmosphere::getStdDensity(attrf(a, "alt") * FT2M);
|
float power = attrf(a, "cruise-power") * HP2W;
|
||||||
float power = attrf(a, "takeoff-power") * HP2W;
|
float rho = Atmosphere::getStdDensity(attrf(a, "cruise-alt") * FT2M);
|
||||||
float omega0 = attrf(a, "takeoff-rpm") * RPM2RAD;
|
|
||||||
|
|
||||||
// FIXME: this is a hack. Find a better way to ask the engine how
|
// Hack, fix this pronto:
|
||||||
// much power it can produce under cruise conditions.
|
float engP = attrf(a, "eng-power") * HP2W;
|
||||||
float cruisePower = (power * (rho/Atmosphere::getStdDensity(0))
|
float engS = attrf(a, "eng-rpm") * RPM2RAD;
|
||||||
* (omega/omega0));
|
|
||||||
|
|
||||||
Propeller* prop = new Propeller(radius, speed, omega, rho, cruisePower,
|
Propeller* prop = new Propeller(radius, speed, omega, rho, power);
|
||||||
omega0, power);
|
PistonEngine* eng = new PistonEngine(engP, engS);
|
||||||
PistonEngine* eng = new PistonEngine(power, omega0);
|
|
||||||
PropEngine* thruster = new PropEngine(prop, eng, moment);
|
PropEngine* thruster = new PropEngine(prop, eng, moment);
|
||||||
_airplane.addThruster(thruster, mass, cg);
|
_airplane.addThruster(thruster, mass, cg);
|
||||||
|
|
||||||
|
if(a->hasAttribute("turbo-mul")) {
|
||||||
|
float mul = attrf(a, "turbo-mul");
|
||||||
|
float mp = attrf(a, "wastegate-mp", 1e6) * INHG2PA;
|
||||||
|
eng->setTurboParams(mul, mp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(a->hasAttribute("takeoff-power")) {
|
||||||
|
float power0 = attrf(a, "takeoff-power") * HP2W;
|
||||||
|
float omega0 = attrf(a, "takeoff-rpm") * RPM2RAD;
|
||||||
|
prop->setTakeoff(omega0, power0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(a->hasAttribute("max-rpm")) {
|
||||||
|
float max = attrf(a, "max-rpm") * RPM2RAD;
|
||||||
|
float min = attrf(a, "min-rpm") * RPM2RAD;
|
||||||
|
thruster->setVariableProp(min, max);
|
||||||
|
}
|
||||||
|
|
||||||
char buf[64];
|
char buf[64];
|
||||||
sprintf(buf, "/engines/engine[%d]", _nextEngine++);
|
sprintf(buf, "/engines/engine[%d]", _nextEngine++);
|
||||||
EngRec* er = new EngRec();
|
EngRec* er = new EngRec();
|
||||||
|
@ -381,6 +398,7 @@ int FGFDM::parseOutput(const char* name)
|
||||||
{
|
{
|
||||||
if(eq(name, "THROTTLE")) return ControlMap::THROTTLE;
|
if(eq(name, "THROTTLE")) return ControlMap::THROTTLE;
|
||||||
if(eq(name, "MIXTURE")) return ControlMap::MIXTURE;
|
if(eq(name, "MIXTURE")) return ControlMap::MIXTURE;
|
||||||
|
if(eq(name, "ADVANCE")) return ControlMap::ADVANCE;
|
||||||
if(eq(name, "REHEAT")) return ControlMap::REHEAT;
|
if(eq(name, "REHEAT")) return ControlMap::REHEAT;
|
||||||
if(eq(name, "PROP")) return ControlMap::PROP;
|
if(eq(name, "PROP")) return ControlMap::PROP;
|
||||||
if(eq(name, "BRAKE")) return ControlMap::BRAKE;
|
if(eq(name, "BRAKE")) return ControlMap::BRAKE;
|
||||||
|
|
|
@ -49,7 +49,7 @@ void Gear::setDynamicFriction(float dfric)
|
||||||
|
|
||||||
void Gear::setBrake(float brake)
|
void Gear::setBrake(float brake)
|
||||||
{
|
{
|
||||||
_brake = brake;
|
_brake = Math::clamp(brake, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Gear::setRotation(float rotation)
|
void Gear::setRotation(float rotation)
|
||||||
|
@ -59,7 +59,7 @@ void Gear::setRotation(float rotation)
|
||||||
|
|
||||||
void Gear::setExtension(float extension)
|
void Gear::setExtension(float extension)
|
||||||
{
|
{
|
||||||
_extension = extension;
|
_extension = Math::clamp(extension, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Gear::getPosition(float* out)
|
void Gear::getPosition(float* out)
|
||||||
|
|
|
@ -7,15 +7,13 @@ Jet::Jet()
|
||||||
{
|
{
|
||||||
_rho0 = Atmosphere::getStdDensity(0);
|
_rho0 = Atmosphere::getStdDensity(0);
|
||||||
_thrust = 0;
|
_thrust = 0;
|
||||||
|
_abThrust = 0;
|
||||||
_reheat = 0;
|
_reheat = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Thruster* Jet::clone()
|
void Jet::stabilize()
|
||||||
{
|
{
|
||||||
Jet* j = new Jet();
|
return; // no-op for now
|
||||||
j->_thrust = _thrust;
|
|
||||||
j->_rho0 = _rho0;
|
|
||||||
return j;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Jet::setDryThrust(float thrust)
|
void Jet::setDryThrust(float thrust)
|
||||||
|
@ -23,14 +21,21 @@ void Jet::setDryThrust(float thrust)
|
||||||
_thrust = thrust;
|
_thrust = thrust;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Jet::setReheatThrust(float thrust)
|
||||||
|
{
|
||||||
|
_abThrust = thrust;
|
||||||
|
}
|
||||||
|
|
||||||
void Jet::setReheat(float reheat)
|
void Jet::setReheat(float reheat)
|
||||||
{
|
{
|
||||||
_reheat = reheat;
|
_reheat = Math::clamp(reheat, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Jet::getThrust(float* out)
|
void Jet::getThrust(float* out)
|
||||||
{
|
{
|
||||||
float t = _thrust * _throttle * (_rho / _rho0);
|
float t = _thrust * _throttle;
|
||||||
|
t += (_abThrust - _thrust) * _reheat;
|
||||||
|
t *= _rho / _rho0;
|
||||||
Math::mul3(t, _dir, out);
|
Math::mul3(t, _dir, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,9 +11,10 @@ class Jet : public Thruster {
|
||||||
public:
|
public:
|
||||||
Jet();
|
Jet();
|
||||||
|
|
||||||
virtual Thruster* clone();
|
virtual Jet* getJet() { return this; }
|
||||||
|
|
||||||
void setDryThrust(float thrust);
|
void setDryThrust(float thrust);
|
||||||
|
void setReheatThrust(float thrust);
|
||||||
void setReheat(float reheat);
|
void setReheat(float reheat);
|
||||||
|
|
||||||
virtual void getThrust(float* out);
|
virtual void getThrust(float* out);
|
||||||
|
@ -21,9 +22,11 @@ public:
|
||||||
virtual void getGyro(float* out);
|
virtual void getGyro(float* out);
|
||||||
virtual float getFuelFlow();
|
virtual float getFuelFlow();
|
||||||
virtual void integrate(float dt);
|
virtual void integrate(float dt);
|
||||||
|
virtual void stabilize();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float _thrust;
|
float _thrust;
|
||||||
|
float _abThrust;
|
||||||
float _rho0;
|
float _rho0;
|
||||||
float _reheat;
|
float _reheat;
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,6 +3,13 @@
|
||||||
#include "Math.hpp"
|
#include "Math.hpp"
|
||||||
namespace yasim {
|
namespace yasim {
|
||||||
|
|
||||||
|
float Math::clamp(float val, float min, float max)
|
||||||
|
{
|
||||||
|
if(val < min) return min;
|
||||||
|
if(val > max) return max;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
float Math::abs(float f)
|
float Math::abs(float f)
|
||||||
{
|
{
|
||||||
return ::fabs(f);
|
return ::fabs(f);
|
||||||
|
|
|
@ -6,6 +6,9 @@ namespace yasim {
|
||||||
class Math
|
class Math
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
// Dumb utilities
|
||||||
|
static float clamp(float val, float min, float max);
|
||||||
|
|
||||||
// Simple wrappers around library routines
|
// Simple wrappers around library routines
|
||||||
static float abs(float f);
|
static float abs(float f);
|
||||||
static float sqrt(float f);
|
static float sqrt(float f);
|
||||||
|
|
|
@ -77,7 +77,7 @@ void Model::initIteration()
|
||||||
localWind(pos, _s, v);
|
localWind(pos, _s, v);
|
||||||
|
|
||||||
t->setWind(v);
|
t->setWind(v);
|
||||||
t->setDensity(_rho);
|
t->setAir(_P, _T);
|
||||||
t->integrate(_integrator.getInterval());
|
t->integrate(_integrator.getInterval());
|
||||||
|
|
||||||
t->getTorque(v);
|
t->getTorque(v);
|
||||||
|
@ -126,6 +126,11 @@ int Model::addThruster(Thruster* t)
|
||||||
return _thrusters.add(t);
|
return _thrusters.add(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Model::numThrusters()
|
||||||
|
{
|
||||||
|
return _thrusters.size();
|
||||||
|
}
|
||||||
|
|
||||||
Thruster* Model::getThruster(int handle)
|
Thruster* Model::getThruster(int handle)
|
||||||
{
|
{
|
||||||
return (Thruster*)_thrusters.get(handle);
|
return (Thruster*)_thrusters.get(handle);
|
||||||
|
@ -146,6 +151,13 @@ int Model::addGear(Gear* gear)
|
||||||
return _gears.add(gear);
|
return _gears.add(gear);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Model::setGroundEffect(float* pos, float span, float mul)
|
||||||
|
{
|
||||||
|
Math::set3(pos, _wingCenter);
|
||||||
|
_groundEffectSpan = span;
|
||||||
|
_groundEffect = mul;
|
||||||
|
}
|
||||||
|
|
||||||
// The first three elements are a unit vector pointing from the global
|
// The first three elements are a unit vector pointing from the global
|
||||||
// origin to the plane, the final element is the distance from the
|
// origin to the plane, the final element is the distance from the
|
||||||
// origin (the radius of the earth, in most implementations). So
|
// origin (the radius of the earth, in most implementations). So
|
||||||
|
@ -156,13 +168,10 @@ void Model::setGroundPlane(double* planeNormal, double fromOrigin)
|
||||||
_ground[3] = fromOrigin;
|
_ground[3] = fromOrigin;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::setAirDensity(float rho)
|
|
||||||
{
|
|
||||||
_rho = rho;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Model::setAir(float pressure, float temp)
|
void Model::setAir(float pressure, float temp)
|
||||||
{
|
{
|
||||||
|
_P = pressure;
|
||||||
|
_T = temp;
|
||||||
_rho = Atmosphere::calcDensity(pressure, temp);
|
_rho = Atmosphere::calcDensity(pressure, temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,6 +206,8 @@ void Model::calcForces(State* s)
|
||||||
|
|
||||||
// Do each surface, remembering that the local velocity at each
|
// Do each surface, remembering that the local velocity at each
|
||||||
// point is different due to rotation.
|
// point is different due to rotation.
|
||||||
|
float faero[3];
|
||||||
|
faero[0] = faero[1] = faero[2] = 0;
|
||||||
for(int i=0; i<_surfaces.size(); i++) {
|
for(int i=0; i<_surfaces.size(); i++) {
|
||||||
Surface* sf = (Surface*)_surfaces.get(i);
|
Surface* sf = (Surface*)_surfaces.get(i);
|
||||||
|
|
||||||
|
@ -207,6 +218,7 @@ void Model::calcForces(State* s)
|
||||||
|
|
||||||
float force[3], torque[3];
|
float force[3], torque[3];
|
||||||
sf->calcForce(vs, _rho, force, torque);
|
sf->calcForce(vs, _rho, force, torque);
|
||||||
|
Math::add3(faero, force, faero);
|
||||||
_body.addForce(pos, force);
|
_body.addForce(pos, force);
|
||||||
_body.addTorque(torque);
|
_body.addTorque(torque);
|
||||||
}
|
}
|
||||||
|
@ -218,6 +230,17 @@ void Model::calcForces(State* s)
|
||||||
float ground[4];
|
float ground[4];
|
||||||
ground[3] = localGround(s, ground);
|
ground[3] = localGround(s, ground);
|
||||||
|
|
||||||
|
// Account for ground effect by multiplying the vertical force
|
||||||
|
// component by an amount linear with the fraction of the wingspan
|
||||||
|
// above the ground.
|
||||||
|
float dist = ground[4] - Math::dot3(ground, _wingCenter);
|
||||||
|
if(dist > 0 && dist < _groundEffectSpan) {
|
||||||
|
float fz = Math::dot3(faero, ground);
|
||||||
|
Math::mul3(fz * _groundEffect * dist/_groundEffectSpan,
|
||||||
|
ground, faero);
|
||||||
|
_body.addForce(faero);
|
||||||
|
}
|
||||||
|
|
||||||
// Convert the velocity and rotation vectors to local coordinates
|
// Convert the velocity and rotation vectors to local coordinates
|
||||||
float lrot[3], lv[3];
|
float lrot[3], lv[3];
|
||||||
Math::vmul33(s->orient, s->rot, lrot);
|
Math::vmul33(s->orient, s->rot, lrot);
|
||||||
|
|
|
@ -35,6 +35,7 @@ public:
|
||||||
Gear* getGear(int handle);
|
Gear* getGear(int handle);
|
||||||
|
|
||||||
// Semi-private methods for use by the Airplane solver.
|
// Semi-private methods for use by the Airplane solver.
|
||||||
|
int numThrusters();
|
||||||
Thruster* getThruster(int handle);
|
Thruster* getThruster(int handle);
|
||||||
void setThruster(int handle, Thruster* t);
|
void setThruster(int handle, Thruster* t);
|
||||||
void initIteration();
|
void initIteration();
|
||||||
|
@ -44,8 +45,8 @@ public:
|
||||||
// Per-iteration settables
|
// Per-iteration settables
|
||||||
//
|
//
|
||||||
void setGroundPlane(double* planeNormal, double fromOrigin);
|
void setGroundPlane(double* planeNormal, double fromOrigin);
|
||||||
|
void setGroundEffect(float* pos, float span, float mul);
|
||||||
void setWind(float* wind);
|
void setWind(float* wind);
|
||||||
void setAirDensity(float rho);
|
|
||||||
void setAir(float pressure, float temp);
|
void setAir(float pressure, float temp);
|
||||||
|
|
||||||
// BodyEnvironment callbacks
|
// BodyEnvironment callbacks
|
||||||
|
@ -65,7 +66,13 @@ private:
|
||||||
Vector _surfaces;
|
Vector _surfaces;
|
||||||
Vector _gears;
|
Vector _gears;
|
||||||
|
|
||||||
|
float _groundEffectSpan;
|
||||||
|
float _groundEffect;
|
||||||
|
float _wingCenter[3];
|
||||||
|
|
||||||
double _ground[4];
|
double _ground[4];
|
||||||
|
float _P;
|
||||||
|
float _T;
|
||||||
float _rho;
|
float _rho;
|
||||||
float _wind[3];
|
float _wind[3];
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#include "Atmosphere.hpp"
|
||||||
|
#include "Math.hpp"
|
||||||
#include "PistonEngine.hpp"
|
#include "PistonEngine.hpp"
|
||||||
namespace yasim {
|
namespace yasim {
|
||||||
|
|
||||||
|
@ -11,13 +13,34 @@ PistonEngine::PistonEngine(float power, float speed)
|
||||||
_omega0 = speed;
|
_omega0 = speed;
|
||||||
|
|
||||||
// We must be at sea level under standard conditions
|
// We must be at sea level under standard conditions
|
||||||
_rho0 = 1.225; // kg/m^3
|
_rho0 = Atmosphere::getStdDensity(0);
|
||||||
|
|
||||||
// Further presume that takeoff is (duh) full throttle and
|
// Further presume that takeoff is (duh) full throttle and
|
||||||
// peak-power, that means that by our efficiency function, we are
|
// peak-power, that means that by our efficiency function, we are
|
||||||
// at 11/8 of "ideal" fuel flow.
|
// at 11/8 of "ideal" fuel flow.
|
||||||
float realFlow = _f0 * (11.0/8.0);
|
float realFlow = _f0 * (11.0/8.0);
|
||||||
_mixCoeff = realFlow * 1.1 / _omega0;
|
_mixCoeff = realFlow * 1.1 / _omega0;
|
||||||
|
|
||||||
|
_turbo = 1;
|
||||||
|
_maxMP = 1e6; // No waste gate on non-turbo engines.
|
||||||
|
}
|
||||||
|
|
||||||
|
void PistonEngine::setTurboParams(float turbo, float maxMP)
|
||||||
|
{
|
||||||
|
_turbo = turbo;
|
||||||
|
_maxMP = maxMP;
|
||||||
|
|
||||||
|
// This changes the "sea level" manifold air density
|
||||||
|
float P0 = Atmosphere::getStdPressure(0);
|
||||||
|
float P = P0 * _turbo;
|
||||||
|
if(P > _maxMP) P = _maxMP;
|
||||||
|
float T = Atmosphere::getStdTemperature(0) * Math::pow(P/P0, 2./7.);
|
||||||
|
_rho0 = P / (287.1 * T);
|
||||||
|
}
|
||||||
|
|
||||||
|
float PistonEngine::getPower()
|
||||||
|
{
|
||||||
|
return _P0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PistonEngine::setThrottle(float t)
|
void PistonEngine::setThrottle(float t)
|
||||||
|
@ -30,13 +53,21 @@ void PistonEngine::setMixture(float m)
|
||||||
_mixture = m;
|
_mixture = m;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PistonEngine::calc(float density, float speed,
|
void PistonEngine::calc(float P, float T, float speed,
|
||||||
float* torqueOut, float* fuelFlowOut)
|
float* torqueOut, float* fuelFlowOut)
|
||||||
{
|
{
|
||||||
// The actual fuel flow
|
// The actual fuel flow
|
||||||
float fuel = _mixture * _mixCoeff * speed;
|
float fuel = _mixture * _mixCoeff * speed;
|
||||||
|
|
||||||
// manifold air density
|
// manifold air density
|
||||||
|
if(_turbo != 1) {
|
||||||
|
float P1 = P * _turbo;
|
||||||
|
if(P1 > _maxMP) P1 = _maxMP;
|
||||||
|
T *= Math::pow(P1/P, 2./7.);
|
||||||
|
P = P1;
|
||||||
|
}
|
||||||
|
float density = P / (287.1 * T);
|
||||||
|
|
||||||
float rho = density * _throttle;
|
float rho = density * _throttle;
|
||||||
|
|
||||||
// How much fuel could be burned with ideal (i.e. uncorrected!)
|
// How much fuel could be burned with ideal (i.e. uncorrected!)
|
||||||
|
|
|
@ -7,16 +7,19 @@ class PistonEngine {
|
||||||
public:
|
public:
|
||||||
// Initializes an engine from known "takeoff" parameters.
|
// Initializes an engine from known "takeoff" parameters.
|
||||||
PistonEngine(float power, float spd);
|
PistonEngine(float power, float spd);
|
||||||
|
void setTurboParams(float mul, float maxMP);
|
||||||
|
|
||||||
void setThrottle(float throttle);
|
void setThrottle(float throttle);
|
||||||
void setMixture(float mixture);
|
void setMixture(float mixture);
|
||||||
|
|
||||||
|
float getPower();
|
||||||
|
|
||||||
// Calculates power output and fuel flow, based on a given
|
// Calculates power output and fuel flow, based on a given
|
||||||
// throttle setting (0-1 corresponding to the fraction of
|
// throttle setting (0-1 corresponding to the fraction of
|
||||||
// "available" manifold pressure), mixture (fuel flux per rpm,
|
// "available" manifold pressure), mixture (fuel flux per rpm,
|
||||||
// 0-1, where 1 is "max rich", or a little bit more than needed
|
// 0-1, where 1 is "max rich", or a little bit more than needed
|
||||||
// for rated power at sea level)
|
// for rated power at sea level)
|
||||||
void calc(float density, float speed,
|
void calc(float pressure, float temp, float speed,
|
||||||
float* powerOut, float* fuelFlowOut);
|
float* powerOut, float* fuelFlowOut);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -29,6 +32,9 @@ private:
|
||||||
// Runtime settables:
|
// Runtime settables:
|
||||||
float _throttle;
|
float _throttle;
|
||||||
float _mixture;
|
float _mixture;
|
||||||
|
|
||||||
|
float _turbo;
|
||||||
|
float _maxMP;
|
||||||
};
|
};
|
||||||
|
|
||||||
}; // namespace yasim
|
}; // namespace yasim
|
||||||
|
|
|
@ -10,6 +10,8 @@ PropEngine::PropEngine(Propeller* prop, PistonEngine* eng, float moment)
|
||||||
_omega = 52.3;
|
_omega = 52.3;
|
||||||
_dir[0] = 1; _dir[1] = 0; _dir[2] = 0;
|
_dir[0] = 1; _dir[1] = 0; _dir[2] = 0;
|
||||||
|
|
||||||
|
_variable = false;
|
||||||
|
|
||||||
_prop = prop;
|
_prop = prop;
|
||||||
_eng = eng;
|
_eng = eng;
|
||||||
_moment = moment;
|
_moment = moment;
|
||||||
|
@ -21,21 +23,23 @@ PropEngine::~PropEngine()
|
||||||
delete _eng;
|
delete _eng;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PropEngine::setAdvance(float advance)
|
||||||
|
{
|
||||||
|
_advance = Math::clamp(advance, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PropEngine::setVariableProp(float min, float max)
|
||||||
|
{
|
||||||
|
_variable = true;
|
||||||
|
_minOmega = min;
|
||||||
|
_maxOmega = max;
|
||||||
|
}
|
||||||
|
|
||||||
float PropEngine::getOmega()
|
float PropEngine::getOmega()
|
||||||
{
|
{
|
||||||
return _omega;
|
return _omega;
|
||||||
}
|
}
|
||||||
|
|
||||||
Thruster* PropEngine::clone()
|
|
||||||
{
|
|
||||||
// FIXME: bloody mess
|
|
||||||
PropEngine* p = new PropEngine(_prop, _eng, _moment);
|
|
||||||
cloneInto(p);
|
|
||||||
p->_prop = new Propeller(*_prop);
|
|
||||||
p->_eng = new PistonEngine(*_eng);
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PropEngine::getThrust(float* out)
|
void PropEngine::getThrust(float* out)
|
||||||
{
|
{
|
||||||
for(int i=0; i<3; i++) out[i] = _thrust[i];
|
for(int i=0; i<3; i++) out[i] = _thrust[i];
|
||||||
|
@ -56,6 +60,44 @@ float PropEngine::getFuelFlow()
|
||||||
return _fuelFlow;
|
return _fuelFlow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PropEngine::stabilize()
|
||||||
|
{
|
||||||
|
float speed = -Math::dot3(_wind, _dir);
|
||||||
|
_eng->setThrottle(_throttle);
|
||||||
|
_eng->setMixture(_mixture);
|
||||||
|
|
||||||
|
if(_variable) {
|
||||||
|
_omega = _minOmega + _advance * (_maxOmega - _minOmega);
|
||||||
|
_prop->modPitch(1e6); // Start at maximum pitch and move down
|
||||||
|
} else {
|
||||||
|
_omega = 52;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool goingUp = false;
|
||||||
|
float step = 10;
|
||||||
|
while(true) {
|
||||||
|
float etau, ptau, dummy;
|
||||||
|
_prop->calc(_rho, speed, _omega, &dummy, &ptau);
|
||||||
|
_eng->calc(_P, _T, _omega, &etau, &dummy);
|
||||||
|
float tdiff = etau - ptau;
|
||||||
|
|
||||||
|
if(Math::abs(tdiff/_moment) < 0.1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if(tdiff > 0) {
|
||||||
|
if(!goingUp) step *= 0.5;
|
||||||
|
goingUp = true;
|
||||||
|
if(!_variable) _omega += step;
|
||||||
|
else _prop->modPitch(1+(step*0.005));
|
||||||
|
} else {
|
||||||
|
if(goingUp) step *= 0.5;
|
||||||
|
goingUp = false;
|
||||||
|
if(!_variable) _omega -= step;
|
||||||
|
else _prop->modPitch(1-(step*0.005));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void PropEngine::integrate(float dt)
|
void PropEngine::integrate(float dt)
|
||||||
{
|
{
|
||||||
float speed = -Math::dot3(_wind, _dir);
|
float speed = -Math::dot3(_wind, _dir);
|
||||||
|
@ -67,14 +109,19 @@ void PropEngine::integrate(float dt)
|
||||||
|
|
||||||
_prop->calc(_rho, speed, _omega,
|
_prop->calc(_rho, speed, _omega,
|
||||||
&thrust, &propTorque);
|
&thrust, &propTorque);
|
||||||
_eng->calc(_rho, _omega, &engTorque, &_fuelFlow);
|
_eng->calc(_P, _T, _omega, &engTorque, &_fuelFlow);
|
||||||
|
|
||||||
// Turn the thrust into a vector and save it
|
// Turn the thrust into a vector and save it
|
||||||
Math::mul3(thrust, _dir, _thrust);
|
Math::mul3(thrust, _dir, _thrust);
|
||||||
|
|
||||||
// Euler-integrate the RPM. This doesn't need the full-on
|
// Euler-integrate the RPM. This doesn't need the full-on
|
||||||
// Runge-Kutta stuff.
|
// Runge-Kutta stuff.
|
||||||
_omega += dt*(engTorque-propTorque)/Math::abs(_moment);
|
float rotacc = (engTorque-propTorque)/Math::abs(_moment);
|
||||||
|
_omega += dt * rotacc;
|
||||||
|
|
||||||
|
// Clamp to a 500 rpm idle. This should probably be settable, and
|
||||||
|
// needs to go away when the startup code gets written.
|
||||||
|
if(_omega < 52.3) _omega = 52.3;
|
||||||
|
|
||||||
// FIXME: Integrate the propeller governor here, when that gets
|
// FIXME: Integrate the propeller governor here, when that gets
|
||||||
// implemented...
|
// implemented...
|
||||||
|
@ -82,13 +129,25 @@ void PropEngine::integrate(float dt)
|
||||||
// Store the total angular momentum into _gyro
|
// Store the total angular momentum into _gyro
|
||||||
Math::mul3(_omega*_moment, _dir, _gyro);
|
Math::mul3(_omega*_moment, _dir, _gyro);
|
||||||
|
|
||||||
// Accumulate the engine torque, it acta on the body as a whole.
|
// Accumulate the engine torque, it acts on the body as a whole.
|
||||||
// (Note: engine torque, not propeller torque. They can be
|
// (Note: engine torque, not propeller torque. They can be
|
||||||
// different, but the difference goes to accelerating the
|
// different, but the difference goes to accelerating the
|
||||||
// rotation. It is the engine torque that is felt at the shaft
|
// rotation. It is the engine torque that is felt at the shaft
|
||||||
// and works on the body.)
|
// and works on the body.)
|
||||||
float tau = _moment < 0 ? engTorque : -engTorque;
|
float tau = _moment < 0 ? engTorque : -engTorque;
|
||||||
Math::mul3(tau, _dir, _torque);
|
Math::mul3(tau, _dir, _torque);
|
||||||
|
|
||||||
|
// Play with the variable propeller, but only if the propeller is
|
||||||
|
// vaguely stable alread (accelerating less than 100 rpm/s)
|
||||||
|
if(_variable && Math::abs(rotacc) < 20) {
|
||||||
|
float target = _minOmega + _advance*(_maxOmega-_minOmega);
|
||||||
|
float mod = 1.04;
|
||||||
|
if(target > _omega) mod = 1/mod;
|
||||||
|
float diff = Math::abs(target - _omega);
|
||||||
|
if(diff < 1) mod = 1 + (mod-1)*diff;
|
||||||
|
if(thrust < 0) mod = 1;
|
||||||
|
_prop->modPitch(mod);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}; // namespace yasim
|
}; // namespace yasim
|
||||||
|
|
|
@ -13,7 +13,12 @@ public:
|
||||||
PropEngine(Propeller* prop, PistonEngine* eng, float moment);
|
PropEngine(Propeller* prop, PistonEngine* eng, float moment);
|
||||||
virtual ~PropEngine();
|
virtual ~PropEngine();
|
||||||
|
|
||||||
virtual Thruster* clone();
|
void setAdvance(float advance);
|
||||||
|
void setVariableProp(float min, float max);
|
||||||
|
|
||||||
|
virtual PropEngine* getPropEngine() { return this; }
|
||||||
|
virtual PistonEngine* getPistonEngine() { return _eng; }
|
||||||
|
virtual Propeller* getPropeller() { return _prop; }
|
||||||
|
|
||||||
// Dynamic output
|
// Dynamic output
|
||||||
virtual void getThrust(float* out);
|
virtual void getThrust(float* out);
|
||||||
|
@ -23,6 +28,7 @@ public:
|
||||||
|
|
||||||
// Runtime instructions
|
// Runtime instructions
|
||||||
virtual void integrate(float dt);
|
virtual void integrate(float dt);
|
||||||
|
virtual void stabilize();
|
||||||
|
|
||||||
float getOmega();
|
float getOmega();
|
||||||
|
|
||||||
|
@ -31,6 +37,11 @@ private:
|
||||||
Propeller* _prop;
|
Propeller* _prop;
|
||||||
PistonEngine* _eng;
|
PistonEngine* _eng;
|
||||||
|
|
||||||
|
bool _variable;
|
||||||
|
float _advance; // control input, 0-1
|
||||||
|
float _maxOmega;
|
||||||
|
float _minOmega;
|
||||||
|
|
||||||
float _omega; // RPM, in radians/sec
|
float _omega; // RPM, in radians/sec
|
||||||
float _thrust[3];
|
float _thrust[3];
|
||||||
float _torque[3];
|
float _torque[3];
|
||||||
|
|
|
@ -1,36 +1,48 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "Atmosphere.hpp"
|
#include "Atmosphere.hpp"
|
||||||
#include "Math.hpp"
|
#include "Math.hpp"
|
||||||
#include "Propeller.hpp"
|
#include "Propeller.hpp"
|
||||||
namespace yasim {
|
namespace yasim {
|
||||||
|
|
||||||
Propeller::Propeller(float radius, float v, float omega,
|
Propeller::Propeller(float radius, float v, float omega,
|
||||||
float rho, float power, float omega0,
|
float rho, float power)
|
||||||
float power0)
|
|
||||||
{
|
{
|
||||||
// Initialize numeric constants:
|
// Initialize numeric constants:
|
||||||
_lambdaPeak = Math::pow(9.0, -1.0/8.0);
|
_lambdaPeak = Math::pow(5.0, -1.0/4.0);
|
||||||
_beta = 1.0/(Math::pow(9.0, -1.0/8.0) - Math::pow(9.0, -9.0/8.0));
|
_beta = 1.0/(Math::pow(5.0, -1.0/4.0) - Math::pow(5.0, -5.0/4.0));
|
||||||
|
|
||||||
_r = radius;
|
_r = radius;
|
||||||
_etaC = 0.85; // make this settable?
|
_etaC = 0.85; // make this settable?
|
||||||
|
|
||||||
_J0 = v/(omega*_lambdaPeak);
|
_J0 = v/(omega*_lambdaPeak);
|
||||||
|
_baseJ0 = _J0;
|
||||||
|
|
||||||
float V2 = v*v + (_r*omega)*(_r*omega);
|
float V2 = v*v + (_r*omega)*(_r*omega);
|
||||||
_F0 = 2*_etaC*power/(rho*v*V2);
|
_F0 = 2*_etaC*power/(rho*v*V2);
|
||||||
|
|
||||||
float stallAngle = 0.25;
|
_matchTakeoff = false;
|
||||||
_lambdaS = _r*(_J0/_r - stallAngle) / _J0;
|
|
||||||
|
|
||||||
// Now compute a correction for zero forward speed to make the
|
|
||||||
// takeoff performance correct.
|
|
||||||
float torque0 = power0/omega0;
|
|
||||||
float thrust, torque;
|
|
||||||
_takeoffCoef = 1;
|
|
||||||
calc(Atmosphere::getStdDensity(0), 0, omega0, &thrust, &torque);
|
|
||||||
_takeoffCoef = torque/torque0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Propeller::setTakeoff(float omega0, float power0)
|
||||||
|
{
|
||||||
|
// Takeoff thrust coefficient at lambda==0
|
||||||
|
_matchTakeoff = true;
|
||||||
|
float V2 = _r*omega0 * _r*omega0;
|
||||||
|
float gamma = _etaC * _beta / _J0;
|
||||||
|
float torque = power0 / omega0;
|
||||||
|
float density = Atmosphere::getStdDensity(0);
|
||||||
|
_tc0 = (torque * gamma) / (0.5 * density * V2 * _F0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Propeller::modPitch(float mod)
|
||||||
|
{
|
||||||
|
_J0 *= mod;
|
||||||
|
if(_J0 < 0.25*_baseJ0) _J0 = 0.25*_baseJ0;
|
||||||
|
if(_J0 > 4*_baseJ0) _J0 = 4*_baseJ0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Propeller::calc(float density, float v, float omega,
|
void Propeller::calc(float density, float v, float omega,
|
||||||
float* thrustOut, float* torqueOut)
|
float* thrustOut, float* torqueOut)
|
||||||
{
|
{
|
||||||
|
@ -47,7 +59,7 @@ void Propeller::calc(float density, float v, float omega,
|
||||||
float torque = 0;
|
float torque = 0;
|
||||||
if(lambda > 1) {
|
if(lambda > 1) {
|
||||||
lambda = 1.0/lambda;
|
lambda = 1.0/lambda;
|
||||||
torque = (density*V2*_F0*_J0)/(8*_etaC*_beta*(1-_lambdaPeak));
|
torque = (density*V2*_F0*_J0)/(4*_etaC*_beta*(1-_lambdaPeak));
|
||||||
}
|
}
|
||||||
|
|
||||||
// There's an undefined point at 1. Just offset by a tiny bit to
|
// There's an undefined point at 1. Just offset by a tiny bit to
|
||||||
|
@ -56,24 +68,18 @@ void Propeller::calc(float density, float v, float omega,
|
||||||
// point number!)
|
// point number!)
|
||||||
if(lambda == 1) lambda = 0.9999;
|
if(lambda == 1) lambda = 0.9999;
|
||||||
|
|
||||||
// Compute thrust, remembering to clamp lambda to the stall point
|
// Calculate lambda^4
|
||||||
float lambda2 = lambda < _lambdaS ? _lambdaS : lambda;
|
float l4 = lambda*lambda; l4 = l4*l4;
|
||||||
float thrust = (0.5*density*V2*_F0/(1-_lambdaPeak))*(1-lambda2);
|
|
||||||
|
|
||||||
// Calculate lambda^8
|
|
||||||
float l8 = lambda*lambda; l8 = l8*l8; l8 = l8*l8;
|
|
||||||
|
|
||||||
// thrust/torque ratio
|
// thrust/torque ratio
|
||||||
float gamma = (_etaC*_beta/_J0)*(1-l8);
|
float gamma = (_etaC*_beta/_J0)*(1-l4);
|
||||||
|
|
||||||
// Correct slow speeds to get the takeoff parameters correct
|
// Compute a thrust, clamp to takeoff thrust to prevend huge
|
||||||
if(lambda < _lambdaPeak) {
|
// numbers at slow speeds.
|
||||||
// This will interpolate takeoffCoef along a descending from 1
|
float tc = (1 - lambda) / (1 - _lambdaPeak);
|
||||||
// at lambda==0 to 0 at the peak, fairing smoothly into the
|
if(_matchTakeoff && tc > _tc0) tc = _tc0;
|
||||||
// flat peak.
|
|
||||||
float frac = (lambda - _lambdaPeak)/_lambdaPeak;
|
float thrust = 0.5 * density * V2 * _F0 * tc;
|
||||||
gamma *= 1 + (_takeoffCoef - 1)*frac*frac;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(torque > 0) {
|
if(torque > 0) {
|
||||||
torque -= thrust/gamma;
|
torque -= thrust/gamma;
|
||||||
|
|
|
@ -14,8 +14,11 @@ public:
|
||||||
// numbers for RPM and power (with air speed and density being
|
// numbers for RPM and power (with air speed and density being
|
||||||
// zero and sea level). RPM values are in radians per second, of
|
// zero and sea level). RPM values are in radians per second, of
|
||||||
// course.
|
// course.
|
||||||
Propeller(float radius, float v, float omega, float rho, float power,
|
Propeller(float radius, float v, float omega, float rho, float power);
|
||||||
float omega0, float power0);
|
|
||||||
|
void setTakeoff(float omega0, float power0);
|
||||||
|
|
||||||
|
void modPitch(float mod);
|
||||||
|
|
||||||
void calc(float density, float v, float omega,
|
void calc(float density, float v, float omega,
|
||||||
float* thrustOut, float* torqueOut);
|
float* thrustOut, float* torqueOut);
|
||||||
|
@ -23,12 +26,13 @@ public:
|
||||||
private:
|
private:
|
||||||
float _r; // characteristic radius
|
float _r; // characteristic radius
|
||||||
float _J0; // zero-thrust advance ratio
|
float _J0; // zero-thrust advance ratio
|
||||||
float _lambdaS; // "propeller stall" normalized advance ratio
|
float _baseJ0; // ... uncorrected for prop advance
|
||||||
float _F0; // thrust coefficient
|
float _F0; // thrust coefficient
|
||||||
float _etaC; // Peak efficiency
|
float _etaC; // Peak efficiency
|
||||||
float _lambdaPeak; // constant, ~0.759835;
|
float _lambdaPeak; // constant, ~0.759835;
|
||||||
float _beta; // constant, ~1.48058;
|
float _beta; // constant, ~1.48058;
|
||||||
float _takeoffCoef; // correction to get the zero-speed torque right
|
float _tc0; // thrust "coefficient" at takeoff
|
||||||
|
bool _matchTakeoff; // Does _tc0 mean anything?
|
||||||
};
|
};
|
||||||
|
|
||||||
}; // namespace yasim
|
}; // namespace yasim
|
||||||
|
|
|
@ -236,8 +236,16 @@ float Surface::controlDrag()
|
||||||
d *= 1 + _spoilerPos * (_spoilerDrag - 1);
|
d *= 1 + _spoilerPos * (_spoilerDrag - 1);
|
||||||
d *= 1 + _slatPos * (_slatDrag - 1);
|
d *= 1 + _slatPos * (_slatDrag - 1);
|
||||||
|
|
||||||
// FIXME: flaps should REDUCE drag when the reduce lift!
|
// Negative flap deflections don't affect drag until their lift
|
||||||
d *= 1 + Math::abs(_flapPos) * (_flapDrag - 1);
|
// multiplier exceeds the "camber" (cz0) of the surface.
|
||||||
|
float fp = _flapPos;
|
||||||
|
if(fp < 0) {
|
||||||
|
fp = -fp;
|
||||||
|
fp -= _cz0/(_flapLift-1);
|
||||||
|
if(fp < 0) fp = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
d *= 1 + fp * (_flapDrag - 1);
|
||||||
|
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,7 @@ Thruster::Thruster()
|
||||||
for(int i=0; i<3; i++) _pos[i] = _wind[i] = 0;
|
for(int i=0; i<3; i++) _pos[i] = _wind[i] = 0;
|
||||||
_throttle = 0;
|
_throttle = 0;
|
||||||
_mixture = 0;
|
_mixture = 0;
|
||||||
_propAdvance = 0;
|
_P = _T = _rho = 0;
|
||||||
_rho = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Thruster::~Thruster()
|
Thruster::~Thruster()
|
||||||
|
@ -38,17 +37,12 @@ void Thruster::setDirection(float* dir)
|
||||||
|
|
||||||
void Thruster::setThrottle(float throttle)
|
void Thruster::setThrottle(float throttle)
|
||||||
{
|
{
|
||||||
_throttle = throttle;
|
_throttle = Math::clamp(throttle, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thruster::setMixture(float mixture)
|
void Thruster::setMixture(float mixture)
|
||||||
{
|
{
|
||||||
_mixture = mixture;
|
_mixture = Math::clamp(mixture, 0, 1);
|
||||||
}
|
|
||||||
|
|
||||||
void Thruster::setPropAdvance(float propAdvance)
|
|
||||||
{
|
|
||||||
_propAdvance = propAdvance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thruster::setWind(float* wind)
|
void Thruster::setWind(float* wind)
|
||||||
|
@ -56,20 +50,11 @@ void Thruster::setWind(float* wind)
|
||||||
for(int i=0; i<3; i++) _wind[i] = wind[i];
|
for(int i=0; i<3; i++) _wind[i] = wind[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thruster::setDensity(float rho)
|
void Thruster::setAir(float pressure, float temp)
|
||||||
{
|
{
|
||||||
_rho = rho;
|
_P = pressure;
|
||||||
}
|
_T = temp;
|
||||||
|
_rho = _P / (287.1 * _T);
|
||||||
void Thruster::cloneInto(Thruster* out)
|
|
||||||
{
|
|
||||||
for(int i=0; i<3; i++) {
|
|
||||||
out->_pos[i] = _pos[i];
|
|
||||||
out->_dir[i] = _dir[i];
|
|
||||||
}
|
|
||||||
out->_throttle = _throttle;
|
|
||||||
out->_mixture = _mixture;
|
|
||||||
out->_propAdvance = _propAdvance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}; // namespace yasim
|
}; // namespace yasim
|
||||||
|
|
|
@ -3,23 +3,33 @@
|
||||||
|
|
||||||
namespace yasim {
|
namespace yasim {
|
||||||
|
|
||||||
|
class Jet;
|
||||||
|
class PropEngine;
|
||||||
|
class Propeller;
|
||||||
|
class PistonEngine;
|
||||||
|
|
||||||
class Thruster {
|
class Thruster {
|
||||||
public:
|
public:
|
||||||
Thruster();
|
Thruster();
|
||||||
virtual ~Thruster();
|
virtual ~Thruster();
|
||||||
|
|
||||||
|
// Typing info, these are the possible sub-type (or sub-parts)
|
||||||
|
// that a thruster might have. Any might return null. A little
|
||||||
|
// clumsy, but much simpler than an RTTI-based implementation.
|
||||||
|
virtual Jet* getJet() { return 0; }
|
||||||
|
virtual PropEngine* getPropEngine() { return 0; }
|
||||||
|
virtual Propeller* getPropeller() { return 0; }
|
||||||
|
virtual PistonEngine* getPistonEngine() { return 0; }
|
||||||
|
|
||||||
// Static data
|
// Static data
|
||||||
void getPosition(float* out);
|
void getPosition(float* out);
|
||||||
void setPosition(float* pos);
|
void setPosition(float* pos);
|
||||||
void getDirection(float* out);
|
void getDirection(float* out);
|
||||||
void setDirection(float* dir);
|
void setDirection(float* dir);
|
||||||
|
|
||||||
virtual Thruster* clone()=0;
|
|
||||||
|
|
||||||
// Controls
|
// Controls
|
||||||
void setThrottle(float throttle);
|
void setThrottle(float throttle);
|
||||||
void setMixture(float mixture);
|
void setMixture(float mixture);
|
||||||
void setPropAdvance(float advance);
|
|
||||||
|
|
||||||
// Dynamic output
|
// Dynamic output
|
||||||
virtual void getThrust(float* out)=0;
|
virtual void getThrust(float* out)=0;
|
||||||
|
@ -29,19 +39,19 @@ public:
|
||||||
|
|
||||||
// Runtime instructions
|
// Runtime instructions
|
||||||
void setWind(float* wind);
|
void setWind(float* wind);
|
||||||
void setDensity(float rho);
|
void setAir(float pressure, float temp);
|
||||||
virtual void integrate(float dt)=0;
|
virtual void integrate(float dt)=0;
|
||||||
|
virtual void stabilize()=0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void cloneInto(Thruster* out);
|
|
||||||
|
|
||||||
float _pos[3];
|
float _pos[3];
|
||||||
float _dir[3];
|
float _dir[3];
|
||||||
float _throttle;
|
float _throttle;
|
||||||
float _mixture;
|
float _mixture;
|
||||||
float _propAdvance;
|
|
||||||
|
|
||||||
float _wind[3];
|
float _wind[3];
|
||||||
|
float _P;
|
||||||
|
float _T;
|
||||||
float _rho;
|
float _rho;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -157,6 +157,8 @@ void Wing::setSpoiler(float start, float end, float lift, float drag)
|
||||||
|
|
||||||
void Wing::setFlap0(float lval, float rval)
|
void Wing::setFlap0(float lval, float rval)
|
||||||
{
|
{
|
||||||
|
lval = Math::clamp(lval, -1, 1);
|
||||||
|
rval = Math::clamp(rval, -1, 1);
|
||||||
for(int i=0; i<_flap0Surfs.size(); i++) {
|
for(int i=0; i<_flap0Surfs.size(); i++) {
|
||||||
((Surface*)_flap0Surfs.get(i))->setFlap(lval);
|
((Surface*)_flap0Surfs.get(i))->setFlap(lval);
|
||||||
if(_mirror) ((Surface*)_flap0Surfs.get(++i))->setFlap(rval);
|
if(_mirror) ((Surface*)_flap0Surfs.get(++i))->setFlap(rval);
|
||||||
|
@ -165,6 +167,8 @@ void Wing::setFlap0(float lval, float rval)
|
||||||
|
|
||||||
void Wing::setFlap1(float lval, float rval)
|
void Wing::setFlap1(float lval, float rval)
|
||||||
{
|
{
|
||||||
|
lval = Math::clamp(lval, -1, 1);
|
||||||
|
rval = Math::clamp(rval, -1, 1);
|
||||||
for(int i=0; i<_flap1Surfs.size(); i++) {
|
for(int i=0; i<_flap1Surfs.size(); i++) {
|
||||||
((Surface*)_flap1Surfs.get(i))->setFlap(lval);
|
((Surface*)_flap1Surfs.get(i))->setFlap(lval);
|
||||||
if(_mirror) ((Surface*)_flap1Surfs.get(++i))->setFlap(rval);
|
if(_mirror) ((Surface*)_flap1Surfs.get(++i))->setFlap(rval);
|
||||||
|
@ -173,6 +177,8 @@ void Wing::setFlap1(float lval, float rval)
|
||||||
|
|
||||||
void Wing::setSpoiler(float lval, float rval)
|
void Wing::setSpoiler(float lval, float rval)
|
||||||
{
|
{
|
||||||
|
lval = Math::clamp(lval, 0, 1);
|
||||||
|
rval = Math::clamp(rval, 0, 1);
|
||||||
for(int i=0; i<_spoilerSurfs.size(); i++) {
|
for(int i=0; i<_spoilerSurfs.size(); i++) {
|
||||||
((Surface*)_spoilerSurfs.get(i))->setSpoiler(lval);
|
((Surface*)_spoilerSurfs.get(i))->setSpoiler(lval);
|
||||||
if(_mirror) ((Surface*)_spoilerSurfs.get(++i))->setSpoiler(rval);
|
if(_mirror) ((Surface*)_spoilerSurfs.get(++i))->setSpoiler(rval);
|
||||||
|
@ -181,10 +187,19 @@ void Wing::setSpoiler(float lval, float rval)
|
||||||
|
|
||||||
void Wing::setSlat(float val)
|
void Wing::setSlat(float val)
|
||||||
{
|
{
|
||||||
|
val = Math::clamp(val, 0, 1);
|
||||||
for(int i=0; i<_slatSurfs.size(); i++)
|
for(int i=0; i<_slatSurfs.size(); i++)
|
||||||
((Surface*)_slatSurfs.get(i))->setSlat(val);
|
((Surface*)_slatSurfs.get(i))->setSlat(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float Wing::getGroundEffect(float* posOut)
|
||||||
|
{
|
||||||
|
for(int i=0; i<3; i++) posOut[i] = _base[i];
|
||||||
|
float span = _length * Math::cos(_sweep) * Math::cos(_dihedral);
|
||||||
|
span = 2*(span + Math::abs(_base[2]));
|
||||||
|
return span;
|
||||||
|
}
|
||||||
|
|
||||||
void Wing::compile()
|
void Wing::compile()
|
||||||
{
|
{
|
||||||
// Have we already been compiled?
|
// Have we already been compiled?
|
||||||
|
|
|
@ -44,6 +44,9 @@ public:
|
||||||
// Compile the thing into a bunch of Surface objects
|
// Compile the thing into a bunch of Surface objects
|
||||||
void compile();
|
void compile();
|
||||||
|
|
||||||
|
// Ground effect information
|
||||||
|
float getGroundEffect(float* posOut);
|
||||||
|
|
||||||
// Query the list of Surface objects
|
// Query the list of Surface objects
|
||||||
int numSurfaces();
|
int numSurfaces();
|
||||||
Surface* getSurface(int n);
|
Surface* getSurface(int n);
|
||||||
|
|
Loading…
Reference in a new issue