Synchronized with JSBSim/CVS.
This commit is contained in:
parent
dfa583c014
commit
f9689a561c
58 changed files with 1767 additions and 1021 deletions
|
@ -9,6 +9,7 @@ set(HEADERS
|
|||
initialization/FGTrimAxis.h
|
||||
initialization/FGSimplexTrim.h
|
||||
initialization/FGTrimmer.h
|
||||
initialization/FGLinearization.h
|
||||
input_output/FGXMLParse.h
|
||||
input_output/FGXMLFileRead.h
|
||||
input_output/FGPropertyManager.h
|
||||
|
@ -100,6 +101,7 @@ set(SOURCES
|
|||
initialization/FGTrimAxis.cpp
|
||||
initialization/FGSimplexTrim.cpp
|
||||
initialization/FGTrimmer.cpp
|
||||
initialization/FGLinearization.cpp
|
||||
input_output/FGGroundCallback.cpp
|
||||
input_output/FGPropertyManager.cpp
|
||||
input_output/FGScript.cpp
|
||||
|
|
|
@ -65,6 +65,7 @@ INCLUDES
|
|||
#include "models/FGOutput.h"
|
||||
#include "initialization/FGInitialCondition.h"
|
||||
#include "initialization/FGSimplexTrim.h"
|
||||
#include "initialization/FGLinearization.h"
|
||||
#include "input_output/FGPropertyManager.h"
|
||||
#include "input_output/FGScript.h"
|
||||
|
||||
|
@ -72,7 +73,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGFDMExec.cpp,v 1.145 2012/11/11 18:43:07 bcoconni Exp $";
|
||||
static const char *IdSrc = "$Id: FGFDMExec.cpp,v 1.148 2013/06/10 01:46:27 jberndt Exp $";
|
||||
static const char *IdHdr = ID_FDMEXEC;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -133,7 +134,8 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root, unsigned int* fdmctr) : Root(root)
|
|||
// Prepare FDMctr for the next child FDM id
|
||||
(*FDMctr)++; // instance. "child" instances are loaded last.
|
||||
|
||||
instance = Root->GetNode("/fdm/jsbsim",IdFDM,true);
|
||||
FGPropertyNode* instanceRoot = Root->GetNode("/fdm/jsbsim",IdFDM,true);
|
||||
instance = new FGPropertyManager(instanceRoot);
|
||||
Debug(0);
|
||||
// this is to catch errors in binding member functions to the property tree.
|
||||
try {
|
||||
|
@ -153,6 +155,7 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root, unsigned int* fdmctr) : Root(root)
|
|||
// instance->Tie("simulation/do_trim_analysis", this, (iPMF)0, &FGFDMExec::DoTrimAnalysis, false);
|
||||
instance->Tie("simulation/do_simple_trim", this, (iPMF)0, &FGFDMExec::DoTrim, false);
|
||||
instance->Tie("simulation/do_simplex_trim", this, (iPMF)0, &FGFDMExec::DoSimplexTrim);
|
||||
instance->Tie("simulation/do_linearization", this, (iPMF)0, &FGFDMExec::DoLinearization);
|
||||
instance->Tie("simulation/reset", this, (iPMF)0, &FGFDMExec::ResetToInitialConditions, false);
|
||||
instance->Tie("simulation/randomseed", this, (iPMF)0, &FGFDMExec::SRand, false);
|
||||
instance->Tie("simulation/terminate", (int *)&Terminate);
|
||||
|
@ -161,56 +164,46 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root, unsigned int* fdmctr) : Root(root)
|
|||
instance->Tie("simulation/frame", (int *)&Frame, false);
|
||||
|
||||
// simplex trim properties
|
||||
instance->SetDouble("trim/solver/rtol",0.0001);
|
||||
instance->SetDouble("trim/solver/speed",2);
|
||||
instance->SetDouble("trim/solver/abstol",0.001);
|
||||
instance->SetDouble("trim/solver/iterMax",2000);
|
||||
instance->SetInt("trim/solver/debugLevel",0);
|
||||
instance->SetDouble("trim/solver/random",0);
|
||||
instance->SetBool("trim/solver/showSimplex",false);
|
||||
// instance->SetBool("trim/solver/showConvergence",true);
|
||||
instance->SetBool("trim/solver/pause",false);
|
||||
instanceRoot->SetDouble("trim/solver/rtol",0.0001);
|
||||
instanceRoot->SetDouble("trim/solver/speed",2);
|
||||
instanceRoot->SetDouble("trim/solver/abstol",0.001);
|
||||
instanceRoot->SetDouble("trim/solver/iterMax",2000);
|
||||
instanceRoot->SetInt("trim/solver/debugLevel",0);
|
||||
instanceRoot->SetDouble("trim/solver/random",0);
|
||||
instanceRoot->SetBool("trim/solver/showSimplex",false);
|
||||
instanceRoot->SetBool("trim/solver/showConvergence",false);
|
||||
instanceRoot->SetBool("trim/solver/pause",false);
|
||||
instanceRoot->SetBool("trim/solver/variablePropPitch",false);
|
||||
|
||||
instance->SetDouble("trim/solver/throttleGuess",0.50);
|
||||
instance->SetDouble("trim/solver/throttleMin",0.0);
|
||||
instance->SetDouble("trim/solver/throttleMax",1.0);
|
||||
// instance->SetDouble("trim/solver/throttleInitialStepSize",0.1);
|
||||
instance->SetDouble("trim/solver/throttleStep",0.1);
|
||||
instanceRoot->SetDouble("trim/solver/throttleGuess",0.50);
|
||||
instanceRoot->SetDouble("trim/solver/throttleMin",0.0);
|
||||
instanceRoot->SetDouble("trim/solver/throttleMax",1.0);
|
||||
instanceRoot->SetDouble("trim/solver/throttleStep",0.1);
|
||||
|
||||
instance->SetDouble("trim/solver/aileronGuess",0);
|
||||
instance->SetDouble("trim/solver/aileronMin",-1.00);
|
||||
instance->SetDouble("trim/solver/aileronMax",1.00);
|
||||
// instance->SetDouble("trim/solver/aileronInitialStepSize",0.1);
|
||||
instance->SetDouble("trim/solver/aileronStep",0.1);
|
||||
instanceRoot->SetDouble("trim/solver/aileronGuess",0);
|
||||
instanceRoot->SetDouble("trim/solver/aileronMin",-1.00);
|
||||
instanceRoot->SetDouble("trim/solver/aileronMax",1.00);
|
||||
instanceRoot->SetDouble("trim/solver/aileronStep",0.1);
|
||||
|
||||
instance->SetDouble("trim/solver/rudderGuess",0);
|
||||
instance->SetDouble("trim/solver/rudderMin",-1.00);
|
||||
instance->SetDouble("trim/solver/rudderMax",1.00);
|
||||
// instance->SetDouble("trim/solver/rudderInitialStepSize",0.1);
|
||||
instance->SetDouble("trim/solver/rudderStep",0.1);
|
||||
instanceRoot->SetDouble("trim/solver/rudderGuess",0);
|
||||
instanceRoot->SetDouble("trim/solver/rudderMin",-1.00);
|
||||
instanceRoot->SetDouble("trim/solver/rudderMax",1.00);
|
||||
instanceRoot->SetDouble("trim/solver/rudderStep",0.1);
|
||||
|
||||
instance->SetDouble("trim/solver/elevatorGuess",-0.1);
|
||||
instance->SetDouble("trim/solver/elevatorMin",-1.0);
|
||||
instance->SetDouble("trim/solver/elevatorMax",1.0);
|
||||
// instance->SetDouble("trim/solver/elevatorInitialStepSize",0.1);
|
||||
instance->SetDouble("trim/solver/elevatorStep",0.1);
|
||||
instanceRoot->SetDouble("trim/solver/elevatorGuess",-0.1);
|
||||
instanceRoot->SetDouble("trim/solver/elevatorMin",-1.0);
|
||||
instanceRoot->SetDouble("trim/solver/elevatorMax",1.0);
|
||||
instanceRoot->SetDouble("trim/solver/elevatorStep",0.1);
|
||||
|
||||
instance->SetDouble("trim/solver/alphaGuess",0.05);
|
||||
instance->SetDouble("trim/solver/alphaMin",-0.1);
|
||||
instance->SetDouble("trim/solver/alphaMax",.18);
|
||||
// instance->SetDouble("trim/solver/alphaInitialStepSize",0.1);
|
||||
instance->SetDouble("trim/solver/alphaStep",0.05);
|
||||
instanceRoot->SetDouble("trim/solver/alphaGuess",0.05);
|
||||
instanceRoot->SetDouble("trim/solver/alphaMin",-0.1);
|
||||
instanceRoot->SetDouble("trim/solver/alphaMax",.18);
|
||||
instanceRoot->SetDouble("trim/solver/alphaStep",0.05);
|
||||
|
||||
instance->SetDouble("trim/solver/betaGuess",0);
|
||||
instance->SetDouble("trim/solver/betaMin",-0.05);
|
||||
instance->SetDouble("trim/solver/betaMax",0.05);
|
||||
// instance->SetDouble("trim/solver/betaInitialStepSize",0.1);
|
||||
instance->SetDouble("trim/solver/betaStep",0.05);
|
||||
|
||||
instance->SetBool("trim/solver/showConvergeStatus",true);
|
||||
// instance->SetBool("trim/solver/pause",true);
|
||||
instance->SetBool("trim/solver/variablePropPitch",false);
|
||||
// instance->SetBool("trim/solver/debugLevel",0);
|
||||
instanceRoot->SetDouble("trim/solver/betaGuess",0);
|
||||
instanceRoot->SetDouble("trim/solver/betaMin",-0.1);
|
||||
instanceRoot->SetDouble("trim/solver/betaMax",0.1);
|
||||
instanceRoot->SetDouble("trim/solver/betaStep",0.0001);
|
||||
|
||||
Constructing = false;
|
||||
}
|
||||
|
@ -223,6 +216,8 @@ FGFDMExec::~FGFDMExec()
|
|||
Unbind();
|
||||
DeAllocate();
|
||||
|
||||
delete instance;
|
||||
|
||||
if (IdFDM == 0) { // Meaning this is no child FDM
|
||||
if(Root != 0) {
|
||||
if(StandAlone)
|
||||
|
@ -922,7 +917,7 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
|
|||
if (result) {
|
||||
struct PropertyCatalogStructure masterPCS;
|
||||
masterPCS.base_string = "";
|
||||
masterPCS.node = (FGPropertyManager*)Root;
|
||||
masterPCS.node = Root->GetNode();
|
||||
BuildPropertyCatalog(&masterPCS);
|
||||
}
|
||||
|
||||
|
@ -944,6 +939,7 @@ void FGFDMExec::BuildPropertyCatalog(struct PropertyCatalogStructure* pcs)
|
|||
int node_idx = 0;
|
||||
|
||||
for (int i=0; i<pcs->node->nChildren(); i++) {
|
||||
string access="";
|
||||
pcsNew->base_string = pcs->base_string + "/" + pcs->node->getChild(i)->getName();
|
||||
node_idx = pcs->node->getChild(i)->getIndex();
|
||||
if (node_idx != 0) {
|
||||
|
@ -953,9 +949,11 @@ void FGFDMExec::BuildPropertyCatalog(struct PropertyCatalogStructure* pcs)
|
|||
if (pcsNew->base_string.substr(0,12) == string("/fdm/jsbsim/")) {
|
||||
pcsNew->base_string = pcsNew->base_string.erase(0,12);
|
||||
}
|
||||
PropertyCatalog.push_back(pcsNew->base_string);
|
||||
if (pcs->node->getChild(i)->getAttribute(SGPropertyNode::READ)) access="R";
|
||||
if (pcs->node->getChild(i)->getAttribute(SGPropertyNode::WRITE)) access+="W";
|
||||
PropertyCatalog.push_back(pcsNew->base_string+" ("+access+")");
|
||||
} else {
|
||||
pcsNew->node = (FGPropertyManager*)pcs->node->getChild(i);
|
||||
pcsNew->node = (FGPropertyNode*)pcs->node->getChild(i);
|
||||
BuildPropertyCatalog(pcsNew);
|
||||
}
|
||||
}
|
||||
|
@ -1193,8 +1191,20 @@ void FGFDMExec::DoSimplexTrim(int mode)
|
|||
FGSimplexTrim trim(this, (JSBSim::TrimMode)mode);
|
||||
sim_time = saved_time;
|
||||
Setsim_time(saved_time);
|
||||
std::cout << "dT: " << dT << std::endl;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGFDMExec::DoLinearization(int mode)
|
||||
{
|
||||
double saved_time;
|
||||
if (Constructing) return;
|
||||
saved_time = sim_time;
|
||||
FGLinearization lin(this,mode);
|
||||
sim_time = saved_time;
|
||||
Setsim_time(saved_time);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_FDMEXEC "$Id: FGFDMExec.h,v 1.80 2012/10/25 04:56:57 jberndt Exp $"
|
||||
#define ID_FDMEXEC "$Id: FGFDMExec.h,v 1.83 2013/06/10 01:46:27 jberndt Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -179,7 +179,7 @@ CLASS DOCUMENTATION
|
|||
property actually maps toa function call of DoTrim().
|
||||
|
||||
@author Jon S. Berndt
|
||||
@version $Revision: 1.80 $
|
||||
@version $Revision: 1.83 $
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -392,13 +392,14 @@ public:
|
|||
/** Retrieves the value of a property.
|
||||
@param property the name of the property
|
||||
@result the value of the specified property */
|
||||
inline double GetPropertyValue(const string& property) {return instance->GetDouble(property);}
|
||||
inline double GetPropertyValue(const string& property)
|
||||
{ return instance->GetNode()->GetDouble(property); }
|
||||
|
||||
/** Sets a property value.
|
||||
@param property the property to be set
|
||||
@param value the value to set the property to */
|
||||
inline void SetPropertyValue(const string& property, double value) {
|
||||
instance->SetDouble(property, value);
|
||||
instance->GetNode()->SetDouble(property, value);
|
||||
}
|
||||
|
||||
/// Returns the model name.
|
||||
|
@ -448,12 +449,13 @@ public:
|
|||
/** Sets (or overrides) the output filename
|
||||
@param fname the name of the file to output data to
|
||||
@return true if successful, false if there is no output specified for the flight model */
|
||||
bool SetOutputFileName(const string& fname) { return Output->SetOutputName(0, fname); }
|
||||
bool SetOutputFileName(const int n, const string& fname) { return Output->SetOutputName(n, fname); }
|
||||
|
||||
/** Retrieves the current output filename.
|
||||
@return the name of the output file for the first output specified by the flight model.
|
||||
@param n index of file
|
||||
@return the name of the output file for the output specified by the flight model.
|
||||
If none is specified, the empty string is returned. */
|
||||
string GetOutputFileName(void) const { return Output->GetOutputName(0); }
|
||||
string GetOutputFileName(int n) const { return Output->GetOutputName(n); }
|
||||
|
||||
/** Executes trimming in the selected mode.
|
||||
* @param mode Specifies how to trim:
|
||||
|
@ -467,6 +469,11 @@ public:
|
|||
void DoTrim(int mode);
|
||||
void DoSimplexTrim(int mode);
|
||||
|
||||
/** Executes linearization with state-space output
|
||||
* You must trim first to get an accurate state-space model
|
||||
*/
|
||||
void DoLinearization(int mode);
|
||||
|
||||
/// Disables data logging to all outputs.
|
||||
void DisableOutput(void) { Output->Disable(); }
|
||||
/// Enables data logging to all outputs.
|
||||
|
@ -490,7 +497,7 @@ public:
|
|||
/// Name of the property.
|
||||
string base_string;
|
||||
/// The node for the property.
|
||||
FGPropertyManager *node;
|
||||
FGPropertyNode_ptr node;
|
||||
};
|
||||
|
||||
/** Builds a catalog of properties.
|
||||
|
|
|
@ -44,7 +44,7 @@ INCLUDES
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGJSBBase.cpp,v 1.35 2012/03/25 11:05:36 bcoconni Exp $";
|
||||
static const char *IdSrc = "$Id: FGJSBBase.cpp,v 1.36 2013/01/25 13:39:11 jberndt Exp $";
|
||||
static const char *IdHdr = ID_JSBBASE;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -106,7 +106,7 @@ const double FGJSBBase::kgtolb = 2.20462;
|
|||
const double FGJSBBase::kgtoslug = 0.06852168;
|
||||
|
||||
const string FGJSBBase::needed_cfg_version = "2.0";
|
||||
const string FGJSBBase::JSBSim_version = "1.0 "__DATE__" "__TIME__;
|
||||
const string FGJSBBase::JSBSim_version = "1.0 " __DATE__ " " __TIME__ ;
|
||||
|
||||
std::queue <FGJSBBase::Message> FGJSBBase::Messages;
|
||||
FGJSBBase::Message FGJSBBase::localMsg;
|
||||
|
|
|
@ -90,9 +90,9 @@ public:
|
|||
|
||||
/** Get the altitude above sea level dependent on the location. */
|
||||
virtual double GetAltitude(const FGLocation& l) const {
|
||||
double pt[3] = { SG_FEET_TO_METER*l(eX),
|
||||
SG_FEET_TO_METER*l(eY),
|
||||
SG_FEET_TO_METER*l(eZ) };
|
||||
double pt[3] = { SG_FEET_TO_METER*l(FGJSBBase::eX),
|
||||
SG_FEET_TO_METER*l(FGJSBBase::eY),
|
||||
SG_FEET_TO_METER*l(FGJSBBase::eZ) };
|
||||
double lat, lon, alt;
|
||||
sgCartToGeod( pt, &lat, &lon, &alt);
|
||||
return alt * SG_METER_TO_FEET;
|
||||
|
@ -102,7 +102,7 @@ public:
|
|||
virtual double GetAGLevel(double t, const FGLocation& l,
|
||||
FGLocation& cont, FGColumnVector3& n,
|
||||
FGColumnVector3& v, FGColumnVector3& w) const {
|
||||
double loc_cart[3] = { l(eX), l(eY), l(eZ) };
|
||||
double loc_cart[3] = { l(FGJSBBase::eX), l(FGJSBBase::eY), l(FGJSBBase::eZ) };
|
||||
double contact[3], normal[3], vel[3], angularVel[3], agl = 0;
|
||||
mInterface->get_agl_ft(t, loc_cart, SG_METER_TO_FEET*2, contact, normal,
|
||||
vel, angularVel, &agl);
|
||||
|
@ -114,7 +114,7 @@ public:
|
|||
}
|
||||
|
||||
virtual double GetTerrainGeoCentRadius(double t, const FGLocation& l) const {
|
||||
double loc_cart[3] = { l(eX), l(eY), l(eZ) };
|
||||
double loc_cart[3] = { l(FGJSBBase::eX), l(FGJSBBase::eY), l(FGJSBBase::eZ) };
|
||||
double contact[3], normal[3], vel[3], angularVel[3], agl = 0;
|
||||
mInterface->get_agl_ft(t, loc_cart, SG_METER_TO_FEET*2, contact, normal,
|
||||
vel, angularVel, &agl);
|
||||
|
@ -192,7 +192,8 @@ FGJSBsim::FGJSBsim( double dt )
|
|||
}
|
||||
}
|
||||
|
||||
fdmex = new FGFDMExec( (FGPropertyManager*)globals->get_props() );
|
||||
PropertyManager = new FGPropertyManager( (FGPropertyNode*)globals->get_props() );
|
||||
fdmex = new FGFDMExec( PropertyManager );
|
||||
|
||||
// Register ground callback.
|
||||
fdmex->SetGroundCallback( new FGFSGroundCallback(this) );
|
||||
|
@ -363,6 +364,7 @@ FGJSBsim::FGJSBsim( double dt )
|
|||
FGJSBsim::~FGJSBsim(void)
|
||||
{
|
||||
delete fdmex;
|
||||
delete PropertyManager;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -71,6 +71,7 @@ class FGOutput;
|
|||
class FGInitialCondition;
|
||||
class FGLocation;
|
||||
class FGAccelerations;
|
||||
class FGPropertyManager;
|
||||
}
|
||||
|
||||
// Adding it here will cause a namespace clash in FlightGear -EMH-
|
||||
|
@ -235,6 +236,7 @@ private:
|
|||
JSBSim::FGGroundReactions* GroundReactions;
|
||||
JSBSim::FGInertial* Inertial;
|
||||
JSBSim::FGAccelerations* Accelerations;
|
||||
JSBSim::FGPropertyManager* PropertyManager;
|
||||
|
||||
int runcount;
|
||||
double trim_elev;
|
||||
|
|
114
src/FDM/JSBSim/initialization/FGLinearization.cpp
Normal file
114
src/FDM/JSBSim/initialization/FGLinearization.cpp
Normal file
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* FGLinearization.cpp
|
||||
* Copyright (C) James Goppert 2011 <james.goppert@gmail.com>
|
||||
*
|
||||
* FGLinearization.h is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FGLinearization.h is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "FGLinearization.h"
|
||||
#include <ctime>
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
// TODO make FGLinearization have X,U,Y selectable by xml config file
|
||||
|
||||
FGLinearization::FGLinearization(FGFDMExec * fdm, int mode)
|
||||
{
|
||||
std::cout << "\nlinearization: " << std::endl;
|
||||
std::clock_t time_start=clock(), time_linDone;
|
||||
FGStateSpace ss(fdm);
|
||||
|
||||
ss.x.add(new FGStateSpace::Vt);
|
||||
ss.x.add(new FGStateSpace::Alpha);
|
||||
ss.x.add(new FGStateSpace::Theta);
|
||||
ss.x.add(new FGStateSpace::Q);
|
||||
|
||||
// get propulsion pointer to determine type/ etc.
|
||||
FGEngine * engine0 = fdm->GetPropulsion()->GetEngine(0);
|
||||
FGThruster * thruster0 = engine0->GetThruster();
|
||||
|
||||
if (thruster0->GetType()==FGThruster::ttPropeller)
|
||||
{
|
||||
ss.x.add(new FGStateSpace::Rpm0);
|
||||
// TODO add variable prop pitch property
|
||||
// if (variablePropPitch) ss.x.add(new FGStateSpace::PropPitch);
|
||||
int numEngines = fdm->GetPropulsion()->GetNumEngines();
|
||||
if (numEngines>1) ss.x.add(new FGStateSpace::Rpm1);
|
||||
if (numEngines>2) ss.x.add(new FGStateSpace::Rpm2);
|
||||
if (numEngines>3) ss.x.add(new FGStateSpace::Rpm3);
|
||||
if (numEngines>4) {
|
||||
std::cerr << "more than 4 engines not currently handled" << std::endl;
|
||||
}
|
||||
}
|
||||
ss.x.add(new FGStateSpace::Beta);
|
||||
ss.x.add(new FGStateSpace::Phi);
|
||||
ss.x.add(new FGStateSpace::P);
|
||||
ss.x.add(new FGStateSpace::Psi);
|
||||
ss.x.add(new FGStateSpace::R);
|
||||
ss.x.add(new FGStateSpace::Latitude);
|
||||
ss.x.add(new FGStateSpace::Longitude);
|
||||
ss.x.add(new FGStateSpace::Alt);
|
||||
|
||||
ss.u.add(new FGStateSpace::ThrottleCmd);
|
||||
ss.u.add(new FGStateSpace::DaCmd);
|
||||
ss.u.add(new FGStateSpace::DeCmd);
|
||||
ss.u.add(new FGStateSpace::DrCmd);
|
||||
|
||||
// state feedback
|
||||
ss.y = ss.x;
|
||||
|
||||
std::vector< std::vector<double> > A,B,C,D;
|
||||
std::vector<double> x0 = ss.x.get(), u0 = ss.u.get();
|
||||
std::vector<double> y0 = x0; // state feedback
|
||||
std::cout << ss << std::endl;
|
||||
|
||||
ss.linearize(x0,u0,y0,A,B,C,D);
|
||||
|
||||
int width=10;
|
||||
std::cout.precision(3);
|
||||
std::cout
|
||||
<< std::fixed
|
||||
<< std::right
|
||||
<< "\nA=\n" << std::setw(width) << A
|
||||
<< "\nB=\n" << std::setw(width) << B
|
||||
<< "\nC=\n" << std::setw(width) << C
|
||||
<< "\n* note: C should be identity, if not, indicates problem with model"
|
||||
<< "\nD=\n" << std::setw(width) << D
|
||||
<< std::endl;
|
||||
|
||||
// write scicoslab file
|
||||
std::string aircraft = fdm->GetAircraft()->GetAircraftName();
|
||||
std::ofstream scicos(std::string(aircraft+"_lin.sce").c_str());
|
||||
scicos.precision(10);
|
||||
width=20;
|
||||
scicos
|
||||
<< std::scientific
|
||||
<< aircraft << ".x0=..\n" << std::setw(width) << x0 << ";\n"
|
||||
<< aircraft << ".u0=..\n" << std::setw(width) << u0 << ";\n"
|
||||
<< aircraft << ".sys = syslin('c',..\n"
|
||||
<< std::setw(width) << A << ",..\n"
|
||||
<< std::setw(width) << B << ",..\n"
|
||||
<< std::setw(width) << C << ",..\n"
|
||||
<< std::setw(width) << D << ");\n"
|
||||
<< aircraft << ".tfm = ss2tf(" << aircraft << ".sys);\n"
|
||||
<< std::endl;
|
||||
|
||||
time_linDone = std::clock();
|
||||
std::cout << "\nlinearization computation time: " << (time_linDone - time_start)/double(CLOCKS_PER_SEC) << " s\n" << std::endl;
|
||||
}
|
||||
|
||||
|
||||
} // JSBSim
|
||||
|
||||
// vim:ts=4:sw=4
|
47
src/FDM/JSBSim/initialization/FGLinearization.h
Normal file
47
src/FDM/JSBSim/initialization/FGLinearization.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* FGLinearization.h
|
||||
* Copyright (C) James Goppert 2010 <james.goppert@gmail.com>
|
||||
*
|
||||
* FGLinearization.h is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FGLinearization.h is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FGLinearization_H_
|
||||
#define FGLinearization_H_
|
||||
|
||||
#include "initialization/FGTrimmer.h"
|
||||
#include "math/FGStateSpace.h"
|
||||
#include <iomanip>
|
||||
#include <fstream>
|
||||
#include "models/FGAircraft.h"
|
||||
#include "models/propulsion/FGEngine.h"
|
||||
#include "models/propulsion/FGTurbine.h"
|
||||
#include "models/propulsion/FGTurboProp.h"
|
||||
#include "math/FGNelderMead.h"
|
||||
#include <stdexcept>
|
||||
#include <fstream>
|
||||
#include <cstdlib>
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
class FGLinearization
|
||||
{
|
||||
public:
|
||||
FGLinearization(FGFDMExec * fdmPtr, int mode);
|
||||
};
|
||||
|
||||
} // JSBSim
|
||||
|
||||
#endif //FGLinearization_H_
|
||||
|
||||
// vim:ts=4:sw=4
|
|
@ -3,16 +3,16 @@
|
|||
* Copyright (C) James Goppert 2010 <james.goppert@gmail.com>
|
||||
*
|
||||
* FGSimplexTrim.cpp is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FGSimplexTrim.cpp is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
* See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* You should have received a copy of the GNU Lesser General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
@ -23,246 +23,95 @@ namespace JSBSim {
|
|||
|
||||
FGSimplexTrim::FGSimplexTrim(FGFDMExec * fdm, TrimMode mode)
|
||||
{
|
||||
std::clock_t time_start=clock(), time_trimDone, time_linDone;
|
||||
std::clock_t time_start=clock(), time_trimDone, time_linDone;
|
||||
|
||||
// variables
|
||||
fdm->Setdt(1./120);
|
||||
FGTrimmer::Constraints constraints;
|
||||
// variables
|
||||
FGTrimmer::Constraints constraints;
|
||||
|
||||
std::cout << "\n-----Performing Simplex Based Trim --------------\n" << std::endl;
|
||||
if (fdm->GetDebugLevel() > 0) {
|
||||
std::cout << "\n-----Performing Simplex Based Trim --------------\n" << std::endl;
|
||||
}
|
||||
|
||||
// defaults
|
||||
constraints.velocity = fdm->GetAuxiliary()->GetVt();
|
||||
constraints.altitude = fdm->GetPropagate()->GetAltitudeASL();
|
||||
std::string aircraft = fdm->GetAircraft()->GetAircraftName();
|
||||
double rtol = fdm->GetPropertyManager()->GetDouble("trim/solver/rtol");
|
||||
double abstol = fdm->GetPropertyManager()->GetDouble("trim/solver/abstol");
|
||||
double speed = fdm->GetPropertyManager()->GetDouble("trim/solver/speed"); // must be > 1, 2 typical
|
||||
double random = fdm->GetPropertyManager()->GetDouble("trim/solver/random");
|
||||
int iterMax = fdm->GetPropertyManager()->GetDouble("trim/solver/iterMax");
|
||||
bool showConvergeStatus = fdm->GetPropertyManager()->GetBool("trim/solver/showConvergeStatus");
|
||||
bool pause = fdm->GetPropertyManager()->GetBool("trim/solver/pause");
|
||||
bool showSimplex = fdm->GetPropertyManager()->GetBool("trim/solver/showSimplex");
|
||||
bool variablePropPitch = fdm->GetPropertyManager()->GetBool("trim/solver/variablePropPitch");
|
||||
//int debugLevel = fdm->GetPropertyManager()->GetInt("trim/solver/debugLevel");
|
||||
// defaults
|
||||
std::string aircraftName = fdm->GetAircraft()->GetAircraftName();
|
||||
FGPropertyNode* node = fdm->GetPropertyManager()->GetNode();
|
||||
double rtol = node->GetDouble("trim/solver/rtol");
|
||||
double abstol = node->GetDouble("trim/solver/abstol");
|
||||
double speed = node->GetDouble("trim/solver/speed"); // must be > 1, 2 typical
|
||||
double random = node->GetDouble("trim/solver/random");
|
||||
int iterMax = node->GetDouble("trim/solver/iterMax");
|
||||
bool showConvergence = node->GetBool("trim/solver/showConvergence");
|
||||
bool pause = node->GetBool("trim/solver/pause");
|
||||
bool showSimplex = node->GetBool("trim/solver/showSimplex");
|
||||
bool variablePropPitch = node->GetBool("trim/solver/variablePropPitch");
|
||||
|
||||
std::string fileName = aircraft;
|
||||
// flight conditions
|
||||
double phi = fdm->GetIC()->GetPhiRadIC();
|
||||
double theta = fdm->GetIC()->GetThetaRadIC();
|
||||
double psi = fdm->GetIC()->GetPsiRadIC();
|
||||
double gd = fdm->GetInertial()->gravity();
|
||||
|
||||
// input
|
||||
//std::cout << "input ( press enter to accept [default] )\n" << std::endl;
|
||||
constraints.velocity = fdm->GetIC()->GetVtrueFpsIC();
|
||||
constraints.altitude = fdm->GetIC()->GetAltitudeASLFtIC();
|
||||
constraints.gamma = fdm->GetIC()->GetFlightPathAngleRadIC();
|
||||
constraints.rollRate = 0;
|
||||
constraints.pitchRate = 0;
|
||||
constraints.yawRate = tan(phi)*gd*cos(theta)/constraints.velocity;
|
||||
|
||||
// load model
|
||||
std::string aircraftName = fdm->GetAircraft()->GetAircraftName();
|
||||
//prompt("\tdebug level\t\t",debugLevel);
|
||||
//fdm->SetDebugLevel(debugLevel);
|
||||
//std::cout << "model selection" << std::endl;
|
||||
//while (1)
|
||||
//{
|
||||
//prompt("\taircraft\t\t",aircraft);
|
||||
//prompt("\toutput file name\t",fileName);
|
||||
//fdm->LoadModel("../aircraft","../engine","../systems",aircraft);
|
||||
//aircraftName = fdm->GetAircraft()->GetAircraftName();
|
||||
//if (aircraftName == "")
|
||||
//{
|
||||
//std::cout << "\tfailed to load aircraft" << std::endl;
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
//std::cout << "\tsuccessfully loaded: " << aircraftName << std::endl;
|
||||
//break;
|
||||
//}
|
||||
//}
|
||||
|
||||
// Turn on propulsion system
|
||||
fdm->GetPropulsion()->InitRunning(-1);
|
||||
|
||||
// get propulsion pointer to determine type/ etc.
|
||||
FGEngine * engine0 = fdm->GetPropulsion()->GetEngine(0);
|
||||
FGThruster * thruster0 = engine0->GetThruster();
|
||||
|
||||
// flight conditions
|
||||
//std::cout << "\nflight conditions: " << std::endl;
|
||||
//prompt("\taltitude, ft\t\t",constraints.altitude);
|
||||
//prompt("\tvelocity, ft/s\t\t",constraints.velocity);
|
||||
//prompt("\tgamma, deg\t\t",constraints.gamma); constraints.gamma = constraints.gamma*M_PI/180;
|
||||
|
||||
//double phi = fdm->GetPropagate()->GetEuler(1);
|
||||
double theta = fdm->GetPropagate()->GetEuler(2);
|
||||
//double psi = fdm->GetPropagate()->GetEuler(3);
|
||||
|
||||
// TODO check that this works properly
|
||||
constraints.gamma = theta;
|
||||
|
||||
//if (thruster0->GetType()==FGThruster::ttPropeller)
|
||||
//prompt("\tvariable prop pitch?\t\t",variablePropPitch);
|
||||
// FIXME, enable
|
||||
|
||||
constraints.rollRate = fdm->GetIC()->GetPRadpsIC();
|
||||
constraints.pitchRate = fdm->GetIC()->GetQRadpsIC();
|
||||
constraints.yawRate = fdm->GetIC()->GetRRadpsIC();
|
||||
constraints.stabAxisRoll = true; // FIXME, make this an option
|
||||
|
||||
// solver properties
|
||||
// TODO make these options
|
||||
//std::cout << "\nsolver properties: " << std::endl;
|
||||
//std::cout << std::scientific;
|
||||
//prompt("\tshow converge status?\t",showConvergeStatus);
|
||||
//prompt("\tshow simplex?\t\t",showSimplex);
|
||||
//prompt("\tpause?\t\t\t",pause);
|
||||
//prompt("\trelative tolerance\t",rtol);
|
||||
//prompt("\tabsolute tolerance\t",abstol);
|
||||
//prompt("\tmax iterations\t\t",iterMax);
|
||||
//prompt("\tconvergence speed\t",speed);
|
||||
//prompt("\trandomization ratio\t",random);
|
||||
//std::cout << std::fixed;
|
||||
// initial solver state
|
||||
int n = 6;
|
||||
std::vector<double> initialGuess(n), lowerBound(n), upperBound(n), initialStepSize(n);
|
||||
|
||||
// initial solver state
|
||||
int n = 6;
|
||||
std::vector<double> initialGuess(n), lowerBound(n), upperBound(n), initialStepSize(n);
|
||||
lowerBound[0] = node->GetDouble("trim/solver/throttleMin");
|
||||
lowerBound[1] = node->GetDouble("trim/solver/elevatorMin");
|
||||
lowerBound[2] = node->GetDouble("trim/solver/alphaMin");
|
||||
lowerBound[3] = node->GetDouble("trim/solver/aileronMin");
|
||||
lowerBound[4] = node->GetDouble("trim/solver/rudderMin");
|
||||
lowerBound[5] = node->GetDouble("trim/solver/betaMin");
|
||||
|
||||
lowerBound[0] = fdm->GetPropertyManager()->GetDouble("trim/solver/throttleMin");
|
||||
lowerBound[1] = fdm->GetPropertyManager()->GetDouble("trim/solver/elevatorMin");
|
||||
lowerBound[2] = fdm->GetPropertyManager()->GetDouble("trim/solver/alphaMin");
|
||||
lowerBound[3] = fdm->GetPropertyManager()->GetDouble("trim/solver/aileronMin");
|
||||
lowerBound[4] = fdm->GetPropertyManager()->GetDouble("trim/solver/rudderMin");
|
||||
lowerBound[5] = fdm->GetPropertyManager()->GetDouble("trim/solver/betaMin");
|
||||
upperBound[0] = node->GetDouble("trim/solver/throttleMax");
|
||||
upperBound[1] = node->GetDouble("trim/solver/elevatorMax");
|
||||
upperBound[2] = node->GetDouble("trim/solver/alphaMax");
|
||||
upperBound[3] = node->GetDouble("trim/solver/aileronMax");
|
||||
upperBound[4] = node->GetDouble("trim/solver/rudderMax");
|
||||
upperBound[5] = node->GetDouble("trim/solver/betaMax");
|
||||
|
||||
upperBound[0] = fdm->GetPropertyManager()->GetDouble("trim/solver/throttleMax");
|
||||
upperBound[1] = fdm->GetPropertyManager()->GetDouble("trim/solver/elevatorMax");
|
||||
upperBound[2] = fdm->GetPropertyManager()->GetDouble("trim/solver/alphaMax");
|
||||
upperBound[3] = fdm->GetPropertyManager()->GetDouble("trim/solver/aileronMax");
|
||||
upperBound[4] = fdm->GetPropertyManager()->GetDouble("trim/solver/rudderMax");
|
||||
upperBound[5] = fdm->GetPropertyManager()->GetDouble("trim/solver/betaMax");
|
||||
initialStepSize[0] = node->GetDouble("trim/solver/throttleStep");
|
||||
initialStepSize[1] = node->GetDouble("trim/solver/elevatorStep");
|
||||
initialStepSize[2] = node->GetDouble("trim/solver/alphaStep");
|
||||
initialStepSize[3] = node->GetDouble("trim/solver/aileronStep");
|
||||
initialStepSize[4] = node->GetDouble("trim/solver/rudderStep");
|
||||
initialStepSize[5] = node->GetDouble("trim/solver/betaStep");
|
||||
|
||||
initialStepSize[0] = fdm->GetPropertyManager()->GetDouble("trim/solver/throttleStep");
|
||||
initialStepSize[1] = fdm->GetPropertyManager()->GetDouble("trim/solver/elevatorStep");
|
||||
initialStepSize[2] = fdm->GetPropertyManager()->GetDouble("trim/solver/alphaStep");
|
||||
initialStepSize[3] = fdm->GetPropertyManager()->GetDouble("trim/solver/aileronStep");
|
||||
initialStepSize[4] = fdm->GetPropertyManager()->GetDouble("trim/solver/rudderStep");
|
||||
initialStepSize[5] = fdm->GetPropertyManager()->GetDouble("trim/solver/betaStep");
|
||||
initialGuess[0] = node->GetDouble("trim/solver/throttleGuess");
|
||||
initialGuess[1] = node->GetDouble("trim/solver/elevatorGuess");
|
||||
initialGuess[2] = node->GetDouble("trim/solver/alphaGuess");
|
||||
initialGuess[3] = node->GetDouble("trim/solver/aileronGuess");
|
||||
initialGuess[4] = node->GetDouble("trim/solver/rudderGuess");
|
||||
initialGuess[5] = node->GetDouble("trim/solver/betaGuess");
|
||||
|
||||
initialGuess[0] = fdm->GetPropertyManager()->GetDouble("trim/solver/throttleGuess");
|
||||
initialGuess[1] = fdm->GetPropertyManager()->GetDouble("trim/solver/elevatorGuess");
|
||||
initialGuess[2] = fdm->GetPropertyManager()->GetDouble("trim/solver/alphaGuess");
|
||||
initialGuess[3] = fdm->GetPropertyManager()->GetDouble("trim/solver/aileronGuess");
|
||||
initialGuess[4] = fdm->GetPropertyManager()->GetDouble("trim/solver/rudderGuess");
|
||||
initialGuess[5] = fdm->GetPropertyManager()->GetDouble("trim/solver/betaGuess");
|
||||
// solve
|
||||
FGTrimmer * trimmer = new FGTrimmer(fdm, &constraints);
|
||||
Callback callback(aircraftName, trimmer);
|
||||
FGNelderMead * solver = NULL;
|
||||
|
||||
// solve
|
||||
FGTrimmer trimmer(fdm, &constraints);
|
||||
Callback callback(fileName,&trimmer);
|
||||
FGNelderMead * solver = NULL;
|
||||
try
|
||||
{
|
||||
solver = new FGNelderMead(&trimmer,initialGuess,
|
||||
lowerBound, upperBound, initialStepSize,iterMax,rtol,
|
||||
abstol,speed,random,showConvergeStatus,showSimplex,pause,&callback);
|
||||
while(solver->status()==1) solver->update();
|
||||
}
|
||||
catch (const std::runtime_error & e)
|
||||
{
|
||||
std::cout << e.what() << std::endl;
|
||||
//exit(1);
|
||||
}
|
||||
solver = new FGNelderMead(trimmer,initialGuess,
|
||||
lowerBound, upperBound, initialStepSize,iterMax,rtol,
|
||||
abstol,speed,random,showConvergence,showSimplex,pause,&callback);
|
||||
while(solver->status()==1) solver->update();
|
||||
time_trimDone = std::clock();
|
||||
|
||||
// output
|
||||
try
|
||||
{
|
||||
trimmer.printSolution(std::cout,solver->getSolution()); // this also loads the solution into the fdm
|
||||
std::cout << "\nfinal cost: " << std::scientific << std::setw(10) << trimmer.eval(solver->getSolution()) << std::endl;
|
||||
}
|
||||
catch(std::runtime_error & e)
|
||||
{
|
||||
std::cout << "caught std::runtime error" << std::endl;
|
||||
std::cout << "exception: " << e.what() << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
time_trimDone = std::clock();
|
||||
std::cout << "\ntrim computation time: " << (time_trimDone - time_start)/double(CLOCKS_PER_SEC) << "s \n" << std::endl;
|
||||
|
||||
//std::cout << "\nsimulating flight to determine trim stability" << std::endl;
|
||||
|
||||
//std::cout << "\nt = 5 seconds" << std::endl;
|
||||
//for (int i=0;i<5*120;i++) fdm->Run();
|
||||
//trimmer.printState();
|
||||
|
||||
//std::cout << "\nt = 10 seconds" << std::endl;
|
||||
//for (int i=0;i<5*120;i++) fdm->Run();
|
||||
//trimmer.printState();
|
||||
|
||||
std::cout << "\nlinearization: " << std::endl;
|
||||
FGStateSpace ss(fdm);
|
||||
|
||||
ss.x.add(new FGStateSpace::Vt);
|
||||
ss.x.add(new FGStateSpace::Alpha);
|
||||
ss.x.add(new FGStateSpace::Theta);
|
||||
ss.x.add(new FGStateSpace::Q);
|
||||
|
||||
if (thruster0->GetType()==FGThruster::ttPropeller)
|
||||
{
|
||||
ss.x.add(new FGStateSpace::Rpm0);
|
||||
if (variablePropPitch) ss.x.add(new FGStateSpace::PropPitch);
|
||||
int numEngines = fdm->GetPropulsion()->GetNumEngines();
|
||||
if (numEngines>1) ss.x.add(new FGStateSpace::Rpm1);
|
||||
if (numEngines>2) ss.x.add(new FGStateSpace::Rpm2);
|
||||
if (numEngines>3) ss.x.add(new FGStateSpace::Rpm3);
|
||||
}
|
||||
ss.x.add(new FGStateSpace::Beta);
|
||||
ss.x.add(new FGStateSpace::Phi);
|
||||
ss.x.add(new FGStateSpace::P);
|
||||
ss.x.add(new FGStateSpace::Psi);
|
||||
ss.x.add(new FGStateSpace::R);
|
||||
ss.x.add(new FGStateSpace::Latitude);
|
||||
ss.x.add(new FGStateSpace::Longitude);
|
||||
ss.x.add(new FGStateSpace::Alt);
|
||||
|
||||
ss.u.add(new FGStateSpace::ThrottleCmd);
|
||||
ss.u.add(new FGStateSpace::DaCmd);
|
||||
ss.u.add(new FGStateSpace::DeCmd);
|
||||
ss.u.add(new FGStateSpace::DrCmd);
|
||||
|
||||
// state feedback
|
||||
ss.y = ss.x;
|
||||
|
||||
std::vector< std::vector<double> > A,B,C,D;
|
||||
std::vector<double> x0 = ss.x.get(), u0 = ss.u.get();
|
||||
std::vector<double> y0 = x0; // state feedback
|
||||
std::cout << ss << std::endl;
|
||||
|
||||
ss.linearize(x0,u0,y0,A,B,C,D);
|
||||
|
||||
int width=10;
|
||||
std::cout.precision(3);
|
||||
std::cout
|
||||
<< std::fixed
|
||||
<< std::right
|
||||
<< "\nA=\n" << std::setw(width) << A
|
||||
<< "\nB=\n" << std::setw(width) << B
|
||||
<< "\nC=\n" << std::setw(width) << C
|
||||
<< "\nD=\n" << std::setw(width) << D
|
||||
<< std::endl;
|
||||
|
||||
// write scicoslab file
|
||||
std::ofstream scicos(std::string(aircraft+"_lin.sce").c_str());
|
||||
scicos.precision(10);
|
||||
width=20;
|
||||
scicos
|
||||
<< std::scientific
|
||||
<< aircraft << ".x0=..\n" << std::setw(width) << x0 << ";\n"
|
||||
<< aircraft << ".u0=..\n" << std::setw(width) << u0 << ";\n"
|
||||
<< aircraft << ".sys = syslin('c',..\n"
|
||||
<< std::setw(width) << A << ",..\n"
|
||||
<< std::setw(width) << B << ",..\n"
|
||||
<< std::setw(width) << C << ",..\n"
|
||||
<< std::setw(width) << D << ");\n"
|
||||
<< aircraft << ".tfm = ss2tf(" << aircraft << ".sys);\n"
|
||||
<< std::endl;
|
||||
|
||||
time_linDone = std::clock();
|
||||
std::cout << "\nlinearization computation time: " << (time_linDone - time_trimDone)/double(CLOCKS_PER_SEC) << " s\n" << std::endl;
|
||||
// output
|
||||
if (fdm->GetDebugLevel() > 0) {
|
||||
trimmer->printSolution(std::cout,solver->getSolution());
|
||||
std::cout << "\nfinal cost: " << std::scientific << std::setw(10) << trimmer->eval(solver->getSolution()) << std::endl;
|
||||
std::cout << "\ntrim computation time: " << (time_trimDone - time_start)/double(CLOCKS_PER_SEC) << "s \n" << std::endl;
|
||||
}
|
||||
|
||||
if (solver) delete solver;
|
||||
if (trimmer) delete trimmer;
|
||||
}
|
||||
|
||||
} // JSBSim
|
||||
|
|
|
@ -3,16 +3,16 @@
|
|||
* Copyright (C) James Goppert 2010 <james.goppert@gmail.com>
|
||||
*
|
||||
* FGSimplexTrim.h is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FGSimplexTrim.h is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
* See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* You should have received a copy of the GNU Lesser General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
@ -37,41 +37,41 @@ namespace JSBSim {
|
|||
class FGSimplexTrim
|
||||
{
|
||||
public:
|
||||
FGSimplexTrim(FGFDMExec * fdmPtr, TrimMode mode);
|
||||
FGSimplexTrim(FGFDMExec * fdmPtr, TrimMode mode);
|
||||
private:
|
||||
template <class varType>
|
||||
void prompt(const std::string & str, varType & var)
|
||||
{
|
||||
std::cout << str + " [" << std::setw(10) << var << "]\t: ";
|
||||
if (std::cin.peek() != '\n')
|
||||
{
|
||||
std::cin >> var;
|
||||
std::cin.ignore(1000, '\n');
|
||||
}
|
||||
else std::cin.get();
|
||||
}
|
||||
template <class varType>
|
||||
void prompt(const std::string & str, varType & var)
|
||||
{
|
||||
std::cout << str + " [" << std::setw(10) << var << "]\t: ";
|
||||
if (std::cin.peek() != '\n')
|
||||
{
|
||||
std::cin >> var;
|
||||
std::cin.ignore(1000, '\n');
|
||||
}
|
||||
else std::cin.get();
|
||||
}
|
||||
|
||||
class Callback : public JSBSim::FGNelderMead::Callback
|
||||
{
|
||||
private:
|
||||
std::ofstream _outputFile;
|
||||
JSBSim::FGTrimmer * _trimmer;
|
||||
public:
|
||||
Callback(std::string fileName, JSBSim::FGTrimmer * trimmer) :
|
||||
_outputFile((fileName + std::string("_simplexTrim.log")).c_str()),
|
||||
_trimmer(trimmer) {
|
||||
}
|
||||
virtual ~Callback() {
|
||||
_outputFile.close();
|
||||
}
|
||||
void eval(const std::vector<double> &v)
|
||||
{
|
||||
_outputFile << _trimmer->eval(v) << std::endl;;
|
||||
//std::cout << "v: ";
|
||||
//for (int i=0;i<v.size();i++) std::cout << v[i] << " ";
|
||||
//std::cout << std::endl;
|
||||
}
|
||||
};
|
||||
class Callback : public JSBSim::FGNelderMead::Callback
|
||||
{
|
||||
private:
|
||||
std::ofstream _outputFile;
|
||||
JSBSim::FGTrimmer * _trimmer;
|
||||
public:
|
||||
Callback(std::string fileName, JSBSim::FGTrimmer * trimmer) :
|
||||
_outputFile((fileName + std::string("_simplexTrim.log")).c_str()),
|
||||
_trimmer(trimmer) {
|
||||
}
|
||||
virtual ~Callback() {
|
||||
_outputFile.close();
|
||||
}
|
||||
void eval(const std::vector<double> &v)
|
||||
{
|
||||
_outputFile << _trimmer->eval(v) << std::endl;;
|
||||
//std::cout << "v: ";
|
||||
//for (int i=0;i<v.size();i++) std::cout << v[i] << " ";
|
||||
//std::cout << std::endl;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
} // JSBSim
|
||||
|
|
|
@ -3,16 +3,16 @@
|
|||
* Copyright (C) James Goppert 2010 <james.goppert@gmail.com>
|
||||
*
|
||||
* FGTrimmer.cpp is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FGTrimmer.cpp is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
* See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* You should have received a copy of the GNU Lesser General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
@ -39,44 +39,56 @@ FGTrimmer::FGTrimmer(FGFDMExec * fdm, Constraints * constraints) :
|
|||
{
|
||||
}
|
||||
|
||||
std::vector<double> FGTrimmer::constrain(const std::vector<double> & v)
|
||||
FGTrimmer::~FGTrimmer()
|
||||
{
|
||||
}
|
||||
|
||||
std::vector<double> FGTrimmer::constrain(const std::vector<double> & dv)
|
||||
{
|
||||
// unpack design vector
|
||||
double throttle = v[0];
|
||||
double elevator = v[1];
|
||||
double alpha = v[2];
|
||||
double aileron = v[3];
|
||||
double rudder = v[4];
|
||||
double beta = v[5];
|
||||
double throttle = dv[0];
|
||||
double elevator = dv[1];
|
||||
double alpha = dv[2];
|
||||
double aileron = dv[3];
|
||||
double rudder = dv[4];
|
||||
double beta = dv[5];
|
||||
|
||||
// initialize constraints
|
||||
double vt = m_constraints->velocity;
|
||||
double altitude = m_constraints->altitude;
|
||||
double phi = 0.0, theta = 0.0, psi = 0.0*M_PI/180.0;
|
||||
double gamma = m_constraints->gamma;
|
||||
double phi = m_fdm->GetIC()->GetPhiRadIC();
|
||||
double theta = m_fdm->GetIC()->GetThetaRadIC();
|
||||
double psi = m_fdm->GetIC()->GetPsiRadIC();
|
||||
double p = 0.0, q = 0.0, r= 0.0;
|
||||
double u = vt*cos(alpha)*cos(beta);
|
||||
double v = vt*sin(beta);
|
||||
double w = vt*sin(alpha)*cos(beta);
|
||||
double lat = m_fdm->GetIC()->GetLatitudeRadIC();
|
||||
double lon = m_fdm->GetIC()->GetLongitudeRadIC();
|
||||
|
||||
// precomputation
|
||||
double sGam = sin(m_constraints->gamma);
|
||||
double sGam = sin(gamma);
|
||||
double sBeta = sin(beta);
|
||||
double cBeta = cos(beta);
|
||||
double tAlpha = tan(alpha);
|
||||
double cAlpha = cos(alpha);
|
||||
|
||||
// rate of climb constraint
|
||||
double a = cAlpha*cBeta;
|
||||
double b = sin(phi)*sBeta+cos(phi)*sin(alpha)*cBeta;
|
||||
theta = atan((a*b+sGam*sqrt(a*a-sGam*sGam+b*b))/(a*a-sGam*sGam));
|
||||
|
||||
// turn coordination constraint, lewis pg. 190
|
||||
double gd = m_fdm->GetInertial()->gravity();
|
||||
double gc = m_constraints->yawRate*vt/gd;
|
||||
a = 1 - gc*tAlpha*sBeta;
|
||||
b = sGam/cBeta;
|
||||
double a = 1 - gc*tAlpha*sBeta;
|
||||
double b = sGam/cBeta;
|
||||
double c = 1 + gc*gc*cBeta*cBeta;
|
||||
phi = atan((gc*cBeta*((a-b*b)+
|
||||
b*tAlpha*sqrt(c*(1-b*b)+gc*gc*sBeta*sBeta)))/
|
||||
(cAlpha*(a*a-b*b*(1+c*tAlpha*tAlpha))));
|
||||
|
||||
// rate of climb constraint
|
||||
a = cAlpha*cBeta;
|
||||
b = sin(phi)*sBeta+cos(phi)*sin(alpha)*cBeta;
|
||||
theta = atan((a*b+sGam*sqrt(a*a-sGam*sGam+b*b))/(a*a-sGam*sGam));
|
||||
|
||||
// turn rates
|
||||
if (m_constraints->rollRate != 0.0) // rolling
|
||||
{
|
||||
|
@ -104,28 +116,13 @@ std::vector<double> FGTrimmer::constrain(const std::vector<double> & v)
|
|||
r = 0.0;
|
||||
}
|
||||
|
||||
// state
|
||||
m_fdm->GetIC()->SetVtrueFpsIC(vt);
|
||||
m_fdm->GetIC()->SetAlphaRadIC(alpha);
|
||||
m_fdm->GetIC()->SetThetaRadIC(theta);
|
||||
m_fdm->GetIC()->SetFlightPathAngleRadIC(m_constraints->gamma);
|
||||
m_fdm->GetIC()->SetQRadpsIC(q);
|
||||
// thrust handled below
|
||||
m_fdm->GetIC()->SetBetaRadIC(beta);
|
||||
m_fdm->GetIC()->SetPhiRadIC(phi);
|
||||
m_fdm->GetIC()->SetPRadpsIC(p);
|
||||
m_fdm->GetIC()->SetRRadpsIC(r);
|
||||
|
||||
// actuator states handled below
|
||||
|
||||
// nav state
|
||||
m_fdm->GetIC()->SetAltitudeASLFtIC(altitude);
|
||||
m_fdm->GetIC()->SetPsiRadIC(psi);
|
||||
//m_fdm->GetIC()->SetLatitudeRadIC(0);
|
||||
//m_fdm->GetIC()->SetLongitudeRadIC(0);
|
||||
|
||||
// apply state
|
||||
m_fdm->RunIC();
|
||||
m_fdm->GetIC()->ResetIC(u, v, w,
|
||||
p, q, r,
|
||||
alpha, beta,
|
||||
phi, theta, psi,
|
||||
lat, lon, altitude,
|
||||
gamma);
|
||||
|
||||
// set controls
|
||||
m_fdm->GetFCS()->SetDeCmd(elevator);
|
||||
|
@ -140,37 +137,46 @@ std::vector<double> FGTrimmer::constrain(const std::vector<double> & v)
|
|||
|
||||
for (unsigned int i=0; i<m_fdm->GetPropulsion()->GetNumEngines(); i++)
|
||||
{
|
||||
//FGEngine * engine = m_fdm->GetPropulsion()->GetEngine(i);
|
||||
m_fdm->GetPropulsion()->GetEngine(i)->InitRunning();
|
||||
m_fdm->GetFCS()->SetThrottleCmd(i,throttle);
|
||||
m_fdm->GetFCS()->SetThrottlePos(i,throttle);
|
||||
}
|
||||
|
||||
// initialize
|
||||
m_fdm->Initialize(m_fdm->GetIC());
|
||||
for (unsigned int i=0; i<m_fdm->GetPropulsion()->GetNumEngines(); i++) {
|
||||
m_fdm->GetPropulsion()->GetEngine(i)->InitRunning();
|
||||
}
|
||||
|
||||
// wait for steady-state
|
||||
//double thrust0 = m_fdm->GetPropulsion()->GetEngine(0)->GetThruster()->GetThrust();
|
||||
//double dThrustMag0 = 0;
|
||||
//for(int i=0;;i++) {
|
||||
//m_fdm->RunIC();
|
||||
//m_fdm->Run();
|
||||
//double thrust = m_fdm->GetPropulsion()->GetEngine(0)->GetThruster()->GetThrust();
|
||||
//double dThrustMag = std::abs(thrust - thrust0);
|
||||
//double d2Thrust = dThrustMag - dThrustMag0;
|
||||
//thrust0= thrust;
|
||||
//dThrustMag0 = dThrustMag;
|
||||
//if (d2Thrust < std::numeric_limits<double>::epsilon() ) {
|
||||
//// thrust difference has converged to minimum
|
||||
//// if d2Thrust > 0 clearly, more interations won't help
|
||||
//// so not using abs(d2Thrust)
|
||||
//break;
|
||||
//} else if (i> 1000) {
|
||||
//std::cout << "thrust failed to converge" << std::endl;
|
||||
//std::cout << "difference: " << dThrustMag << std::endl;
|
||||
//throw std::runtime_error("thrust failed to converge");
|
||||
//break;
|
||||
//}
|
||||
//}
|
||||
//m_fdm->RunIC();
|
||||
// wait for stable state
|
||||
double cost = compute_cost();
|
||||
for(int i=0;;i++) {
|
||||
m_fdm->GetPropulsion()->GetSteadyState();
|
||||
m_fdm->SetTrimStatus(true);
|
||||
m_fdm->DisableOutput();
|
||||
m_fdm->SuspendIntegration();
|
||||
m_fdm->Run();
|
||||
m_fdm->SetTrimStatus(false);
|
||||
m_fdm->EnableOutput();
|
||||
m_fdm->ResumeIntegration();
|
||||
|
||||
double costNew = compute_cost();
|
||||
double dcost = fabs(costNew - cost);
|
||||
if (dcost < std::numeric_limits<double>::epsilon()) {
|
||||
if(m_fdm->GetDebugLevel() > 1) {
|
||||
std::cout << "cost convergd, i: " << i << std::endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (i > 1000) {
|
||||
if(m_fdm->GetDebugLevel() > 1) {
|
||||
std::cout << "cost failed to converge, dcost: "
|
||||
<< std::scientific
|
||||
<< dcost << std::endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
cost = costNew;
|
||||
}
|
||||
|
||||
std::vector<double> data;
|
||||
data.push_back(phi);
|
||||
|
@ -182,7 +188,7 @@ void FGTrimmer::printSolution(std::ostream & stream, const std::vector<double> &
|
|||
{
|
||||
eval(v);
|
||||
|
||||
double dt = m_fdm->GetDeltaT();
|
||||
//double dt = m_fdm->GetDeltaT();
|
||||
double thrust = m_fdm->GetPropulsion()->GetEngine(0)->GetThruster()->GetThrust();
|
||||
double elevator = m_fdm->GetFCS()->GetDePos(ofNorm);
|
||||
double aileron = m_fdm->GetFCS()->GetDaLPos(ofNorm);
|
||||
|
@ -192,23 +198,15 @@ void FGTrimmer::printSolution(std::ostream & stream, const std::vector<double> &
|
|||
double lon = m_fdm->GetPropagate()->GetLongitudeDeg();
|
||||
double vt = m_fdm->GetAuxiliary()->GetVt();
|
||||
|
||||
// run a step to compute derivatives
|
||||
//for (int i=0;i<10000;i++) {
|
||||
//while (old - m_fdm->GetPropulsion()->GetEngine(i)->CalcFuelNeed() < 1e-5) {
|
||||
//m_fdm->RunIC();
|
||||
//m_fdm->Run();
|
||||
//}
|
||||
//}
|
||||
|
||||
double dthrust = (m_fdm->GetPropulsion()->GetEngine(0)->
|
||||
GetThruster()->GetThrust()-thrust)/dt;
|
||||
double delevator = (m_fdm->GetFCS()->GetDePos(ofNorm)-elevator)/dt;
|
||||
double daileron = (m_fdm->GetFCS()->GetDaLPos(ofNorm)-aileron)/dt;
|
||||
double drudder = (m_fdm->GetFCS()->GetDrPos(ofNorm)-rudder)/dt;
|
||||
double dthrottle = (m_fdm->GetFCS()->GetThrottlePos(0)-throttle)/dt;
|
||||
double dlat = (m_fdm->GetPropagate()->GetLatitudeDeg()-lat)/dt;
|
||||
double dlon = (m_fdm->GetPropagate()->GetLongitudeDeg()-lon)/dt;
|
||||
double dvt = (m_fdm->GetAuxiliary()->GetVt()-vt)/dt;
|
||||
//double dthrust = (m_fdm->GetPropulsion()->GetEngine(0)->
|
||||
//GetThruster()->GetThrust()-thrust)/dt;
|
||||
//double delevator = (m_fdm->GetFCS()->GetDePos(ofNorm)-elevator)/dt;
|
||||
//double daileron = (m_fdm->GetFCS()->GetDaLPos(ofNorm)-aileron)/dt;
|
||||
//double drudder = (m_fdm->GetFCS()->GetDrPos(ofNorm)-rudder)/dt;
|
||||
//double dthrottle = (m_fdm->GetFCS()->GetThrottlePos(0)-throttle)/dt;
|
||||
//double dlat = (m_fdm->GetPropagate()->GetLatitudeDeg()-lat)/dt;
|
||||
//double dlon = (m_fdm->GetPropagate()->GetLongitudeDeg()-lon)/dt;
|
||||
//double dvt = (m_fdm->GetAuxiliary()->GetVt()-vt)/dt;
|
||||
|
||||
// reinitialize with correct state
|
||||
eval(v);
|
||||
|
@ -247,29 +245,29 @@ void FGTrimmer::printSolution(std::ostream & stream, const std::vector<double> &
|
|||
<< "\n\naircraft d/dt state"
|
||||
<< std::scientific
|
||||
|
||||
<< "\n\td/dt vt\t\t\t:\t" << dvt
|
||||
//<< "\n\td/dt vt\t\t\t:\t" << dvt
|
||||
<< "\n\td/dt alpha, deg/s\t:\t" << m_fdm->GetAuxiliary()->Getadot()*180/M_PI
|
||||
<< "\n\td/dt theta, deg/s\t:\t" << m_fdm->GetAuxiliary()->GetEulerRates(2)*180/M_PI
|
||||
<< "\n\td/dt q, rad/s^2\t\t:\t" << m_fdm->GetAccelerations()->GetPQRdot(2)
|
||||
<< "\n\td/dt thrust, lbf\t:\t" << dthrust
|
||||
//<< "\n\td/dt thrust, lbf\t:\t" << dthrust
|
||||
<< "\n\td/dt beta, deg/s\t:\t" << m_fdm->GetAuxiliary()->Getbdot()*180/M_PI
|
||||
<< "\n\td/dt phi, deg/s\t\t:\t" << m_fdm->GetAuxiliary()->GetEulerRates(1)*180/M_PI
|
||||
<< "\n\td/dt p, rad/s^2\t\t:\t" << m_fdm->GetAccelerations()->GetPQRdot(1)
|
||||
<< "\n\td/dt r, rad/s^2\t\t:\t" << m_fdm->GetAccelerations()->GetPQRdot(3)
|
||||
|
||||
// d/dt actuator states
|
||||
<< "\n\nd/dt actuator state"
|
||||
<< "\n\td/dt throttle, %/s\t:\t" << dthrottle
|
||||
<< "\n\td/dt elevator, %/s\t:\t" << delevator
|
||||
<< "\n\td/dt aileron, %/s\t:\t" << daileron
|
||||
<< "\n\td/dt rudder, %/s\t:\t" << drudder
|
||||
//<< "\n\nd/dt actuator state"
|
||||
//<< "\n\td/dt throttle, %/s\t:\t" << dthrottle
|
||||
//<< "\n\td/dt elevator, %/s\t:\t" << delevator
|
||||
//<< "\n\td/dt aileron, %/s\t:\t" << daileron
|
||||
//<< "\n\td/dt rudder, %/s\t:\t" << drudder
|
||||
|
||||
// nav state
|
||||
<< "\n\nd/dt nav state"
|
||||
<< "\n\td/dt altitude, ft/s\t:\t" << m_fdm->GetPropagate()->Gethdot()
|
||||
<< "\n\td/dt psi, deg/s\t\t:\t" << m_fdm->GetAuxiliary()->GetEulerRates(3)
|
||||
<< "\n\td/dt lat, deg/s\t\t:\t" << dlat
|
||||
<< "\n\td/dt lon, deg/s\t\t:\t" << dlon
|
||||
//<< "\n\td/dt lat, deg/s\t\t:\t" << dlat
|
||||
//<< "\n\td/dt lon, deg/s\t\t:\t" << dlon
|
||||
<< std::fixed
|
||||
|
||||
<< "\n\npropulsion system state"
|
||||
|
@ -343,39 +341,17 @@ void FGTrimmer::printState(std::ostream & stream)
|
|||
|
||||
}
|
||||
|
||||
double FGTrimmer::eval(const std::vector<double> & v)
|
||||
double FGTrimmer::compute_cost()
|
||||
{
|
||||
double cost = 0;
|
||||
double cost0 = -1;
|
||||
|
||||
double dvt=0;
|
||||
double dalpha = 0;
|
||||
double dbeta = 0;
|
||||
double dp = 0;
|
||||
double dq = 0;
|
||||
double dr = 0;
|
||||
|
||||
double dvt0 = 0;
|
||||
double dalpha0 = 0;
|
||||
double dbeta0 = 0;
|
||||
double dp0 = 0;
|
||||
double dq0 = 0;
|
||||
double dr0 = 0;
|
||||
|
||||
uint16_t steadyCount = 0;
|
||||
|
||||
for(int i=0;;i++) {
|
||||
constrain(v);
|
||||
|
||||
dvt = (m_fdm->GetPropagate()->GetUVW(1)*m_fdm->GetAccelerations()->GetUVWdot(1) +
|
||||
double dvt = (m_fdm->GetPropagate()->GetUVW(1)*m_fdm->GetAccelerations()->GetUVWdot(1) +
|
||||
m_fdm->GetPropagate()->GetUVW(2)*m_fdm->GetAccelerations()->GetUVWdot(2) +
|
||||
m_fdm->GetPropagate()->GetUVW(3)*m_fdm->GetAccelerations()->GetUVWdot(3))/
|
||||
m_fdm->GetAuxiliary()->GetVt(); // from lewis, vtrue dot
|
||||
dalpha = m_fdm->GetAuxiliary()->Getadot();
|
||||
dbeta = m_fdm->GetAuxiliary()->Getbdot();
|
||||
dp = m_fdm->GetAccelerations()->GetPQRdot(1);
|
||||
dq = m_fdm->GetAccelerations()->GetPQRdot(2);
|
||||
dr = m_fdm->GetAccelerations()->GetPQRdot(3);
|
||||
double dalpha = m_fdm->GetAuxiliary()->Getadot();
|
||||
double dbeta = m_fdm->GetAuxiliary()->Getbdot();
|
||||
double dp = m_fdm->GetAccelerations()->GetPQRdot(1);
|
||||
double dq = m_fdm->GetAccelerations()->GetPQRdot(2);
|
||||
double dr = m_fdm->GetAccelerations()->GetPQRdot(3);
|
||||
|
||||
if(m_fdm->GetDebugLevel() > 1) {
|
||||
std::cout
|
||||
|
@ -388,33 +364,15 @@ double FGTrimmer::eval(const std::vector<double> & v)
|
|||
<< std::endl;
|
||||
}
|
||||
|
||||
cost = dvt*dvt +
|
||||
return dvt*dvt +
|
||||
100.0*(dalpha*dalpha + dbeta*dbeta) +
|
||||
10.0*(dp*dp + dq*dq + dr*dr);
|
||||
|
||||
double deltaCost = std::abs(cost - cost0);
|
||||
cost0 = cost;
|
||||
dvt0 = dvt;
|
||||
dalpha0 = dalpha;
|
||||
dbeta0 = dbeta;
|
||||
dp0 = dp;
|
||||
dq0 = dq;
|
||||
dr0 = dr;
|
||||
|
||||
if (deltaCost < 1e-10) {
|
||||
if (steadyCount++ > 3) break;
|
||||
} else if (i> 1000) {
|
||||
std::cout << "deltaCost: " << std::scientific << std::setw(10)
|
||||
<< deltaCost << std::endl;
|
||||
break;
|
||||
//throw std::runtime_error("cost failed to converge");
|
||||
} else {
|
||||
steadyCount=0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return cost;
|
||||
double FGTrimmer::eval(const std::vector<double> & v)
|
||||
{
|
||||
constrain(v);
|
||||
return compute_cost();
|
||||
}
|
||||
|
||||
} // JSBSim
|
||||
|
|
|
@ -3,16 +3,16 @@
|
|||
* Copyright (C) James Goppert 2010 <james.goppert@gmail.com>
|
||||
*
|
||||
* FGTrimmer.h is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FGTrimmer.h is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
* See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* You should have received a copy of the GNU Lesser General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
@ -42,9 +42,11 @@ public:
|
|||
bool coordinatedTurn, stabAxisRoll;
|
||||
};
|
||||
FGTrimmer(FGFDMExec * fdm, Constraints * constraints);
|
||||
std::vector<double> constrain(const vector<double> & v);
|
||||
~FGTrimmer();
|
||||
std::vector<double> constrain(const vector<double> & v);
|
||||
void printSolution(std::ostream & stream, const vector<double> & v);
|
||||
void printState(std::ostream & stream);
|
||||
double compute_cost();
|
||||
double eval(const vector<double> & v);
|
||||
static void limit(double min, double max, double &val)
|
||||
{
|
||||
|
|
|
@ -38,7 +38,6 @@ SENTRY
|
|||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include "FGJSBBase.h"
|
||||
#include "simgear/structure/SGReferenced.hxx"
|
||||
#include "simgear/structure/SGSharedPtr.hxx"
|
||||
|
||||
|
@ -46,7 +45,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_GROUNDCALLBACK "$Id: FGGroundCallback.h,v 1.15 2011/11/19 14:14:57 bcoconni Exp $"
|
||||
#define ID_GROUNDCALLBACK "$Id: FGGroundCallback.h,v 1.16 2013/02/02 13:23:40 bcoconni Exp $"
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
|
@ -63,14 +62,14 @@ CLASS DOCUMENTATION
|
|||
ball formed earth with an adjustable terrain elevation.
|
||||
|
||||
@author Mathias Froehlich
|
||||
@version $Id: FGGroundCallback.h,v 1.15 2011/11/19 14:14:57 bcoconni Exp $
|
||||
@version $Id: FGGroundCallback.h,v 1.16 2013/02/02 13:23:40 bcoconni Exp $
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS DECLARATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
class FGGroundCallback : public FGJSBBase, public SGReferenced
|
||||
class FGGroundCallback : public SGReferenced
|
||||
{
|
||||
public:
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ INCLUDES
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGOutputType.cpp,v 1.5 2013/01/14 22:44:51 bcoconni Exp $";
|
||||
static const char *IdSrc = "$Id: FGOutputType.cpp,v 1.6 2013/01/26 17:06:49 bcoconni Exp $";
|
||||
static const char *IdHdr = ID_OUTPUTTYPE;
|
||||
|
||||
using namespace std;
|
||||
|
@ -136,7 +136,7 @@ bool FGOutputType::Load(Element* element)
|
|||
while (property_element) {
|
||||
string caption="";
|
||||
string property_str = property_element->GetDataLine();
|
||||
FGPropertyManager* node = PropertyManager->GetNode(property_str);
|
||||
FGPropertyNode* node = PropertyManager->GetNode(property_str);
|
||||
if (!node) {
|
||||
cerr << fgred << highint << endl << " No property by the name "
|
||||
<< property_str << " has been defined. This property will " << endl
|
||||
|
|
|
@ -44,7 +44,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_OUTPUTTYPE "$Id: FGOutputType.h,v 1.4 2013/01/12 20:56:19 bcoconni Exp $"
|
||||
#define ID_OUTPUTTYPE "$Id: FGOutputType.h,v 1.5 2013/01/26 17:06:49 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -53,7 +53,6 @@ FORWARD DECLARATIONS
|
|||
namespace JSBSim {
|
||||
|
||||
class FGFDMExec;
|
||||
class FGPropertyManager;
|
||||
class Element;
|
||||
class FGAerodynamics;
|
||||
class FGAuxiliary;
|
||||
|
@ -122,7 +121,7 @@ public:
|
|||
/** Set the list of properties that should be output for this output instance.
|
||||
@param outputProperties list of properties that should be output
|
||||
*/
|
||||
void SetOutputProperties(std::vector<FGPropertyManager *> & outputProperties)
|
||||
void SetOutputProperties(std::vector<FGPropertyNode_ptr> & outputProperties)
|
||||
{
|
||||
OutputProperties = outputProperties;
|
||||
}
|
||||
|
@ -197,7 +196,7 @@ public:
|
|||
protected:
|
||||
int OutputIdx;
|
||||
int SubSystems;
|
||||
std::vector <FGPropertyManager*> OutputProperties;
|
||||
std::vector <FGPropertyNode_ptr> OutputProperties;
|
||||
std::vector <std::string> OutputCaptions;
|
||||
bool enabled;
|
||||
|
||||
|
|
|
@ -48,8 +48,6 @@ COMMENTS, REFERENCES, and NOTES [use "class documentation" below for API docs]
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
std::vector<SGPropertyNode_ptr> FGPropertyManager::tied_properties;
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGPropertyManager::Unbind(void)
|
||||
|
@ -81,32 +79,32 @@ string FGPropertyManager::mkPropertyName(string name, bool lowercase) {
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
FGPropertyManager*
|
||||
FGPropertyManager::GetNode (const string &path, bool create)
|
||||
FGPropertyNode*
|
||||
FGPropertyNode::GetNode (const string &path, bool create)
|
||||
{
|
||||
SGPropertyNode* node = getNode(path.c_str(), create);
|
||||
if (node == 0) {
|
||||
cerr << "FGPropertyManager::GetNode() No node found for " << path << endl;
|
||||
}
|
||||
return (FGPropertyManager*)node;
|
||||
return (FGPropertyNode*)node;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
FGPropertyManager*
|
||||
FGPropertyManager::GetNode (const string &relpath, int index, bool create)
|
||||
FGPropertyNode*
|
||||
FGPropertyNode::GetNode (const string &relpath, int index, bool create)
|
||||
{
|
||||
SGPropertyNode* node = getNode(relpath.c_str(), index, create);
|
||||
if (node == 0) {
|
||||
cerr << "FGPropertyManager::GetNode() No node found for " << relpath
|
||||
<< "[" << index << "]" << endl;
|
||||
}
|
||||
return (FGPropertyManager*)node;
|
||||
return (FGPropertyNode*)node;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
bool FGPropertyManager::HasNode (const string &path)
|
||||
bool FGPropertyNode::HasNode (const string &path)
|
||||
{
|
||||
const SGPropertyNode* node = getNode(path.c_str(), false);
|
||||
return (node != 0);
|
||||
|
@ -114,14 +112,14 @@ bool FGPropertyManager::HasNode (const string &path)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
string FGPropertyManager::GetName( void ) const
|
||||
string FGPropertyNode::GetName( void ) const
|
||||
{
|
||||
return string( getName() );
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
string FGPropertyManager::GetPrintableName( void ) const
|
||||
string FGPropertyNode::GetPrintableName( void ) const
|
||||
{
|
||||
string temp_string(getName());
|
||||
size_t initial_location=0;
|
||||
|
@ -142,7 +140,7 @@ string FGPropertyManager::GetPrintableName( void ) const
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
string FGPropertyManager::GetFullyQualifiedName(void) const
|
||||
string FGPropertyNode::GetFullyQualifiedName(void) const
|
||||
{
|
||||
vector<string> stack;
|
||||
stack.push_back( getDisplayName(true) );
|
||||
|
@ -168,7 +166,7 @@ string FGPropertyManager::GetFullyQualifiedName(void) const
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
string FGPropertyManager::GetRelativeName( const string &path ) const
|
||||
string FGPropertyNode::GetRelativeName( const string &path ) const
|
||||
{
|
||||
string temp_string = GetFullyQualifiedName();
|
||||
size_t len = path.length();
|
||||
|
@ -182,91 +180,91 @@ string FGPropertyManager::GetRelativeName( const string &path ) const
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
bool FGPropertyManager::GetBool (const string &name, bool defaultValue) const
|
||||
bool FGPropertyNode::GetBool (const string &name, bool defaultValue) const
|
||||
{
|
||||
return getBoolValue(name.c_str(), defaultValue);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
int FGPropertyManager::GetInt (const string &name, int defaultValue ) const
|
||||
int FGPropertyNode::GetInt (const string &name, int defaultValue ) const
|
||||
{
|
||||
return getIntValue(name.c_str(), defaultValue);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
int FGPropertyManager::GetLong (const string &name, long defaultValue ) const
|
||||
int FGPropertyNode::GetLong (const string &name, long defaultValue ) const
|
||||
{
|
||||
return getLongValue(name.c_str(), defaultValue);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
float FGPropertyManager::GetFloat (const string &name, float defaultValue ) const
|
||||
float FGPropertyNode::GetFloat (const string &name, float defaultValue ) const
|
||||
{
|
||||
return getFloatValue(name.c_str(), defaultValue);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGPropertyManager::GetDouble (const string &name, double defaultValue ) const
|
||||
double FGPropertyNode::GetDouble (const string &name, double defaultValue ) const
|
||||
{
|
||||
return getDoubleValue(name.c_str(), defaultValue);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
string FGPropertyManager::GetString (const string &name, string defaultValue ) const
|
||||
string FGPropertyNode::GetString (const string &name, string defaultValue ) const
|
||||
{
|
||||
return string(getStringValue(name.c_str(), defaultValue.c_str()));
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
bool FGPropertyManager::SetBool (const string &name, bool val)
|
||||
bool FGPropertyNode::SetBool (const string &name, bool val)
|
||||
{
|
||||
return setBoolValue(name.c_str(), val);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
bool FGPropertyManager::SetInt (const string &name, int val)
|
||||
bool FGPropertyNode::SetInt (const string &name, int val)
|
||||
{
|
||||
return setIntValue(name.c_str(), val);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
bool FGPropertyManager::SetLong (const string &name, long val)
|
||||
bool FGPropertyNode::SetLong (const string &name, long val)
|
||||
{
|
||||
return setLongValue(name.c_str(), val);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
bool FGPropertyManager::SetFloat (const string &name, float val)
|
||||
bool FGPropertyNode::SetFloat (const string &name, float val)
|
||||
{
|
||||
return setFloatValue(name.c_str(), val);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
bool FGPropertyManager::SetDouble (const string &name, double val)
|
||||
bool FGPropertyNode::SetDouble (const string &name, double val)
|
||||
{
|
||||
return setDoubleValue(name.c_str(), val);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
bool FGPropertyManager::SetString (const string &name, const string &val)
|
||||
bool FGPropertyNode::SetString (const string &name, const string &val)
|
||||
{
|
||||
return setStringValue(name.c_str(), val.c_str());
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGPropertyManager::SetArchivable (const string &name, bool state )
|
||||
void FGPropertyNode::SetArchivable (const string &name, bool state )
|
||||
{
|
||||
SGPropertyNode * node = getNode(name.c_str());
|
||||
if (node == 0)
|
||||
|
@ -279,7 +277,7 @@ void FGPropertyManager::SetArchivable (const string &name, bool state )
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGPropertyManager::SetReadable (const string &name, bool state )
|
||||
void FGPropertyNode::SetReadable (const string &name, bool state )
|
||||
{
|
||||
SGPropertyNode * node = getNode(name.c_str());
|
||||
if (node == 0)
|
||||
|
@ -292,7 +290,7 @@ void FGPropertyManager::SetReadable (const string &name, bool state )
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGPropertyManager::SetWritable (const string &name, bool state )
|
||||
void FGPropertyNode::SetWritable (const string &name, bool state )
|
||||
{
|
||||
SGPropertyNode * node = getNode(name.c_str());
|
||||
if (node == 0)
|
||||
|
@ -307,7 +305,7 @@ void FGPropertyManager::SetWritable (const string &name, bool state )
|
|||
|
||||
void FGPropertyManager::Untie (const string &name)
|
||||
{
|
||||
SGPropertyNode* property = getNode(name.c_str());
|
||||
SGPropertyNode* property = root->getNode(name.c_str());
|
||||
if (!property) {
|
||||
cerr << "Attempt to untie a non-existant property." << name << endl;
|
||||
return;
|
||||
|
@ -331,7 +329,7 @@ void FGPropertyManager::Untie (const string &name)
|
|||
|
||||
void FGPropertyManager::Tie (const string &name, bool *pointer, bool useDefault)
|
||||
{
|
||||
SGPropertyNode* property = getNode(name.c_str(), true);
|
||||
SGPropertyNode* property = root->getNode(name.c_str(), true);
|
||||
if (!property) {
|
||||
cerr << "Could not get or create property " << name << endl;
|
||||
return;
|
||||
|
@ -350,7 +348,7 @@ void FGPropertyManager::Tie (const string &name, bool *pointer, bool useDefault)
|
|||
void FGPropertyManager::Tie (const string &name, int *pointer,
|
||||
bool useDefault )
|
||||
{
|
||||
SGPropertyNode* property = getNode(name.c_str(), true);
|
||||
SGPropertyNode* property = root->getNode(name.c_str(), true);
|
||||
if (!property) {
|
||||
cerr << "Could not get or create property " << name << endl;
|
||||
return;
|
||||
|
@ -369,7 +367,7 @@ void FGPropertyManager::Tie (const string &name, int *pointer,
|
|||
void FGPropertyManager::Tie (const string &name, long *pointer,
|
||||
bool useDefault )
|
||||
{
|
||||
SGPropertyNode* property = getNode(name.c_str(), true);
|
||||
SGPropertyNode* property = root->getNode(name.c_str(), true);
|
||||
if (!property) {
|
||||
cerr << "Could not get or create property " << name << endl;
|
||||
return;
|
||||
|
@ -388,7 +386,7 @@ void FGPropertyManager::Tie (const string &name, long *pointer,
|
|||
void FGPropertyManager::Tie (const string &name, float *pointer,
|
||||
bool useDefault )
|
||||
{
|
||||
SGPropertyNode* property = getNode(name.c_str(), true);
|
||||
SGPropertyNode* property = root->getNode(name.c_str(), true);
|
||||
if (!property) {
|
||||
cerr << "Could not get or create property " << name << endl;
|
||||
return;
|
||||
|
@ -406,7 +404,7 @@ void FGPropertyManager::Tie (const string &name, float *pointer,
|
|||
|
||||
void FGPropertyManager::Tie (const string &name, double *pointer, bool useDefault)
|
||||
{
|
||||
SGPropertyNode* property = getNode(name.c_str(), true);
|
||||
SGPropertyNode* property = root->getNode(name.c_str(), true);
|
||||
if (!property) {
|
||||
cerr << "Could not get or create property " << name << endl;
|
||||
return;
|
||||
|
|
|
@ -53,7 +53,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_PROPERTYMANAGER "$Id: FGPropertyManager.h,v 1.24 2013/01/06 14:50:31 bcoconni Exp $"
|
||||
#define ID_PROPERTYMANAGER "$Id: FGPropertyManager.h,v 1.26 2013/06/10 01:49:06 jberndt Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -73,24 +73,11 @@ CLASS DOCUMENTATION
|
|||
CLASS DECLARATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
class FGPropertyManager : public SGPropertyNode
|
||||
class FGPropertyNode : public SGPropertyNode
|
||||
{
|
||||
private:
|
||||
static std::vector<SGPropertyNode_ptr> tied_properties;
|
||||
public:
|
||||
/// Constructor
|
||||
FGPropertyManager(void) {}
|
||||
/// Destructor
|
||||
virtual ~FGPropertyManager(void) {}
|
||||
|
||||
/** Property-ify a name
|
||||
* replaces spaces with '-' and, optionally, makes name all lower case
|
||||
* @param name string to change
|
||||
* @param lowercase true to change all upper case chars to lower
|
||||
* NOTE: this function changes its argument and thus relies
|
||||
* on pass by value
|
||||
*/
|
||||
std::string mkPropertyName(std::string name, bool lowercase);
|
||||
virtual ~FGPropertyNode(void) {}
|
||||
|
||||
/**
|
||||
* Get a property node.
|
||||
|
@ -99,10 +86,10 @@ class FGPropertyManager : public SGPropertyNode
|
|||
* @param create true to create the node if it doesn't exist.
|
||||
* @return The node, or 0 if none exists and none was created.
|
||||
*/
|
||||
FGPropertyManager*
|
||||
FGPropertyNode*
|
||||
GetNode (const std::string &path, bool create = false);
|
||||
|
||||
FGPropertyManager*
|
||||
FGPropertyNode*
|
||||
GetNode (const std::string &relpath, int index, bool create = false);
|
||||
|
||||
/**
|
||||
|
@ -384,7 +371,38 @@ class FGPropertyManager : public SGPropertyNode
|
|||
* @param state The state of the write attribute (defaults to true).
|
||||
*/
|
||||
void SetWritable (const std::string &name, bool state = true);
|
||||
};
|
||||
|
||||
typedef SGSharedPtr<FGPropertyNode> FGPropertyNode_ptr;
|
||||
typedef SGSharedPtr<const FGPropertyNode> FGConstPropertyNode_ptr;
|
||||
|
||||
class FGPropertyManager
|
||||
{
|
||||
public:
|
||||
/// Default constructor
|
||||
FGPropertyManager(void) { root = new FGPropertyNode; }
|
||||
|
||||
/// Constructor
|
||||
FGPropertyManager(FGPropertyNode* _root) : root(_root) {};
|
||||
|
||||
/// Destructor
|
||||
virtual ~FGPropertyManager(void) { Unbind(); }
|
||||
|
||||
FGPropertyNode* GetNode(void) const { return root; }
|
||||
FGPropertyNode* GetNode(const std::string &path, bool create = false)
|
||||
{ return root->GetNode(path, create); }
|
||||
FGPropertyNode* GetNode(const std::string &relpath, int index, bool create = false)
|
||||
{ return root->GetNode(relpath, index, create); }
|
||||
bool HasNode(const std::string& path) const { return root->HasNode(path); }
|
||||
|
||||
/** Property-ify a name
|
||||
* replaces spaces with '-' and, optionally, makes name all lower case
|
||||
* @param name string to change
|
||||
* @param lowercase true to change all upper case chars to lower
|
||||
* NOTE: this function changes its argument and thus relies
|
||||
* on pass by value
|
||||
*/
|
||||
std::string mkPropertyName(std::string name, bool lowercase);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Convenience functions for tying properties, with logging.
|
||||
|
@ -531,7 +549,7 @@ class FGPropertyManager : public SGPropertyNode
|
|||
template <class V> inline void
|
||||
Tie (const std::string &name, V (*getter)(), void (*setter)(V) = 0, bool useDefault = true)
|
||||
{
|
||||
SGPropertyNode* property = getNode(name.c_str(), true);
|
||||
SGPropertyNode* property = root->getNode(name.c_str(), true);
|
||||
if (!property) {
|
||||
std::cerr << "Could not get or create property " << name << std::endl;
|
||||
return;
|
||||
|
@ -540,6 +558,8 @@ class FGPropertyManager : public SGPropertyNode
|
|||
if (!property->tie(SGRawValueFunctions<V>(getter, setter), useDefault))
|
||||
std::cerr << "Failed to tie property " << name << " to functions" << std::endl;
|
||||
else {
|
||||
if (setter == 0) property->setAttribute(SGPropertyNode::WRITE, false);
|
||||
if (getter == 0) property->setAttribute(SGPropertyNode::READ, false);
|
||||
tied_properties.push_back(property);
|
||||
if (FGJSBBase::debug_lvl & 0x20) std::cout << name << std::endl;
|
||||
}
|
||||
|
@ -567,7 +587,7 @@ class FGPropertyManager : public SGPropertyNode
|
|||
template <class V> inline void Tie (const std::string &name, int index, V (*getter)(int),
|
||||
void (*setter)(int, V) = 0, bool useDefault = true)
|
||||
{
|
||||
SGPropertyNode* property = getNode(name.c_str(), true);
|
||||
SGPropertyNode* property = root->getNode(name.c_str(), true);
|
||||
if (!property) {
|
||||
std::cerr << "Could not get or create property " << name << std::endl;
|
||||
return;
|
||||
|
@ -576,6 +596,8 @@ class FGPropertyManager : public SGPropertyNode
|
|||
if (!property->tie(SGRawValueFunctionsIndexed<V>(index, getter, setter), useDefault))
|
||||
std::cerr << "Failed to tie property " << name << " to indexed functions" << std::endl;
|
||||
else {
|
||||
if (setter == 0) property->setAttribute(SGPropertyNode::WRITE, false);
|
||||
if (getter == 0) property->setAttribute(SGPropertyNode::READ, false);
|
||||
tied_properties.push_back(property);
|
||||
if (FGJSBBase::debug_lvl & 0x20) std::cout << name << std::endl;
|
||||
}
|
||||
|
@ -605,7 +627,7 @@ class FGPropertyManager : public SGPropertyNode
|
|||
Tie (const std::string &name, T * obj, V (T::*getter)() const,
|
||||
void (T::*setter)(V) = 0, bool useDefault = true)
|
||||
{
|
||||
SGPropertyNode* property = getNode(name.c_str(), true);
|
||||
SGPropertyNode* property = root->getNode(name.c_str(), true);
|
||||
if (!property) {
|
||||
std::cerr << "Could not get or create property " << name << std::endl;
|
||||
return;
|
||||
|
@ -614,6 +636,8 @@ class FGPropertyManager : public SGPropertyNode
|
|||
if (!property->tie(SGRawValueMethods<T,V>(*obj, getter, setter), useDefault))
|
||||
std::cerr << "Failed to tie property " << name << " to object methods" << std::endl;
|
||||
else {
|
||||
if (setter == 0) property->setAttribute(SGPropertyNode::WRITE, false);
|
||||
if (getter == 0) property->setAttribute(SGPropertyNode::READ, false);
|
||||
tied_properties.push_back(property);
|
||||
if (FGJSBBase::debug_lvl & 0x20) std::cout << name << std::endl;
|
||||
}
|
||||
|
@ -642,7 +666,7 @@ class FGPropertyManager : public SGPropertyNode
|
|||
Tie (const std::string &name, T * obj, int index, V (T::*getter)(int) const,
|
||||
void (T::*setter)(int, V) = 0, bool useDefault = true)
|
||||
{
|
||||
SGPropertyNode* property = getNode(name.c_str(), true);
|
||||
SGPropertyNode* property = root->getNode(name.c_str(), true);
|
||||
if (!property) {
|
||||
std::cerr << "Could not get or create property " << name << std::endl;
|
||||
return;
|
||||
|
@ -651,10 +675,16 @@ class FGPropertyManager : public SGPropertyNode
|
|||
if (!property->tie(SGRawValueMethodsIndexed<T,V>(*obj, index, getter, setter), useDefault))
|
||||
std::cerr << "Failed to tie property " << name << " to indexed object methods" << std::endl;
|
||||
else {
|
||||
if (setter == 0) property->setAttribute(SGPropertyNode::WRITE, false);
|
||||
if (getter == 0) property->setAttribute(SGPropertyNode::READ, false);
|
||||
tied_properties.push_back(property);
|
||||
if (FGJSBBase::debug_lvl & 0x20) std::cout << name << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<SGPropertyNode_ptr> tied_properties;
|
||||
FGPropertyNode_ptr root;
|
||||
};
|
||||
}
|
||||
#endif // FGPROPERTYMANAGER_H
|
||||
|
|
|
@ -55,7 +55,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGScript.cpp,v 1.50 2012/09/05 04:49:13 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGScript.cpp,v 1.51 2013/06/10 01:50:43 jberndt Exp $";
|
||||
static const char *IdHdr = ID_FGSCRIPT;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -309,7 +309,14 @@ bool FGScript::LoadScript(string script, double deltaT, const string initfile)
|
|||
set_element = event_element->FindElement("set");
|
||||
while (set_element) {
|
||||
prop_name = set_element->GetAttributeValue("name");
|
||||
if (PropertyManager->HasNode(prop_name)) {
|
||||
newEvent->SetParam.push_back( PropertyManager->GetNode(prop_name) );
|
||||
} else {
|
||||
newEvent->SetParam.push_back( 0L );
|
||||
cerr << "Property " << prop_name << " will be late-bound." << endl;
|
||||
}
|
||||
newEvent->SetParamName.push_back( prop_name );
|
||||
|
||||
//Todo - should probably do some safety checking here to make sure one or the other
|
||||
//of value or function is specified.
|
||||
if (!set_element->GetAttributeValue("value").empty()) {
|
||||
|
@ -374,104 +381,114 @@ bool FGScript::RunScript(void)
|
|||
|
||||
// Iterate over all events.
|
||||
for (unsigned int ev_ctr=0; ev_ctr < Events.size(); ev_ctr++) {
|
||||
|
||||
struct event &thisEvent = Events[ev_ctr];
|
||||
|
||||
// Determine whether the set of conditional tests for this condition equate
|
||||
// to true and should cause the event to execute. If the conditions evaluate
|
||||
// to true, then the event is triggered. If the event is not persistent,
|
||||
// then this trigger will remain set true. If the event is persistent,
|
||||
// the trigger will reset to false when the condition evaluates to false.
|
||||
if (Events[ev_ctr].Condition->Evaluate()) {
|
||||
if (!Events[ev_ctr].Triggered) {
|
||||
if (thisEvent.Condition->Evaluate()) {
|
||||
if (!thisEvent.Triggered) {
|
||||
|
||||
// The conditions are true, do the setting of the desired Event parameters
|
||||
for (i=0; i<Events[ev_ctr].SetValue.size(); i++) {
|
||||
Events[ev_ctr].OriginalValue[i] = Events[ev_ctr].SetParam[i]->getDoubleValue();
|
||||
if (Events[ev_ctr].Functions[i] != 0) { // Parameter should be set to a function value
|
||||
for (i=0; i<thisEvent.SetValue.size(); i++) {
|
||||
if (thisEvent.SetParam[i] == 0L) { // Late bind property if necessary
|
||||
if (PropertyManager->HasNode(thisEvent.SetParamName[i])) {
|
||||
thisEvent.SetParam[i] = PropertyManager->GetNode(thisEvent.SetParamName[i]);
|
||||
} else {
|
||||
throw("No property, \""+thisEvent.SetParamName[i]+"\" is defined.");
|
||||
}
|
||||
}
|
||||
thisEvent.OriginalValue[i] = thisEvent.SetParam[i]->getDoubleValue();
|
||||
if (thisEvent.Functions[i] != 0) { // Parameter should be set to a function value
|
||||
try {
|
||||
Events[ev_ctr].SetValue[i] = Events[ev_ctr].Functions[i]->GetValue();
|
||||
thisEvent.SetValue[i] = thisEvent.Functions[i]->GetValue();
|
||||
} catch (string msg) {
|
||||
std::cerr << std::endl << "A problem occurred in the execution of the script. " << msg << endl;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
switch (Events[ev_ctr].Type[i]) {
|
||||
switch (thisEvent.Type[i]) {
|
||||
case FG_VALUE:
|
||||
case FG_BOOL:
|
||||
Events[ev_ctr].newValue[i] = Events[ev_ctr].SetValue[i];
|
||||
thisEvent.newValue[i] = thisEvent.SetValue[i];
|
||||
break;
|
||||
case FG_DELTA:
|
||||
Events[ev_ctr].newValue[i] = Events[ev_ctr].OriginalValue[i] + Events[ev_ctr].SetValue[i];
|
||||
thisEvent.newValue[i] = thisEvent.OriginalValue[i] + thisEvent.SetValue[i];
|
||||
break;
|
||||
default:
|
||||
cerr << "Invalid Type specified" << endl;
|
||||
break;
|
||||
}
|
||||
Events[ev_ctr].StartTime = currentTime + Events[ev_ctr].Delay;
|
||||
Events[ev_ctr].ValueSpan[i] = Events[ev_ctr].newValue[i] - Events[ev_ctr].OriginalValue[i];
|
||||
Events[ev_ctr].Transiting[i] = true;
|
||||
thisEvent.StartTime = currentTime + thisEvent.Delay;
|
||||
thisEvent.ValueSpan[i] = thisEvent.newValue[i] - thisEvent.OriginalValue[i];
|
||||
thisEvent.Transiting[i] = true;
|
||||
}
|
||||
}
|
||||
Events[ev_ctr].Triggered = true;
|
||||
thisEvent.Triggered = true;
|
||||
|
||||
} else if (Events[ev_ctr].Persistent) { // If the event is persistent, reset the trigger.
|
||||
Events[ev_ctr].Triggered = false; // Reset the trigger for persistent events
|
||||
Events[ev_ctr].Notified = false; // Also reset the notification flag
|
||||
} else if (Events[ev_ctr].Continuous) { // If the event is continuous, reset the trigger.
|
||||
Events[ev_ctr].Triggered = false; // Reset the trigger for persistent events
|
||||
Events[ev_ctr].Notified = false; // Also reset the notification flag
|
||||
} else if (thisEvent.Persistent) { // If the event is persistent, reset the trigger.
|
||||
thisEvent.Triggered = false; // Reset the trigger for persistent events
|
||||
thisEvent.Notified = false; // Also reset the notification flag
|
||||
} else if (thisEvent.Continuous) { // If the event is continuous, reset the trigger.
|
||||
thisEvent.Triggered = false; // Reset the trigger for persistent events
|
||||
thisEvent.Notified = false; // Also reset the notification flag
|
||||
}
|
||||
|
||||
if ((currentTime >= Events[ev_ctr].StartTime) && Events[ev_ctr].Triggered) {
|
||||
if ((currentTime >= thisEvent.StartTime) && thisEvent.Triggered) {
|
||||
|
||||
for (i=0; i<Events[ev_ctr].SetValue.size(); i++) {
|
||||
if (Events[ev_ctr].Transiting[i]) {
|
||||
Events[ev_ctr].TimeSpan = currentTime - Events[ev_ctr].StartTime;
|
||||
switch (Events[ev_ctr].Action[i]) {
|
||||
for (i=0; i<thisEvent.SetValue.size(); i++) {
|
||||
if (thisEvent.Transiting[i]) {
|
||||
thisEvent.TimeSpan = currentTime - thisEvent.StartTime;
|
||||
switch (thisEvent.Action[i]) {
|
||||
case FG_RAMP:
|
||||
if (Events[ev_ctr].TimeSpan <= Events[ev_ctr].TC[i]) {
|
||||
newSetValue = Events[ev_ctr].TimeSpan/Events[ev_ctr].TC[i] * Events[ev_ctr].ValueSpan[i] + Events[ev_ctr].OriginalValue[i];
|
||||
if (thisEvent.TimeSpan <= thisEvent.TC[i]) {
|
||||
newSetValue = thisEvent.TimeSpan/thisEvent.TC[i] * thisEvent.ValueSpan[i] + thisEvent.OriginalValue[i];
|
||||
} else {
|
||||
newSetValue = Events[ev_ctr].newValue[i];
|
||||
if (Events[ev_ctr].Continuous != true) Events[ev_ctr].Transiting[i] = false;
|
||||
newSetValue = thisEvent.newValue[i];
|
||||
if (thisEvent.Continuous != true) thisEvent.Transiting[i] = false;
|
||||
}
|
||||
break;
|
||||
case FG_STEP:
|
||||
newSetValue = Events[ev_ctr].newValue[i];
|
||||
newSetValue = thisEvent.newValue[i];
|
||||
|
||||
// If this is not a continuous event, reset the transiting flag.
|
||||
// Otherwise, it is known that the event is a continuous event.
|
||||
// Furthermore, if the event is to be determined by a function,
|
||||
// then the function will be continuously calculated.
|
||||
if (Events[ev_ctr].Continuous != true)
|
||||
Events[ev_ctr].Transiting[i] = false;
|
||||
else if (Events[ev_ctr].Functions[i] != 0)
|
||||
newSetValue = Events[ev_ctr].Functions[i]->GetValue();
|
||||
if (thisEvent.Continuous != true)
|
||||
thisEvent.Transiting[i] = false;
|
||||
else if (thisEvent.Functions[i] != 0)
|
||||
newSetValue = thisEvent.Functions[i]->GetValue();
|
||||
|
||||
break;
|
||||
case FG_EXP:
|
||||
newSetValue = (1 - exp( -Events[ev_ctr].TimeSpan/Events[ev_ctr].TC[i] )) * Events[ev_ctr].ValueSpan[i] + Events[ev_ctr].OriginalValue[i];
|
||||
newSetValue = (1 - exp( -thisEvent.TimeSpan/thisEvent.TC[i] )) * thisEvent.ValueSpan[i] + thisEvent.OriginalValue[i];
|
||||
break;
|
||||
default:
|
||||
cerr << "Invalid Action specified" << endl;
|
||||
break;
|
||||
}
|
||||
Events[ev_ctr].SetParam[i]->setDoubleValue(newSetValue);
|
||||
thisEvent.SetParam[i]->setDoubleValue(newSetValue);
|
||||
}
|
||||
}
|
||||
|
||||
// Print notification values after setting them
|
||||
if (Events[ev_ctr].Notify && !Events[ev_ctr].Notified) {
|
||||
cout << endl << " Event " << event_ctr << " (" << Events[ev_ctr].Name << ")"
|
||||
if (thisEvent.Notify && !thisEvent.Notified) {
|
||||
cout << endl << " Event " << event_ctr << " (" << thisEvent.Name << ")"
|
||||
<< " executed at time: " << currentTime << endl;
|
||||
if (!Events[ev_ctr].Description.empty()) {
|
||||
cout << " " << Events[ev_ctr].Description << endl;
|
||||
if (!thisEvent.Description.empty()) {
|
||||
cout << " " << thisEvent.Description << endl;
|
||||
}
|
||||
for (j=0; j<Events[ev_ctr].NotifyProperties.size();j++) {
|
||||
// cout << " " << Events[ev_ctr].NotifyProperties[j]->GetRelativeName()
|
||||
cout << " " << Events[ev_ctr].DisplayString[j]
|
||||
<< " = " << Events[ev_ctr].NotifyProperties[j]->getDoubleValue() << endl;
|
||||
for (j=0; j<thisEvent.NotifyProperties.size();j++) {
|
||||
// cout << " " << thisEvent.NotifyProperties[j]->GetRelativeName()
|
||||
cout << " " << thisEvent.DisplayString[j]
|
||||
<< " = " << thisEvent.NotifyProperties[j]->getDoubleValue() << endl;
|
||||
}
|
||||
cout << endl;
|
||||
Events[ev_ctr].Notified = true;
|
||||
thisEvent.Notified = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_FGSCRIPT "$Id: FGScript.h,v 1.22 2012/09/05 04:49:13 jberndt Exp $"
|
||||
#define ID_FGSCRIPT "$Id: FGScript.h,v 1.24 2013/06/10 01:50:43 jberndt Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -158,7 +158,7 @@ CLASS DOCUMENTATION
|
|||
comes the "run" section, where the conditions are
|
||||
described in "event" clauses.</p>
|
||||
@author Jon S. Berndt
|
||||
@version "$Id: FGScript.h,v 1.22 2012/09/05 04:49:13 jberndt Exp $"
|
||||
@version "$Id: FGScript.h,v 1.24 2013/06/10 01:50:43 jberndt Exp $"
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -220,8 +220,9 @@ private:
|
|||
double TimeSpan;
|
||||
string Name;
|
||||
string Description;
|
||||
vector <FGPropertyManager*> SetParam;
|
||||
vector <FGPropertyManager*> NotifyProperties;
|
||||
vector <FGPropertyNode_ptr> SetParam;
|
||||
vector <std::string> SetParamName;
|
||||
vector <FGPropertyNode_ptr> NotifyProperties;
|
||||
vector <string> DisplayString;
|
||||
vector <eAction> Action;
|
||||
vector <eType> Type;
|
||||
|
|
|
@ -45,7 +45,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGCondition.cpp,v 1.17 2012/10/27 20:29:01 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGCondition.cpp,v 1.18 2013/01/26 17:06:49 bcoconni Exp $";
|
||||
static const char *IdHdr = ID_CONDITION;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -126,7 +126,7 @@ FGCondition::FGCondition(const string& test, FGPropertyManager* PropertyManager)
|
|||
exit(-1);
|
||||
}
|
||||
|
||||
FGPropertyManager *node = PropertyManager->GetNode(property1, false);
|
||||
FGPropertyNode *node = PropertyManager->GetNode(property1, false);
|
||||
if (node) {
|
||||
TestParam1 = new FGPropertyValue(node);
|
||||
} else {
|
||||
|
|
|
@ -43,7 +43,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGFunction.cpp,v 1.46 2012/09/25 12:43:13 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGFunction.cpp,v 1.50 2013/06/10 02:05:12 jberndt Exp $";
|
||||
static const char *IdHdr = ID_FUNCTION;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -64,6 +64,9 @@ const std::string FGFunction::difference_string = "difference";
|
|||
const std::string FGFunction::product_string = "product";
|
||||
const std::string FGFunction::quotient_string = "quotient";
|
||||
const std::string FGFunction::pow_string = "pow";
|
||||
const std::string FGFunction::sqrt_string = "sqrt";
|
||||
const std::string FGFunction::toradians_string = "toradians";
|
||||
const std::string FGFunction::todegrees_string = "todegrees";
|
||||
const std::string FGFunction::exp_string = "exp";
|
||||
const std::string FGFunction::log2_string = "log2";
|
||||
const std::string FGFunction::ln_string = "ln";
|
||||
|
@ -121,6 +124,11 @@ FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, const string& pr
|
|||
if (operation == function_string) {
|
||||
sCopyTo = el->GetAttributeValue("copyto");
|
||||
if (!sCopyTo.empty()) {
|
||||
|
||||
if (sCopyTo.find("#") != string::npos) {
|
||||
if (is_number(Prefix)) sCopyTo = replace(sCopyTo,"#",Prefix);
|
||||
}
|
||||
|
||||
pCopyTo = PropertyManager->GetNode(sCopyTo);
|
||||
if (pCopyTo == 0L) cerr << "Property \"" << sCopyTo << "\" must be previously defined in function "
|
||||
<< Name << endl;
|
||||
|
@ -136,6 +144,12 @@ FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, const string& pr
|
|||
Type = eQuotient;
|
||||
} else if (operation == pow_string) {
|
||||
Type = ePow;
|
||||
} else if (operation == sqrt_string) {
|
||||
Type = eSqrt;
|
||||
} else if (operation == toradians_string) {
|
||||
Type = eToRadians;
|
||||
} else if (operation == todegrees_string) {
|
||||
Type = eToDegrees;
|
||||
} else if (operation == log2_string) {
|
||||
Type = eLog2;
|
||||
} else if (operation == ln_string) {
|
||||
|
@ -240,13 +254,13 @@ FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, const string& pr
|
|||
property_name = replace(property_name,"#",Prefix);
|
||||
}
|
||||
}
|
||||
FGPropertyManager* newNode = 0L;
|
||||
FGPropertyNode* newNode = 0L;
|
||||
if (PropertyManager->HasNode(property_name)) {
|
||||
newNode = PropertyManager->GetNode(property_name);
|
||||
Parameters.push_back(new FGPropertyValue( newNode ));
|
||||
} else {
|
||||
cerr << fgcyan << "Warning: The property " + property_name + " is initially undefined."
|
||||
<< reset << endl;
|
||||
// cerr << fgcyan << "Warning: The property " + property_name + " is initially undefined."
|
||||
// << reset << endl;
|
||||
Parameters.push_back(new FGPropertyValue( property_name,
|
||||
PropertyManager ));
|
||||
}
|
||||
|
@ -260,6 +274,9 @@ FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, const string& pr
|
|||
operation == sum_string ||
|
||||
operation == quotient_string ||
|
||||
operation == pow_string ||
|
||||
operation == sqrt_string ||
|
||||
operation == toradians_string ||
|
||||
operation == todegrees_string ||
|
||||
operation == exp_string ||
|
||||
operation == log2_string ||
|
||||
operation == ln_string ||
|
||||
|
@ -385,6 +402,15 @@ double FGFunction::GetValue(void) const
|
|||
case ePow:
|
||||
temp = pow(temp,Parameters[1]->GetValue());
|
||||
break;
|
||||
case eSqrt:
|
||||
temp = sqrt(temp);
|
||||
break;
|
||||
case eToRadians:
|
||||
temp *= M_PI/180.0;
|
||||
break;
|
||||
case eToDegrees:
|
||||
temp *= 180.0/M_PI;
|
||||
break;
|
||||
case eExp:
|
||||
temp = exp(temp);
|
||||
break;
|
||||
|
@ -780,13 +806,15 @@ void FGFunction::bind(void)
|
|||
}
|
||||
}
|
||||
|
||||
// JMT commenting out on 2013/01/28 on advice of jentron - temporary fix
|
||||
// for in-flux JSBSim property tie changes.
|
||||
// if (PropertyManager->HasNode(tmp)) {
|
||||
// cout << "Property " << tmp << " has already been successfully bound (late)." << endl;
|
||||
// } else {
|
||||
if (PropertyManager->HasNode(tmp)) {
|
||||
FGPropertyNode* property = PropertyManager->GetNode(tmp);
|
||||
if (property->isTied()) {
|
||||
cout << "Property " << tmp << " has already been successfully bound (late)." << endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PropertyManager->Tie( tmp, this, &FGFunction::GetValue);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,12 +37,13 @@ INCLUDES
|
|||
#include <vector>
|
||||
#include <string>
|
||||
#include "FGParameter.h"
|
||||
#include "input_output/FGPropertyManager.h"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_FUNCTION "$Id: FGFunction.h,v 1.26 2012/09/25 12:43:13 jberndt Exp $"
|
||||
#define ID_FUNCTION "$Id: FGFunction.h,v 1.30 2013/06/10 02:25:18 jberndt Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -50,7 +51,6 @@ FORWARD DECLARATIONS
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
class FGPropertyManager;
|
||||
class Element;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -69,6 +69,9 @@ A function definition consists of an operation, a value, a table, or a property
|
|||
- product (takes n args)
|
||||
- quotient (takes 2 args)
|
||||
- pow (takes 2 args)
|
||||
- sqrt (takes one argument)
|
||||
- toradians (takes one argument)
|
||||
- todegrees (takes one argument)
|
||||
- exp (takes 2 args)
|
||||
- log2 (takes 1 arg)
|
||||
- ln (takes 1 arg)
|
||||
|
@ -125,7 +128,7 @@ members of the function element. Almost always, the first operation within the
|
|||
function element will be a product or sum. For example:
|
||||
|
||||
@code
|
||||
<function name="aero/coefficient/Clr">
|
||||
<function name="aero/moment/Clr">
|
||||
<description>Roll moment due to yaw rate</description>
|
||||
<product>
|
||||
<property>aero/qbar-area</property>
|
||||
|
@ -155,6 +158,535 @@ an operation (such as sum) which can contain other items. The point to keep in
|
|||
mind is that it evaluates to a single value - which is just what the trigonometric
|
||||
functions require (except atan2, which takes two arguments).
|
||||
|
||||
<h2>Specific Function Definitions</h2>
|
||||
|
||||
Note: In the definitions below, a "property" refers to a single property specified
|
||||
within either the <property></property> tag or the shortcut tag, \<p>\</p>. The
|
||||
keyword "value" refers to a single numeric value specified either within the \<value>\</value>
|
||||
tag or the shortcut <v></v> tag. The keyword "table" refers to a single table specified
|
||||
either within the \<table>\</table> tag or the shortcut <t></t> tag. The plural form of any
|
||||
of the three words refers to one or more instances of a property, value, or table.
|
||||
|
||||
- @b sum, sums the values of all immediate child elements:
|
||||
@code
|
||||
<sum>
|
||||
{properties, values, tables, or other function elements}
|
||||
</sum>
|
||||
|
||||
Example: Mach + 0.01
|
||||
|
||||
<sum>
|
||||
<p> velocities/mach </p>
|
||||
<v> 0.01 </v>
|
||||
</sum>
|
||||
@endcode
|
||||
- @b difference, subtracts the values of all immediate child elements from the value of the first child element:
|
||||
@code
|
||||
<difference>
|
||||
{properties, values, tables, or other function elements}
|
||||
</difference>
|
||||
|
||||
Example: Mach - 0.01
|
||||
|
||||
<difference>
|
||||
<p> velocities/mach </p>
|
||||
<v> 0.01 </v>
|
||||
</difference>
|
||||
@endcode
|
||||
- @b product multiplies together the values of all immediate child elements:
|
||||
@code
|
||||
<product>
|
||||
{properties, values, tables, or other function elements}
|
||||
</product>
|
||||
|
||||
Example: qbar*S*beta*CY_beta
|
||||
|
||||
<product>
|
||||
<property> aero/qbar-psf </property>
|
||||
<property> metrics/Sw-sqft </property>
|
||||
<property> aero/beta-rad </property>
|
||||
<property> aero/coefficient/CY_beta </property>
|
||||
</product>
|
||||
@endcode
|
||||
- @b quotient, divides the value of the first immediate child element by the second immediate child element:
|
||||
@code
|
||||
<quotient>
|
||||
{property, value, table, or other function element}
|
||||
{property, value, table, or other function element}
|
||||
</quotient>
|
||||
|
||||
Example: (2*GM)/R
|
||||
|
||||
<quotient>
|
||||
<product>
|
||||
<v> 2.0 </v>
|
||||
<p> guidance/executive/gm </p>
|
||||
</product>
|
||||
<p> position/radius-to-vehicle-ft </p>
|
||||
</quotient>
|
||||
@endcode
|
||||
- @b pow, raises the value of the first immediate child element to the power of the value
|
||||
of the second immediate child element:
|
||||
@code
|
||||
<pow>
|
||||
{property, value, table, or other function element}
|
||||
{property, value, table, or other function element}
|
||||
</pow>
|
||||
|
||||
Example: Mach^2
|
||||
|
||||
<pow>
|
||||
<p> velocities/mach </p>
|
||||
<v> 2.0 </v>
|
||||
</pow>
|
||||
@endcode
|
||||
- @b sqrt, takes the square root of the value of the immediate child element:
|
||||
@code
|
||||
<sqrt>
|
||||
{property, value, table, or other function element}
|
||||
</sqrt>
|
||||
|
||||
Example: square root of 25
|
||||
|
||||
<sqrt> <v> 25.0 </v> </sqrt>
|
||||
@endcode
|
||||
- @b toradians, converts a presumed argument in degrees to radians by multiplying
|
||||
the value of the immediate child element by pi/180:
|
||||
@code
|
||||
<toradians>
|
||||
{property, value, table, or other function element}
|
||||
</toradians>
|
||||
|
||||
Example: convert 45 degrees to radians
|
||||
|
||||
<toradians> <v> 45 </v> </toradians>
|
||||
@endcode
|
||||
- @b todegrees, converts a presumed argument in radians to degrees by multiplying
|
||||
the value of the immediate child element by 180/pi:
|
||||
@code
|
||||
<todegrees>
|
||||
{property, value, table, or other function element}
|
||||
</todegrees>
|
||||
|
||||
Example: convert 0.5*pi radians to degrees
|
||||
|
||||
<todegrees>
|
||||
<product> <v> 0.5 </v> <pi/> </product>
|
||||
</todegrees>
|
||||
@endcode
|
||||
- @b exp, raises "e" to the power of the immediate child element:
|
||||
@code
|
||||
<exp>
|
||||
{property, value, table, or other function element}
|
||||
</exp>
|
||||
|
||||
Example: raise "e" to the 1.5 power, e^1.5
|
||||
|
||||
<exp> <v> 1.5 </v> </exp>
|
||||
@endcode
|
||||
- @b log2, calculates the log base 2 value of the immediate child element:
|
||||
@code
|
||||
<log2>
|
||||
{property, value, table, or other function element}
|
||||
</log2>
|
||||
|
||||
Example:
|
||||
<log2> <v> 128 </v> </log2>
|
||||
@endcode
|
||||
- @b ln, calculates the natural logarithm of the value of the immediate child element:
|
||||
@code
|
||||
<ln>
|
||||
{property, value, table, or other function element}
|
||||
</ln>
|
||||
|
||||
Example: ln(128)
|
||||
|
||||
<ln> <v> 200 </v> </ln>
|
||||
@endcode
|
||||
- @b log10 calculates the base 10 logarithm of the value of the immediate child element
|
||||
@code
|
||||
<log10>
|
||||
{property, value, table, or other function element}
|
||||
</log10>
|
||||
|
||||
Example log(Mach)
|
||||
|
||||
<log10> <p> velocities/mach </p> </log10>
|
||||
@endcode
|
||||
- @b abs calculates the absolute value of the immediate child element
|
||||
@code
|
||||
<abs>
|
||||
{property, value, table, or other function element}
|
||||
</abs>
|
||||
|
||||
Example:
|
||||
|
||||
<abs> <p> flight-path/gamma-rad </p> </abs>
|
||||
@endcode
|
||||
- @b sin calculates the sine of the value of the immediate child element (the argument is expected to be in radians)
|
||||
@code
|
||||
<sin>
|
||||
{property, value, table, or other function element}
|
||||
</sin>
|
||||
|
||||
Example:
|
||||
|
||||
<sin> <toradians> <p> fcs/heading-true-degrees </p> </toradians> </sin>
|
||||
@endcode
|
||||
- @b cos calculates the cosine of the value of the immediate child element (the argument is expected to be in radians)
|
||||
@code
|
||||
<cos>
|
||||
{property, value, table, or other function element}
|
||||
</cos>
|
||||
|
||||
Example:
|
||||
|
||||
<cos> <toradians> <p> fcs/heading-true-degrees </p> </toradians> </cos>
|
||||
@endcode
|
||||
- @b tan calculates the tangent of the value of the immediate child element (the argument is expected to be in radians)
|
||||
@code
|
||||
<tan>
|
||||
{property, value, table, or other function element}
|
||||
</tan>
|
||||
|
||||
Example:
|
||||
|
||||
<tan> <toradians> <p> fcs/heading-true-degrees </p> </toradians> </tan>
|
||||
@endcode
|
||||
- @b asin calculates the arcsine (inverse sine) of the value of the immediate child element. The
|
||||
value provided should be in the range from -1 to +1. The value returned
|
||||
will be expressed in radians, and will be in the range from -pi/2 to
|
||||
+pi/2.
|
||||
@code
|
||||
<asin>
|
||||
{property, value, table, or other function element}
|
||||
</asin>
|
||||
|
||||
Example:
|
||||
|
||||
<asin> <v> 0.5 </v> </asin>
|
||||
@endcode
|
||||
- @b acos calculates the arccosine (inverse cosine) of the value of the immediate child element. The
|
||||
value provided should be in the range from -1 to +1. The value returned
|
||||
will be expressed in radians, and will be in the range from 0 to pi.
|
||||
@code
|
||||
<acos>
|
||||
{property, value, table, or other function element}
|
||||
</acos>
|
||||
|
||||
Example:
|
||||
|
||||
<acos> <v> 0.5 </v> </acos>
|
||||
@endcode
|
||||
- @b atan calculates the inverse tangent of the value of the immediate child element.
|
||||
The value returned will be expressed in radians, and will be in the
|
||||
range from -pi/2 to +pi/2.
|
||||
@code
|
||||
<atan>
|
||||
{property, value, table, or other function element}
|
||||
</atan>
|
||||
|
||||
Example:
|
||||
|
||||
<atan> <v> 0.5 </v> </atan>
|
||||
@endcode
|
||||
- @b atan2 calculates the inverse tangent of the value of the immediate child
|
||||
elements, Y/X (in that order). It even works for X values near zero.
|
||||
The value returned will be expressed in radians, and in the range
|
||||
-pi to +pi.
|
||||
@code
|
||||
<atan2>
|
||||
{property, value, table, or other function element} {property, value, table, or other function element}
|
||||
</atan2>
|
||||
|
||||
Example: inverse tangent of 0.5/0.25, evaluates to: 1.107 radians
|
||||
|
||||
<atan2> <v> 0.5 </<v> <v> 0.25 </v> </atan2>
|
||||
@endcode
|
||||
- @b min returns the smallest value from all the immediate child elements
|
||||
@code
|
||||
<min>
|
||||
{properties, values, tables, or other function elements}
|
||||
</min>
|
||||
|
||||
Example: returns the lesser of velocity and 2500
|
||||
|
||||
<min>
|
||||
<p> velocities/eci-velocity-mag-fps </p>
|
||||
<v> 2500.0 </v>
|
||||
</min>
|
||||
@endcode
|
||||
- @b max returns the largest value from all the immediate child elements
|
||||
@code
|
||||
<max>
|
||||
{properties, values, tables, or other function elements}
|
||||
</max>
|
||||
|
||||
Example: returns the greater of velocity and 15000
|
||||
|
||||
<max>
|
||||
<p> velocities/eci-velocity-mag-fps </p>
|
||||
<v> 15000.0 </v>
|
||||
</max>
|
||||
@endcode
|
||||
- @b avg returns the average value of all the immediate child elements
|
||||
@code
|
||||
<avg>
|
||||
{properties, values, tables, or other function elements}
|
||||
</avg>
|
||||
|
||||
Example: returns the average of the four numbers below, evaluates to 0.50.
|
||||
|
||||
<avg>
|
||||
<v> 0.25 </v>
|
||||
<v> 0.50 </v>
|
||||
<v> 0.75 </v>
|
||||
<v> 0.50 </v>
|
||||
</avg>
|
||||
@endcode
|
||||
- @b fraction returns the fractional part of the value of the immediate child element
|
||||
@code
|
||||
<fraction>
|
||||
{property, value, table, or other function element}
|
||||
</fraction>
|
||||
|
||||
Example: returns the fractional part of pi - or, roughly, 0.1415926...
|
||||
|
||||
<fraction> <pi/> </fraction>
|
||||
@endcode
|
||||
- @b integer returns the integer portion of the value of the immediate child element
|
||||
@code
|
||||
<integer>
|
||||
{property, value, table, or other function element}
|
||||
</integer>
|
||||
@endcode
|
||||
- @b mod returns the remainder from the integer division of the value of the
|
||||
first immediate child element by the second immediate child element,
|
||||
X/Y (X modulo Y). The value returned is the value X-I*Y, for the
|
||||
largest integer I such that if Y is nonzero, the result has the
|
||||
same sign as X and magnitude less than the magnitude of Y. For
|
||||
instance, the expression "5 mod 2" would evaluate to 1 because 5
|
||||
divided by 2 leaves a quotient of 2 and a remainder of 1, while
|
||||
"9 mod 3" would evaluate to 0 because the division of 9 by 3 has a
|
||||
quotient of 3 and leaves a remainder of 0.
|
||||
@code
|
||||
<mod>
|
||||
{property, value, table, or other function element} {property, value, table, or other function element}
|
||||
</mod>
|
||||
|
||||
Example: 5 mod 2, evaluates to 1
|
||||
|
||||
<mod> <v> 5 </v> <v> 2 </v> </mod>
|
||||
@endcode
|
||||
- @b lt returns a 1 if the value of the first immediate child element is less
|
||||
than the value of the second immediate child element, returns 0
|
||||
otherwise
|
||||
@code
|
||||
<lt>
|
||||
{property, value, table, or other function element}
|
||||
{property, value, table, or other function element}
|
||||
</lt>
|
||||
|
||||
Example: returns 1 if thrust is less than 10,000, returns 0 otherwise
|
||||
|
||||
<lt>
|
||||
<p> propulsion/engine[2]/thrust-lbs </p>
|
||||
<v> 10000.0 </v>
|
||||
</lt>
|
||||
@endcode
|
||||
- @b le returns a 1 if the value of the first immediate child element is less
|
||||
than or equal to the value of the second immediate child element, returns 0
|
||||
otherwise
|
||||
@code
|
||||
<le>
|
||||
{property, value, table, or other function element}
|
||||
{property, value, table, or other function element}
|
||||
</le>
|
||||
|
||||
Example: returns 1 if thrust is less than or equal to 10,000, returns 0 otherwise
|
||||
|
||||
<le>
|
||||
<p> propulsion/engine[2]/thrust-lbs </p>
|
||||
<v> 10000.0 </v>
|
||||
</le>
|
||||
@endcode
|
||||
- @b gt returns a 1 if the value of the first immediate child element is greater
|
||||
than the value of the second immediate child element, returns 0
|
||||
otherwise
|
||||
@code
|
||||
<gt>
|
||||
{property, value, table, or other function element}
|
||||
{property, value, table, or other function element}
|
||||
</gt>
|
||||
|
||||
Example: returns 1 if thrust is greater than 10,000, returns 0 otherwise
|
||||
|
||||
<gt>
|
||||
<p> propulsion/engine[2]/thrust-lbs </p>
|
||||
<v> 10000.0 </v>
|
||||
</gt>
|
||||
@endcode
|
||||
- @b ge returns a 1 if the value of the first immediate child element is greater
|
||||
than or equal to the value of the second immediate child element, returns 0
|
||||
otherwise
|
||||
@code
|
||||
<ge>
|
||||
{property, value, table, or other function element}
|
||||
{property, value, table, or other function element}
|
||||
</ge>
|
||||
|
||||
Example: returns 1 if thrust is greater than or equal to 10,000, returns 0 otherwise
|
||||
|
||||
<ge>
|
||||
<p> propulsion/engine[2]/thrust-lbs </p>
|
||||
<v> 10000.0 </v>
|
||||
</ge>
|
||||
@endcode
|
||||
- @b eq returns a 1 if the value of the first immediate child element is
|
||||
equal to the second immediate child element, returns 0
|
||||
otherwise
|
||||
@code
|
||||
<eq>
|
||||
{property, value, table, or other function element}
|
||||
{property, value, table, or other function element}
|
||||
</eq>
|
||||
|
||||
Example: returns 1 if thrust is equal to 10,000, returns 0 otherwise
|
||||
|
||||
<eq>
|
||||
<p> propulsion/engine[2]/thrust-lbs </p>
|
||||
<v> 10000.0 </v>
|
||||
</eq>
|
||||
@endcode
|
||||
- @b nq returns a 1 if the value of the first immediate child element is not
|
||||
equal to the value of the second immediate child element, returns 0
|
||||
otherwise
|
||||
@code
|
||||
<nq>
|
||||
{property, value, table, or other function element}
|
||||
{property, value, table, or other function element}
|
||||
</nq>
|
||||
|
||||
Example: returns 1 if thrust is not 0, returns 0 otherwise
|
||||
|
||||
<nq>
|
||||
<p> propulsion/engine[2]/thrust-lbs </p>
|
||||
<v> 0.0 </v>
|
||||
</nq>
|
||||
@endcode
|
||||
- @b and returns a 1 if the values of the immediate child elements are all 1,
|
||||
returns 0 otherwise. Values provided are expected to be either 1 or 0
|
||||
within machine precision.
|
||||
@code
|
||||
<and>
|
||||
{properties, values, tables, or other function elements}
|
||||
</and>
|
||||
|
||||
Example: returns 1 if the specified flags are all 1
|
||||
|
||||
<and>
|
||||
<p> guidance/first-stage-flight-flag </p>
|
||||
<p> control/engines-running-flag </p>
|
||||
</and>
|
||||
@endcode
|
||||
- @b or returns a 1 if the values of any of the immediate child elements 1,
|
||||
returns 0 otherwise. Values provided are expected to be either 1 or 0
|
||||
within machine precision.
|
||||
@code
|
||||
<or>
|
||||
{properties, values, tables, or other function elements}
|
||||
</or>
|
||||
|
||||
Example: returns 1 if any of the specified flags are 1
|
||||
|
||||
<or>
|
||||
<p> guidance/first-stage-flight-flag </p>
|
||||
<p> control/engines-running-flag </p>
|
||||
</or>
|
||||
@endcode
|
||||
- @b not returns the inverse of the value of the supplied immediate child element
|
||||
(e.g., returns 1 if supplied a 0)
|
||||
@code
|
||||
<not>
|
||||
{property, value, table, or other function element}
|
||||
</not>
|
||||
|
||||
Example: returns 0 if the value of the supplied flag is 1
|
||||
|
||||
<not> <p> guidance/first-stage-flight-flag </p> </not>
|
||||
@endcode
|
||||
- @b ifthen if the value of the first immediate child element is 1, then the
|
||||
value of the second immediate child element is returned, otherwise
|
||||
the value of the third child element is returned
|
||||
@code
|
||||
<ifthen>
|
||||
{property, value, table, or other function element}
|
||||
{property, value, table, or other function element}
|
||||
{property, value, table, or other function element}
|
||||
</ifthen>
|
||||
|
||||
Example: if flight-mode is greater than 2, then a value of 0.00 is returned,
|
||||
otherwise the value of the property control/pitch-lag is returned.
|
||||
|
||||
<ifthen>
|
||||
<gt> <p> executive/flight-mode </p> <v> 2 </v> </gt>
|
||||
<v> 0.00 </v>
|
||||
<p> control/pitch-lag </p>
|
||||
</ifthen>
|
||||
@endcode
|
||||
- @b switch uses the integer value of the first immediate child element as an
|
||||
index to select one of the subsequent immediate child elements to
|
||||
return the value of
|
||||
@code
|
||||
<switch>
|
||||
{property, value, table, or other function element}
|
||||
{property, value, table, or other function element}
|
||||
{property, value, table, or other function element}
|
||||
...
|
||||
</switch>
|
||||
|
||||
Example: if flight-mode is 2, the switch function returns 0.50
|
||||
|
||||
<switch>
|
||||
<p> executive/flight-mode </p>
|
||||
<v> 0.25 </v>
|
||||
<v> 0.50 </v>
|
||||
<v> 0.75 </v>
|
||||
<v> 1.00 </v>
|
||||
</switch>
|
||||
@endcode
|
||||
- @b random Takes no arguments and returns a Gaussian distributed random number
|
||||
@code <random/> @endcode
|
||||
- @b urandom Takes no arguments and returns a uniformly distributed random number
|
||||
between -1 and +1
|
||||
@code<urandom/>@endcode
|
||||
- @b pi Takes no argument and returns the value of Pi
|
||||
@code<pi/>@endcode
|
||||
- @b interpolate1d returns the result from a 1-dimensional interpolation of the
|
||||
supplied values, with the value of the first immediate child
|
||||
element representing the lookup value into the table, and the
|
||||
following pairs of values representing the independent and
|
||||
dependent values. The first provided child element is expected
|
||||
to be a property. The interpolation does not extrapolate, but
|
||||
holds the highest value if the provided lookup value goes
|
||||
outside of the provided range.
|
||||
@code
|
||||
<interpolate1d>
|
||||
{property, value, table, or other function element}
|
||||
{property, value, table, or other function element} {property, value, table, or other function element}
|
||||
...
|
||||
</interpolate1d>
|
||||
|
||||
Example: If mach is 0.4, the interpolation will return 0.375. If mach is 1.5, the interpolation
|
||||
will return 0.60.
|
||||
|
||||
<interpolate1d>
|
||||
<p> velocities/mach </p>
|
||||
<v> 0.00 </v> <v> 0.25 </v>
|
||||
<v> 0.80 </v> <v> 0.50 </v>
|
||||
<v> 0.90 </v> <v> 0.60 </v>
|
||||
</interpolate1d>
|
||||
@endcode
|
||||
@author Jon Berndt
|
||||
*/
|
||||
|
||||
|
@ -225,6 +757,9 @@ private:
|
|||
static const std::string product_string;
|
||||
static const std::string quotient_string;
|
||||
static const std::string pow_string;
|
||||
static const std::string sqrt_string;
|
||||
static const std::string toradians_string;
|
||||
static const std::string todegrees_string;
|
||||
static const std::string exp_string;
|
||||
static const std::string log2_string;
|
||||
static const std::string ln_string;
|
||||
|
@ -265,8 +800,8 @@ private:
|
|||
static const std::string switch_string;
|
||||
static const std::string interpolate1d_string;
|
||||
double cachedValue;
|
||||
enum functionType {eTopLevel=0, eProduct, eDifference, eSum, eQuotient, ePow,
|
||||
eExp, eAbs, eSign, eSin, eCos, eTan, eASin, eACos, eATan, eATan2,
|
||||
enum functionType {eTopLevel=0, eProduct, eDifference, eSum, eQuotient, ePow, eSqrt, eToRadians,
|
||||
eToDegrees, eExp, eAbs, eSign, eSin, eCos, eTan, eASin, eACos, eATan, eATan2,
|
||||
eMin, eMax, eAvg, eFrac, eInteger, eMod, eRandom, eUrandom, ePi,
|
||||
eLog2, eLn, eLog10, eLT, eLE, eGE, eGT, eEQ, eNE, eAND, eOR, eNOT,
|
||||
eIfThen, eSwitch, eInterpolate1D, eRotation_alpha_local,
|
||||
|
@ -274,7 +809,7 @@ private:
|
|||
eRotation_wf_to_bf} Type;
|
||||
std::string Name;
|
||||
std::string sCopyTo; // Property name to copy function value to
|
||||
FGPropertyManager* pCopyTo; // Property node for CopyTo property string
|
||||
FGPropertyNode_ptr pCopyTo; // Property node for CopyTo property string
|
||||
|
||||
unsigned int GetBinary(double) const;
|
||||
void bind(void);
|
||||
|
|
|
@ -3,16 +3,16 @@
|
|||
* Copyright (C) James Goppert 2010 <james.goppert@gmail.com>
|
||||
*
|
||||
* FGNelderMead.cpp is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FGNelderMead.cpp is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
* See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* You should have received a copy of the GNU Lesser General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
|||
#include <cstdlib>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <ctime>
|
||||
|
||||
|
@ -33,7 +34,7 @@ FGNelderMead::FGNelderMead(Function * f, const std::vector<double> & initialGues
|
|||
const std::vector<double> & upperBound,
|
||||
const std::vector<double> & initialStepSize, int iterMax,
|
||||
double rtol, double abstol, double speed, double randomization,
|
||||
bool showConvergeStatus,
|
||||
bool showConvergeStatus,
|
||||
bool showSimplex, bool pause, Callback * callback) :
|
||||
m_f(f), m_callback(callback), m_randomization(randomization),
|
||||
m_lowerBound(lowerBound), m_upperBound(upperBound),
|
||||
|
@ -41,227 +42,227 @@ FGNelderMead::FGNelderMead(Function * f, const std::vector<double> & initialGues
|
|||
m_iMax(1), m_iNextMax(1), m_iMin(1),
|
||||
m_simplex(m_nVert), m_cost(m_nVert), m_elemSum(m_nDim),
|
||||
m_status(1),
|
||||
initialGuess(initialGuess), initialStepSize(initialStepSize),
|
||||
iterMax(iterMax), iter(), rtol(rtol), abstol(abstol),
|
||||
speed(speed), showConvergeStatus(showConvergeStatus), showSimplex(showSimplex),
|
||||
pause(pause), rtolI(), minCostPrevResize(1), minCost(), minCostPrev(), maxCost(),
|
||||
nextMaxCost()
|
||||
initialGuess(initialGuess), initialStepSize(initialStepSize),
|
||||
iterMax(iterMax), iter(), rtol(rtol), abstol(abstol),
|
||||
speed(speed), showConvergeStatus(showConvergeStatus), showSimplex(showSimplex),
|
||||
pause(pause), rtolI(), minCostPrevResize(1), minCost(), minCostPrev(), maxCost(),
|
||||
nextMaxCost()
|
||||
{
|
||||
srand ( time(NULL) ); // seed random number generator
|
||||
srand ( time(NULL) ); // seed random number generator
|
||||
}
|
||||
|
||||
void FGNelderMead::update()
|
||||
{
|
||||
std::cout.precision(3);
|
||||
|
||||
// reinitialize simplex whenever rtol condition is met
|
||||
if ( rtolI < rtol || iter == 0)
|
||||
{
|
||||
std::vector<double> guess(m_nDim);
|
||||
if (iter == 0)
|
||||
{
|
||||
//std::cout << "constructing simplex" << std::endl;
|
||||
guess = initialGuess;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (std::abs(minCost-minCostPrevResize) < abstol)
|
||||
{
|
||||
std::cout << "\nunable to escape local minimum" << std::endl;
|
||||
m_status = -1;
|
||||
return;
|
||||
}
|
||||
//std::cout << "reinitializing step size" << std::endl;
|
||||
guess = m_simplex[m_iMin];
|
||||
minCostPrevResize = minCost;
|
||||
}
|
||||
constructSimplex(guess,initialStepSize);
|
||||
}
|
||||
// reinitialize simplex whenever rtol condition is met
|
||||
if ( rtolI < rtol || iter == 0)
|
||||
{
|
||||
std::vector<double> guess(m_nDim);
|
||||
if (iter == 0)
|
||||
{
|
||||
//std::cout << "constructing simplex" << std::endl;
|
||||
guess = initialGuess;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (std::abs(minCost-minCostPrevResize) < std::numeric_limits<float>::epsilon())
|
||||
{
|
||||
throw std::runtime_error("unable to escape local minimum!");
|
||||
m_status = -1;
|
||||
return;
|
||||
}
|
||||
//std::cout << "reinitializing step size" << std::endl;
|
||||
guess = m_simplex[m_iMin];
|
||||
minCostPrevResize = minCost;
|
||||
}
|
||||
constructSimplex(guess,initialStepSize);
|
||||
}
|
||||
|
||||
// find vertex costs
|
||||
for (int vertex=0;vertex<m_nVert;vertex++)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_cost[vertex] = m_f->eval(m_simplex[vertex]);
|
||||
}
|
||||
catch (const std::exception & e)
|
||||
{
|
||||
m_status = -1;
|
||||
throw;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// find vertex costs
|
||||
for (int vertex=0;vertex<m_nVert;vertex++)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_cost[vertex] = eval(m_simplex[vertex]);
|
||||
}
|
||||
catch (const std::exception & e)
|
||||
{
|
||||
m_status = -1;
|
||||
throw;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// find max cost, next max cost, and min cost
|
||||
m_iMax = m_iNextMax = m_iMin = 0;
|
||||
for (int vertex=0;vertex<m_nVert;vertex++)
|
||||
{
|
||||
if ( m_cost[vertex] > m_cost[m_iMax] )
|
||||
{
|
||||
m_iMax = vertex;
|
||||
}
|
||||
else if ( m_cost[vertex] > m_cost[m_iNextMax] || m_iMax == m_iNextMax ) m_iNextMax = vertex;
|
||||
else if ( m_cost[vertex] < m_cost[m_iMin] ) m_iMin = vertex;
|
||||
// find max cost, next max cost, and min cost
|
||||
m_iMax = m_iNextMax = m_iMin = 0;
|
||||
for (int vertex=0;vertex<m_nVert;vertex++)
|
||||
{
|
||||
if ( m_cost[vertex] > m_cost[m_iMax] )
|
||||
{
|
||||
m_iMax = vertex;
|
||||
}
|
||||
else if ( m_cost[vertex] > m_cost[m_iNextMax] || m_iMax == m_iNextMax ) m_iNextMax = vertex;
|
||||
else if ( m_cost[vertex] < m_cost[m_iMin] ) m_iMin = vertex;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// callback
|
||||
if (m_callback) m_callback->eval(m_simplex[m_iMin]);
|
||||
// callback
|
||||
if (m_callback) m_callback->eval(m_simplex[m_iMin]);
|
||||
|
||||
// compute relative tolerance
|
||||
rtolI = 2*std::abs(m_cost[m_iMax] -
|
||||
m_cost[m_iMin])/(std::abs(m_cost[m_iMax]+std::abs(m_cost[m_iMin])+
|
||||
std::numeric_limits<double>::epsilon()));
|
||||
// compute relative tolerance
|
||||
rtolI = 2*std::abs(m_cost[m_iMax] -
|
||||
m_cost[m_iMin])/(std::abs(m_cost[m_iMax]+std::abs(m_cost[m_iMin])+
|
||||
std::numeric_limits<double>::epsilon()));
|
||||
|
||||
// check for max iteration break condition
|
||||
if (iter > iterMax)
|
||||
{
|
||||
std::cout << "\nmax iterations exceeded" << std::endl;
|
||||
m_status = -1;
|
||||
return;
|
||||
}
|
||||
// check for convergence break condition
|
||||
else if ( m_cost[m_iMin] < abstol )
|
||||
{
|
||||
std::cout << "\nsimplex converged" << std::endl;
|
||||
m_status = 0;
|
||||
return;
|
||||
}
|
||||
// check for max iteration break condition
|
||||
if (iter > iterMax)
|
||||
{
|
||||
m_status = -1;
|
||||
throw std::runtime_error("max iterations exceeded!");
|
||||
return;
|
||||
}
|
||||
// check for convergence break condition
|
||||
else if ( m_cost[m_iMin] < abstol )
|
||||
{
|
||||
//std::cout << "\nsimplex converged" << std::endl;
|
||||
m_status = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// compute element sum of simplex vertices
|
||||
for (int dim=0;dim<m_nDim;dim++)
|
||||
{
|
||||
m_elemSum[dim] = 0;
|
||||
for (int vertex=0;vertex<m_nVert;vertex++)
|
||||
m_elemSum[dim] += m_simplex[vertex][dim];
|
||||
}
|
||||
// compute element sum of simplex vertices
|
||||
for (int dim=0;dim<m_nDim;dim++)
|
||||
{
|
||||
m_elemSum[dim] = 0;
|
||||
for (int vertex=0;vertex<m_nVert;vertex++)
|
||||
m_elemSum[dim] += m_simplex[vertex][dim];
|
||||
}
|
||||
|
||||
// min and max costs
|
||||
minCostPrev = minCost;
|
||||
minCost = m_cost[m_iMin];
|
||||
maxCost = m_cost[m_iMax];
|
||||
nextMaxCost = m_cost[m_iNextMax];
|
||||
// min and max costs
|
||||
minCostPrev = minCost;
|
||||
minCost = m_cost[m_iMin];
|
||||
maxCost = m_cost[m_iMax];
|
||||
nextMaxCost = m_cost[m_iNextMax];
|
||||
|
||||
// output cost and simplex
|
||||
if (showConvergeStatus)
|
||||
{
|
||||
if ( (minCostPrev + std::numeric_limits<float>::epsilon() )
|
||||
< minCost && minCostPrev != 0)
|
||||
{
|
||||
std::cout << "\twarning: simplex cost increased"
|
||||
<< std::scientific
|
||||
<< "\n\tcost: " << minCost
|
||||
<< "\n\tcost previous: " << minCostPrev
|
||||
<< std::fixed << std::endl;
|
||||
}
|
||||
// output cost and simplex
|
||||
if (showConvergeStatus)
|
||||
{
|
||||
if ( (minCostPrev + std::numeric_limits<float>::epsilon() )
|
||||
< minCost && minCostPrev != 0)
|
||||
{
|
||||
std::cout << "\twarning: simplex cost increased"
|
||||
<< std::scientific
|
||||
<< "\n\tcost: " << minCost
|
||||
<< "\n\tcost previous: " << minCostPrev
|
||||
<< std::fixed << std::endl;
|
||||
}
|
||||
|
||||
std::cout << "i: " << iter
|
||||
<< std::scientific
|
||||
<< "\tcost: " << m_cost[m_iMin]
|
||||
<< "\trtol: " << rtolI
|
||||
<< std::fixed
|
||||
<< "\talpha: " << m_simplex[m_iMin][2]*180/M_PI
|
||||
<< "\tbeta: " << m_simplex[m_iMin][5]*180/M_PI
|
||||
<< "\tthrottle: " << m_simplex[m_iMin][0]
|
||||
<< "\televator: " << m_simplex[m_iMin][1]
|
||||
<< "\taileron: " << m_simplex[m_iMin][3]
|
||||
<< "\trudder: " << m_simplex[m_iMin][4]
|
||||
<< std::endl;
|
||||
}
|
||||
if (showSimplex)
|
||||
{
|
||||
std::cout << "simplex: " << std::endl;;
|
||||
for (int j=0;j<m_nVert;j++)
|
||||
std::cout << "\t" << std::scientific
|
||||
<< std::setw(10) << m_cost[j];
|
||||
std::cout << std::endl;
|
||||
for (int j=0;j<m_nVert;j++) std::cout << "\t\t" << j;
|
||||
std::cout << std::endl;
|
||||
for (int i=0;i<m_nDim;i++)
|
||||
{
|
||||
for (int j=0;j<m_nVert;j++)
|
||||
std::cout << "\t" << std::setw(10) << m_simplex[j][i];
|
||||
std::cout << std::endl;
|
||||
}
|
||||
std::cout << std::fixed
|
||||
<< "\n\tiMax: " << m_iMax
|
||||
<< "\t\tiNextMax: " << m_iNextMax
|
||||
<< "\t\tiMin: " << m_iMin << std::endl;
|
||||
}
|
||||
std::cout << "i: " << iter
|
||||
<< std::scientific
|
||||
<< "\tcost: " << m_cost[m_iMin]
|
||||
<< "\trtol: " << rtolI
|
||||
<< std::fixed
|
||||
<< "\talpha: " << m_simplex[m_iMin][2]*180/M_PI
|
||||
<< "\tbeta: " << m_simplex[m_iMin][5]*180/M_PI
|
||||
<< "\tthrottle: " << m_simplex[m_iMin][0]
|
||||
<< "\televator: " << m_simplex[m_iMin][1]
|
||||
<< "\taileron: " << m_simplex[m_iMin][3]
|
||||
<< "\trudder: " << m_simplex[m_iMin][4]
|
||||
<< std::endl;
|
||||
}
|
||||
if (showSimplex)
|
||||
{
|
||||
std::cout << "simplex: " << std::endl;;
|
||||
for (int j=0;j<m_nVert;j++)
|
||||
std::cout << "\t" << std::scientific
|
||||
<< std::setw(10) << m_cost[j];
|
||||
std::cout << std::endl;
|
||||
for (int j=0;j<m_nVert;j++) std::cout << "\t\t" << j;
|
||||
std::cout << std::endl;
|
||||
for (int i=0;i<m_nDim;i++)
|
||||
{
|
||||
for (int j=0;j<m_nVert;j++)
|
||||
std::cout << "\t" << std::setw(10) << m_simplex[j][i];
|
||||
std::cout << std::endl;
|
||||
}
|
||||
std::cout << std::fixed
|
||||
<< "\n\tiMax: " << m_iMax
|
||||
<< "\t\tiNextMax: " << m_iNextMax
|
||||
<< "\t\tiMin: " << m_iMin << std::endl;
|
||||
}
|
||||
|
||||
if (pause)
|
||||
{
|
||||
std::cout << "paused, press any key to continue" << std::endl;
|
||||
std::cin.get();
|
||||
}
|
||||
if (pause)
|
||||
{
|
||||
std::cout << "paused, press any key to continue" << std::endl;
|
||||
std::cin.get();
|
||||
}
|
||||
|
||||
|
||||
// costs
|
||||
|
||||
try
|
||||
{
|
||||
// try inversion
|
||||
double costTry = tryStretch(-1.0);
|
||||
//std::cout << "cost Try 0: " << costTry << std::endl;
|
||||
// costs
|
||||
|
||||
try
|
||||
{
|
||||
// try inversion
|
||||
double costTry = tryStretch(-1.0);
|
||||
//std::cout << "cost Try 0: " << costTry << std::endl;
|
||||
|
||||
// if lower cost than best, then try further stretch by double speed factor
|
||||
if (costTry < minCost)
|
||||
{
|
||||
double costTry0 = costTry;
|
||||
costTry = tryStretch(speed);
|
||||
//std::cout << "cost Try 1: " << costTry << std::endl;
|
||||
// if lower cost than best, then try further stretch by double speed factor
|
||||
if (costTry < minCost)
|
||||
{
|
||||
double costTry0 = costTry;
|
||||
costTry = tryStretch(speed);
|
||||
//std::cout << "cost Try 1: " << costTry << std::endl;
|
||||
|
||||
if (showSimplex)
|
||||
{
|
||||
if (costTry < costTry0) std::cout << "inversion about: " << m_iMax << std::endl;
|
||||
else std::cout << "inversion and stretch about: " << m_iMax << std::endl;
|
||||
}
|
||||
}
|
||||
// otherwise try a contraction
|
||||
else if (costTry > nextMaxCost)
|
||||
{
|
||||
// 1d contraction
|
||||
costTry = tryStretch(1./speed);
|
||||
//std::cout << "cost Try 2: " << costTry << std::endl;
|
||||
if (showSimplex)
|
||||
{
|
||||
if (costTry < costTry0) std::cout << "inversion about: " << m_iMax << std::endl;
|
||||
else std::cout << "inversion and stretch about: " << m_iMax << std::endl;
|
||||
}
|
||||
}
|
||||
// otherwise try a contraction
|
||||
else if (costTry > nextMaxCost)
|
||||
{
|
||||
// 1d contraction
|
||||
costTry = tryStretch(1./speed);
|
||||
//std::cout << "cost Try 2: " << costTry << std::endl;
|
||||
|
||||
// if greater than max cost, contract about min
|
||||
if (costTry > maxCost)
|
||||
{
|
||||
if (showSimplex)
|
||||
std::cout << "multiD contraction about: " << m_iMin << std::endl;
|
||||
contract();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (showSimplex)
|
||||
std::cout << "contraction about: " << m_iMin << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
// if greater than max cost, contract about min
|
||||
if (costTry > maxCost)
|
||||
{
|
||||
if (showSimplex)
|
||||
std::cout << "multiD contraction about: " << m_iMin << std::endl;
|
||||
contract();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (showSimplex)
|
||||
std::cout << "contraction about: " << m_iMin << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
catch (const std::exception & e)
|
||||
{
|
||||
throw;
|
||||
m_status = -1;
|
||||
return;
|
||||
}
|
||||
catch (const std::exception & e)
|
||||
{
|
||||
throw;
|
||||
m_status = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// iteration
|
||||
iter++;
|
||||
// iteration
|
||||
iter++;
|
||||
|
||||
}
|
||||
|
||||
int FGNelderMead::status()
|
||||
{
|
||||
return m_status;
|
||||
return m_status;
|
||||
}
|
||||
|
||||
double FGNelderMead::getRandomFactor()
|
||||
{
|
||||
double randFact = 1+(float(rand() % 1000)/500-1)*m_randomization;
|
||||
//std::cout << "random factor: " << randFact << std::endl;;
|
||||
return randFact;
|
||||
double randFact = 1+(float(rand() % 1000)/500-1)*m_randomization;
|
||||
//std::cout << "random factor: " << randFact << std::endl;;
|
||||
return randFact;
|
||||
}
|
||||
|
||||
std::vector<double> FGNelderMead::getSolution()
|
||||
|
@ -271,8 +272,8 @@ std::vector<double> FGNelderMead::getSolution()
|
|||
|
||||
double FGNelderMead::tryStretch(double factor)
|
||||
{
|
||||
// randomize factor so we can avoid locking situations
|
||||
factor = factor*getRandomFactor();
|
||||
// randomize factor so we can avoid locking situations
|
||||
factor = factor*getRandomFactor();
|
||||
|
||||
// create trial vertex
|
||||
double a= (1.0-factor)/m_nDim;
|
||||
|
@ -285,23 +286,7 @@ double FGNelderMead::tryStretch(double factor)
|
|||
}
|
||||
|
||||
// find trial cost
|
||||
double costTry0 = 0, costTry = 0;
|
||||
try
|
||||
{
|
||||
costTry0 = m_f->eval(tryVertex);
|
||||
costTry = m_f->eval(tryVertex);
|
||||
}
|
||||
catch(const std::exception & e)
|
||||
{
|
||||
throw;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (std::abs(costTry0-costTry) > std::numeric_limits<float>::epsilon())
|
||||
{
|
||||
//std::cout << "\twarning: dynamics not stable!" << std::endl;
|
||||
//return 1000000*m_cost[m_iMax];
|
||||
}
|
||||
double costTry = eval(tryVertex);
|
||||
|
||||
// if trial cost lower than max
|
||||
if (costTry < m_cost[m_iMax])
|
||||
|
@ -337,7 +322,7 @@ void FGNelderMead::constructSimplex(const std::vector<double> & guess,
|
|||
for (int vertex=0;vertex<m_nVert;vertex++)
|
||||
{
|
||||
m_simplex[vertex] = guess;
|
||||
}
|
||||
}
|
||||
|
||||
for (int dim=0;dim<m_nDim;dim++)
|
||||
{
|
||||
|
@ -370,6 +355,30 @@ void FGNelderMead::boundVertex(std::vector<double> & vertex,
|
|||
}
|
||||
}
|
||||
|
||||
double FGNelderMead::eval(const std::vector<double> & vertex, bool check)
|
||||
{
|
||||
if (check) {
|
||||
double cost0 = m_f->eval(vertex);
|
||||
double cost1 = m_f->eval(vertex);
|
||||
if ((cost0 - cost1) > std::numeric_limits<float>::epsilon()) {
|
||||
std::stringstream msg;
|
||||
msg.precision(10);
|
||||
msg << std::scientific
|
||||
<< "dynamics not stable!"
|
||||
<< "\tdiff: " << cost1 - cost0
|
||||
<< "\tcost0: " << cost0
|
||||
<< "\tcost1: " << cost1
|
||||
<< std::endl;
|
||||
std::cout << msg.str();
|
||||
//throw std::runtime_error(msg.str());
|
||||
} else {
|
||||
return cost1;
|
||||
}
|
||||
} else {
|
||||
return m_f->eval(vertex);
|
||||
}
|
||||
}
|
||||
|
||||
} // JSBSim
|
||||
|
||||
|
||||
|
|
|
@ -3,16 +3,16 @@
|
|||
* Copyright (C) James Goppert 2010 <james.goppert@gmail.com>
|
||||
*
|
||||
* FGNelderMead.h is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FGNelderMead.h is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
* See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* You should have received a copy of the GNU Lesser General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
@ -35,7 +35,7 @@ public:
|
|||
virtual double eval(const std::vector<double> & v) = 0;
|
||||
virtual ~Function() {};
|
||||
};
|
||||
class Callback
|
||||
class Callback
|
||||
{
|
||||
public:
|
||||
virtual void eval(const std::vector<double> & v) = 0;
|
||||
|
@ -49,43 +49,44 @@ public:
|
|||
double rtol=std::numeric_limits<float>::epsilon(),
|
||||
double abstol=std::numeric_limits<float>::epsilon(),
|
||||
double speed = 2.0,
|
||||
double randomization=0.1,
|
||||
double randomization=0.1,
|
||||
bool showConvergeStatus=true,bool showSimplex=false,
|
||||
bool pause=false,
|
||||
Callback * callback=NULL);
|
||||
Callback * callback=NULL);
|
||||
std::vector<double> getSolution();
|
||||
|
||||
void update();
|
||||
int status();
|
||||
void update();
|
||||
int status();
|
||||
|
||||
private:
|
||||
// attributes
|
||||
Function * m_f;
|
||||
Callback * m_callback;
|
||||
double m_randomization;
|
||||
Callback * m_callback;
|
||||
double m_randomization;
|
||||
const std::vector<double> & m_lowerBound;
|
||||
const std::vector<double> & m_upperBound;
|
||||
int m_nDim, m_nVert, m_iMax, m_iNextMax, m_iMin;
|
||||
std::vector< std::vector<double> > m_simplex;
|
||||
std::vector<double> m_cost;
|
||||
std::vector<double> m_elemSum;
|
||||
int m_status;
|
||||
int m_status;
|
||||
const std::vector<double> & initialGuess;
|
||||
const std::vector<double> & initialStepSize;
|
||||
int iterMax, iter;
|
||||
double rtol,abstol,speed;
|
||||
bool showConvergeStatus, showSimplex, pause;
|
||||
double rtolI, minCostPrevResize, minCost, minCostPrev,
|
||||
maxCost, nextMaxCost;
|
||||
int iterMax, iter;
|
||||
double rtol,abstol,speed;
|
||||
bool showConvergeStatus, showSimplex, pause;
|
||||
double rtolI, minCostPrevResize, minCost, minCostPrev,
|
||||
maxCost, nextMaxCost;
|
||||
|
||||
// methods
|
||||
double getRandomFactor();
|
||||
double getRandomFactor();
|
||||
double tryStretch(double factor);
|
||||
void contract();
|
||||
void constructSimplex(const std::vector<double> & guess, const std::vector<double> & stepSize);
|
||||
void boundVertex(std::vector<double> & vertex,
|
||||
const std::vector<double> & upperBound,
|
||||
const std::vector<double> & lowerBound);
|
||||
double eval(const std::vector<double> & vertex, bool check = false);
|
||||
};
|
||||
|
||||
} // JSBSim
|
||||
|
|
|
@ -30,17 +30,18 @@ INCLUDES
|
|||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include "FGPropertyValue.h"
|
||||
#include "input_output/FGPropertyManager.h"
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGPropertyValue.cpp,v 1.7 2011/04/05 20:20:21 andgi Exp $";
|
||||
static const char *IdSrc = "$Id: FGPropertyValue.cpp,v 1.8 2013/01/26 17:06:49 bcoconni Exp $";
|
||||
static const char *IdHdr = ID_PROPERTYVALUE;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS IMPLEMENTATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
FGPropertyValue::FGPropertyValue(FGPropertyManager* propNode)
|
||||
FGPropertyValue::FGPropertyValue(FGPropertyNode* propNode)
|
||||
: PropertyManager(0L), PropertyNode(propNode)
|
||||
{
|
||||
}
|
||||
|
@ -56,7 +57,7 @@ FGPropertyValue::FGPropertyValue(std::string propName, FGPropertyManager* proper
|
|||
|
||||
double FGPropertyValue::GetValue(void) const
|
||||
{
|
||||
FGPropertyManager* node = PropertyNode;
|
||||
FGPropertyNode* node = PropertyNode;
|
||||
|
||||
if (!PropertyNode) {
|
||||
// The node cannot be cached since this is a const method.
|
||||
|
|
|
@ -42,7 +42,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_PROPERTYVALUE "$Id: FGPropertyValue.h,v 1.9 2011/04/05 20:20:21 andgi Exp $"
|
||||
#define ID_PROPERTYVALUE "$Id: FGPropertyValue.h,v 1.10 2013/01/26 17:06:49 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -66,18 +66,18 @@ class FGPropertyValue : public FGParameter
|
|||
{
|
||||
public:
|
||||
|
||||
FGPropertyValue(FGPropertyManager* propNode);
|
||||
FGPropertyValue(FGPropertyNode* propNode);
|
||||
FGPropertyValue(std::string propName, FGPropertyManager* propertyManager);
|
||||
~FGPropertyValue() {};
|
||||
|
||||
double GetValue(void) const;
|
||||
void SetNode(FGPropertyManager* node) {PropertyNode = node;}
|
||||
void SetNode(FGPropertyNode* node) {PropertyNode = node;}
|
||||
|
||||
std::string GetName(void) const;
|
||||
|
||||
private:
|
||||
FGPropertyManager* PropertyManager; // Property root used to do late binding.
|
||||
FGPropertyManager* PropertyNode;
|
||||
FGPropertyNode_ptr PropertyNode;
|
||||
std::string PropertyName;
|
||||
};
|
||||
|
||||
|
|
|
@ -3,22 +3,23 @@
|
|||
* Copyright (C) James Goppert 2010 <james.goppert@gmail.com>
|
||||
*
|
||||
* FGStateSpace.cpp is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FGStateSpace.cpp is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
* See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* You should have received a copy of the GNU Lesser General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "FGStateSpace.h"
|
||||
#include <limits>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
|
||||
namespace JSBSim
|
||||
{
|
||||
|
@ -77,7 +78,23 @@ void FGStateSpace::numericalJacobian(std::vector< std::vector<double> > & J, Co
|
|||
if (computeYDerivative) fn2 = y.getDeriv(iY);
|
||||
else fn2 = y.get(iY);
|
||||
|
||||
J[iY][iX] = (8*(f1-fn1)-(f2-fn2))/(12*h); // 3rd order taylor approx from lewis, pg 203
|
||||
double diff1 = f1-fn1;
|
||||
double diff2 = f2-fn2;
|
||||
|
||||
// correct for angle wrap
|
||||
if (x.getComp(iX)->getUnit().compare("rad") == 0) {
|
||||
while(diff1 > M_PI) diff1 -= 2*M_PI;
|
||||
if(diff1 < -M_PI) diff1 += 2*M_PI;
|
||||
if(diff2 > M_PI) diff2 -= 2*M_PI;
|
||||
if(diff2 < -M_PI) diff2 += 2*M_PI;
|
||||
} else if (x.getComp(iX)->getUnit().compare("deg") == 0) {
|
||||
if(diff1 > 180) diff1 -= 360;
|
||||
if(diff1 < -180) diff1 += 360;
|
||||
if(diff2 > 180) diff2 -= 360;
|
||||
if(diff2 < -180) diff2 += 360;
|
||||
}
|
||||
J[iY][iX] = (8*diff1-diff2)/(12*h); // 3rd order taylor approx from lewis, pg 203
|
||||
|
||||
x.set(x0);
|
||||
|
||||
if (m_fdm->GetDebugLevel() > 1)
|
||||
|
|
|
@ -3,16 +3,16 @@
|
|||
* Copyright (C) James Goppert 2010 <james.goppert@gmail.com>
|
||||
*
|
||||
* FGStateSpace.h is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* FGStateSpace.h is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
* See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* You should have received a copy of the GNU Lesser General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
@ -30,6 +30,7 @@
|
|||
#include "models/FGFCS.h"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
|
||||
namespace JSBSim
|
||||
{
|
||||
|
@ -57,9 +58,9 @@ public:
|
|||
std::vector<double> x0 = m_stateSpace->x.get();
|
||||
double f0 = get();
|
||||
double dt0 = m_fdm->GetDeltaT();
|
||||
double time0 = m_fdm->GetSimTime();
|
||||
double time0 = m_fdm->GetSimTime();
|
||||
m_fdm->Setdt(1./120.);
|
||||
m_fdm->DisableOutput();
|
||||
m_fdm->DisableOutput();
|
||||
m_fdm->Run();
|
||||
double f1 = get();
|
||||
m_stateSpace->x.set(x0);
|
||||
|
@ -75,8 +76,8 @@ public:
|
|||
}
|
||||
double deriv = (f1-f0)/m_fdm->GetDeltaT();
|
||||
m_fdm->Setdt(dt0); // restore original value
|
||||
m_fdm->Setsim_time(time0);
|
||||
m_fdm->EnableOutput();
|
||||
m_fdm->Setsim_time(time0);
|
||||
m_fdm->EnableOutput();
|
||||
return deriv;
|
||||
}
|
||||
void setStateSpace(FGStateSpace * stateSpace)
|
||||
|
@ -141,7 +142,7 @@ public:
|
|||
void set(int i, double val)
|
||||
{
|
||||
m_components[i]->set(val);
|
||||
m_fdm->RunIC();
|
||||
m_stateSpace->run();
|
||||
};
|
||||
double get(int i)
|
||||
{
|
||||
|
@ -174,12 +175,12 @@ public:
|
|||
void set(vector<double> vals)
|
||||
{
|
||||
for (int i=0;i<getSize();i++) m_components[i]->set(vals[i]);
|
||||
m_fdm->RunIC();
|
||||
m_stateSpace->run();
|
||||
}
|
||||
void set(double * array)
|
||||
{
|
||||
for (int i=0;i<getSize();i++) m_components[i]->set(array[i]);
|
||||
m_fdm->RunIC();
|
||||
m_stateSpace->run();
|
||||
}
|
||||
std::string getName(int i) const
|
||||
{
|
||||
|
@ -218,6 +219,51 @@ public:
|
|||
|
||||
void setFdm(FGFDMExec * fdm) { m_fdm = fdm; }
|
||||
|
||||
void run() {
|
||||
// initialize
|
||||
m_fdm->Initialize(m_fdm->GetIC());
|
||||
for (unsigned int i=0; i<m_fdm->GetPropulsion()->GetNumEngines(); i++) {
|
||||
m_fdm->GetPropulsion()->GetEngine(i)->InitRunning();
|
||||
}
|
||||
|
||||
// wait for stable state
|
||||
double cost = stateSum();
|
||||
for(int i=0;i<1000;i++) {
|
||||
m_fdm->GetPropulsion()->GetSteadyState();
|
||||
m_fdm->SetTrimStatus(true);
|
||||
m_fdm->DisableOutput();
|
||||
m_fdm->SuspendIntegration();
|
||||
m_fdm->Run();
|
||||
m_fdm->SetTrimStatus(false);
|
||||
m_fdm->EnableOutput();
|
||||
m_fdm->ResumeIntegration();
|
||||
|
||||
double costNew = stateSum();
|
||||
double dcost = fabs(costNew - cost);
|
||||
if (dcost < std::numeric_limits<double>::epsilon()) {
|
||||
if(m_fdm->GetDebugLevel() > 1) {
|
||||
std::cout << "cost convergd, i: " << i << std::endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (i > 1000) {
|
||||
if(m_fdm->GetDebugLevel() > 1) {
|
||||
std::cout << "cost failed to converge, dcost: "
|
||||
<< std::scientific
|
||||
<< dcost << std::endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
cost = costNew;
|
||||
}
|
||||
}
|
||||
|
||||
double stateSum() {
|
||||
double sum = 0;
|
||||
for (int i=0;i<x.getSize();i++) sum += x.get(i);
|
||||
return sum;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
x.clear();
|
||||
u.clear();
|
||||
|
@ -272,7 +318,7 @@ public:
|
|||
|
||||
};
|
||||
|
||||
class VGround : public Component
|
||||
class VGround : public Component
|
||||
{
|
||||
public:
|
||||
VGround() : Component("VGround","ft/s") {};
|
||||
|
@ -282,11 +328,11 @@ public:
|
|||
}
|
||||
void set(double val)
|
||||
{
|
||||
m_fdm->GetIC()->SetVgroundFpsIC(val);
|
||||
m_fdm->GetIC()->SetVgroundFpsIC(val);
|
||||
}
|
||||
};
|
||||
|
||||
class AccelX : public Component
|
||||
class AccelX : public Component
|
||||
{
|
||||
public:
|
||||
AccelX() : Component("AccelX","ft/s^2") {};
|
||||
|
@ -296,11 +342,11 @@ public:
|
|||
}
|
||||
void set(double val)
|
||||
{
|
||||
// XXX: not possible to implement currently
|
||||
// XXX: not possible to implement currently
|
||||
}
|
||||
};
|
||||
|
||||
class AccelY : public Component
|
||||
class AccelY : public Component
|
||||
{
|
||||
public:
|
||||
AccelY() : Component("AccelY","ft/s^2") {};
|
||||
|
@ -310,11 +356,11 @@ public:
|
|||
}
|
||||
void set(double val)
|
||||
{
|
||||
// XXX: not possible to implement currently
|
||||
// XXX: not possible to implement currently
|
||||
}
|
||||
};
|
||||
|
||||
class AccelZ : public Component
|
||||
class AccelZ : public Component
|
||||
{
|
||||
public:
|
||||
AccelZ() : Component("AccelZ","ft/s^2") {};
|
||||
|
@ -324,7 +370,7 @@ public:
|
|||
}
|
||||
void set(double val)
|
||||
{
|
||||
// XXX: not possible to implement currently
|
||||
// XXX: not possible to implement currently
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -338,8 +384,13 @@ public:
|
|||
}
|
||||
void set(double val)
|
||||
{
|
||||
m_fdm->GetIC()->SetFlightPathAngleRadIC(m_fdm->GetIC()->GetThetaRadIC()-val);
|
||||
double beta = m_fdm->GetIC()->GetBetaDegIC();
|
||||
double psi = m_fdm->GetIC()->GetPsiRadIC();
|
||||
double theta = m_fdm->GetIC()->GetThetaRadIC();
|
||||
m_fdm->GetIC()->SetAlphaRadIC(val);
|
||||
m_fdm->GetIC()->SetBetaRadIC(beta);
|
||||
m_fdm->GetIC()->SetPsiRadIC(psi);
|
||||
m_fdm->GetIC()->SetThetaRadIC(theta);
|
||||
}
|
||||
double getDeriv() const
|
||||
{
|
||||
|
@ -357,8 +408,8 @@ public:
|
|||
}
|
||||
void set(double val)
|
||||
{
|
||||
m_fdm->GetIC()->SetFlightPathAngleRadIC(val-m_fdm->GetIC()->GetAlphaRadIC());
|
||||
m_fdm->GetIC()->SetThetaRadIC(val);
|
||||
m_fdm->GetIC()->SetFlightPathAngleRadIC(val-m_fdm->GetIC()->GetAlphaRadIC());
|
||||
//m_fdm->GetIC()->SetThetaRadIC(val);
|
||||
}
|
||||
double getDeriv() const
|
||||
{
|
||||
|
@ -412,7 +463,9 @@ public:
|
|||
}
|
||||
void set(double val)
|
||||
{
|
||||
double psi = m_fdm->GetIC()->GetPsiRadIC();
|
||||
m_fdm->GetIC()->SetBetaRadIC(val);
|
||||
m_fdm->GetIC()->SetPsiRadIC(psi);
|
||||
}
|
||||
double getDeriv() const
|
||||
{
|
||||
|
@ -621,11 +674,11 @@ public:
|
|||
}
|
||||
void set(double val)
|
||||
{
|
||||
m_fdm->GetPropulsion()->GetEngine(0)->GetThruster()->SetRPM(val);
|
||||
m_fdm->GetPropulsion()->GetEngine(0)->GetThruster()->SetRPM(val);
|
||||
}
|
||||
};
|
||||
|
||||
class Rpm1 : public Component
|
||||
class Rpm1 : public Component
|
||||
{
|
||||
public:
|
||||
Rpm1() : Component("Rpm1","rev/min") {};
|
||||
|
@ -635,25 +688,25 @@ public:
|
|||
}
|
||||
void set(double val)
|
||||
{
|
||||
m_fdm->GetPropulsion()->GetEngine(1)->GetThruster()->SetRPM(val);
|
||||
m_fdm->GetPropulsion()->GetEngine(1)->GetThruster()->SetRPM(val);
|
||||
}
|
||||
};
|
||||
|
||||
class Rpm2 : public Component
|
||||
class Rpm2 : public Component
|
||||
{
|
||||
public:
|
||||
Rpm2() : Component("Rpmr2","rev/min") {};
|
||||
Rpm2() : Component("Rpm2","rev/min") {};
|
||||
double get() const
|
||||
{
|
||||
return m_fdm->GetPropulsion()->GetEngine(2)->GetThruster()->GetRPM();
|
||||
}
|
||||
void set(double val)
|
||||
{
|
||||
m_fdm->GetPropulsion()->GetEngine(2)->GetThruster()->SetRPM(val);
|
||||
m_fdm->GetPropulsion()->GetEngine(2)->GetThruster()->SetRPM(val);
|
||||
}
|
||||
};
|
||||
|
||||
class Rpm3 : public Component
|
||||
class Rpm3 : public Component
|
||||
{
|
||||
public:
|
||||
Rpm3() : Component("Rpm3","rev/min") {};
|
||||
|
@ -663,7 +716,7 @@ public:
|
|||
}
|
||||
void set(double val)
|
||||
{
|
||||
m_fdm->GetPropulsion()->GetEngine(3)->GetThruster()->SetRPM(val);
|
||||
m_fdm->GetPropulsion()->GetEngine(3)->GetThruster()->SetRPM(val);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -718,7 +771,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class Pi : public Component
|
||||
class Pi : public Component
|
||||
{
|
||||
public:
|
||||
Pi() : Component("P inertial","rad/s") {};
|
||||
|
@ -728,10 +781,10 @@ public:
|
|||
}
|
||||
void set(double val)
|
||||
{
|
||||
//Set PQR from PQRi
|
||||
//VState.vPQR = VState.vPQRi - Ti2b * vOmegaEarth;
|
||||
//Set PQR from PQRi
|
||||
//VState.vPQR = VState.vPQRi - Ti2b * vOmegaEarth;
|
||||
m_fdm->GetIC()->SetQRadpsIC(val + \
|
||||
(m_fdm->GetPropagate()->GetPQR(1) - m_fdm->GetPropagate()->GetPQRi(1)));
|
||||
(m_fdm->GetPropagate()->GetPQR(1) - m_fdm->GetPropagate()->GetPQRi(1)));
|
||||
}
|
||||
double getDeriv() const
|
||||
{
|
||||
|
@ -739,7 +792,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class Qi : public Component
|
||||
class Qi : public Component
|
||||
{
|
||||
public:
|
||||
Qi() : Component("Q inertial","rad/s") {};
|
||||
|
@ -749,10 +802,10 @@ public:
|
|||
}
|
||||
void set(double val)
|
||||
{
|
||||
//Set PQR from PQRi
|
||||
//VState.vPQR = VState.vPQRi - Ti2b * vOmegaEarth;
|
||||
//Set PQR from PQRi
|
||||
//VState.vPQR = VState.vPQRi - Ti2b * vOmegaEarth;
|
||||
m_fdm->GetIC()->SetQRadpsIC(val + \
|
||||
(m_fdm->GetPropagate()->GetPQR(2) - m_fdm->GetPropagate()->GetPQRi(2)));
|
||||
(m_fdm->GetPropagate()->GetPQR(2) - m_fdm->GetPropagate()->GetPQRi(2)));
|
||||
}
|
||||
double getDeriv() const
|
||||
{
|
||||
|
@ -760,7 +813,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class Ri : public Component
|
||||
class Ri : public Component
|
||||
{
|
||||
public:
|
||||
Ri() : Component("R inertial","rad/s") {};
|
||||
|
@ -770,10 +823,10 @@ public:
|
|||
}
|
||||
void set(double val)
|
||||
{
|
||||
//Set PQR from PQRi
|
||||
//VState.vPQR = VState.vPQRi - Ti2b * vOmegaEarth;
|
||||
//Set PQR from PQRi
|
||||
//VState.vPQR = VState.vPQRi - Ti2b * vOmegaEarth;
|
||||
m_fdm->GetIC()->SetQRadpsIC(val + \
|
||||
(m_fdm->GetPropagate()->GetPQR(3) - m_fdm->GetPropagate()->GetPQRi(3)));
|
||||
(m_fdm->GetPropagate()->GetPQR(3) - m_fdm->GetPropagate()->GetPQRi(3)));
|
||||
}
|
||||
double getDeriv() const
|
||||
{
|
||||
|
@ -781,7 +834,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class Vn : public Component
|
||||
class Vn : public Component
|
||||
{
|
||||
public:
|
||||
Vn() : Component("Vel north","feet/s") {};
|
||||
|
@ -795,12 +848,12 @@ public:
|
|||
}
|
||||
double getDeriv() const
|
||||
{
|
||||
//get NED accel from body accel
|
||||
//get NED accel from body accel
|
||||
return (m_fdm->GetPropagate()->GetTb2l()*m_fdm->GetAccelerations()->GetUVWdot())(1);
|
||||
}
|
||||
};
|
||||
|
||||
class Ve : public Component
|
||||
class Ve : public Component
|
||||
{
|
||||
public:
|
||||
Ve() : Component("Vel east","feet/s") {};
|
||||
|
@ -814,12 +867,12 @@ public:
|
|||
}
|
||||
double getDeriv() const
|
||||
{
|
||||
//get NED accel from body accel
|
||||
//get NED accel from body accel
|
||||
return (m_fdm->GetPropagate()->GetTb2l()*m_fdm->GetAccelerations()->GetUVWdot())(2);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class Vd : public Component
|
||||
class Vd : public Component
|
||||
{
|
||||
public:
|
||||
Vd() : Component("Vel down","feet/s") {};
|
||||
|
@ -833,35 +886,35 @@ public:
|
|||
}
|
||||
double getDeriv() const
|
||||
{
|
||||
//get NED accel from body accel
|
||||
//get NED accel from body accel
|
||||
return (m_fdm->GetPropagate()->GetTb2l()*m_fdm->GetAccelerations()->GetUVWdot())(3);
|
||||
}
|
||||
};
|
||||
|
||||
class COG : public Component
|
||||
class COG : public Component
|
||||
{
|
||||
public:
|
||||
COG() : Component("Course Over Ground","rad") {};
|
||||
double get() const
|
||||
{
|
||||
//cog = atan2(Ve,Vn)
|
||||
//cog = atan2(Ve,Vn)
|
||||
return atan2(m_fdm->GetPropagate()->GetVel(2),m_fdm->GetPropagate()->GetVel(1));
|
||||
}
|
||||
void set(double val)
|
||||
{
|
||||
//set Vn and Ve according to vGround and COG
|
||||
m_fdm->GetIC()->SetVNorthFpsIC(m_fdm->GetAuxiliary()->GetVground()*cos(val));
|
||||
m_fdm->GetIC()->SetVEastFpsIC(m_fdm->GetAuxiliary()->GetVground()*sin(val));
|
||||
//set Vn and Ve according to vGround and COG
|
||||
m_fdm->GetIC()->SetVNorthFpsIC(m_fdm->GetAuxiliary()->GetVground()*cos(val));
|
||||
m_fdm->GetIC()->SetVEastFpsIC(m_fdm->GetAuxiliary()->GetVground()*sin(val));
|
||||
}
|
||||
double getDeriv() const
|
||||
{
|
||||
double Vn = m_fdm->GetPropagate()->GetVel(1);
|
||||
double Vndot = (m_fdm->GetPropagate()->GetTb2l()*m_fdm->GetAccelerations()->GetUVWdot())(1);
|
||||
double Ve = m_fdm->GetPropagate()->GetVel(2);
|
||||
double Vedot = (m_fdm->GetPropagate()->GetTb2l()*m_fdm->GetAccelerations()->GetUVWdot())(2);
|
||||
double Vn = m_fdm->GetPropagate()->GetVel(1);
|
||||
double Vndot = (m_fdm->GetPropagate()->GetTb2l()*m_fdm->GetAccelerations()->GetUVWdot())(1);
|
||||
double Ve = m_fdm->GetPropagate()->GetVel(2);
|
||||
double Vedot = (m_fdm->GetPropagate()->GetTb2l()*m_fdm->GetAccelerations()->GetUVWdot())(2);
|
||||
|
||||
//dCOG/dt = dCOG/dVe*dVe/dt + dCOG/dVn*dVn/dt
|
||||
return Vn/(Vn*Vn+Ve*Ve)*Vedot - Ve/(Vn*Vn+Ve*Ve)*Vndot;
|
||||
//dCOG/dt = dCOG/dVe*dVe/dt + dCOG/dVn*dVn/dt
|
||||
return Vn/(Vn*Vn+Ve*Ve)*Vedot - Ve/(Vn*Vn+Ve*Ve)*Vndot;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGTable.cpp,v 1.28 2011/06/13 12:07:10 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGTable.cpp,v 1.29 2013/01/26 17:06:49 bcoconni Exp $";
|
||||
static const char *IdHdr = ID_TABLE;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -122,7 +122,7 @@ FGTable::FGTable(FGPropertyManager* propMan, Element* el) : PropertyManager(prop
|
|||
string call_type;
|
||||
string parent_type;
|
||||
string brkpt_string;
|
||||
FGPropertyManager* node;
|
||||
FGPropertyNode* node;
|
||||
Element *tableData=0;
|
||||
Element *parent_element=0;
|
||||
Element *axisElement=0;
|
||||
|
|
|
@ -38,16 +38,17 @@ SENTRY
|
|||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include "FGParameter.h"
|
||||
#include <iosfwd>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "FGParameter.h"
|
||||
#include "input_output/FGPropertyManager.h"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_TABLE "$Id: FGTable.h,v 1.14 2011/06/13 11:46:08 jberndt Exp $"
|
||||
#define ID_TABLE "$Id: FGTable.h,v 1.15 2013/01/26 17:06:49 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -55,7 +56,6 @@ FORWARD DECLARATIONS
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
class FGPropertyManager;
|
||||
class Element;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -233,7 +233,7 @@ combustion_efficiency = Lookup_Combustion_Efficiency->GetValue(equivalence_ratio
|
|||
@endcode
|
||||
|
||||
@author Jon S. Berndt
|
||||
@version $Id: FGTable.h,v 1.14 2011/06/13 11:46:08 jberndt Exp $
|
||||
@version $Id: FGTable.h,v 1.15 2013/01/26 17:06:49 bcoconni Exp $
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -290,8 +290,8 @@ public:
|
|||
double operator()(unsigned int r, unsigned int c) const {return GetElement(r, c);}
|
||||
// double operator()(unsigned int r, unsigned int c, unsigned int t) {GetElement(r, c, t);}
|
||||
|
||||
void SetRowIndexProperty(FGPropertyManager *node) {lookupProperty[eRow] = node;}
|
||||
void SetColumnIndexProperty(FGPropertyManager *node) {lookupProperty[eColumn] = node;}
|
||||
void SetRowIndexProperty(FGPropertyNode *node) {lookupProperty[eRow] = node;}
|
||||
void SetColumnIndexProperty(FGPropertyNode *node) {lookupProperty[eColumn] = node;}
|
||||
|
||||
unsigned int GetNumRows() const {return nRows;}
|
||||
|
||||
|
@ -303,7 +303,7 @@ private:
|
|||
enum type {tt1D, tt2D, tt3D} Type;
|
||||
enum axis {eRow=0, eColumn, eTable};
|
||||
bool internal;
|
||||
FGPropertyManager *lookupProperty[3];
|
||||
FGPropertyNode_ptr lookupProperty[3];
|
||||
double** Data;
|
||||
std::vector <FGTable*> Tables;
|
||||
unsigned int nRows, nCols, nTables, dimension;
|
||||
|
|
|
@ -48,7 +48,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGAerodynamics.cpp,v 1.46 2012/07/26 04:33:46 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGAerodynamics.cpp,v 1.47 2013/06/10 01:59:16 jberndt Exp $";
|
||||
static const char *IdHdr = ID_AERODYNAMICS;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -180,6 +180,12 @@ bool FGAerodynamics::Run(bool Holding)
|
|||
// JSB 4/27/12 - After use, convert wind axes to produce normal lift
|
||||
// and drag values - not negative ones!
|
||||
|
||||
// As a clarification, JSBSim assumes that drag and lift values are defined
|
||||
// in wind axes - BUT with a 180 rotation about the Y axis. That is, lift and
|
||||
// drag will be positive up and aft, respectively, so that they are reported
|
||||
// as positive numbers. However, the wind axes themselves assume that the X
|
||||
// and Z forces are positive forward and down.
|
||||
|
||||
switch (axisType) {
|
||||
case atBodyXYZ: // Forces already in body axes; no manipulation needed
|
||||
vFw = in.Tb2w*vFnative;
|
||||
|
|
|
@ -50,7 +50,7 @@ INCLUDES
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGAtmosphere.cpp,v 1.54 2012/09/17 12:38:07 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGAtmosphere.cpp,v 1.55 2013/01/26 17:06:49 bcoconni Exp $";
|
||||
static const char *IdHdr = ID_ATMOSPHERE;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -111,20 +111,21 @@ bool FGAtmosphere::Run(bool Holding)
|
|||
|
||||
void FGAtmosphere::Calculate(double altitude)
|
||||
{
|
||||
FGPropertyNode* node = PropertyManager->GetNode();
|
||||
if (!PropertyManager->HasNode("atmosphere/override/temperature"))
|
||||
Temperature = GetTemperature(altitude);
|
||||
else
|
||||
Temperature = PropertyManager->getDoubleValue("atmosphere/override/temperature");
|
||||
Temperature = GetTemperature(altitude);
|
||||
else
|
||||
Temperature = node->GetDouble("atmosphere/override/temperature");
|
||||
|
||||
if (!PropertyManager->HasNode("atmosphere/override/pressure"))
|
||||
Pressure = GetPressure(altitude);
|
||||
else
|
||||
Pressure = PropertyManager->getDoubleValue("atmosphere/override/pressure");
|
||||
Pressure = GetPressure(altitude);
|
||||
else
|
||||
Pressure = node->GetDouble("atmosphere/override/pressure");
|
||||
|
||||
if (!PropertyManager->HasNode("atmosphere/override/density"))
|
||||
Density = Pressure/(Reng*Temperature);
|
||||
else
|
||||
Density = PropertyManager->getDoubleValue("atmosphere/override/density");
|
||||
Density = Pressure/(Reng*Temperature);
|
||||
else
|
||||
Density = node->GetDouble("atmosphere/override/density");
|
||||
|
||||
Soundspeed = sqrt(SHRatio*Reng*(Temperature));
|
||||
PressureAltitude = altitude;
|
||||
|
|
|
@ -50,7 +50,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGAuxiliary.cpp,v 1.60 2012/09/30 16:49:17 bcoconni Exp $";
|
||||
static const char *IdSrc = "$Id: FGAuxiliary.cpp,v 1.61 2013/06/10 01:56:14 jberndt Exp $";
|
||||
static const char *IdHdr = ID_AUXILIARY;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -76,7 +76,7 @@ FGAuxiliary::FGAuxiliary(FGFDMExec* fdmex) : FGModel(fdmex)
|
|||
seconds_in_day = 0.0;
|
||||
hoverbmac = hoverbcg = 0.0;
|
||||
Re = 0.0;
|
||||
Nz = 0.0;
|
||||
Nz = Ny = 0.0;
|
||||
lon_relative_position = lat_relative_position = relative_position = 0.0;
|
||||
|
||||
vPilotAccel.InitMatrix();
|
||||
|
@ -111,7 +111,7 @@ bool FGAuxiliary::InitModel(void)
|
|||
seconds_in_day = 0.0;
|
||||
hoverbmac = hoverbcg = 0.0;
|
||||
Re = 0.0;
|
||||
Nz = 0.0;
|
||||
Nz = Ny = 0.0;
|
||||
lon_relative_position = lat_relative_position = relative_position = 0.0;
|
||||
|
||||
vPilotAccel.InitMatrix();
|
||||
|
@ -228,6 +228,7 @@ bool FGAuxiliary::Run(bool Holding)
|
|||
vNcg = in.vBodyAccel/in.SLGravity;
|
||||
// Nz is Acceleration in "g's", along normal axis (-Z body axis)
|
||||
Nz = -vNcg(eZ);
|
||||
Ny = vNcg(eY);
|
||||
vPilotAccel = in.vBodyAccel + in.vPQRdot * in.ToEyePt;
|
||||
vPilotAccel += in.vPQR * (in.vPQR * in.ToEyePt);
|
||||
|
||||
|
@ -373,6 +374,7 @@ void FGAuxiliary::bind(void)
|
|||
PropertyManager->Tie("accelerations/n-pilot-y-norm", this, eY, (PMF)&FGAuxiliary::GetNpilot);
|
||||
PropertyManager->Tie("accelerations/n-pilot-z-norm", this, eZ, (PMF)&FGAuxiliary::GetNpilot);
|
||||
PropertyManager->Tie("accelerations/Nz", this, &FGAuxiliary::GetNz);
|
||||
PropertyManager->Tie("accelerations/Ny", this, &FGAuxiliary::GetNy);
|
||||
PropertyManager->Tie("forces/load-factor", this, &FGAuxiliary::GetNlf);
|
||||
/* PropertyManager->Tie("atmosphere/headwind-fps", this, &FGAuxiliary::GetHeadWind, true);
|
||||
PropertyManager->Tie("atmosphere/crosswind-fps", this, &FGAuxiliary::GetCrossWind, true); */
|
||||
|
|
|
@ -48,7 +48,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_AUXILIARY "$Id: FGAuxiliary.h,v 1.27 2012/09/15 11:17:21 bcoconni Exp $"
|
||||
#define ID_AUXILIARY "$Id: FGAuxiliary.h,v 1.28 2013/06/10 01:56:27 jberndt Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -99,7 +99,7 @@ CLASS DOCUMENTATION
|
|||
to the JSBSim vPQRdot vector, and the w parameter is equivalent to vPQR.
|
||||
|
||||
@author Tony Peden, Jon Berndt
|
||||
@version $Id: FGAuxiliary.h,v 1.27 2012/09/15 11:17:21 bcoconni Exp $
|
||||
@version $Id: FGAuxiliary.h,v 1.28 2013/06/10 01:56:27 jberndt Exp $
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -225,6 +225,9 @@ public:
|
|||
/** The vertical acceleration in g's of the aircraft center of gravity. */
|
||||
double GetNz (void) const { return Nz; }
|
||||
|
||||
/** The lateral acceleration in g's of the aircraft center of gravity. */
|
||||
double GetNy (void) const { return Ny; }
|
||||
|
||||
const FGColumnVector3& GetNwcg(void) const { return vNwcg; }
|
||||
|
||||
double GetHOverBCG(void) const { return hoverbcg; }
|
||||
|
@ -312,7 +315,7 @@ private:
|
|||
double alpha, beta;
|
||||
double adot,bdot;
|
||||
double psigt, gamma;
|
||||
double Nz;
|
||||
double Nz, Ny;
|
||||
double seconds_in_day; // seconds since current GMT day began
|
||||
int day_of_year; // GMT day, 1 .. 366
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGFCS.cpp,v 1.79 2012/12/12 06:19:57 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGFCS.cpp,v 1.80 2013/01/26 17:06:49 bcoconni Exp $";
|
||||
static const char *IdHdr = ID_FCS;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -541,7 +541,7 @@ bool FGFCS::Load(Element* el, SystemType systype)
|
|||
|
||||
interface_property_string = property_element->GetDataLine();
|
||||
if (PropertyManager->HasNode(interface_property_string)) {
|
||||
FGPropertyManager* node = PropertyManager->GetNode(interface_property_string);
|
||||
FGPropertyNode* node = PropertyManager->GetNode(interface_property_string);
|
||||
if (debug_lvl > 0)
|
||||
cout << " " << "Overriding value for property " << interface_property_string
|
||||
<< " (old value: " << node->getDoubleValue() << " new value: " << value << ")" << endl;
|
||||
|
@ -564,7 +564,7 @@ bool FGFCS::Load(Element* el, SystemType systype)
|
|||
FGFCSChannel* newChannel = 0;
|
||||
|
||||
string sOnOffProperty = channel_element->GetAttributeValue("execute");
|
||||
FGPropertyManager* OnOffPropertyNode = 0;
|
||||
FGPropertyNode* OnOffPropertyNode = 0;
|
||||
if (sOnOffProperty.length() > 0) {
|
||||
OnOffPropertyNode = PropertyManager->GetNode(sOnOffProperty);
|
||||
if (OnOffPropertyNode == 0) {
|
||||
|
|
|
@ -44,7 +44,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_FCSCHANNEL "$Id: FGFCSChannel.h,v 1.1 2012/10/15 05:02:29 jberndt Exp $"
|
||||
#define ID_FCSCHANNEL "$Id: FGFCSChannel.h,v 1.2 2013/01/26 17:06:50 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -70,7 +70,7 @@ typedef std::vector <FGFCSComponent*> FCSCompVec;
|
|||
class FGFCSChannel {
|
||||
public:
|
||||
/// Constructor
|
||||
FGFCSChannel(FGPropertyManager* node=0) :
|
||||
FGFCSChannel(FGPropertyNode* node=0) :
|
||||
OnOffNode(node)
|
||||
{
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ public:
|
|||
|
||||
private:
|
||||
FCSCompVec FCSComponents;
|
||||
const FGPropertyManager* OnOffNode;
|
||||
FGConstPropertyNode_ptr OnOffNode;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
Author: Anders Gidenstam
|
||||
Date started: 01/21/2006
|
||||
|
||||
----- Copyright (C) 2006 - 2011 Anders Gidenstam (anders(at)gidenstam.org) --
|
||||
----- Copyright (C) 2006 - 2013 Anders Gidenstam (anders(at)gidenstam.org) --
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the Free Software
|
||||
|
@ -50,14 +50,14 @@ using std::max;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGGasCell.cpp,v 1.15 2011/08/06 13:47:59 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGGasCell.cpp,v 1.18 2013/04/17 20:24:27 andgi Exp $";
|
||||
static const char *IdHdr = ID_GASCELL;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS IMPLEMENTATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
/* Constants. */
|
||||
const double FGGasCell::R = 3.4071; // [lbs ft/(mol Rankine)]
|
||||
const double FGGasCell::R = 3.4071; // [lbf ft/(mol Rankine)]
|
||||
const double FGGasCell::M_air = 0.0019186; // [slug/mol]
|
||||
const double FGGasCell::M_hydrogen = 0.00013841; // [slug/mol]
|
||||
const double FGGasCell::M_helium = 0.00027409; // [slug/mol]
|
||||
|
@ -202,7 +202,7 @@ FGGasCell::FGGasCell(FGFDMExec* exec, Element* el, int num, const struct Inputs&
|
|||
|
||||
property_name = base_property_name + "/max_volume-ft3";
|
||||
PropertyManager->Tie( property_name.c_str(), &MaxVolume, false );
|
||||
PropertyManager->SetWritable( property_name, false );
|
||||
PropertyManager->GetNode()->SetWritable( property_name, false );
|
||||
property_name = base_property_name + "/temp-R";
|
||||
PropertyManager->Tie( property_name.c_str(), &Temperature, false );
|
||||
property_name = base_property_name + "/pressure-psf";
|
||||
|
@ -325,7 +325,7 @@ void FGGasCell::Calculate(double dt)
|
|||
// FixMe: CellHeight should depend on current volume.
|
||||
const double CellHeight = 2 * Zradius + Zwidth; // [ft]
|
||||
const double GasMass = Contents * M_gas(); // [slug]
|
||||
const double GasVolume = Contents * R * Temperature / Pressure; // [ft³]
|
||||
const double GasVolume = Contents * R * Temperature / Pressure; // [ft^3]
|
||||
const double GasDensity = GasMass / GasVolume;
|
||||
const double DeltaPressure =
|
||||
Pressure + CellHeight * g * (AirDensity - GasDensity) - AirPressure;
|
||||
|
@ -468,7 +468,7 @@ void FGGasCell::Debug(int from)
|
|||
cout << " Initial pressure: " << Pressure << " lbs/ft2" << endl;
|
||||
cout << " Initial volume: " << Volume << " ft3" << endl;
|
||||
cout << " Initial mass: " << GetMass() << " slug mass" << endl;
|
||||
cout << " Initial weight: " << GetMass()*lbtoslug << " lbs force" <<
|
||||
cout << " Initial weight: " << GetMass()*slugtolb << " lbs force" <<
|
||||
endl;
|
||||
cout << " Heat transfer: " << endl;
|
||||
}
|
||||
|
@ -485,7 +485,7 @@ void FGGasCell::Debug(int from)
|
|||
cout << " Pressure: " << Pressure << " lbs/ft2" << endl;
|
||||
cout << " Volume: " << Volume << " ft3" << endl;
|
||||
cout << " Mass: " << GetMass() << " slug mass" << endl;
|
||||
cout << " Weight: " << GetMass()*lbtoslug << " lbs force" << endl;
|
||||
cout << " Weight: " << GetMass()*slugtolb << " lbs force" << endl;
|
||||
}
|
||||
if (debug_lvl & 16) { // Sanity checking
|
||||
}
|
||||
|
@ -634,7 +634,7 @@ FGBallonet::FGBallonet(FGFDMExec* exec, Element* el, int num, FGGasCell* parent,
|
|||
|
||||
property_name = base_property_name + "/max_volume-ft3";
|
||||
PropertyManager->Tie( property_name, &MaxVolume, false );
|
||||
PropertyManager->SetWritable( property_name, false );
|
||||
PropertyManager->GetNode()->SetWritable( property_name, false );
|
||||
|
||||
property_name = base_property_name + "/temp-R";
|
||||
PropertyManager->Tie( property_name, &Temperature, false );
|
||||
|
@ -820,7 +820,7 @@ void FGBallonet::Debug(int from)
|
|||
cout << " Initial pressure: " << Pressure << " lbs/ft2" << endl;
|
||||
cout << " Initial volume: " << Volume << " ft3" << endl;
|
||||
cout << " Initial mass: " << GetMass() << " slug mass" << endl;
|
||||
cout << " Initial weight: " << GetMass()*lbtoslug <<
|
||||
cout << " Initial weight: " << GetMass()*slugtolb <<
|
||||
" lbs force" << endl;
|
||||
cout << " Heat transfer: " << endl;
|
||||
}
|
||||
|
@ -838,7 +838,7 @@ void FGBallonet::Debug(int from)
|
|||
cout << " Pressure: " << Pressure << " lbs/ft2" << endl;
|
||||
cout << " Volume: " << Volume << " ft3" << endl;
|
||||
cout << " Mass: " << GetMass() << " slug mass" << endl;
|
||||
cout << " Weight: " << GetMass()*lbtoslug << " lbs force" << endl;
|
||||
cout << " Weight: " << GetMass()*slugtolb << " lbs force" << endl;
|
||||
}
|
||||
if (debug_lvl & 16) { // Sanity checking
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
Author: Anders Gidenstam
|
||||
Date started: 01/21/2006
|
||||
|
||||
----- Copyright (C) 2006 - 2011 Anders Gidenstam (anders(at)gidenstam.org) --
|
||||
----- Copyright (C) 2006 - 2013 Anders Gidenstam (anders(at)gidenstam.org) --
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the Free Software
|
||||
|
@ -50,7 +50,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_GASCELL "$Id: FGGasCell.h,v 1.12 2011/08/06 13:47:59 jberndt Exp $"
|
||||
#define ID_GASCELL "$Id: FGGasCell.h,v 1.13 2013/04/17 20:24:27 andgi Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -238,7 +238,7 @@ private:
|
|||
std::string type;
|
||||
int CellNum;
|
||||
// Structural constants
|
||||
double MaxVolume; // [ft^2]
|
||||
double MaxVolume; // [ft^3]
|
||||
double MaxOverpressure; // [lbs/ft^2]
|
||||
FGColumnVector3 vXYZ; // [in]
|
||||
double Xradius, Yradius, Zradius; // [ft]
|
||||
|
@ -251,8 +251,8 @@ private:
|
|||
// Variables
|
||||
double Pressure; // [lbs/ft^2]
|
||||
double Contents; // [mol]
|
||||
double Volume; // [ft^2]
|
||||
double dVolumeIdeal; // [ft^2]
|
||||
double Volume; // [ft^3]
|
||||
double dVolumeIdeal; // [ft^3]
|
||||
double Temperature; // [Rankine]
|
||||
double Buoyancy; // [lbs] Note: Gross lift.
|
||||
// Does not include the weight of the gas itself.
|
||||
|
@ -344,7 +344,7 @@ public:
|
|||
private:
|
||||
int CellNum;
|
||||
// Structural constants
|
||||
double MaxVolume; // [ft^2]
|
||||
double MaxVolume; // [ft^3]
|
||||
double MaxOverpressure; // [lbs/ft^2]
|
||||
FGColumnVector3 vXYZ; // [in]
|
||||
double Xradius, Yradius, Zradius; // [ft]
|
||||
|
@ -357,8 +357,8 @@ private:
|
|||
// Variables
|
||||
double Pressure; // [lbs/ft^2]
|
||||
double Contents; // [mol]
|
||||
double Volume; // [ft^2]
|
||||
double dVolumeIdeal; // [ft^2]
|
||||
double Volume; // [ft^3]
|
||||
double dVolumeIdeal; // [ft^3]
|
||||
double dU; // [lbs ft / sec]
|
||||
double Temperature; // [Rankine]
|
||||
double ValveOpen; // 0 <= ValveOpen <= 1 (or higher).
|
||||
|
|
|
@ -53,7 +53,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGInput.cpp,v 1.24 2012/11/23 16:30:36 bcoconni Exp $";
|
||||
static const char *IdSrc = "$Id: FGInput.cpp,v 1.25 2013/01/26 17:06:50 bcoconni Exp $";
|
||||
static const char *IdHdr = ID_INPUT;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -94,7 +94,7 @@ bool FGInput::Run(bool Holding)
|
|||
string line, token;
|
||||
size_t start=0, string_start=0, string_end=0;
|
||||
double value=0;
|
||||
FGPropertyManager* node=0;
|
||||
FGPropertyNode* node=0;
|
||||
|
||||
if (FGModel::Run(Holding)) return true; // fast exit if nothing to do
|
||||
if (port == 0) return false; // Do nothing here if port not defined
|
||||
|
|
|
@ -61,7 +61,7 @@ DEFINITIONS
|
|||
GLOBAL DATA
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
static const char *IdSrc = "$Id: FGLGear.cpp,v 1.103 2013/01/13 12:44:52 bcoconni Exp $";
|
||||
static const char *IdSrc = "$Id: FGLGear.cpp,v 1.104 2013/01/25 14:02:13 jberndt Exp $";
|
||||
static const char *IdHdr = ID_LGEAR;
|
||||
|
||||
// Body To Structural (body frame is rotated 180 deg about Y and lengths are given in
|
||||
|
@ -357,8 +357,9 @@ const FGColumnVector3& FGLGear::GetBodyForces(void)
|
|||
|
||||
ResetReporting();
|
||||
}
|
||||
}
|
||||
else if (gearPos < 0.01) { // Gear UP
|
||||
|
||||
} else if (gearPos < 0.01) { // Gear UP
|
||||
|
||||
WOW = false;
|
||||
vWhlVelVec.InitMatrix();
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGOutput.cpp,v 1.71 2012/12/15 16:13:58 bcoconni Exp $";
|
||||
static const char *IdSrc = "$Id: FGOutput.cpp,v 1.72 2013/01/26 17:06:50 bcoconni Exp $";
|
||||
static const char *IdHdr = ID_OUTPUT;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -207,7 +207,7 @@ bool FGOutput::SetDirectivesFile(const std::string& fname)
|
|||
|
||||
bool FGOutput::Load(int subSystems, std::string protocol, std::string type,
|
||||
std::string port, std::string name, double outRate,
|
||||
std::vector<FGPropertyManager *> & outputProperties)
|
||||
std::vector<FGPropertyNode_ptr> & outputProperties)
|
||||
{
|
||||
unsigned int idx = OutputTypes.size();
|
||||
FGOutputType* Output = 0;
|
||||
|
|
|
@ -48,7 +48,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_OUTPUT "$Id: FGOutput.h,v 1.26 2012/09/05 21:49:19 bcoconni Exp $"
|
||||
#define ID_OUTPUT "$Id: FGOutput.h,v 1.27 2013/01/26 17:06:50 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -122,7 +122,7 @@ CLASS DOCUMENTATION
|
|||
|
||||
The class FGOutput is the manager of the outputs requested by the user. It
|
||||
manages a list of instances derived from the abstract class FGOutputType.
|
||||
@version $Id: FGOutput.h,v 1.26 2012/09/05 21:49:19 bcoconni Exp $
|
||||
@version $Id: FGOutput.h,v 1.27 2013/01/26 17:06:50 bcoconni Exp $
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -216,7 +216,7 @@ public:
|
|||
@result true if the execution succeeded. */
|
||||
bool Load(int subSystems, std::string protocol, std::string type,
|
||||
std::string port, std::string name, double outRate,
|
||||
std::vector<FGPropertyManager *> & outputProperties);
|
||||
std::vector<FGPropertyNode_ptr> & outputProperties);
|
||||
/** Get the name identifier to which the output will be directed.
|
||||
@param idx ID of the output instance from which the name identifier must
|
||||
be obtained
|
||||
|
|
|
@ -77,7 +77,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGPropagate.cpp,v 1.111 2013/01/19 13:49:37 bcoconni Exp $";
|
||||
static const char *IdSrc = "$Id: FGPropagate.cpp,v 1.112 2013/06/10 01:57:52 jberndt Exp $";
|
||||
static const char *IdHdr = ID_PROPAGATE;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -673,6 +673,10 @@ void FGPropagate::bind(void)
|
|||
PropertyManager->Tie("attitude/theta-rad", this, (int)eTht, (PMF)&FGPropagate::GetEuler);
|
||||
PropertyManager->Tie("attitude/psi-rad", this, (int)ePsi, (PMF)&FGPropagate::GetEuler);
|
||||
|
||||
PropertyManager->Tie("attitude/phi-deg", this, (int)ePhi, (PMF)&FGPropagate::GetEulerDeg);
|
||||
PropertyManager->Tie("attitude/theta-deg", this, (int)eTht, (PMF)&FGPropagate::GetEulerDeg);
|
||||
PropertyManager->Tie("attitude/psi-deg", this, (int)ePsi, (PMF)&FGPropagate::GetEulerDeg);
|
||||
|
||||
PropertyManager->Tie("attitude/roll-rad", this, (int)ePhi, (PMF)&FGPropagate::GetEuler);
|
||||
PropertyManager->Tie("attitude/pitch-rad", this, (int)eTht, (PMF)&FGPropagate::GetEuler);
|
||||
PropertyManager->Tie("attitude/heading-true-rad", this, (int)ePsi, (PMF)&FGPropagate::GetEuler);
|
||||
|
|
|
@ -49,7 +49,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_PROPAGATE "$Id: FGPropagate.h,v 1.74 2013/01/19 13:49:37 bcoconni Exp $"
|
||||
#define ID_PROPAGATE "$Id: FGPropagate.h,v 1.75 2013/06/10 01:58:01 jberndt Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -93,7 +93,7 @@ CLASS DOCUMENTATION
|
|||
@endcode
|
||||
|
||||
@author Jon S. Berndt, Mathias Froehlich, Bertrand Coconnier
|
||||
@version $Id: FGPropagate.h,v 1.74 2013/01/19 13:49:37 bcoconni Exp $
|
||||
@version $Id: FGPropagate.h,v 1.75 2013/06/10 01:58:01 jberndt Exp $
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -247,6 +247,23 @@ public:
|
|||
*/
|
||||
const FGColumnVector3& GetEuler(void) const { return VState.qAttitudeLocal.GetEuler(); }
|
||||
|
||||
/** Retrieves the Euler angles (in degrees) that define the vehicle orientation.
|
||||
Extracts the Euler angles from the quaternion that stores the orientation
|
||||
in the Local frame. The order of rotation used is Yaw-Pitch-Roll. The
|
||||
vector returned is represented by an FGColumnVector reference. The vector
|
||||
for the Euler angles is organized (Phi, Theta, Psi). The vector
|
||||
is 1-based, so that the first element can be retrieved using the "()" operator.
|
||||
In other words, the returned vector item with subscript (1) is Phi.
|
||||
Various convenience enumerators are defined in FGJSBBase. The relevant
|
||||
enumerators for the vector returned by this call are, ePhi=1, eTht=2, ePsi=3.
|
||||
units degrees
|
||||
@return The Euler angle vector, where the first item in the
|
||||
vector is the angle about the X axis, the second is the
|
||||
angle about the Y axis, and the third item is the angle
|
||||
about the Z axis (Phi, Theta, Psi).
|
||||
*/
|
||||
const FGColumnVector3& GetEulerDeg(void) const { return VState.qAttitudeLocal.GetEuler() * radtodeg; }
|
||||
|
||||
/** Retrieves a body frame velocity component.
|
||||
Retrieves a body frame velocity component. The velocity returned is
|
||||
extracted from the vUVW vector (an FGColumnVector). The vector for the
|
||||
|
@ -341,6 +358,18 @@ public:
|
|||
*/
|
||||
double GetEuler(int axis) const { return VState.qAttitudeLocal.GetEuler(axis); }
|
||||
|
||||
/** Retrieves a vehicle Euler angle component in degrees.
|
||||
Retrieves an Euler angle (Phi, Theta, or Psi) from the quaternion that
|
||||
stores the vehicle orientation relative to the Local frame. The order of
|
||||
rotations used is Yaw-Pitch-Roll. The Euler angle with subscript (1) is
|
||||
Phi. Various convenience enumerators are defined in FGJSBBase. The
|
||||
relevant enumerators for the Euler angle returned by this call are,
|
||||
ePhi=1, eTht=2, ePsi=3 (e.g. GetEuler(eTht) returns Theta).
|
||||
units degrees
|
||||
@return An Euler angle in degrees.
|
||||
*/
|
||||
double GetEulerDeg(int axis) const { return VState.qAttitudeLocal.GetEuler(axis) * radtodeg; }
|
||||
|
||||
/** Retrieves the cosine of a vehicle Euler angle component.
|
||||
Retrieves the cosine of an Euler angle (Phi, Theta, or Psi) from the
|
||||
quaternion that stores the vehicle orientation relative to the Local frame.
|
||||
|
|
|
@ -43,7 +43,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGActuator.cpp,v 1.25 2013/01/12 19:24:05 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGActuator.cpp,v 1.28 2013/06/10 02:04:50 jberndt Exp $";
|
||||
static const char *IdHdr = ID_ACTUATOR;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -83,12 +83,12 @@ FGActuator::FGActuator(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, eleme
|
|||
Element* ratelim_el = element->FindElement("rate_limit");
|
||||
while ( ratelim_el ) {
|
||||
rate_limited = true;
|
||||
FGPropertyManager* rate_limit_prop=0;
|
||||
FGPropertyNode* rate_limit_prop=0;
|
||||
|
||||
string rate_limit_str = ratelim_el->GetDataLine();
|
||||
trim(rate_limit_str);
|
||||
if (is_number(rate_limit_str)) {
|
||||
rate_limit = fabs(element->FindElementValueAsNumber("rate_limit"));
|
||||
rate_limit = fabs(element->FindElementValueAsNumber("rate_limit"));
|
||||
} else {
|
||||
if (rate_limit_str[0] == '-') rate_limit_str.erase(0,1);
|
||||
rate_limit_prop = PropertyManager->GetNode(rate_limit_str, true);
|
||||
|
@ -104,7 +104,7 @@ FGActuator::FGActuator(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, eleme
|
|||
} else if (sense.substr(0,4) == "decr") {
|
||||
if (rate_limit_prop != 0) rate_limit_decr_prop = rate_limit_prop;
|
||||
else rate_limit_decr = -rate_limit;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rate_limit_incr = rate_limit;
|
||||
rate_limit_decr = -rate_limit;
|
||||
|
@ -157,7 +157,8 @@ bool FGActuator::Run(void )
|
|||
Output = PreviousOutput;
|
||||
} else {
|
||||
if (lag != 0.0) Lag(); // models actuator lag
|
||||
if (rate_limit != 0) RateLimit(); // limit the actuator rate
|
||||
if (rate_limit != 0 || (rate_limit_incr_prop != 0
|
||||
|| rate_limit_decr_prop != 0)) RateLimit(); // limit the actuator rate
|
||||
if (deadband_width != 0.0) Deadband();
|
||||
if (hysteresis_width != 0.0) Hysteresis();
|
||||
if (bias != 0.0) Bias(); // models a finite bias
|
||||
|
|
|
@ -44,7 +44,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_ACTUATOR "$Id: FGActuator.h,v 1.14 2013/01/12 19:24:05 jberndt Exp $"
|
||||
#define ID_ACTUATOR "$Id: FGActuator.h,v 1.15 2013/01/26 17:06:50 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -120,7 +120,7 @@ Example:
|
|||
@endcode
|
||||
|
||||
@author Jon S. Berndt
|
||||
@version $Revision: 1.14 $
|
||||
@version $Revision: 1.15 $
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -160,8 +160,8 @@ private:
|
|||
double rate_limit;
|
||||
double rate_limit_incr;
|
||||
double rate_limit_decr;
|
||||
FGPropertyManager* rate_limit_incr_prop;
|
||||
FGPropertyManager* rate_limit_decr_prop;
|
||||
FGPropertyNode_ptr rate_limit_incr_prop;
|
||||
FGPropertyNode_ptr rate_limit_decr_prop;
|
||||
double hysteresis_width;
|
||||
double deadband_width;
|
||||
double lag;
|
||||
|
|
|
@ -43,7 +43,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_DEADBAND "$Id: FGDeadBand.h,v 1.9 2009/10/24 22:59:30 jberndt Exp $"
|
||||
#define ID_DEADBAND "$Id: FGDeadBand.h,v 1.10 2013/01/26 17:06:50 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -53,7 +53,6 @@ namespace JSBSim {
|
|||
|
||||
class FGFCS;
|
||||
class Element;
|
||||
class FGPropertyManager;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS DOCUMENTATION
|
||||
|
@ -80,7 +79,7 @@ CLASS DOCUMENTATION
|
|||
produce no output. For example, say that the width value is 2.0. If the
|
||||
input is between -1.0 and +1.0, the output will be zero.
|
||||
@author Jon S. Berndt
|
||||
@version $Id: FGDeadBand.h,v 1.9 2009/10/24 22:59:30 jberndt Exp $
|
||||
@version $Id: FGDeadBand.h,v 1.10 2013/01/26 17:06:50 bcoconni Exp $
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -98,7 +97,7 @@ public:
|
|||
private:
|
||||
double width;
|
||||
double gain;
|
||||
FGPropertyManager* WidthPropertyNode;
|
||||
FGPropertyNode_ptr WidthPropertyNode;
|
||||
double WidthPropertySign;
|
||||
|
||||
void Debug(int from);
|
||||
|
|
|
@ -48,7 +48,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGFCSComponent.cpp,v 1.34 2011/09/11 11:36:04 bcoconni Exp $";
|
||||
static const char *IdSrc = "$Id: FGFCSComponent.cpp,v 1.35 2013/01/26 17:06:50 bcoconni Exp $";
|
||||
static const char *IdHdr = ID_FCSCOMPONENT;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -121,7 +121,7 @@ FGFCSComponent::FGFCSComponent(FGFCS* _fcs, Element* element) : fcs(_fcs)
|
|||
} else {
|
||||
InputSigns.push_back( 1.0);
|
||||
}
|
||||
FGPropertyManager* node = 0L;
|
||||
FGPropertyNode* node = 0L;
|
||||
if (PropertyManager->HasNode(input)) {
|
||||
node = PropertyManager->GetNode(input);
|
||||
InputNodes.push_back(new FGPropertyValue( node ));
|
||||
|
@ -138,7 +138,7 @@ FGFCSComponent::FGFCSComponent(FGFCS* _fcs, Element* element) : fcs(_fcs)
|
|||
while (out_elem) {
|
||||
IsOutput = true;
|
||||
string output_node_name = out_elem->GetDataLine();
|
||||
FGPropertyManager* OutputNode = PropertyManager->GetNode( output_node_name, true );
|
||||
FGPropertyNode* OutputNode = PropertyManager->GetNode( output_node_name, true );
|
||||
OutputNodes.push_back(OutputNode);
|
||||
if (!OutputNode) {
|
||||
cerr << endl << " Unable to process property: " << output_node_name << endl;
|
||||
|
|
|
@ -46,7 +46,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_FCSCOMPONENT "$Id: FGFCSComponent.h,v 1.20 2011/06/16 03:39:38 jberndt Exp $"
|
||||
#define ID_FCSCOMPONENT "$Id: FGFCSComponent.h,v 1.21 2013/01/26 17:06:50 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -55,7 +55,6 @@ FORWARD DECLARATIONS
|
|||
namespace JSBSim {
|
||||
|
||||
class FGFCS;
|
||||
class FGPropertyManager;
|
||||
class Element;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -81,7 +80,7 @@ CLASS DOCUMENTATION
|
|||
- FGActuator
|
||||
|
||||
@author Jon S. Berndt
|
||||
@version $Id: FGFCSComponent.h,v 1.20 2011/06/16 03:39:38 jberndt Exp $
|
||||
@version $Id: FGFCSComponent.h,v 1.21 2013/01/26 17:06:50 bcoconni Exp $
|
||||
@see Documentation for the FGFCS class, and for the configuration file class
|
||||
*/
|
||||
|
||||
|
@ -107,10 +106,10 @@ public:
|
|||
protected:
|
||||
FGFCS* fcs;
|
||||
FGPropertyManager* PropertyManager;
|
||||
FGPropertyManager* treenode;
|
||||
std::vector <FGPropertyManager*> OutputNodes;
|
||||
FGPropertyManager* ClipMinPropertyNode;
|
||||
FGPropertyManager* ClipMaxPropertyNode;
|
||||
FGPropertyNode_ptr treenode;
|
||||
std::vector <FGPropertyNode_ptr> OutputNodes;
|
||||
FGPropertyNode_ptr ClipMinPropertyNode;
|
||||
FGPropertyNode_ptr ClipMaxPropertyNode;
|
||||
std::vector <FGPropertyValue*> InputNodes;
|
||||
std::vector <std::string> InputNames;
|
||||
std::vector <float> InputSigns;
|
||||
|
|
|
@ -43,7 +43,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_FILTER "$Id: FGFilter.h,v 1.12 2009/10/24 22:59:30 jberndt Exp $"
|
||||
#define ID_FILTER "$Id: FGFilter.h,v 1.13 2013/01/26 17:06:50 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -228,7 +228,7 @@ is so that the last component in a "string" can copy its value to the appropriat
|
|||
output, such as the elevator, or speedbrake, etc.
|
||||
|
||||
@author Jon S. Berndt
|
||||
@version $Revision: 1.12 $
|
||||
@version $Revision: 1.13 $
|
||||
|
||||
*/
|
||||
|
||||
|
@ -263,8 +263,8 @@ private:
|
|||
double PreviousInput2;
|
||||
double PreviousOutput1;
|
||||
double PreviousOutput2;
|
||||
FGPropertyManager* Trigger;
|
||||
FGPropertyManager* PropertyNode[7];
|
||||
FGPropertyNode_ptr Trigger;
|
||||
FGPropertyNode_ptr PropertyNode[7];
|
||||
void CalculateDynamicFilters(void);
|
||||
void ReadFilterCoefficients(Element* el, int index);
|
||||
bool DynamicFilter;
|
||||
|
|
|
@ -44,7 +44,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_GAIN "$Id: FGGain.h,v 1.14 2009/10/24 22:59:30 jberndt Exp $"
|
||||
#define ID_GAIN "$Id: FGGain.h,v 1.15 2013/01/26 17:06:50 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -208,7 +208,7 @@ CLASS DOCUMENTATION
|
|||
@endcode
|
||||
|
||||
@author Jon S. Berndt
|
||||
@version $Revision: 1.14 $
|
||||
@version $Revision: 1.15 $
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -225,7 +225,7 @@ public:
|
|||
|
||||
private:
|
||||
FGTable* Table;
|
||||
FGPropertyManager* GainPropertyNode;
|
||||
FGPropertyNode_ptr GainPropertyNode;
|
||||
double GainPropertySign;
|
||||
double Gain;
|
||||
double InMin, InMax, OutMin, OutMax;
|
||||
|
|
|
@ -44,7 +44,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGPID.cpp,v 1.20 2012/05/10 12:10:48 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGPID.cpp,v 1.21 2013/02/02 06:05:26 jberndt Exp $";
|
||||
static const char *IdHdr = ID_PID;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -135,6 +135,14 @@ FGPID::FGPID(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, element)
|
|||
}
|
||||
|
||||
FGFCSComponent::bind();
|
||||
string tmp;
|
||||
if (Name.find("/") == string::npos) {
|
||||
tmp = "fcs/" + PropertyManager->mkPropertyName(Name, true);
|
||||
} else {
|
||||
tmp = Name;
|
||||
}
|
||||
typedef double (FGPID::*PMF)(void) const;
|
||||
PropertyManager->Tie(tmp+"/initial-integrator-value", this, (PMF)0, &FGPID::SetInitialOutput);
|
||||
|
||||
Debug(0);
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_PID "$Id: FGPID.h,v 1.13 2012/05/10 12:10:48 jberndt Exp $"
|
||||
#define ID_PID "$Id: FGPID.h,v 1.15 2013/02/02 06:05:26 jberndt Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -116,7 +116,7 @@ For example,
|
|||
</pre>
|
||||
|
||||
@author Jon S. Berndt
|
||||
@version $Revision: 1.13 $
|
||||
@version $Revision: 1.15 $
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -135,6 +135,11 @@ public:
|
|||
/// These define the indices use to select the various integrators.
|
||||
enum eIntegrateType {eNone = 0, eRectEuler, eTrapezoidal, eAdamsBashforth2, eAdamsBashforth3};
|
||||
|
||||
void SetInitialOutput(double val) {
|
||||
I_out_total = val;
|
||||
Output = val;
|
||||
}
|
||||
|
||||
private:
|
||||
double Kp, Ki, Kd;
|
||||
double I_out_total;
|
||||
|
@ -147,11 +152,11 @@ private:
|
|||
|
||||
eIntegrateType IntType;
|
||||
|
||||
FGPropertyManager *Trigger;
|
||||
FGPropertyManager* KpPropertyNode;
|
||||
FGPropertyManager* KiPropertyNode;
|
||||
FGPropertyManager* KdPropertyNode;
|
||||
FGPropertyManager* ProcessVariableDot;
|
||||
FGPropertyNode_ptr Trigger;
|
||||
FGPropertyNode_ptr KpPropertyNode;
|
||||
FGPropertyNode_ptr KiPropertyNode;
|
||||
FGPropertyNode_ptr KdPropertyNode;
|
||||
FGPropertyNode_ptr ProcessVariableDot;
|
||||
|
||||
void Debug(int from);
|
||||
};
|
||||
|
|
|
@ -44,7 +44,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_SENSOR "$Id: FGSensor.h,v 1.21 2012/01/08 12:39:14 bcoconni Exp $"
|
||||
#define ID_SENSOR "$Id: FGSensor.h,v 1.22 2013/06/10 01:59:16 jberndt Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -76,7 +76,7 @@ Syntax:
|
|||
<drift_rate> number </drift_rate>
|
||||
<gain> number </gain>
|
||||
<bias> number </bias>
|
||||
<delay> number < /delay>
|
||||
<delay [type="time|frames"]> number < /delay>
|
||||
</sensor>
|
||||
@endcode
|
||||
|
||||
|
@ -124,7 +124,7 @@ The delay element can specify a frame delay. The integer number provided is
|
|||
the number of frames to delay the output signal.
|
||||
|
||||
@author Jon S. Berndt
|
||||
@version $Revision: 1.21 $
|
||||
@version $Revision: 1.22 $
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -48,7 +48,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_SWITCH "$Id: FGSwitch.h,v 1.15 2012/10/27 20:29:01 jberndt Exp $"
|
||||
#define ID_SWITCH "$Id: FGSwitch.h,v 1.16 2013/01/26 17:06:50 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -127,7 +127,7 @@ ap/attitude_hold takes the value 1), the value of the switch component will be
|
|||
whatever value fcs/roll-ap-error-summer is.
|
||||
|
||||
@author Jon S. Berndt
|
||||
@version $Id: FGSwitch.h,v 1.15 2012/10/27 20:29:01 jberndt Exp $
|
||||
@version $Id: FGSwitch.h,v 1.16 2013/01/26 17:06:50 bcoconni Exp $
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -185,7 +185,7 @@ private:
|
|||
} else {
|
||||
sign = 1.0;
|
||||
}
|
||||
FGPropertyManager *node = propMan->GetNode(value, false);
|
||||
FGPropertyNode *node = propMan->GetNode(value, false);
|
||||
if (node) {
|
||||
OutputProp = new FGPropertyValue(node);
|
||||
} else {
|
||||
|
|
|
@ -47,7 +47,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGRocket.cpp,v 1.29 2013/01/12 21:11:59 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGRocket.cpp,v 1.30 2013/06/10 02:00:11 jberndt Exp $";
|
||||
static const char *IdHdr = ID_ROCKET;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -250,8 +250,8 @@ string FGRocket::GetEngineLabels(const string& delimiter)
|
|||
{
|
||||
std::ostringstream buf;
|
||||
|
||||
buf << Name << " Total Impulse (engine " << EngineNumber << " in psf)" << delimiter
|
||||
<< Name << " Total Vacuum Impulse (engine " << EngineNumber << " in psf)" << delimiter
|
||||
buf << Name << " Total Impulse (engine " << EngineNumber << " in lbf)" << delimiter
|
||||
<< Name << " Total Vacuum Impulse (engine " << EngineNumber << " in lbf)" << delimiter
|
||||
<< Thruster->GetThrusterLabels(EngineNumber, delimiter);
|
||||
|
||||
return buf.str();
|
||||
|
|
|
@ -48,7 +48,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_ROTOR "$Id: FGRotor.h,v 1.14 2012/03/18 15:48:36 jentron Exp $"
|
||||
#define ID_ROTOR "$Id: FGRotor.h,v 1.15 2013/01/26 17:06:50 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -230,7 +230,7 @@ CLASS DOCUMENTATION
|
|||
</dl>
|
||||
|
||||
@author Thomas Kreitler
|
||||
@version $Id: FGRotor.h,v 1.14 2012/03/18 15:48:36 jentron Exp $
|
||||
@version $Id: FGRotor.h,v 1.15 2013/01/26 17:06:50 bcoconni Exp $
|
||||
*/
|
||||
|
||||
|
||||
|
@ -369,7 +369,7 @@ private:
|
|||
double MaximalRPM;
|
||||
int ExternalRPM;
|
||||
int RPMdefinition;
|
||||
FGPropertyManager* ExtRPMsource;
|
||||
FGPropertyNode_ptr ExtRPMsource;
|
||||
double SourceGearRatio;
|
||||
|
||||
// 'real' rotor parameters
|
||||
|
|
|
@ -47,7 +47,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGTank.cpp,v 1.36 2013/01/12 19:25:30 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGTank.cpp,v 1.37 2013/06/10 02:04:12 jberndt Exp $";
|
||||
static const char *IdHdr = ID_TANK;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -118,6 +118,13 @@ FGTank::FGTank(FGFDMExec* exec, Element* el, int tank_number)
|
|||
Capacity = 0.00001;
|
||||
Contents = 0.0;
|
||||
}
|
||||
if (Contents > Capacity) {
|
||||
cerr << "Tank content (" << Contents << " lbs) is greater than tank capacity ("
|
||||
<< Capacity << " lbs) for tank " << tank_number
|
||||
<< "! Did you accidentally swap contents and capacity?" << endl;
|
||||
throw("tank definition error");
|
||||
}
|
||||
|
||||
PctFull = 100.0*Contents/Capacity; // percent full; 0 to 100.0
|
||||
|
||||
// Check whether this is a solid propellant "tank". Initialize it if true.
|
||||
|
|
Loading…
Reference in a new issue