1
0
Fork 0

YASim CLI tool refactoring

This commit is contained in:
Henning Stahlke 2018-02-06 00:10:03 +01:00
parent da961b97f2
commit 1b21f85c52
8 changed files with 312 additions and 304 deletions

View file

@ -13,18 +13,17 @@
#include "Thruster.hpp"
#include "Hitch.hpp"
#include "Airplane.hpp"
#include "yasim-common.hpp"
namespace yasim {
//default prop names
static const char* DEF_PROP_ELEVATOR_TRIM = "/controls/flight/elevator-trim";
// gadgets
inline float abs(float f) { return f<0 ? -f : f; }
Airplane::Airplane()
{
_approachConfig.isApproach = true;
}
Airplane::~Airplane()
@ -50,12 +49,12 @@ Airplane::~Airplane()
}
for(i=0; i<_solveWeights.size(); i++)
delete (SolveWeight*)_solveWeights.get(i);
for(i=0; i<_cruiseConfig.controls.size(); i++) {
ControlSetting* c = (ControlSetting*)_cruiseConfig.controls.get(i);
for(i=0; i<_config[CRUISE].controls.size(); i++) {
ControlSetting* c = (ControlSetting*)_config[CRUISE].controls.get(i);
delete c;
}
for(i=0; i<_approachConfig.controls.size(); i++) {
ControlSetting* c = (ControlSetting*)_approachConfig.controls.get(i);
for(i=0; i<_config[APPROACH].controls.size(); i++) {
ControlSetting* c = (ControlSetting*)_config[APPROACH].controls.get(i);
delete c;
}
delete _wing;
@ -130,23 +129,18 @@ void Airplane::updateGearState()
}
}
void Airplane::setApproach(float speed, float altitude, float aoa, float fuel, float gla)
/// setup a config record
void Airplane::setConfig(Configuration cfg, float speed, float altitude, float fuel, float gla, float aoa)
{
_approachConfig.speed = speed;
_approachConfig.altitude = altitude;
// solver assumes fixed (given) AoA for approach, so setup once
_approachConfig.state.setupOrientationFromAoa(aoa);
_approachConfig.aoa = aoa; // not strictly needed, see runConfig()
_approachConfig.fuel = fuel;
_approachConfig.glideAngle = gla;
}
void Airplane::setCruise(float speed, float altitude, float fuel, float gla)
{
_cruiseConfig.speed = speed;
_cruiseConfig.altitude = altitude;
_cruiseConfig.fuel = fuel;
_cruiseConfig.glideAngle = gla;
_config[cfg].id = cfg;
_config[cfg].speed = speed;
_config[cfg].altitude = altitude;
// solver assumes fixed (given) AoA for approach, so setup once;
// solver will change this for cruise config
_config[cfg].state.setupOrientationFromAoa(aoa);
_config[cfg].aoa = aoa; // not strictly needed, see runConfig()
_config[cfg].fuel = fuel;
_config[cfg].glideAngle = gla;
}
/// set property name for elevator
@ -174,14 +168,7 @@ Airplane::ControlSetting* Airplane::_addControlSetting(Configuration cfg, const
ControlSetting* c = new ControlSetting();
c->propHandle = _controlMap.getInputPropertyHandle(prop);
c->val = val;
switch (cfg) {
case APPROACH:
_approachConfig.controls.add(c);
break;
case CRUISE:
_cruiseConfig.controls.add(c);
break;
}
_config[cfg].controls.add(c);
return c;
}
@ -202,7 +189,7 @@ void Airplane::addControlInput(const char* propName, ControlMap::ControlType typ
void Airplane::addSolutionWeight(Configuration cfg, int idx, float wgt)
{
SolveWeight* w = new SolveWeight();
w->approach = (cfg == APPROACH);
w->cfg = cfg;
w->id = idx;
w->wgt = wgt;
_solveWeights.add(w);
@ -594,8 +581,8 @@ void Airplane::compile(bool verbose)
t->handle = body->addMass(0, t->pos);
totalFuel += t->cap;
}
_cruiseConfig.weight = _emptyWeight + totalFuel*_cruiseConfig.fuel;
_approachConfig.weight = _emptyWeight + totalFuel*_approachConfig.fuel;
_config[CRUISE].weight = _emptyWeight + totalFuel*_config[CRUISE].fuel;
_config[APPROACH].weight = _emptyWeight + totalFuel*_config[APPROACH].fuel;
body->recalc();
@ -680,12 +667,12 @@ void Airplane::solveGear()
// The force at max compression should be sufficient to stop a
// plane moving downwards at 2x the approach descent rate. Assume
// a 3 degree approach.
float descentRate = 2.0f*_approachConfig.speed/19.1f;
float descentRate = 2.0f*_config[APPROACH].speed/19.1f;
// Spread the kinetic energy according to the gear weights. This
// will results in an equal compression fraction (not distance) of
// each gear.
float energy = 0.5f*_approachConfig.weight*descentRate*descentRate;
float energy = 0.5f*_config[APPROACH].weight*descentRate*descentRate;
for(i=0; i<_gears.size(); i++) {
GearRec* gr = (GearRec*)_gears.get(i);
@ -700,7 +687,7 @@ void Airplane::solveGear()
gr->gear->setSpring(k * gr->gear->getSpring());
// Critically damped (too damped, too!)
gr->gear->setDamping(2*Math::sqrt(k*_approachConfig.weight*gr->wgt)
gr->gear->setDamping(2*Math::sqrt(k*_config[APPROACH].weight*gr->wgt)
* gr->gear->getDamping());
}
}
@ -733,14 +720,14 @@ void Airplane::stabilizeThrust()
}
/// Setup weights for cruise or approach during solve.
void Airplane::setupWeights(bool isApproach)
void Airplane::setupWeights(Configuration cfg)
{
int i;
for(i=0; i<_weights.size(); i++)
setWeight(i, 0);
for(i=0; i<_solveWeights.size(); i++) {
SolveWeight* w = (SolveWeight*)_solveWeights.get(i);
if(w->approach == isApproach)
if(w->cfg == cfg)
setWeight(w->id, w->wgt);
}
}
@ -760,8 +747,8 @@ void Airplane::setControlValues(const Vector& controls)
void Airplane::runConfig(Config &cfg)
{
// aoa is consider to be given for approach so we calculate orientation
// for approach only once in setApproach() but everytime for cruise here.
if (!cfg.isApproach) {
// for approach only once in setConfig() but everytime for cruise here.
if (!(cfg.id == APPROACH)) {
cfg.state.setupOrientationFromAoa(cfg.aoa);
}
cfg.state.setupSpeedAndPosition(cfg.speed, cfg.glideAngle);
@ -775,7 +762,7 @@ void Airplane::runConfig(Config &cfg)
cfg.state.globalToLocal(wind, wind);
setFuelFraction(cfg.fuel);
setupWeights(cfg.isApproach);
setupWeights(cfg.id);
// Set up the thruster parameters and iterate until the thrust
// stabilizes.
@ -875,7 +862,7 @@ float Airplane::_getPitch(Config &cfg)
}
///helper for solveAirplane()
float Airplane::_getLift(Config &cfg)
float Airplane::_getLiftForce(Config &cfg)
{
float tmp[3];
_model.getBody()->getAccel(tmp);
@ -883,6 +870,15 @@ float Airplane::_getLift(Config &cfg)
return cfg.weight * tmp[2];
}
///helper for solveAirplane()
float Airplane::_getDragForce(Config &cfg)
{
float tmp[3];
_model.getBody()->getAccel(tmp);
cfg.state.localToGlobal(tmp, tmp);
return cfg.weight * tmp[0];
}
void Airplane::solveAirplane(bool verbose)
{
static const float ARCMIN = 0.0002909f;
@ -911,28 +907,26 @@ void Airplane::solveAirplane(bool verbose)
return;
}
// Run an iteration at cruise, and extract the needed numbers:
runConfig(_cruiseConfig);
runConfig(_config[CRUISE]);
_model.getThrust(tmp);
float thrust = tmp[0] + _cruiseConfig.weight * Math::sin(_cruiseConfig.glideAngle) * 9.81;
float thrust = tmp[0] + _config[CRUISE].weight * Math::sin(_config[CRUISE].glideAngle) * 9.81;
_model.getBody()->getAccel(tmp);
_cruiseConfig.state.localToGlobal(tmp, tmp);
float xforce = _cruiseConfig.weight * tmp[0];
float clift0 = _getLift(_cruiseConfig);
float cpitch0 = _getPitch(_cruiseConfig);
float cDragForce = _getDragForce(_config[CRUISE]);
float clift0 = _getLiftForce(_config[CRUISE]);
float cpitch0 = _getPitch(_config[CRUISE]);
// Run an approach iteration, and do likewise
runConfig(_approachConfig);
double apitch0 = _getPitch(_approachConfig);
float alift = _getLift(_approachConfig);
runConfig(_config[APPROACH]);
double apitch0 = _getPitch(_config[APPROACH]);
float alift = _getLiftForce(_config[APPROACH]);
// Modify the cruise AoA a bit to get a derivative
_cruiseConfig.aoa += ARCMIN;
runConfig(_cruiseConfig);
_cruiseConfig.aoa -= ARCMIN;
_config[CRUISE].aoa += ARCMIN;
runConfig(_config[CRUISE]);
_config[CRUISE].aoa -= ARCMIN;
float clift1 = _getLift(_cruiseConfig);
float clift1 = _getLiftForce(_config[CRUISE]);
// Do the same with the tail incidence
float savedIncidence = _tailIncidence->val;
@ -942,16 +936,16 @@ void Airplane::solveAirplane(bool verbose)
_failureMsg = "Tail incidence out of bounds.";
return;
};
runConfig(_cruiseConfig);
runConfig(_config[CRUISE]);
_tailIncidenceCopy->val = _tailIncidence->val = savedIncidence;
_tail->setIncidence(_tailIncidence->val);
float cpitch1 = _getPitch(_cruiseConfig);
float cpitch1 = _getPitch(_config[CRUISE]);
// Now calculate:
float awgt = 9.8f * _approachConfig.weight;
float awgt = 9.8f * _config[APPROACH].weight;
float dragFactor = thrust / (thrust-xforce);
float dragFactor = thrust / (thrust-cDragForce);
float liftFactor = awgt / (awgt+alift);
// Sanity:
@ -964,10 +958,10 @@ void Airplane::solveAirplane(bool verbose)
// variable).
const float ELEVDIDDLE = 0.001f;
_approachElevator->val += ELEVDIDDLE;
runConfig(_approachConfig);
runConfig(_config[APPROACH]);
_approachElevator->val -= ELEVDIDDLE;
double apitch1 = _getPitch(_approachConfig);
double apitch1 = _getPitch(_config[APPROACH]);
// Now apply the values we just computed. Note that the
// "minor" variables are deferred until we get the lift/drag
@ -990,14 +984,14 @@ void Airplane::solveAirplane(bool verbose)
if (verbose) {
fprintf(stdout,"%4d\t%f\t%f\t%f\t%f\n", _solutionIterations, aoaDelta, tailDelta, clift0, cpitch1);
}
_cruiseConfig.aoa += _solverDelta*aoaDelta;
_config[CRUISE].aoa += _solverDelta*aoaDelta;
_tailIncidence->val += _solverDelta*tailDelta;
_cruiseConfig.aoa = Math::clamp(_cruiseConfig.aoa, -0.175f, 0.175f);
_config[CRUISE].aoa = Math::clamp(_config[CRUISE].aoa, -0.175f, 0.175f);
_tailIncidence->val = Math::clamp(_tailIncidence->val, -0.175f, 0.175f);
if(abs(xforce/_cruiseConfig.weight) < _solverThreshold*0.0001 &&
abs(alift/_approachConfig.weight) < _solverThreshold*0.0001 &&
if(abs(cDragForce/_config[CRUISE].weight) < _solverThreshold*0.0001 &&
abs(alift/_config[APPROACH].weight) < _solverThreshold*0.0001 &&
abs(aoaDelta) < _solverThreshold*.000017 &&
abs(tailDelta) < _solverThreshold*.000017)
{
@ -1024,7 +1018,7 @@ void Airplane::solveAirplane(bool verbose)
} else if(_liftRatio < 1e-04 || _liftRatio > 1e4) {
_failureMsg = "Lift ratio beyond reasonable bounds.";
return;
} else if(Math::abs(_cruiseConfig.aoa) >= .17453293) {
} else if(Math::abs(_config[CRUISE].aoa) >= .17453293) {
_failureMsg = "Cruise AoA > 10 degrees";
return;
} else if(Math::abs(_tailIncidence->val) >= .17453293) {
@ -1058,12 +1052,12 @@ void Airplane::solveHelicopter(bool verbose)
applyDragFactor(Math::pow(15.7/1000, 1/_solverDelta));
applyLiftRatio(Math::pow(104, 1/_solverDelta));
}
_cruiseConfig.state.setupState(0,0,0);
_model.setState(&_cruiseConfig.state);
setupWeights(true);
_config[CRUISE].state.setupState(0,0,0);
_model.setState(&_config[CRUISE].state);
setupWeights(APPROACH);
_controlMap.reset();
_model.getBody()->reset();
_model.setStandardAtmosphere(_cruiseConfig.altitude);
_model.setStandardAtmosphere(_config[CRUISE].altitude);
}
float Airplane::getCGMAC()

