1
0
Fork 0

YASim: more output for CLI tool, e.g. wingspan, area, levers, load factor...

This commit is contained in:
Henning Stahlke 2017-12-19 22:11:08 +01:00
parent c325a8d2cd
commit 2538ab717a
9 changed files with 333 additions and 174 deletions

View file

@ -511,7 +511,7 @@ void Airplane::compile()
// The Wing objects
if (_wing)
{
if (baseN != 0) {
if (baseN != nullptr) {
_wingsN = baseN->getChild("wing", 0, true);
_wing->setPropertyNode(_wingsN);
}
@ -528,14 +528,14 @@ void Airplane::compile()
}
if (_tail)
{
if (baseN != 0) {
if (baseN != nullptr) {
_wingsN = baseN->getChild("tail", 0, true);
_tail->setPropertyNode(_wingsN);
}
aeroWgt += compileWing(_tail);
}
int i;
for(i=0; i<_vstabs.size(); i++)
for(int i=0; i<_vstabs.size(); i++)
{
Wing* vs = (Wing*)_vstabs.get(i);
if (baseN != 0) {
@ -546,32 +546,37 @@ void Airplane::compile()
}
// The fuselage(s)
for(i=0; i<_fuselages.size(); i++)
for(int i=0; i<_fuselages.size(); i++)
aeroWgt += compileFuselage((Fuselage*)_fuselages.get(i));
// Count up the absolute weight we have
float nonAeroWgt = _ballast;
for(i=0; i<_thrusters.size(); i++)
for(int i=0; i<_thrusters.size(); i++)
nonAeroWgt += ((ThrustRec*)_thrusters.get(i))->mass;
// Rescale to the specified empty weight
float wscale = (_emptyWeight-nonAeroWgt)/aeroWgt;
for(i=firstMass; i<body->numMasses(); i++) {
for(int i=firstMass; i<body->numMasses(); i++) {
body->setMass(i, body->getMass(i)*wscale);
}
if (_wingsN != nullptr) {
float w = _wingsN->getNode("weight", true)->getFloatValue();
_wingsN->getNode("mass", true)->setFloatValue(w * wscale);
//if we have prop tree, give scale factor to each wing so it can export its mass to the prop tree
if (baseN != nullptr) {
if (_wing) _wing->weight2mass(wscale);
if (_tail) _tail->weight2mass(wscale);
for(int i=0; i<_vstabs.size(); i++)
{
((Wing*)_vstabs.get(i))->weight2mass(wscale);
}
}
// Add the thruster masses
for(i=0; i<_thrusters.size(); i++) {
for(int i=0; i<_thrusters.size(); i++) {
ThrustRec* t = (ThrustRec*)_thrusters.get(i);
body->addMass(t->mass, t->cg, true);
}
// Add the tanks, empty for now.
float totalFuel = 0;
for(i=0; i<_tanks.size(); i++) {
for(int i=0; i<_tanks.size(); i++) {
Tank* t = (Tank*)_tanks.get(i);
t->handle = body->addMass(0, t->pos);
totalFuel += t->cap;
@ -583,11 +588,11 @@ void Airplane::compile()
body->recalc();
// Add surfaces for the landing gear.
for(i=0; i<_gears.size(); i++)
for(int i=0; i<_gears.size(); i++)
compileGear((GearRec*)_gears.get(i));
// The Thruster objects
for(i=0; i<_thrusters.size(); i++) {
for(int i=0; i<_thrusters.size(); i++) {
ThrustRec* tr = (ThrustRec*)_thrusters.get(i);
tr->handle = _model.addThruster(tr->thruster);
}
@ -727,8 +732,7 @@ void Airplane::setupWeights(bool isApproach)
}
}
/// load values for controls as defined in cruise/approach configuration
void Airplane::loadControls(const Vector& controls)
void Airplane::setControlValues(const Vector& controls)
{
_controls.reset();
for(int i=0; i < controls.size(); i++) {
@ -738,7 +742,6 @@ void Airplane::loadControls(const Vector& controls)
_controls.applyControls();
}
/// Helper for solve()
void Airplane::runConfig(Config &cfg)
{
// aoa is consider to be given for approach so we calculate orientation
@ -749,7 +752,7 @@ void Airplane::runConfig(Config &cfg)
cfg.state.setupSpeedAndPosition(cfg.speed, cfg.glideAngle);
_model.setState(&cfg.state);
_model.setStandardAtmosphere(cfg.altitude);
loadControls(cfg.controls);
setControlValues(cfg.controls);
// The local wind
float wind[3];
@ -846,6 +849,24 @@ float Airplane::normFactor(float f)
return f;
}
///helper for Airplane::solve()
float Airplane::_getPitch(Config &cfg)
{
float tmp[3];
_model.getBody()->getAngularAccel(tmp);
cfg.state.localToGlobal(tmp, tmp);
return tmp[1];
}
///helper for Airplane::solve()
float Airplane::_getLift(Config &cfg)
{
float tmp[3];
_model.getBody()->getAccel(tmp);
cfg.state.localToGlobal(tmp, tmp);
return cfg.weight * tmp[2];
}
void Airplane::solve()
{
static const float ARCMIN = 0.0002909f;
@ -859,50 +880,35 @@ void Airplane::solve()
_failureMsg = "Solution failed to converge after 10000 iterations";
return;
}
// Run an iteration at cruise, and extract the needed numbers:
runConfig(_cruiseConfig);
_model.getThrust(tmp);
float thrust = tmp[0] + _cruiseConfig.weight * Math::sin(_cruiseConfig.glideAngle) * 9.81;
_model.getBody()->getAccel(tmp);
_cruiseConfig.state.localToGlobal(tmp, tmp);
float xforce = _cruiseConfig.weight * tmp[0];
float clift0 = _cruiseConfig.weight * tmp[2];
_model.getBody()->getAngularAccel(tmp);
_cruiseConfig.state.localToGlobal(tmp, tmp);
float pitch0 = tmp[1];
float clift0 = _getLift(_cruiseConfig);
float pitch0 = _getPitch(_cruiseConfig);
// Run an approach iteration, and do likewise
runConfig(_approachConfig);
_model.getBody()->getAngularAccel(tmp);
_approachConfig.state.localToGlobal(tmp, tmp);
double apitch0 = tmp[1];
_model.getBody()->getAccel(tmp);
_approachConfig.state.localToGlobal(tmp, tmp);
float alift = _approachConfig.weight * tmp[2];
double apitch0 = _getPitch(_approachConfig);
float alift = _getLift(_approachConfig);
// Modify the cruise AoA a bit to get a derivative
_cruiseConfig.aoa += ARCMIN;
runConfig(_cruiseConfig);
_cruiseConfig.aoa -= ARCMIN;
_model.getBody()->getAccel(tmp);
_cruiseConfig.state.localToGlobal(tmp, tmp);
float clift1 = _cruiseConfig.weight * tmp[2];
float clift1 = _getLift(_cruiseConfig);
// Do the same with the tail incidence
_tail->setIncidence(_tailIncidence + ARCMIN);
runConfig(_cruiseConfig);
_tail->setIncidence(_tailIncidence);
_model.getBody()->getAngularAccel(tmp);
_cruiseConfig.state.localToGlobal(tmp, tmp);
float pitch1 = tmp[1];
float pitch1 = _getPitch(_cruiseConfig);
// Now calculate:
float awgt = 9.8f * _approachConfig.weight;
@ -925,9 +931,7 @@ void Airplane::solve()
runConfig(_approachConfig);
_approachElevator.val -= ELEVDIDDLE;
_model.getBody()->getAngularAccel(tmp);
_approachConfig.state.localToGlobal(tmp, tmp);
double apitch1 = tmp[1];
double apitch1 = _getPitch(_approachConfig);
float elevDelta = -apitch0 * (ELEVDIDDLE/(apitch1-apitch0));
// Now apply the values we just computed. Note that the
@ -1021,4 +1025,53 @@ float Airplane::getCGMAC()
return 0;
}
float Airplane::getWingSpan() const
{
if (_wing == nullptr) return -1;
return _wing->getSpan();
}
float Airplane::getWingArea() const
{
if (_wing == nullptr) return -1;
return _wing->getArea();
}
float Airplane::_getWingLoad(float mass) const
{
if (_wing == nullptr) return -1;
float area = _wing->getArea();
if (area == 0) return -1;
else return mass / area;
}
/// get x-distance between CG and 25% MAC of w
float Airplane::_getWingLever(Wing* w) const
{
if (w == nullptr) return -1;
float cg[3];
_model.getCG(cg);
// aerodynamic center is at 25% of MAC
float ac = w->getMACx() - 0.25f * w->getMACLength();
return ac - cg[0];
}
/// get max thrust with standard atmosphere at sea level
float Airplane::getMaxThrust()
{
float wind[3] {0,0,0};
float thrust[3] {0,0,0};
float sum[3] {0,0,0};
for(int i=0; i<_thrusters.size(); i++) {
Thruster* t = ((ThrustRec*)_thrusters.get(i))->thruster;
t->setWind(wind);
t->setStandardAtmosphere(0);
t->setThrottle(1);
t->stabilize();
t->getThrust(thrust);
Math::add3(thrust, sum, sum);
}
return sum[0];
}
}; // namespace yasim

View file

@ -37,10 +37,10 @@ public:
void setPilotPos(float* pos) { Math::set3(pos, _pilotPos); }
void getPilotPos(float* out) { Math::set3(_pilotPos, out); }
void getPilotAccel(float* out);
void setEmptyWeight(float weight) { _emptyWeight = weight; }
float getEmptyWeight() const { return _emptyWeight; }
Wing* getWing();
bool hasWing() const { return (_wing != nullptr); }
@ -83,11 +83,11 @@ public:
int numTanks() const { return _tanks.size(); }
void setFuelFraction(float frac); // 0-1, total amount of fuel
// get fuel in kg
/// get fuel in kg
float getFuel(int tank) const { return ((Tank*)_tanks.get(tank))->fill; }
// set fuel in kg
/// set fuel in kg
float setFuel(int tank, float fuel) { return ((Tank*)_tanks.get(tank))->fill = fuel; }
// get fuel density in kg/m^3
/// get fuel density in kg/m^3
float getFuelDensity(int tank) const { return ((Tank*)_tanks.get(tank))->density; }
float getTankCapacity(int tank) const { return ((Tank*)_tanks.get(tank))->cap; }
@ -104,17 +104,30 @@ public:
float getApproachElevator() const { return _approachElevator.val; }
const char* getFailureMsg() const { return _failureMsg; }
void loadApproachControls() { loadControls(_approachConfig.controls); }
void loadCruiseControls() { loadControls(_cruiseConfig.controls); }
void setApproachControls() { setControlValues(_approachConfig.controls); }
void setCruiseControls() { setControlValues(_cruiseConfig.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)
float getCGMAC(); // return c.g. x as fraction of MAC
// set desired range for C.G. in % of MAC, 0% = leading edge, 100% trailing edge
/// set desired range for C.G. in % of MAC, 0% = leading edge, 100% trailing edge
void setDesiredCGRangeInPercentOfMAC(float MACPercentMin, float MACPercentMax) { _cgDesiredMin = MACPercentMin; _cgDesiredMax = MACPercentMax; }
float getCGSoftLimitXMin() const { return _cgDesiredAft; } // get x-coordinate limit calculated from MAC and setCGRange values
float getCGSoftLimitXMax() const { return _cgDesiredFront; } // get x-coordinate limit calculated from MAC and setCGRange values
void setAutoBallast(bool allowed) { _autoBallast = allowed; }
void setMTOW(float mtow) { _mtow = mtow; }
float getMTOW() const { return _mtow; }
float getWingSpan() const;
float getWingArea() const;
float getWingLoadEmpty() const { return _getWingLoad(_emptyWeight); };
float getWingLoadMTOW() const { return _getWingLoad(_mtow); };
/// get x-distance between CG and 25% MAC of wing
float getWingLever() const { return _getWingLever(_wing); };
/// get x-distance between CG and 25% MAC of tail
float getTailLever() const { return _getWingLever(_tail); };
float getMaxThrust();
float getThrust2WeightEmpty() { return getMaxThrust()/(_emptyWeight * KG2N); };
float getThrust2WeightMTOW() { return getMaxThrust()/(_mtow*KG2N); };
private:
struct Tank {
@ -161,17 +174,21 @@ private:
float fuel {0};
float glideAngle {0};
float aoa {0};
float altitude;
float weight;
float altitude {0};
float weight {0};
State state;
Vector controls;
};
Config _cruiseConfig;
Config _approachConfig;
void loadControls(const Vector& controls);
/// load values for controls as defined in cruise/approach configuration
void setControlValues(const Vector& controls);
/// Helper for solve()
void runConfig(Config &cfg);
void solveGear();
float _getPitch(Config &cfg);
float _getLift(Config &cfg);
void solve();
void solveHelicopter();
float compileWing(Wing* w);
@ -186,11 +203,17 @@ private:
void updateGearState();
void setupWeights(bool isApproach);
void calculateCGHardLimits();
///calculate mass divided by area of main wing
float _getWingLoad(float mass) const;
///calculate distance between CGx and AC of wing w
float _getWingLever(Wing* w) const;
Model _model;
ControlMap _controls;
float _emptyWeight {0};
///max take of weight
float _mtow {0};
float _pilotPos[3] {0, 0, 0};
Wing* _wing {nullptr};
@ -216,14 +239,18 @@ private:
float _tailIncidence {0};
ControlSetting _approachElevator;
const char* _failureMsg {0};
float _cgMax {-1e6}; // hard limits for cg from gear position
float _cgMin {1e6}; // hard limits for cg from gear position
float _cgDesiredMax {0.3f}; // desired cg max in %MAC from config
float _cgDesiredMin {0.25f}; // desired cg min in %MAC from config
float _cgDesiredFront {0}; // calculated desired cg x max
float _cgDesiredAft {0}; // calculated desired cg x min
bool _autoBallast = false;
/// hard limits for cg from gear position
float _cgMax {-1e6};
/// hard limits for cg from gear position
float _cgMin {1e6};
/// desired cg max in %MAC from config
float _cgDesiredMax {0.3f};
/// desired cg min in %MAC from config
float _cgDesiredMin {0.25f};
/// calculated desired cg x max
float _cgDesiredFront {0};
/// calculated desired cg x min
float _cgDesiredAft {0};
};
}; // namespace yasim

View file

@ -285,7 +285,10 @@ void FGFDM::parseAirplane(const XMLAttributes* a)
SG_LOG(SG_FLIGHT, SG_DEV_ALERT, "This aircraft does not use the latest yasim configuration version.");
}
_airplane.setDesiredCGRangeInPercentOfMAC(attrf(a, "cg-min", 0.25f), attrf(a, "cg-max", 0.3f));
if (attrb(a, "auto-ballast")) { _airplane.setAutoBallast(true); }
if (a->hasAttribute("mtow-lbs")) { _airplane.setMTOW(attrf(a, "mtow-lbs") * LBS2KG); }
else if (a->hasAttribute("mtow-kg")) { _airplane.setMTOW(attrf(a, "mtow-kg")); }
}
void FGFDM::parseApproachCruise(const XMLAttributes* a, const char* name)
@ -566,6 +569,8 @@ void FGFDM::parseWing(const XMLAttributes* a, const char* type, Airplane* airpla
}
else if (!strcmp(type, "hstab")) {
w = airplane->getTail();
if (a->hasAttribute("incidence-max")) w->setIncidenceMax(attrf(a, "incidence-max") * DEG2RAD);
if (a->hasAttribute("incidence-min")) w->setIncidenceMin(attrf(a, "incidence-min") * DEG2RAD);
} else {
w = new Wing(airplane, mirror);
}

View file

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

View file

@ -59,18 +59,19 @@ public:
// regenerate its internal tables. This step is expensive, so
// it's exposed to the client who can amortize the call across
// multiple changes. see also _recalcStatic()
/// calculate the total mass, centre of gravity and inertia tensor
void recalc();
// Resets the current force/torque parameters to zero.
/// Resets the current force/torque parameters to zero.
void reset();
// Applies a force at the center of gravity.
/// Applies a force at the center of gravity.
void addForce(const float* force) { Math::add3(_force, force, _force); }
// Applies a force at the specified position.
/// Applies a force at the specified position.
void addForce(const float* pos, const float* force);
// Adds a torque with the specified axis and magnitude
/// Adds a torque with the specified axis and magnitude
void addTorque(const float* torque) { Math::add3(_torque, torque, _torque); }
// Sets the rotation rate of the body (about its c.g.) within the

View file

@ -47,24 +47,30 @@ int Wing::addWingSection(float* base, float chord, float wingLength, float taper
ws->_twist = twist;
ws->_camber = camber;
ws->_inducedDrag = idrag;
ws->_id = _sections.add(ws);
ws->calculateGeometry();
int idx = _sections.add(ws);
// first / only section
if (idx == 0) {
if (ws->_id == 0) {
_mac = ws->getMAC();
_wingspan = ws->_wingspan;
_netSpan = ws->_sectionSpan;
_area = ws->getArea();
_meanChord = ws->_meanChord;
_sweepLEMin = _sweepLEMax = ws->calculateSweepAngleLeadingEdge();
}
// append section: Calculate wing MAC from MACs of section and prev wing
else {
_mac = Wing::calculateMAC(_mac, ws->getMAC());
_wingspan += ws->_wingspan;
_netSpan += ws->_sectionSpan;
_area += ws->getArea();
_meanChord = _meanChord * ws->_meanChord * 0.5f;
float s = ws->calculateSweepAngleLeadingEdge();
if (_sweepLEMax < s) _sweepLEMax = s;
if (_sweepLEMin > s) _sweepLEMin = s;
}
_chord2float(ws->_tipChord, _tip);
return idx;
_wingSpan = 2 * _tip[1];
_taper = ws->_tipChord.length / ((WingSection*)_sections.get(0))->_rootChord.length;
return ws->_id;
}
Chord Wing::_float2chord(float* pos, float lenght)
@ -135,19 +141,22 @@ void Wing::WingSection::calculateTipChord() {
void Wing::WingSection::calculateSpan()
{
// wingspan in y-direction (not for vstab)
_wingspan = Math::abs(2*_tipChord.y);
_aspectRatio = _wingspan / _meanChord;
_sectionSpan = Math::abs(_rootChord.y - _tipChord.y);
}
void Wing::WingSection::calculateMAC()
{
//FIXME call static method, use absolute y values
// http://www.nasascale.org/p2/wp-content/uploads/mac-calculator.htm
const float commonFactor = _rootChord.length*(0.5+_taper)/(3*_rootChord.length*(1+_taper));
//const float commonFactor = _rootChord.length*(0.5+_taper)/(3*_rootChord.length*(1+_taper));
const float commonFactor = (0.5+_taper)/(3*(1+_taper));
_mac.length = _rootChord.length-(2*_rootChord.length*(1-_taper)*commonFactor);
// y distance to root chord
_mac.y = Math::abs(2*(_tipChord.y-_rootChord.y))*commonFactor;
// MAC leading edge x = midpoint + half MAC length
_mac.x = _rootChord.x-Math::tan(_sweepAngleCenterLine)*_mac.y + _mac.length/2;
_mac.z = _rootChord.z+Math::tan(_dihedral)*_mac.y;
//add root y to get aircraft coordinates
_mac.y += _rootChord.y;
}
@ -169,16 +178,20 @@ void Wing::WingSection::setIncidence(float incidence)
((SurfRec*)_surfs.get(i))->surface->setIncidence(incidence + _sectionIncidence);
}
// root and tip (x,y) coordinates are on leading edge
Chord Wing::calculateMAC(Chord root, Chord tip)
/// root and tip (x,y) coordinates are on leading edge
Chord Wing::calculateMAC(const Chord root, const Chord tip)
{
assert(root.length > 0);
// http://www.nasascale.org/p2/wp-content/uploads/mac-calculator.htm
//taper = tip.length / root.length;
const float commonFactor = (root.length*0.5+tip.length)/(3*(root.length+tip.length));
Chord m;
m.length = root.length-(2*(root.length - tip.length)*commonFactor);
m.y = Math::abs(2*(tip.y - root.y))*commonFactor + root.y;
m.x = root.x - (root.x - tip.x)*(root.y - m.y)/(root.y - tip.y);
float dy = tip.y - root.y;
m.y = Math::abs(2*dy)*commonFactor;
m.z = root.z + m.y*(tip.z-root.z)/dy;
m.x = root.x - m.y*(root.x - tip.x)/dy;
m.y += root.y;
return m;
}
@ -344,6 +357,12 @@ void Wing::compile()
writeInfoToProptree();
}
float Wing::getArea() const
{
if (_mirror) return 2 * _area;
else return _area;
};
void Wing::multiplyLiftRatio(float factor)
{
WingSection* ws;
@ -366,6 +385,11 @@ void Wing::multiplyDragCoefficient(float factor)
void Wing::setIncidence(float incidence)
{
if (incidence < _incidenceMin || incidence > _incidenceMax)
{
fprintf(stderr, "YASim: cannot set incidence, parameter out of range.");
return;
}
WingSection* ws;
for (int section=0; section < _sections.size(); section++)
{
@ -472,24 +496,22 @@ void Wing::writeInfoToProptree()
if (_wingN == nullptr)
return;
WingSection* ws = (WingSection*)_sections.get(0);
float chord = ws->_rootChord.length;
ws = (WingSection*)_sections.get(_sections.size()-1);
float taper = ws->_rootChord.length * ws->_taper;
_wingN->getNode("root-chord", true)->setFloatValue(ws->_rootChord.length);
_wingN->getNode("tip-x", true)->setFloatValue(_tip[0]);
_wingN->getNode("tip-y", true)->setFloatValue(_tip[1]);
_wingN->getNode("tip-z", true)->setFloatValue(_tip[2]);
_wingN->getNode("base-x", true)->setFloatValue(_base[0]);
_wingN->getNode("base-y", true)->setFloatValue(_base[1]);
_wingN->getNode("base-z", true)->setFloatValue(_base[2]);
_wingN->getNode("chord", true)->setFloatValue(chord);
_wingN->getNode("taper", true)->setFloatValue(taper);
_wingN->getNode("wing-span", true)->setFloatValue(_wingspan);
_wingN->getNode("wing-area", true)->setFloatValue(_wingspan*_meanChord);
_wingN->getNode("aspect-ratio", true)->setFloatValue(_aspectRatio);
_wingN->getNode("standard-mean-chord", true)->setFloatValue(_meanChord);
_wingN->getNode("mac", true)->setFloatValue(_mac.length);
_wingN->getNode("mac-x", true)->setFloatValue(_mac.x);
_wingN->getNode("mac-y", true)->setFloatValue(_mac.y);
_wingN->getNode("taper", true)->setFloatValue(getTaper());
_wingN->getNode("wing-span", true)->setFloatValue(getSpan());
_wingN->getNode("wing-area", true)->setFloatValue(getArea());
_wingN->getNode("aspect-ratio", true)->setFloatValue(getAspectRatio());
_wingN->getNode("standard-mean-chord", true)->setFloatValue(getSMC());
_wingN->getNode("mac", true)->setFloatValue(getMACLength());
_wingN->getNode("mac-x", true)->setFloatValue(getMACx());
_wingN->getNode("mac-y", true)->setFloatValue(getMACy());
_wingN->getNode("mac-z", true)->setFloatValue(getMACz());
float wgt = 0;
float dragSum = 0;
@ -510,6 +532,14 @@ void Wing::writeInfoToProptree()
_wingN->getNode("drag", true)->setFloatValue(dragSum);
}
void Wing::weight2mass(float scale)
{
if (_wingN == nullptr)
return;
float wgt = _wingN->getNode("weight", true)->getFloatValue();
_wingN->getNode("mass", true)->setFloatValue(wgt * scale);
}
// estimate a mass distibution and add masses to the model
// they will be scaled to match total mass of aircraft later
float Wing::updateModel(Model* model)

View file

@ -1,6 +1,7 @@
#ifndef _WING_HPP
#define _WING_HPP
#include "yasim-common.hpp"
#include "Vector.hpp"
#include "Version.hpp"
#include "Math.hpp"
@ -50,11 +51,12 @@ class Wing {
struct WingSection {
int _id;
/// length and midpoint (not leading edge!) of root chord
Chord _rootChord;
// length is distance from base to tip, not wing span
/// length is distance from base to tip, not wing span
float _length {0};
float _taper {1};
// sweep of center line, not leading edge!
/// sweep of center line, not leading edge!
float _sweepAngleCenterLine {0};
float _dihedral {0};
float _twist {0};
@ -63,7 +65,7 @@ class Wing {
StallParams _stallParams;
//fixed incidence of section as given in config XML
///fixed incidence of section as given in config XML
float _sectionIncidence {0};
float _dragScale {1};
float _liftRatio {1};
@ -74,13 +76,14 @@ class Wing {
float _orient[9];
float _rightOrient[9];
Chord _tipChord;
float _meanChord {0}; // std. mean chord
Chord _mac; // mean aerodynamic chord (x,y) leading edge
float _wingspan {0};
float _aspectRatio {1};
// all SurfRec of this wing
/// std. mean chord
float _meanChord {0};
/// mean aerodynamic chord, (x,y) leading edge!
Chord _mac;
float _sectionSpan {0};
/// all SurfRec of this wing
Vector _surfs;
// surfaces having a certain type of flap (flap, slat, spoiler)
/// surfaces having a certain type of flap (flap, slat, spoiler)
Vector _flapSurfs[sizeof(WingFlaps)];
void calculateGeometry();
@ -96,7 +99,7 @@ class Wing {
// valid only after Wing::compile() was called
Chord getMAC() const { return _mac; };
float getArea() const { return _wingspan*_meanChord; };
float getArea() const { return _sectionSpan*_meanChord; };
void setDragCoefficient(float scale);
void multiplyDragCoefficient(float factor);
// The ratio of force along the Z (lift) direction of each wing
@ -116,19 +119,29 @@ class Wing {
Version* _version;
bool _mirror {false};
Vector _sections;
Chord _mac;
// midpoint (not leading edge!) of wing root chord
float _base[3] {0,0,0};
// midpoint (not leading edge!) of wing tip
float _tip[3] {0,0,0};
float _wingspan {0};
float _netSpan {0};
float _wingSpan {0};
float _area {0};
float _aspectRatio {0};
float _meanChord {0};
Chord _mac;
float _taper {1};
float _incidence {0};
float _incidenceMin {-20*DEG2RAD};
float _incidenceMax {20*DEG2RAD};
float _weight {0};
float _sweepLEMin {0};
float _sweepLEMax {0};
//-- private methods
Chord _float2chord(float* pos, float lenght = 0);
void _chord2float(Chord c, float* pos);
//copy float[3] to chord x,y,z
static Chord _float2chord(float* pos, float lenght = 0);
//copy chord x,y,z to float[3]
static void _chord2float(Chord c, float* pos);
void interp(const float* v1, const float* v2, const float frac, float* out);
void writeInfoToProptree();
@ -139,7 +152,7 @@ public:
int addWingSection(float* base, float chord, float wingLength,
float taper = 1, float sweep = 0, float dihedral = 0, float twist = 0, float camber = 0, float idrag = 1, float incidence = 0);
static Chord calculateMAC(Chord root, Chord tip);
static Chord calculateMAC(const Chord root, const Chord tip);
void setFlapParams(int section, WingFlaps type, FlapParams fp);
void setSectionDrag(int section, float pdrag);
@ -150,17 +163,24 @@ public:
void multiplyLiftRatio(float factor);
void multiplyDragCoefficient(float factor);
void setIncidence(float incidence);
void setIncidenceMin(float min) { _incidenceMin = min; };
void setIncidenceMax(float max) { _incidenceMax = max; };
void weight2mass(float scale);
bool isMirrored() const { return _mirror; };
void getBase(float* base) const { Math::set3(_base, base); };
void getTip(float* tip) const { Math::set3(_tip, tip); };
float getSpan() const { return _wingspan; };
float getArea() const { return _area; };
float getSpan() const { return _wingSpan; };
float getTaper() const { return _taper; };
float getArea() const;
float getAspectRatio() const { return _aspectRatio; };
float getSMC() const { return _meanChord; };
float getMACLength() const { return _mac.length; }; // get length of MAC
float getMACx() const { return _mac.x; }; // get x-coord of MAC leading edge
float getMACy() const { return _mac.y; }; // get y-coord of MAC leading edge
float getMACz() const { return _mac.z; }; // get y-coord of MAC leading edge
float getSweepLEMin() const { return _sweepLEMin; }; //min sweep angle of leading edge
float getSweepLEMax() const { return _sweepLEMax; }; //max sweep angle of leading edge
//-----------------------------
// propergate the control axes value for the sub-surfaces

View file

@ -20,6 +20,7 @@ namespace yasim {
static const float LBS2N = 4.44822f;
static const float N2LB = 1/LBS2N;
static const float KG2N = 9.81f;
static const float LBS2KG = 0.45359237f;
static const float KG2LBS = 1/LBS2KG;
static const float CM2GALS = 264.172037284f;

View file

@ -54,10 +54,10 @@ void yasim_graph(Airplane* a, const float alt, const float kts, int cfg = CONFIG
switch (cfg) {
case CONFIG_APPROACH:
a->loadApproachControls();
a->setApproachControls();
break;
case CONFIG_CRUISE:
a->loadCruiseControls();
a->setCruiseControls();
break;
case CONFIG_NONE:
break;
@ -129,10 +129,10 @@ void yasim_drag(Airplane* a, const float aoa, const float alt, int cfg = CONFIG_
switch (cfg) {
case CONFIG_APPROACH:
a->loadApproachControls();
a->setApproachControls();
break;
case CONFIG_CRUISE:
a->loadCruiseControls();
a->setCruiseControls();
break;
case CONFIG_NONE:
break;
@ -237,7 +237,7 @@ int main(int argc, char** argv)
printf("= YASim solution results =\n");
printf("==========================\n");
float aoa = a->getCruiseAoA() * RAD2DEG;
float tail = -1 * a->getTailIncidence() * RAD2DEG;
float tailIncidence = -1 * a->getTailIncidence() * RAD2DEG;
float drag = 1000 * a->getDragCoefficient();
float cg[3];
a->getModel()->getBody()->getCG(cg);
@ -246,28 +246,49 @@ int main(int argc, char** argv)
float SI_inertia[9];
a->getModel()->getBody()->getInertiaMatrix(SI_inertia);
float MAC = 0, MACx = 0, MACy = 0;
float sweepMin = 0, sweepMax = 0;
Wing* wing {nullptr};
Wing* tail {nullptr};
if (a->hasWing()) {
wing = a->getWing();
MAC = wing->getMACLength();
MACx = wing->getMACx();
MACy = wing->getMACy();
tail = a->getTail();
}
printf(" Iterations: %d\n", a->getSolutionIterations());
printf(" Drag Coefficient: %.3f\n", drag);
printf(" Lift Ratio: %.3f\n", a->getLiftRatio());
printf(" Cruise AoA: %.2f deg\n", aoa);
printf(" Tail Incidence: %.2f deg\n", tail);
printf(" Tail Incidence: %.2f deg\n", tailIncidence);
printf("Approach Elevator: %.3f\n\n", a->getApproachElevator());
printf(" CG: x:%.3f, y:%.3f, z:%.3f\n", cg[0], cg[1], cg[2]);
if (wing) {
MAC = wing->getMACLength();
MACx = wing->getMACx();
MACy = wing->getMACy();
sweepMin = wing->getSweepLEMin() * RAD2DEG;
sweepMax = wing->getSweepLEMax() * RAD2DEG;
printf(" Wing MAC: (x:%.2f, y:%.2f), length:%.1f \n", MACx, MACy, MAC);
printf(" hard limit CG-x: %.3f \n", a->getCGHardLimitXMax());
printf(" soft limit CG-x: %.3f \n", a->getCGSoftLimitXMax());
printf(" CG-x: %.3f \n", cg[0]);
printf(" hard limit CG-x: %.3f m\n", a->getCGHardLimitXMax());
printf(" soft limit CG-x: %.3f m\n", a->getCGSoftLimitXMax());
printf(" CG-x: %.3f m\n", cg[0]);
printf(" CG-x rel. MAC: %3.0f%%\n", a->getCGMAC()*100);
printf(" soft limit CG-x: %.3f \n", a->getCGSoftLimitXMin());
printf(" hard limit CG-x: %.3f \n", a->getCGHardLimitXMin());
printf(" soft limit CG-x: %.3f m\n", a->getCGSoftLimitXMin());
printf(" hard limit CG-x: %.3f m\n", a->getCGHardLimitXMin());
printf("\n");
printf(" wing span: %.2f m\n", a->getWingSpan());
printf(" sweep lead. edge: %.1f .. %.1f deg\n", sweepMin, sweepMax);
printf(" wing area: %.2f m²\n", a->getWingArea());
printf(" wing load empty: %.2f kg/m² (Empty %.0f kg)\n", a->getWingLoadEmpty(), a->getEmptyWeight());
printf(" wing load MTOW: %.2f kg/m² (MTOW %.0f kg)\n", a->getWingLoadMTOW(), a->getMTOW());
printf("\n");
printf(" tail span: %.3f m\n", tail->getSpan());
printf(" tail area: %.3f m²\n", tail->getArea());
printf("\n");
printf(" wing lever: %.3f m\n", a->getWingLever());
printf(" tail lever: %.3f m\n", a->getTailLever());
printf("\n");
printf(" max thrust: %.2f kN\n", a->getMaxThrust()/1000);
printf(" thrust/empty: %.2f\n", a->getThrust2WeightEmpty());
printf(" thrust/mtow: %.2f\n", a->getThrust2WeightMTOW());
}
printf("\nInertia tensor [kg*m^2], origo at CG:\n\n");
printf(" %7.0f, %7.0f, %7.0f\n", SI_inertia[0], SI_inertia[1], SI_inertia[2]);