YASim solver convergence workaround
This commit is contained in:
parent
c2e7842110
commit
25e34cc49c
3 changed files with 28 additions and 3 deletions
|
@ -877,6 +877,21 @@ float Airplane::_getDragForce(Config &cfg)
|
||||||
return cfg.weight * tmp[0];
|
return cfg.weight * tmp[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is a heuristic approach to "force" solver converge due to numeric
|
||||||
|
// problems. To be replaced by a better solution later.
|
||||||
|
float Airplane::_checkConvergence(float prev, float current)
|
||||||
|
{
|
||||||
|
static int damping {0};
|
||||||
|
//different sign and almost same value -> oscilation;
|
||||||
|
if ((prev*current) < 0 && (abs(current + prev) < 0.01f)) {
|
||||||
|
if (!damping) fprintf(stderr,"YASim warning: possible convergence problem.\n");
|
||||||
|
damping++;
|
||||||
|
if (current < 1) current *= abs(current); // quadratic
|
||||||
|
else current = sqrt(current);
|
||||||
|
}
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
void Airplane::solveAirplane(bool verbose)
|
void Airplane::solveAirplane(bool verbose)
|
||||||
{
|
{
|
||||||
static const float ARCMIN = 0.0002909f;
|
static const float ARCMIN = 0.0002909f;
|
||||||
|
@ -899,6 +914,7 @@ void Airplane::solveAirplane(bool verbose)
|
||||||
fprintf(stdout,"i\tdAoa\tdTail\tcl0\tcp1\n");
|
fprintf(stdout,"i\tdAoa\tdTail\tcl0\tcp1\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float prevTailDelta {0};
|
||||||
while(1) {
|
while(1) {
|
||||||
if(_solutionIterations++ > _solverMaxIterations) {
|
if(_solutionIterations++ > _solverMaxIterations) {
|
||||||
_failureMsg = "Solution failed to converge!";
|
_failureMsg = "Solution failed to converge!";
|
||||||
|
@ -920,9 +936,10 @@ void Airplane::solveAirplane(bool verbose)
|
||||||
float alift = _getLiftForce(_config[APPROACH]);
|
float alift = _getLiftForce(_config[APPROACH]);
|
||||||
|
|
||||||
// Modify the cruise AoA a bit to get a derivative
|
// Modify the cruise AoA a bit to get a derivative
|
||||||
|
float savedAoa = _config[CRUISE].aoa;
|
||||||
_config[CRUISE].aoa += ARCMIN;
|
_config[CRUISE].aoa += ARCMIN;
|
||||||
runConfig(_config[CRUISE]);
|
runConfig(_config[CRUISE]);
|
||||||
_config[CRUISE].aoa -= ARCMIN;
|
_config[CRUISE].aoa = savedAoa;
|
||||||
|
|
||||||
float clift1 = _getLiftForce(_config[CRUISE]);
|
float clift1 = _getLiftForce(_config[CRUISE]);
|
||||||
|
|
||||||
|
@ -978,7 +995,12 @@ void Airplane::solveAirplane(bool verbose)
|
||||||
// OK, now we can adjust the minor variables:
|
// OK, now we can adjust the minor variables:
|
||||||
float aoaDelta = -clift0 * (ARCMIN/(clift1-clift0));
|
float aoaDelta = -clift0 * (ARCMIN/(clift1-clift0));
|
||||||
float tailDelta = -cpitch0 * (ARCMIN/(cpitch1-cpitch0));
|
float tailDelta = -cpitch0 * (ARCMIN/(cpitch1-cpitch0));
|
||||||
|
// following is a hack against oszilation variables,
|
||||||
|
// needs more research to get a fully understood - it works
|
||||||
|
if (_solverMode > 0) {
|
||||||
|
tailDelta = _checkConvergence(prevTailDelta, tailDelta);
|
||||||
|
prevTailDelta = tailDelta;
|
||||||
|
}
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
fprintf(stdout,"%4d\t%f\t%f\t%f\t%f\n", _solutionIterations, aoaDelta, tailDelta, clift0, cpitch1);
|
fprintf(stdout,"%4d\t%f\t%f\t%f\t%f\n", _solutionIterations, aoaDelta, tailDelta, clift0, cpitch1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,6 +137,7 @@ public:
|
||||||
void setSolverTweak(float f) { _solverDelta = f; };
|
void setSolverTweak(float f) { _solverDelta = f; };
|
||||||
void setSolverThreshold(float threshold) { _solverThreshold = threshold; };
|
void setSolverThreshold(float threshold) { _solverThreshold = threshold; };
|
||||||
void setSolverMaxIterations(int i) { _solverMaxIterations = i; };
|
void setSolverMaxIterations(int i) { _solverMaxIterations = i; };
|
||||||
|
void setSolverMode(int i) { _solverMode = i; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Tank {
|
struct Tank {
|
||||||
|
@ -198,6 +199,7 @@ private:
|
||||||
float _getPitch(Config &cfg);
|
float _getPitch(Config &cfg);
|
||||||
float _getLiftForce(Config &cfg);
|
float _getLiftForce(Config &cfg);
|
||||||
float _getDragForce(Config &cfg);
|
float _getDragForce(Config &cfg);
|
||||||
|
float _checkConvergence(float prev, float current);
|
||||||
void solveAirplane(bool verbose = false);
|
void solveAirplane(bool verbose = false);
|
||||||
void solveHelicopter(bool verbose = false);
|
void solveHelicopter(bool verbose = false);
|
||||||
float compileWing(Wing* w);
|
float compileWing(Wing* w);
|
||||||
|
@ -222,6 +224,7 @@ private:
|
||||||
/// set property name controling tail trim (incidence)
|
/// set property name controling tail trim (incidence)
|
||||||
void setHstabTrimControl(const char* propName);
|
void setHstabTrimControl(const char* propName);
|
||||||
|
|
||||||
|
int _solverMode {1};
|
||||||
float _solverDelta {0.3226f};
|
float _solverDelta {0.3226f};
|
||||||
// How close to the solution are we trying get?
|
// How close to the solution are we trying get?
|
||||||
// Trying too hard can result in oscillations (no convergence).
|
// Trying too hard can result in oscillations (no convergence).
|
||||||
|
|
|
@ -283,7 +283,7 @@ void FGFDM::parseAirplane(const XMLAttributes* a)
|
||||||
|
|
||||||
if (a->hasAttribute("mtow-lbs")) { _airplane.setMTOW(attrf(a, "mtow-lbs") * LBS2KG); }
|
if (a->hasAttribute("mtow-lbs")) { _airplane.setMTOW(attrf(a, "mtow-lbs") * LBS2KG); }
|
||||||
else if (a->hasAttribute("mtow-kg")) { _airplane.setMTOW(attrf(a, "mtow-kg")); }
|
else if (a->hasAttribute("mtow-kg")) { _airplane.setMTOW(attrf(a, "mtow-kg")); }
|
||||||
|
if (a->hasAttribute("solver-mode")) { _airplane.setSolverMode(attri(a, "solver-mode")); }
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGFDM::parseApproachCruise(const XMLAttributes* a, const char* name)
|
void FGFDM::parseApproachCruise(const XMLAttributes* a, const char* name)
|
||||||
|
|
Loading…
Reference in a new issue