View file

@ -25,8 +25,11 @@ public:
~Airplane();
enum Configuration {
NONE,
APPROACH,
CRUISE,
TAKEOFF, // for testing
TEST, // for testing
};
void iterate(float dt);
@ -61,8 +64,8 @@ public:
int addWeight(const float* pos, float size);
void setWeight(int handle, float mass);
void setApproach(float speed, float altitude, float aoa, float fuel, float gla);
void setCruise(float speed, float altitude, float fuel, float gla);
void setConfig(Configuration cfg, float speed, float altitude, float fuel,
float gla = 0, float aoa = 0);
/// add (fixed) control setting to approach/cruise config (for solver)
void addControlSetting(Configuration cfg, const char* prop, float val);
@ -100,14 +103,15 @@ public:
int getSolutionIterations() const { return _solutionIterations; }
float getDragCoefficient() const { return _dragFactor; }
float getLiftRatio() const { return _liftRatio; }
float getCruiseAoA() const { return _cruiseConfig.aoa; }
float getCruiseAoA() const { return _config[CRUISE].aoa; }
float getTailIncidence()const;
float getApproachElevator() const;
const char* getFailureMsg() const { return _failureMsg; }
float getMass() const { return _model.getMass(); };
// next two are used only in yasim CLI tool
void setApproachControls() { setControlValues(_approachConfig.controls); }
void setCruiseControls() { setControlValues(_cruiseConfig.controls); }
void setApproachControls() { setControlValues(_config[APPROACH].controls); }
void setCruiseControls() { setControlValues(_config[CRUISE].controls); }
float getCGHardLimitXMin() const { return _cgMin; } // get min x-coordinate for c.g (from main gear)
float getCGHardLimitXMax() const { return _cgMax; } // get max x-coordinate for c.g (from nose gear)
@ -166,7 +170,7 @@ private:
};
struct SolveWeight {
int id {-1};
bool approach {false};
Configuration cfg {APPROACH};
float wgt {0};
};
struct ContactRec {
@ -174,7 +178,7 @@ private:
float p[3] {0,0,0};
};
struct Config {
bool isApproach {false};
Configuration id;
float speed {0};
float fuel {0};
float glideAngle {0};
@ -184,8 +188,7 @@ private:
State state;
Vector controls;
};
Config _cruiseConfig;
Config _approachConfig;
Config _config[Configuration::TEST];
/// load values for controls as defined in cruise/approach configuration
void setControlValues(const Vector& controls);
@ -193,7 +196,8 @@ private:
void runConfig(Config &cfg);
void solveGear();
float _getPitch(Config &cfg);
float _getLift(Config &cfg);
float _getLiftForce(Config &cfg);
float _getDragForce(Config &cfg);
void solveAirplane(bool verbose = false);
void solveHelicopter(bool verbose = false);
float compileWing(Wing* w);
@ -206,7 +210,7 @@ private:
void compileContactPoints();
float normFactor(float f);
void updateGearState();
void setupWeights(bool isApproach);
void setupWeights(Configuration cfg);
void calculateCGHardLimits();
///calculate mass divided by area of main wing
float _getWingLoad(float mass) const;

View file

@ -302,12 +302,12 @@ void FGFDM::parseApproachCruise(const XMLAttributes* a, const char* name)
float gla = attrf(a, "glide-angle", 0) * DEG2RAD;
if (!strcmp(name, "approach")) {
float aoa = attrf(a, "aoa", 0) * DEG2RAD;
_airplane.setApproach(spd, alt, aoa, attrf(a, "fuel", 0.2), gla);
_airplaneCfg = Airplane::Configuration::APPROACH;
_airplane.setConfig(_airplaneCfg, spd, alt, attrf(a, "fuel", 0.2), gla, aoa);
}
else {
_airplane.setCruise(spd, alt, attrf(a, "fuel", 0.5),gla);
_airplaneCfg = Airplane::Configuration::CRUISE;
_airplane.setConfig(_airplaneCfg, spd, alt, attrf(a, "fuel", 0.5), gla);
}
}

View file

@ -99,18 +99,16 @@ void Model::getThrust(float* out) const
void Model::initIteration()
{
// Precompute torque and angular momentum for the thrusters
int i;
for(i=0; i<3; i++)
_gyro[i] = _torque[i] = 0;
Math::zero3(_torque);
Math::zero3(_gyro);
// Need a local altitude for the wind calculation
float lground[4];
_s->planeGlobalToLocal(_global_ground, lground);
float alt = Math::abs(lground[3]);
for(i=0; i<_thrusters.size(); i++) {
for(int i=0; i<_thrusters.size(); i++) {
Thruster* t = (Thruster*)_thrusters.get(i);
// Get the wind velocity at the thruster location
float pos[3], v[3];
t->getPosition(pos);
@ -134,12 +132,12 @@ void Model::initIteration()
_turb->offset(toff);
}
for(i=0; i<_gears.size(); i++) {
for(int i=0; i<_gears.size(); i++) {
Gear* g = (Gear*)_gears.get(i);
g->integrate(_integrator.getInterval());
}
for(i=0; i<_hitches.size(); i++) {
for(int i=0; i<_hitches.size(); i++) {
Hitch* h = (Hitch*)_hitches.get(i);
h->integrate(_integrator.getInterval());
}
@ -272,7 +270,7 @@ void Model::calcForces(State* s)
// calcForces. They get computed before we begin the integration
// step.
_body.setGyro(_gyro);
_body.addTorque(_torque);
_body.setTorque(_torque);
int i,j;
for(i=0; i<_thrusters.size(); i++) {
Thruster* t = (Thruster*)_thrusters.get(i);

View file

@ -30,6 +30,7 @@ public:
RigidBody* getBody() { return &_body; }
void getCG(float* cg) const { return _body.getCG(cg); }
float getMass() const {return _body.getTotalMass(); }
Integrator* getIntegrator() { return &_integrator; }
void setTurbulence(Turbulence* turb) { _turb = turb; }

View file

@ -73,6 +73,7 @@ public:
/// Adds a torque with the specified axis and magnitude
void addTorque(const float* torque) { Math::add3(_torque, torque, _torque); }
void setTorque(const float* torque) { Math::set3(torque, _torque); }
// Sets the rotation rate of the body (about its c.g.) within the
// surrounding environment. This is needed to compute torque on

View file

@ -38,6 +38,7 @@ namespace yasim {
static const float INCIDENCE_MIN = -20*DEG2RAD;
static const float INCIDENCE_MAX = 20*DEG2RAD;
static const char* DEF_PROP_ELEVATOR_TRIM = "/controls/flight/elevator-trim";
}; //namespace yasim
#endif // ifndef _YASIM_COMMON_HPP

View file

@ -28,11 +28,35 @@ double fgGetDouble (const char * name, double defaultValue = 0.0) { return 0; }
bool fgSetDouble (const char * name, double defaultValue = 0.0) { return 0; }
enum Config
void _setup(Airplane* a, Airplane::Configuration cfgID, float altitude)
{
CONFIG_NONE,
CONFIG_APPROACH,
CONFIG_CRUISE,
Model* m = a->getModel();
m->setStandardAtmosphere(altitude);
switch (cfgID) {
case Airplane::APPROACH:
fprintf(stderr,"Setting approach controls.\n");
a->setApproachControls();
break;
case Airplane::CRUISE:
fprintf(stderr,"Setting cruise controls.\n");
a->setCruiseControls();
break;
default:
break;
}
m->getBody()->recalc();
};
void _calculateAcceleration(Airplane* a, float aoa_rad, float speed_mps, float* output)
{
Model* m = a->getModel();
State s;
s.setupState(aoa_rad, speed_mps, 0);
m->getBody()->reset();
m->initIteration();
m->calcForces(&s);
m->getBody()->getAccel(output);
s.localToGlobal(output, output);
};
// Generate a graph of lift, drag and L/D against AoA at the specified
@ -45,40 +69,18 @@ enum Config
"dat" using 1:3 with lines title 'drag', \
"dat" using 1:4 with lines title 'LD'
*/
void yasim_graph(Airplane* a, const float alt, const float kts, int cfg = CONFIG_NONE)
void yasim_graph(Airplane* a, const float alt, const float kts, Airplane::Configuration cfgID)
{
Model* m = a->getModel();
State s;
m->setStandardAtmosphere(alt);
switch (cfg) {
case CONFIG_APPROACH:
a->setApproachControls();
break;
case CONFIG_CRUISE:
a->setCruiseControls();
break;
case CONFIG_NONE:
break;
}
//if we fake the properties we could also use FGFDM::getExternalInput()
m->getBody()->recalc();
_setup(a, cfgID, alt);
float speed = kts * KTS2MPS;
float acc[3] {0,0,0};
float cl_max = 0, cd_min = 1e6, ld_max = 0;
int cl_max_deg = 0, cd_min_deg = 0, ld_max_deg = 0;
printf("aoa\tlift\tdrag\n");
for(int deg=-15; deg<=90; deg++) {
float aoa = deg * DEG2RAD;
s.setupState(aoa, kts * KTS2MPS, 0);
m->getBody()->reset();
m->initIteration();
m->calcForces(&s);
float acc[3];
m->getBody()->getAccel(acc);
Math::tmul33(s.orient, acc, acc);
_calculateAcceleration(a, aoa, speed, acc);
float drag = acc[0] * (-1/9.8);
float lift = 1 + acc[2] * (1/9.8);
float ld = lift/drag;
@ -95,7 +97,7 @@ void yasim_graph(Airplane* a, const float alt, const float kts, int cfg = CONFIG
ld_max= ld;
ld_max_deg = deg;
}
printf("%2d\t%.4f\t%.4f\t%.4f\n", deg, lift, drag, ld);
printf("%2d\t%.4f\t%.4f\n", deg, lift, drag);
}
printf("# cl_max %.4f at %d deg\n", cl_max, cl_max_deg);
printf("# cd_min %.4f at %d deg\n", cd_min, cd_min_deg);
@ -105,56 +107,32 @@ void yasim_graph(Airplane* a, const float alt, const float kts, int cfg = CONFIG
void yasim_masses(Airplane* a)
{
RigidBody* body = a->getModel()->getBody();
int i, N = body->numMasses();
int N = body->numMasses();
float pos[3];
float m, mass = 0;
printf("id posx posy posz mass\n");
for (i = 0; i < N; i++)
printf("id\tposx\tposy\tposz\tmass\n");
for (int i = 0; i < N; i++)
{
body->getMassPosition(i, pos);
m = body->getMass(i);
printf("%d %.3f %.3f %.3f %.3f\n", i, pos[0], pos[1], pos[2], m);
printf("%d\t%.3f\t%.3f\t%.3f\t%.3f\n", i, pos[0], pos[1], pos[2], m);
mass += m;
}
printf("Total mass: %g", mass);
}
void yasim_drag(Airplane* a, const float aoa, const float alt, int cfg = CONFIG_NONE)
void yasim_drag(Airplane* a, const float aoa, const float alt, Airplane::Configuration cfgID)
{
fprintf(stderr,"yasim_drag");
Model* m = a->getModel();
State s;
_setup(a, cfgID, alt);
m->setStandardAtmosphere(alt);
switch (cfg) {
case CONFIG_APPROACH:
a->setApproachControls();
break;
case CONFIG_CRUISE:
a->setCruiseControls();
break;
case CONFIG_NONE:
break;
}
m->getBody()->recalc();
float cd_min = 1e6;
int cd_min_kts = 0;
float acc[3] {0,0,0};
printf("#kts, drag\n");
for(int kts=15; kts<=150; kts++) {
s.setupState(aoa, kts * KTS2MPS, 0);
m->getBody()->reset();
m->initIteration();
m->calcForces(&s);
float acc[3];
m->getBody()->getAccel(acc);
Math::tmul33(s.orient, acc, acc);
_calculateAcceleration(a, aoa,kts * KTS2MPS, acc);
float drag = acc[0] * (-1/9.8);
if (cd_min > drag) {
cd_min = drag;
cd_min_kts = kts;
@ -164,6 +142,26 @@ void yasim_drag(Airplane* a, const float aoa, const float alt, int cfg = CONFIG_
printf("# cd_min %g at %d kts\n", cd_min, cd_min_kts);
}
void findMinSpeed(Airplane* a, float alt)
{
a->addControlSetting(Airplane::CRUISE, DEF_PROP_ELEVATOR_TRIM, 0.7f);
_setup(a, Airplane::CRUISE, alt);
float acc[3];
printf("aoa\tknots\tlift\n");
for(int deg=0; deg<=20; deg++) {
float aoa = deg * DEG2RAD;
for(int kts=15; kts<=180; kts++) {
_calculateAcceleration(a, aoa, kts * KTS2MPS, acc);
float lift = acc[2];
if (lift > 0) {
printf("%d\t%d\t%f\n", deg, kts, lift);
break;
}
}
}
}
void report(Airplane* a)
{
printf("==========================\n");
@ -279,10 +277,10 @@ int main(int argc, char** argv)
}
if(!a->getFailureMsg() && argc > 2 ) {
bool test = (strcmp(argv[2], "-test") == 0);
if((strcmp(argv[2], "-g") == 0) || test)
{
Airplane::Configuration cfg = Airplane::NONE;
float alt = 5000, kts = 100;
int cfg = CONFIG_NONE;
if((strcmp(argv[2], "-g") == 0) || test) {
for(int i=3; i<argc; i++) {
if (std::strcmp(argv[i], "-a") == 0) {
if (i+1 < argc) alt = std::atof(argv[++i]);
@ -290,8 +288,8 @@ int main(int argc, char** argv)
else if(std::strcmp(argv[i], "-s") == 0) {
if(i+1 < argc) kts = std::atof(argv[++i]);
}
else if(std::strcmp(argv[i], "-approach") == 0) cfg = CONFIG_APPROACH;
else if(std::strcmp(argv[i], "-cruise") == 0) cfg = CONFIG_CRUISE;
else if(std::strcmp(argv[i], "-approach") == 0) cfg = Airplane::APPROACH;
else if(std::strcmp(argv[i], "-cruise") == 0) cfg = Airplane::CRUISE;
else return usage();
}
if (test) {
@ -306,13 +304,12 @@ int main(int argc, char** argv)
}
else if(strcmp(argv[2], "-d") == 0) {
float alt = 2000, aoa = a->getCruiseAoA();
int cfg = CONFIG_NONE;
for(int i=3; i<argc; i++) {
if (std::strcmp(argv[i], "-a") == 0) {
if (i+1 < argc) alt = std::atof(argv[++i]);
}
else if(std::strcmp(argv[i], "-approach") == 0) cfg = CONFIG_APPROACH;
else if(std::strcmp(argv[i], "-cruise") == 0) cfg = CONFIG_CRUISE;
else if(std::strcmp(argv[i], "-approach") == 0) cfg = Airplane::APPROACH;
else if(std::strcmp(argv[i], "-cruise") == 0) cfg = Airplane::CRUISE;
else return usage();
}
yasim_drag(a, aoa, alt, cfg);
@ -320,6 +317,18 @@ int main(int argc, char** argv)
else if(strcmp(argv[2], "-m") == 0) {
yasim_masses(a);
}
else if(strcmp(argv[2], "--min-speed") == 0) {
alt = 10;
for(int i=3; i<argc; i++) {
if (std::strcmp(argv[i], "-a") == 0) {
if (i+1 < argc) alt = std::atof(argv[++i]);
}
else if(std::strcmp(argv[i], "-approach") == 0) cfg = Airplane::APPROACH;
else if(std::strcmp(argv[i], "-cruise") == 0) cfg = Airplane::CRUISE;
else return usage();
}
findMinSpeed(a, alt);
}
}
else {
report(a);