Sync. withn JSBSim CVS
This commit is contained in:
parent
b1eebb21a6
commit
30e535bc7b
29 changed files with 383 additions and 135 deletions
|
@ -94,7 +94,8 @@ void checkTied ( FGPropertyManager *node )
|
|||
for (int i=0; i<N; i++) {
|
||||
if (node->getChild(i)->nChildren() ) {
|
||||
checkTied( (FGPropertyManager*)node->getChild(i) );
|
||||
} else if ( node->getChild(i)->isTied() ) {
|
||||
}
|
||||
if ( node->getChild(i)->isTied() ) {
|
||||
name = ((FGPropertyManager*)node->getChild(i))->GetFullyQualifiedName();
|
||||
node->Untie(name);
|
||||
}
|
||||
|
@ -108,7 +109,6 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root) : Root(root)
|
|||
{
|
||||
|
||||
Frame = 0;
|
||||
FirstModel = 0;
|
||||
Error = 0;
|
||||
GroundCallback = 0;
|
||||
State = 0;
|
||||
|
@ -221,30 +221,11 @@ bool FGFDMExec::Allocate(void)
|
|||
// class needs valid pointers to the above
|
||||
// model classes
|
||||
|
||||
// Initialize models so they can communicate with each other
|
||||
|
||||
Atmosphere->InitModel();
|
||||
FCS->InitModel();
|
||||
Propulsion->InitModel();
|
||||
MassBalance->InitModel();
|
||||
Aerodynamics->InitModel();
|
||||
Inertial->InitModel();
|
||||
GroundReactions->InitModel();
|
||||
ExternalReactions->InitModel();
|
||||
BuoyantForces->InitModel();
|
||||
Aircraft->InitModel();
|
||||
Propagate->InitModel();
|
||||
Auxiliary->InitModel();
|
||||
Input->InitModel();
|
||||
|
||||
IC = new FGInitialCondition(this);
|
||||
|
||||
// Schedule a model. The second arg (the integer) is the pass number. For
|
||||
// instance, the atmosphere model could get executed every fifth pass it is called
|
||||
// by the executive. IC and Trim objects are NOT scheduled.
|
||||
// instance, the atmosphere model could get executed every fifth pass it is called.
|
||||
|
||||
Schedule(Input, 1);
|
||||
Schedule(Atmosphere, 1);
|
||||
Schedule(Atmosphere, 30);
|
||||
Schedule(FCS, 1);
|
||||
Schedule(Propulsion, 1);
|
||||
Schedule(MassBalance, 1);
|
||||
|
@ -257,6 +238,13 @@ bool FGFDMExec::Allocate(void)
|
|||
Schedule(Propagate, 1);
|
||||
Schedule(Auxiliary, 1);
|
||||
|
||||
// Initialize models so they can communicate with each other
|
||||
|
||||
vector <FGModel*>::iterator it;
|
||||
for (it = Models.begin(); it != Models.end(); ++it) (*it)->InitModel();
|
||||
|
||||
IC = new FGInitialCondition(this);
|
||||
|
||||
modelLoaded = false;
|
||||
|
||||
return result;
|
||||
|
@ -290,7 +278,6 @@ bool FGFDMExec::DeAllocate(void)
|
|||
|
||||
delete GroundCallback;
|
||||
|
||||
FirstModel = 0L;
|
||||
Error = 0;
|
||||
|
||||
State = 0;
|
||||
|
@ -309,35 +296,18 @@ bool FGFDMExec::DeAllocate(void)
|
|||
Auxiliary = 0;
|
||||
Script = 0;
|
||||
|
||||
Models.clear();
|
||||
|
||||
modelLoaded = false;
|
||||
return modelLoaded;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
int FGFDMExec::Schedule(FGModel* model, int rate)
|
||||
void FGFDMExec::Schedule(FGModel* model, int rate)
|
||||
{
|
||||
FGModel* model_iterator;
|
||||
|
||||
model_iterator = FirstModel;
|
||||
|
||||
if (model_iterator == 0L) { // this is the first model
|
||||
|
||||
FirstModel = model;
|
||||
FirstModel->NextModel = 0L;
|
||||
FirstModel->SetRate(rate);
|
||||
|
||||
} else { // subsequent model
|
||||
|
||||
while (model_iterator->NextModel != 0L) {
|
||||
model_iterator = model_iterator->NextModel;
|
||||
}
|
||||
model_iterator->NextModel = model;
|
||||
model_iterator->NextModel->SetRate(rate);
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
model->SetRate(rate);
|
||||
Models.push_back(model);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -345,10 +315,6 @@ int FGFDMExec::Schedule(FGModel* model, int rate)
|
|||
bool FGFDMExec::Run(void)
|
||||
{
|
||||
bool success=true;
|
||||
FGModel* model_iterator;
|
||||
|
||||
model_iterator = FirstModel;
|
||||
if (model_iterator == 0L) return false;
|
||||
|
||||
Debug(2);
|
||||
|
||||
|
@ -357,14 +323,11 @@ bool FGFDMExec::Run(void)
|
|||
ChildFDMList[i]->Run();
|
||||
}
|
||||
|
||||
// returns true if success
|
||||
// false if complete
|
||||
// returns true if success, false if complete
|
||||
if (Script != 0 && !State->IntegrationSuspended()) success = Script->RunScript();
|
||||
|
||||
while (model_iterator != 0L) {
|
||||
model_iterator->Run();
|
||||
model_iterator = model_iterator->NextModel;
|
||||
}
|
||||
vector <FGModel*>::iterator it;
|
||||
for (it = Models.begin(); it != Models.end(); ++it) (*it)->Run();
|
||||
|
||||
Frame++;
|
||||
if (!Holding()) State->IncrTime();
|
||||
|
@ -406,15 +369,10 @@ void FGFDMExec::ResetToInitialConditions(int mode)
|
|||
|
||||
void FGFDMExec::ResetToInitialConditions(void)
|
||||
{
|
||||
FGModel* model_iterator;
|
||||
if (Constructing) return;
|
||||
|
||||
model_iterator = FirstModel;
|
||||
if (model_iterator == 0L || Constructing) return;
|
||||
|
||||
while (model_iterator != 0L) {
|
||||
model_iterator->InitModel();
|
||||
model_iterator = model_iterator->NextModel;
|
||||
}
|
||||
vector <FGModel*>::iterator it;
|
||||
for (it = Models.begin(); it != Models.end(); ++it) (*it)->InitModel();
|
||||
|
||||
RunIC();
|
||||
if (Script) Script->ResetEvents();
|
||||
|
|
|
@ -222,7 +222,7 @@ public:
|
|||
@param model A pointer to the model being scheduled.
|
||||
@param rate The rate at which to execute the model as described above.
|
||||
@return Currently returns 0 always. */
|
||||
int Schedule(FGModel* model, int rate);
|
||||
void Schedule(FGModel* model, int rate);
|
||||
|
||||
/** This function executes each scheduled model in succession.
|
||||
@return true if successful, false if sim should be ended */
|
||||
|
@ -488,7 +488,6 @@ private:
|
|||
|
||||
static FGPropertyManager *master;
|
||||
|
||||
FGModel* FirstModel;
|
||||
FGGroundCallback* GroundCallback;
|
||||
FGState* State;
|
||||
FGAtmosphere* Atmosphere;
|
||||
|
@ -514,6 +513,7 @@ private:
|
|||
vector <string> PropertyCatalog;
|
||||
vector <FGOutput*> Outputs;
|
||||
vector <childData*> ChildFDMList;
|
||||
vector <FGModel*> Models;
|
||||
|
||||
bool ReadFileHeader(Element*);
|
||||
bool ReadChild(Element*);
|
||||
|
|
|
@ -31,6 +31,7 @@ INCLUDES
|
|||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <cstdlib>
|
||||
#include <cmath>
|
||||
#include "FGFunction.h"
|
||||
#include "FGTable.h"
|
||||
#include "FGPropertyValue.h"
|
||||
|
@ -56,6 +57,7 @@ FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, const string& pr
|
|||
string operation, property_name;
|
||||
cached = false;
|
||||
cachedValue = -HUGE_VAL;
|
||||
invlog2val = 1.0/log10(2.0);
|
||||
|
||||
property_string = "property";
|
||||
value_string = "value";
|
||||
|
@ -72,6 +74,9 @@ FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, const string& pr
|
|||
quotient_string = "quotient";
|
||||
pow_string = "pow";
|
||||
exp_string = "exp";
|
||||
log2_string = "log2";
|
||||
ln_string = "ln";
|
||||
log10_string = "log10";
|
||||
abs_string = "abs";
|
||||
sin_string = "sin";
|
||||
cos_string = "cos";
|
||||
|
@ -103,6 +108,12 @@ FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, const string& pr
|
|||
Type = eQuotient;
|
||||
} else if (operation == pow_string) {
|
||||
Type = ePow;
|
||||
} else if (operation == log2_string) {
|
||||
Type = eLog2;
|
||||
} else if (operation == ln_string) {
|
||||
Type = eLn;
|
||||
} else if (operation == log10_string) {
|
||||
Type = eLog10;
|
||||
} else if (operation == abs_string) {
|
||||
Type = eAbs;
|
||||
} else if (operation == sin_string) {
|
||||
|
@ -174,6 +185,9 @@ FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, const string& pr
|
|||
operation == quotient_string ||
|
||||
operation == pow_string ||
|
||||
operation == exp_string ||
|
||||
operation == log2_string ||
|
||||
operation == ln_string ||
|
||||
operation == log10_string ||
|
||||
operation == abs_string ||
|
||||
operation == sin_string ||
|
||||
operation == cos_string ||
|
||||
|
@ -259,6 +273,18 @@ double FGFunction::GetValue(void) const
|
|||
case eExp:
|
||||
temp = exp(temp);
|
||||
break;
|
||||
case eLog2:
|
||||
if (temp > 0.00) temp = log10(temp)*invlog2val;
|
||||
else temp = -HUGE_VAL;
|
||||
break;
|
||||
case eLn:
|
||||
if (temp > 0.00) temp = log(temp);
|
||||
else temp = -HUGE_VAL;
|
||||
break;
|
||||
case eLog10:
|
||||
if (temp > 0.00) temp = log10(temp);
|
||||
else temp = -HUGE_VAL;
|
||||
break;
|
||||
case eAbs:
|
||||
temp = fabs(temp);
|
||||
break;
|
||||
|
@ -335,7 +361,12 @@ string FGFunction::GetValueAsString(void) const
|
|||
void FGFunction::bind(void)
|
||||
{
|
||||
if ( !Name.empty() ) {
|
||||
string tmp = PropertyManager->mkPropertyName(Prefix + Name, false); // Allow upper case
|
||||
string tmp;
|
||||
if (Prefix.empty())
|
||||
tmp = PropertyManager->mkPropertyName(Name, false); // Allow upper case
|
||||
else
|
||||
tmp = PropertyManager->mkPropertyName(Prefix + "/" + Name, false); // Allow upper case
|
||||
|
||||
PropertyManager->Tie( tmp, this, &FGFunction::GetValue);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,6 +70,9 @@ A function definition consists of an operation, a value, a table, or a property
|
|||
- quotient (takes 2 args)
|
||||
- pow (takes 2 args)
|
||||
- exp (takes 2 args)
|
||||
- log2 (takes 1 arg)
|
||||
- ln (takes 1 arg)
|
||||
- log10 (takes 1 arg)
|
||||
- abs (takes n args)
|
||||
- sin (takes 1 arg)
|
||||
- cos (takes 1 arg)
|
||||
|
@ -193,6 +196,7 @@ private:
|
|||
std::vector <FGParameter*> Parameters;
|
||||
FGPropertyManager* const PropertyManager;
|
||||
bool cached;
|
||||
double invlog2val;
|
||||
std::string Prefix;
|
||||
std::string description_string;
|
||||
std::string property_string;
|
||||
|
@ -208,6 +212,9 @@ private:
|
|||
std::string quotient_string;
|
||||
std::string pow_string;
|
||||
std::string exp_string;
|
||||
std::string log2_string;
|
||||
std::string ln_string;
|
||||
std::string log10_string;
|
||||
std::string abs_string;
|
||||
std::string sin_string;
|
||||
std::string cos_string;
|
||||
|
@ -226,7 +233,7 @@ private:
|
|||
double cachedValue;
|
||||
enum functionType {eTopLevel=0, eProduct, eDifference, eSum, eQuotient, ePow,
|
||||
eExp, eAbs, eSin, eCos, eTan, eASin, eACos, eATan, eATan2,
|
||||
eMin, eMax, eAvg, eFrac, eInteger, eMod, eRandom} Type;
|
||||
eMin, eMax, eAvg, eFrac, eInteger, eMod, eRandom, eLog2, eLn, eLog10} Type;
|
||||
std::string Name;
|
||||
void bind(void);
|
||||
void Debug(int from);
|
||||
|
|
|
@ -39,6 +39,8 @@ INCLUDES
|
|||
|
||||
#include "FGMatrix33.h"
|
||||
#include "FGColumnVector3.h"
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
@ -65,6 +67,23 @@ FGMatrix33::FGMatrix33(void)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
string FGMatrix33::Dump(const string& delimiter) const
|
||||
{
|
||||
ostringstream buffer;
|
||||
buffer << std::setw(18) << std::setprecision(16) << Entry(1,1) << delimiter;
|
||||
buffer << std::setw(18) << std::setprecision(16) << Entry(1,2) << delimiter;
|
||||
buffer << std::setw(18) << std::setprecision(16) << Entry(1,3) << delimiter;
|
||||
buffer << std::setw(18) << std::setprecision(16) << Entry(2,1) << delimiter;
|
||||
buffer << std::setw(18) << std::setprecision(16) << Entry(2,2) << delimiter;
|
||||
buffer << std::setw(18) << std::setprecision(16) << Entry(2,3) << delimiter;
|
||||
buffer << std::setw(18) << std::setprecision(16) << Entry(3,1) << delimiter;
|
||||
buffer << std::setw(18) << std::setprecision(16) << Entry(3,2) << delimiter;
|
||||
buffer << std::setw(18) << std::setprecision(16) << Entry(3,3);
|
||||
return buffer.str();
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
ostream& operator<<(ostream& os, const FGMatrix33& M)
|
||||
{
|
||||
for (unsigned int i=1; i<=M.Rows(); i++) {
|
||||
|
|
|
@ -158,6 +158,11 @@ public:
|
|||
*/
|
||||
~FGMatrix33(void) { Debug(1); }
|
||||
|
||||
/** Prints the contents of the matrix.
|
||||
@param delimeter the item separator (tab or comma)
|
||||
@return a string with the delimeter-separated contents of the matrix */
|
||||
std::string Dump(const std::string& delimeter) const;
|
||||
|
||||
/** Read access the entries of the matrix.
|
||||
@param row Row index.
|
||||
@param col Column index.
|
||||
|
|
|
@ -108,9 +108,6 @@ FGAerodynamics::~FGAerodynamics()
|
|||
|
||||
delete[] Coeff;
|
||||
|
||||
for (i=0; i<variables.size(); i++)
|
||||
delete variables[i];
|
||||
|
||||
delete AeroRPShift;
|
||||
|
||||
Debug(1);
|
||||
|
@ -137,12 +134,14 @@ bool FGAerodynamics::InitModel(void)
|
|||
|
||||
bool FGAerodynamics::Run(void)
|
||||
{
|
||||
unsigned int axis_ctr, ctr, i;
|
||||
unsigned int axis_ctr, ctr;
|
||||
double alpha, twovel;
|
||||
|
||||
if (FGModel::Run()) return true;
|
||||
if (FDMExec->Holding()) return false; // if paused don't execute
|
||||
|
||||
RunPreFunctions();
|
||||
|
||||
// calculate some oft-used quantities for speed
|
||||
|
||||
twovel = 2*Auxiliary->GetVt();
|
||||
|
@ -173,13 +172,6 @@ bool FGAerodynamics::Run(void)
|
|||
vFw.InitMatrix();
|
||||
vFnative.InitMatrix();
|
||||
|
||||
// Tell the variable functions to cache their values, so while the aerodynamic
|
||||
// functions are being calculated for each axis, these functions do not get
|
||||
// calculated each time, but instead use the values that have already
|
||||
// been calculated for this frame.
|
||||
|
||||
for (i=0; i<variables.size(); i++) variables[i]->cacheValue(true);
|
||||
|
||||
for (axis_ctr = 0; axis_ctr < 3; axis_ctr++) {
|
||||
for (ctr=0; ctr < Coeff[axis_ctr].size(); ctr++) {
|
||||
vFnative(axis_ctr+1) += Coeff[axis_ctr][ctr]->GetValue();
|
||||
|
@ -233,6 +225,8 @@ bool FGAerodynamics::Run(void)
|
|||
}
|
||||
}
|
||||
|
||||
RunPostFunctions();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -324,7 +318,7 @@ bool FGAerodynamics::Load(Element *element)
|
|||
document = element;
|
||||
}
|
||||
|
||||
FGModel::Load(element); // Perform base class Load
|
||||
FGModel::Load(element); // Perform base class Pre-Load
|
||||
|
||||
DetermineAxisSystem(); // Detemine if Lift/Side/Drag, etc. is used.
|
||||
|
||||
|
@ -349,12 +343,6 @@ bool FGAerodynamics::Load(Element *element)
|
|||
AeroRPShift = new FGFunction(PropertyManager, function_element);
|
||||
}
|
||||
|
||||
function_element = document->FindElement("function");
|
||||
while (function_element) {
|
||||
variables.push_back( new FGFunction(PropertyManager, function_element) );
|
||||
function_element = document->FindNextElement("function");
|
||||
}
|
||||
|
||||
axis_element = document->FindElement("axis");
|
||||
while (axis_element) {
|
||||
CoeffArray ca;
|
||||
|
@ -368,6 +356,8 @@ bool FGAerodynamics::Load(Element *element)
|
|||
axis_element = document->FindNextElement("axis");
|
||||
}
|
||||
|
||||
FGModel::PostLoad(element); // Perform base class Post-Load
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -427,15 +417,6 @@ string FGAerodynamics::GetCoefficientStrings(const string& delimeter) const
|
|||
bool firstime = true;
|
||||
unsigned int axis, sd;
|
||||
|
||||
for (sd = 0; sd < variables.size(); sd++) {
|
||||
if (firstime) {
|
||||
firstime = false;
|
||||
} else {
|
||||
CoeffStrings += delimeter;
|
||||
}
|
||||
CoeffStrings += variables[sd]->GetName();
|
||||
}
|
||||
|
||||
for (axis = 0; axis < 6; axis++) {
|
||||
for (sd = 0; sd < Coeff[axis].size(); sd++) {
|
||||
if (firstime) {
|
||||
|
@ -455,12 +436,6 @@ string FGAerodynamics::GetCoefficientValues(const string& delimeter) const
|
|||
{
|
||||
ostringstream buf;
|
||||
|
||||
buf.precision(6);
|
||||
for (unsigned int sd = 0; sd < variables.size(); sd++) {
|
||||
if (buf.tellp() > 0) buf << delimeter;
|
||||
buf << setw(9) << variables[sd]->GetValue();
|
||||
}
|
||||
|
||||
for (unsigned int axis = 0; axis < 6; axis++) {
|
||||
for (unsigned int sd = 0; sd < Coeff[axis].size(); sd++) {
|
||||
if (buf.tellp() > 0) buf << delimeter;
|
||||
|
|
|
@ -114,6 +114,8 @@ bool FGAircraft::Run(void)
|
|||
if (FGModel::Run()) return true;
|
||||
if (FDMExec->Holding()) return false;
|
||||
|
||||
RunPreFunctions();
|
||||
|
||||
vForces.InitMatrix();
|
||||
if (!HoldDown) {
|
||||
vForces += Aerodynamics->GetForces();
|
||||
|
@ -139,6 +141,8 @@ bool FGAircraft::Run(void)
|
|||
vNwcg = Aerodynamics->GetTb2w() * vNcg;
|
||||
vNwcg(3) = -1*vNwcg(3) + 1;
|
||||
|
||||
RunPostFunctions();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -199,6 +203,8 @@ bool FGAircraft::Load(Element* el)
|
|||
}
|
||||
}
|
||||
|
||||
FGModel::PostLoad(el);
|
||||
|
||||
Debug(2);
|
||||
|
||||
return true;
|
||||
|
|
|
@ -139,6 +139,8 @@ bool FGAtmosphere::Run(void)
|
|||
if (FGModel::Run()) return true;
|
||||
if (FDMExec->Holding()) return false;
|
||||
|
||||
RunPreFunctions();
|
||||
|
||||
T_dev = 0.0;
|
||||
h = Propagate->GetAltitudeASL();
|
||||
|
||||
|
@ -149,6 +151,8 @@ bool FGAtmosphere::Run(void)
|
|||
CalculateDerived();
|
||||
}
|
||||
|
||||
RunPostFunctions();
|
||||
|
||||
Debug(2);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -142,6 +142,8 @@ bool FGAuxiliary::Run()
|
|||
if (FGModel::Run()) return true; // return true if error returned from base class
|
||||
if (FDMExec->Holding()) return false;
|
||||
|
||||
RunPreFunctions();
|
||||
|
||||
const FGColumnVector3& vPQR = Propagate->GetPQR();
|
||||
const FGColumnVector3& vUVW = Propagate->GetUVW();
|
||||
const FGColumnVector3& vUVWdot = Propagate->GetUVWdot();
|
||||
|
@ -290,6 +292,8 @@ bool FGAuxiliary::Run()
|
|||
|
||||
CalculateRelativePosition();
|
||||
|
||||
RunPostFunctions();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -95,6 +95,8 @@ bool FGBuoyantForces::Run(void)
|
|||
if (FDMExec->Holding()) return false; // if paused don't execute
|
||||
if (NoneDefined) return true;
|
||||
|
||||
RunPreFunctions();
|
||||
|
||||
vTotalForces.InitMatrix();
|
||||
vTotalMoments.InitMatrix();
|
||||
|
||||
|
@ -104,6 +106,8 @@ bool FGBuoyantForces::Run(void)
|
|||
vTotalMoments += Cells[i]->GetMoments();
|
||||
}
|
||||
|
||||
RunPostFunctions();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -135,6 +139,8 @@ bool FGBuoyantForces::Load(Element *element)
|
|||
gas_cell_element = document->FindNextElement("gas_cell");
|
||||
}
|
||||
|
||||
FGModel::PostLoad(element);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -85,6 +85,8 @@ bool FGExternalReactions::Load(Element* el)
|
|||
force_element = el->FindNextElement("force");
|
||||
}
|
||||
|
||||
FGModel::PostLoad(el);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -115,6 +117,8 @@ bool FGExternalReactions::Run()
|
|||
if (FDMExec->Holding()) return false; // if paused don't execute
|
||||
if (NoneDefined) return true;
|
||||
|
||||
RunPreFunctions();
|
||||
|
||||
vTotalForces.InitMatrix();
|
||||
vTotalMoments.InitMatrix();
|
||||
|
||||
|
@ -123,6 +127,8 @@ bool FGExternalReactions::Run()
|
|||
vTotalMoments += Forces[i]->GetMoments();
|
||||
}
|
||||
|
||||
RunPostFunctions();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -198,6 +198,8 @@ bool FGFCS::Run(void)
|
|||
if (FGModel::Run()) return true; // fast exit if nothing to do
|
||||
if (FDMExec->Holding()) return false;
|
||||
|
||||
RunPreFunctions();
|
||||
|
||||
for (i=0; i<ThrottlePos.size(); i++) ThrottlePos[i] = ThrottleCmd[i];
|
||||
for (i=0; i<MixturePos.size(); i++) MixturePos[i] = MixtureCmd[i];
|
||||
for (i=0; i<PropAdvance.size(); i++) PropAdvance[i] = PropAdvanceCmd[i];
|
||||
|
@ -218,6 +220,8 @@ bool FGFCS::Run(void)
|
|||
// Execute Flight Control System
|
||||
for (i=0; i<FCSComponents.size(); i++) FCSComponents[i]->Run();
|
||||
|
||||
RunPostFunctions();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -89,6 +89,8 @@ bool FGGroundReactions::Run(void)
|
|||
if (FGModel::Run()) return true;
|
||||
if (FDMExec->Holding()) return false;
|
||||
|
||||
RunPreFunctions();
|
||||
|
||||
vForces.InitMatrix();
|
||||
vMoments.InitMatrix();
|
||||
|
||||
|
@ -102,6 +104,8 @@ bool FGGroundReactions::Run(void)
|
|||
vMoments += lGear[i]->GetMoments();
|
||||
}
|
||||
|
||||
RunPostFunctions();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -138,6 +142,8 @@ bool FGGroundReactions::Load(Element* el)
|
|||
|
||||
for (unsigned int i=0; i<lGear.size();i++) lGear[i]->bind();
|
||||
|
||||
FGModel::PostLoad(el);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -185,7 +191,7 @@ string FGGroundReactions::GetGroundReactionValues(string delimeter)
|
|||
for (unsigned int i=0;i<lGear.size();i++) {
|
||||
if (lGear[i]->IsBogey()) {
|
||||
FGLGear *gear = lGear[i];
|
||||
buf << (gear->GetWOW() ? "1, " : "0, ")
|
||||
buf << (gear->GetWOW() ? "1" : "0") << delimeter
|
||||
<< setprecision(5) << gear->GetCompLen() << delimeter
|
||||
<< setprecision(6) << gear->GetCompVel() << delimeter
|
||||
<< setprecision(10) << gear->GetCompForce() << delimeter
|
||||
|
|
|
@ -114,11 +114,15 @@ bool FGInertial::Run(void)
|
|||
if (FGModel::Run()) return true;
|
||||
if (FDMExec->Holding()) return false;
|
||||
|
||||
RunPreFunctions();
|
||||
|
||||
// Gravitation accel
|
||||
double r = Propagate->GetRadius();
|
||||
gAccel = GetGAccel(r);
|
||||
earthPosAngle += State->Getdt()*RotationRate;
|
||||
|
||||
RunPostFunctions();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -105,6 +105,8 @@ bool FGInput::Run(void)
|
|||
// return false if no error
|
||||
// This model DOES execute if "Exec->Holding"
|
||||
|
||||
RunPreFunctions();
|
||||
|
||||
data = socket->Receive(); // get socket transmission if present
|
||||
|
||||
if (data.size() > 0) {
|
||||
|
@ -213,6 +215,8 @@ bool FGInput::Run(void)
|
|||
}
|
||||
}
|
||||
|
||||
RunPostFunctions();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -152,6 +152,8 @@ bool FGMassBalance::Load(Element* el)
|
|||
|
||||
Mass = lbtoslug*Weight;
|
||||
|
||||
FGModel::PostLoad(el);
|
||||
|
||||
Debug(2);
|
||||
return true;
|
||||
}
|
||||
|
@ -166,6 +168,8 @@ bool FGMassBalance::Run(void)
|
|||
if (FGModel::Run()) return true;
|
||||
if (FDMExec->Holding()) return false;
|
||||
|
||||
RunPreFunctions();
|
||||
|
||||
double ChildFDMWeight = 0.0;
|
||||
for (int fdm=0; fdm<FDMExec->GetFDMCount(); fdm++) {
|
||||
if (FDMExec->GetChildFDM(fdm)->mated) ChildFDMWeight += FDMExec->GetChildFDM(fdm)->exec->GetMassBalance()->GetWeight();
|
||||
|
@ -226,6 +230,8 @@ bool FGMassBalance::Run(void)
|
|||
k2, k4, k5,
|
||||
k3, k5, k6 );
|
||||
|
||||
RunPostFunctions();
|
||||
|
||||
Debug(0);
|
||||
|
||||
return false;
|
||||
|
|
|
@ -105,6 +105,9 @@ FGModel::~FGModel()
|
|||
for (unsigned int i=0; i<interface_properties.size(); i++) delete interface_properties[i];
|
||||
interface_properties.clear();
|
||||
|
||||
for (unsigned int i=0; i<PreFunctions.size(); i++) delete PreFunctions[i];
|
||||
for (unsigned int i=0; i<PostFunctions.size(); i++) delete PostFunctions[i];
|
||||
|
||||
if (debug_lvl & 2) cout << "Destroyed: FGModel" << endl;
|
||||
}
|
||||
|
||||
|
@ -146,15 +149,16 @@ bool FGModel::InitModel(void)
|
|||
bool FGModel::Load(Element* el)
|
||||
{
|
||||
// Interface properties are all stored in the interface properties array.
|
||||
|
||||
string interface_property_string = "";
|
||||
|
||||
Element *property_element = el->FindElement("property");
|
||||
if (property_element && debug_lvl > 0) cout << endl << " Declared properties" << endl << endl;
|
||||
if (property_element && debug_lvl > 0) cout << endl << " Declared properties"
|
||||
<< endl << endl;
|
||||
while (property_element) {
|
||||
interface_property_string = property_element->GetDataLine();
|
||||
if (PropertyManager->HasNode(interface_property_string)) {
|
||||
cerr << " Property " << interface_property_string << " is already defined." << endl;
|
||||
cerr << " Property " << interface_property_string
|
||||
<< " is already defined." << endl;
|
||||
} else {
|
||||
double value=0.0;
|
||||
if ( ! property_element->GetAttributeValue("value").empty())
|
||||
|
@ -162,23 +166,82 @@ bool FGModel::Load(Element* el)
|
|||
interface_properties.push_back(new double(value));
|
||||
PropertyManager->Tie(interface_property_string, interface_properties.back());
|
||||
if (debug_lvl > 0)
|
||||
cout << " " << interface_property_string << " (initial value: " << value << ")" << endl;
|
||||
cout << " " << interface_property_string << " (initial value: "
|
||||
<< value << ")" << endl << endl;
|
||||
}
|
||||
property_element = el->FindNextElement("property");
|
||||
}
|
||||
|
||||
// End of interface property loading logic
|
||||
|
||||
// Load model pre-functions, if any
|
||||
|
||||
Element *function = el->FindElement("function");
|
||||
while (function) {
|
||||
if (function->GetAttributeValue("type") == "pre") {
|
||||
PreFunctions.push_back(new FGFunction(PropertyManager, function));
|
||||
} else if (function->GetAttributeValue("type").empty()) { // Assume pre-function
|
||||
string funcname = function->GetAttributeValue("name");
|
||||
PreFunctions.push_back(new FGFunction(PropertyManager, function));
|
||||
}
|
||||
function = el->FindNextElement("function");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGModel::PostLoad(Element* el)
|
||||
{
|
||||
// Load model post-functions, if any
|
||||
|
||||
Element *function = el->FindElement("function");
|
||||
while (function) {
|
||||
if (function->GetAttributeValue("type") == "post") {
|
||||
PostFunctions.push_back(new FGFunction(PropertyManager, function));
|
||||
}
|
||||
function = el->FindNextElement("function");
|
||||
}
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// Tell the Functions to cache values, so when the function values
|
||||
// are being used in the model, the functions do not get
|
||||
// calculated each time, but instead use the values that have already
|
||||
// been calculated for this frame.
|
||||
|
||||
void FGModel::RunPreFunctions(void)
|
||||
{
|
||||
vector <FGFunction*>::iterator it;
|
||||
for (it = PreFunctions.begin(); it != PreFunctions.end(); it++)
|
||||
(*it)->GetValue();
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// Tell the Functions to cache values, so when the function values
|
||||
// are being used in the model, the functions do not get
|
||||
// calculated each time, but instead use the values that have already
|
||||
// been calculated for this frame.
|
||||
|
||||
void FGModel::RunPostFunctions(void)
|
||||
{
|
||||
vector <FGFunction*>::iterator it;
|
||||
for (it = PostFunctions.begin(); it != PostFunctions.end(); it++)
|
||||
(*it)->GetValue();
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
bool FGModel::Run()
|
||||
{
|
||||
if (debug_lvl & 4) cout << "Entering Run() for model " << Name << endl;
|
||||
|
||||
if (exe_ctr++ >= rate) exe_ctr = 1;
|
||||
if (rate == 1) return false; // Fast exit if nothing to do
|
||||
|
||||
if (exe_ctr == 1) return false;
|
||||
if (exe_ctr >= rate) exe_ctr = 1;
|
||||
|
||||
if (exe_ctr++ == 1) return false;
|
||||
else return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ INCLUDES
|
|||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include "FGJSBBase.h"
|
||||
#include "math/FGFunction.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
@ -93,11 +94,6 @@ public:
|
|||
/// Destructor
|
||||
~FGModel();
|
||||
|
||||
/** Loads this model.
|
||||
@param el a pointer to the element
|
||||
@return true if model is successfully loaded*/
|
||||
virtual bool Load(Element* el);
|
||||
|
||||
FGModel* NextModel;
|
||||
std::string Name;
|
||||
|
||||
|
@ -116,6 +112,16 @@ protected:
|
|||
int exe_ctr;
|
||||
int rate;
|
||||
|
||||
void RunPreFunctions(void);
|
||||
void RunPostFunctions(void);
|
||||
|
||||
/** Loads this model.
|
||||
@param el a pointer to the element
|
||||
@return true if model is successfully loaded*/
|
||||
virtual bool Load(Element* el);
|
||||
|
||||
void PostLoad(Element* el);
|
||||
|
||||
virtual void Debug(int from);
|
||||
|
||||
FGFDMExec* FDMExec;
|
||||
|
@ -133,6 +139,8 @@ protected:
|
|||
FGPropagate* Propagate;
|
||||
FGAuxiliary* Auxiliary;
|
||||
FGPropertyManager* PropertyManager;
|
||||
std::vector <FGFunction*> PreFunctions;
|
||||
std::vector <FGFunction*> PostFunctions;
|
||||
|
||||
std::vector <double*> interface_properties;
|
||||
};
|
||||
|
|
|
@ -188,6 +188,7 @@ bool FGOutput::Run(void)
|
|||
if (FGModel::Run()) return true;
|
||||
|
||||
if (enabled && !State->IntegrationSuspended()&& !FDMExec->Holding()) {
|
||||
RunPreFunctions();
|
||||
if (Type == otSocket) {
|
||||
SocketOutput();
|
||||
} else if (Type == otFlightGear) {
|
||||
|
@ -201,6 +202,7 @@ bool FGOutput::Run(void)
|
|||
} else {
|
||||
// Not a valid type of output
|
||||
}
|
||||
RunPostFunctions();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -396,22 +398,22 @@ void FGOutput::DelimitedOutput(const string& fname)
|
|||
}
|
||||
if (SubSystems & ssForces) {
|
||||
outstream << delimeter;
|
||||
outstream << Aerodynamics->GetvFw() << delimeter;
|
||||
outstream << Aerodynamics->GetvFw().Dump(delimeter) << delimeter;
|
||||
outstream << Aerodynamics->GetLoD() << delimeter;
|
||||
outstream << Aerodynamics->GetForces() << delimeter;
|
||||
outstream << Propulsion->GetForces() << delimeter;
|
||||
outstream << GroundReactions->GetForces() << delimeter;
|
||||
outstream << ExternalReactions->GetForces() << delimeter;
|
||||
outstream << BuoyantForces->GetForces() << delimeter;
|
||||
outstream << Aerodynamics->GetForces().Dump(delimeter) << delimeter;
|
||||
outstream << Propulsion->GetForces().Dump(delimeter) << delimeter;
|
||||
outstream << GroundReactions->GetForces().Dump(delimeter) << delimeter;
|
||||
outstream << ExternalReactions->GetForces().Dump(delimeter) << delimeter;
|
||||
outstream << BuoyantForces->GetForces().Dump(delimeter) << delimeter;
|
||||
outstream << Aircraft->GetForces().Dump(delimeter);
|
||||
}
|
||||
if (SubSystems & ssMoments) {
|
||||
outstream << delimeter;
|
||||
outstream << Aerodynamics->GetMoments() << delimeter;
|
||||
outstream << Propulsion->GetMoments() << delimeter;
|
||||
outstream << GroundReactions->GetMoments() << delimeter;
|
||||
outstream << ExternalReactions->GetMoments() << delimeter;
|
||||
outstream << BuoyantForces->GetMoments() << delimeter;
|
||||
outstream << Aerodynamics->GetMoments().Dump(delimeter) << delimeter;
|
||||
outstream << Propulsion->GetMoments().Dump(delimeter) << delimeter;
|
||||
outstream << GroundReactions->GetMoments().Dump(delimeter) << delimeter;
|
||||
outstream << ExternalReactions->GetMoments().Dump(delimeter) << delimeter;
|
||||
outstream << BuoyantForces->GetMoments().Dump(delimeter) << delimeter;
|
||||
outstream << Aircraft->GetMoments().Dump(delimeter);
|
||||
}
|
||||
if (SubSystems & ssAtmosphere) {
|
||||
|
@ -428,9 +430,9 @@ void FGOutput::DelimitedOutput(const string& fname)
|
|||
}
|
||||
if (SubSystems & ssMassProps) {
|
||||
outstream << delimeter;
|
||||
outstream << MassBalance->GetJ() << delimeter;
|
||||
outstream << MassBalance->GetJ().Dump(delimeter) << delimeter;
|
||||
outstream << MassBalance->GetMass() << delimeter;
|
||||
outstream << MassBalance->GetXYZcg();
|
||||
outstream << MassBalance->GetXYZcg().Dump(delimeter);
|
||||
}
|
||||
if (SubSystems & ssPropagate) {
|
||||
outstream.precision(14);
|
||||
|
|
|
@ -233,6 +233,8 @@ bool FGPropagate::Run(void)
|
|||
if (FGModel::Run()) return true; // Fast return if we have nothing to do ...
|
||||
if (FDMExec->Holding()) return false;
|
||||
|
||||
RunPreFunctions();
|
||||
|
||||
RecomputeLocalTerrainRadius();
|
||||
|
||||
// Calculate current aircraft radius from center of planet
|
||||
|
@ -344,6 +346,8 @@ bool FGPropagate::Run(void)
|
|||
last2_vLocationDot = last_vLocationDot;
|
||||
last_vLocationDot = vLocationDot;
|
||||
|
||||
RunPreFunctions();
|
||||
|
||||
Debug(2);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -147,6 +147,8 @@ bool FGPropulsion::Run(void)
|
|||
if (FGModel::Run()) return true;
|
||||
if (FDMExec->Holding()) return false;
|
||||
|
||||
RunPreFunctions();
|
||||
|
||||
double dt = State->Getdt();
|
||||
|
||||
vForces.InitMatrix();
|
||||
|
@ -169,6 +171,8 @@ bool FGPropulsion::Run(void)
|
|||
if (refuel) DoRefuel( dt * rate );
|
||||
if (dump) DumpFuel( dt * rate );
|
||||
|
||||
RunPostFunctions();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -333,6 +337,7 @@ bool FGPropulsion::Load(Element* el)
|
|||
if (el->FindElement("dump-rate"))
|
||||
DumpRate = el->FindElementValueAsNumberConvertTo("dump-rate", "LBS/MIN");
|
||||
|
||||
FGModel::PostLoad(el);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -148,6 +148,8 @@ bool MSIS::Run(void)
|
|||
if (FGModel::Run()) return true;
|
||||
if (FDMExec->Holding()) return false;
|
||||
|
||||
RunPreFunctions();
|
||||
|
||||
//do temp, pressure, and density first
|
||||
if (!useExternal) {
|
||||
// get sea-level values
|
||||
|
@ -180,6 +182,8 @@ bool MSIS::Run(void)
|
|||
|
||||
CalculateDerived();
|
||||
|
||||
RunPostFunctions();
|
||||
|
||||
Debug(2);
|
||||
|
||||
return false;
|
||||
|
|
|
@ -74,6 +74,7 @@ FGEngine::FGEngine(FGFDMExec* exec, Element* engine_element, int engine_number)
|
|||
SLFuelFlowMax = 0.0;
|
||||
MaxThrottle = 1.0;
|
||||
MinThrottle = 0.0;
|
||||
FuelDensity = 6.0;
|
||||
unsigned int i;
|
||||
|
||||
ResetToIC(); // initialize dynamic terms
|
||||
|
@ -122,7 +123,9 @@ FGEngine::FGEngine(FGFDMExec* exec, Element* engine_element, int engine_number)
|
|||
if (local_element) {
|
||||
while (local_element) {
|
||||
int tankID = (int)local_element->GetDataAsNumber();
|
||||
AddFeedTank( tankID , Propulsion->GetTank(tankID)->GetPriority());
|
||||
FGTank* tank = Propulsion->GetTank(tankID);
|
||||
AddFeedTank( tankID , tank->GetPriority());
|
||||
FuelDensity = tank->GetDensity();
|
||||
local_element = engine_element->GetParent()->FindNextElement("feed");
|
||||
}
|
||||
} else {
|
||||
|
@ -139,6 +142,8 @@ FGEngine::FGEngine(FGFDMExec* exec, Element* engine_element, int engine_number)
|
|||
property_name = base_property_name + "/fuel-flow-rate-pps";
|
||||
PropertyManager->Tie( property_name.c_str(), this, &FGEngine::GetFuelFlowRate);
|
||||
|
||||
//cout << "Engine[" << EngineNumber << "] using fuel density: " << FuelDensity << endl;
|
||||
|
||||
Debug(0);
|
||||
}
|
||||
|
||||
|
|
|
@ -113,7 +113,6 @@ CLASS DOCUMENTATION
|
|||
@endcode
|
||||
<pre>
|
||||
NOTES:
|
||||
Engines feed from all tanks equally.
|
||||
|
||||
Not all thruster types can be matched with a given engine type. See the class
|
||||
documentation for engine and thruster classes.
|
||||
|
@ -226,6 +225,7 @@ protected:
|
|||
|
||||
double FuelFlow_gph;
|
||||
double FuelFlow_pph;
|
||||
double FuelDensity;
|
||||
|
||||
FGFDMExec* FDMExec;
|
||||
FGState* State;
|
||||
|
|
|
@ -71,6 +71,8 @@ FGRocket::FGRocket(FGFDMExec* exec, Element *el, int engine_number)
|
|||
SLOxiFlowMax = 0.0;
|
||||
BuildupTime = 0.0;
|
||||
It = 0.0;
|
||||
ThrustVariation = 0.0;
|
||||
TotalIspVariation = 0.0;
|
||||
|
||||
// Defaults
|
||||
MinThrottle = 0.0;
|
||||
|
@ -89,9 +91,19 @@ FGRocket::FGRocket(FGFDMExec* exec, Element *el, int engine_number)
|
|||
if (el->FindElement("sloxiflowmax"))
|
||||
SLOxiFlowMax = el->FindElementValueAsNumberConvertTo("sloxiflowmax", "LBS/SEC");
|
||||
|
||||
// If there is a thrust table element, this is a solid propellant engine.
|
||||
thrust_table_element = el->FindElement("thrust_table");
|
||||
if (thrust_table_element) {
|
||||
ThrustTable = new FGTable(PropertyManager, thrust_table_element);
|
||||
Element* variation_element = el->FindElement("variation");
|
||||
if (variation_element) {
|
||||
if (variation_element->FindElement("thrust")) {
|
||||
ThrustVariation = variation_element->FindElementValueAsNumber("thrust");
|
||||
}
|
||||
if (variation_element->FindElement("total_isp")) {
|
||||
TotalIspVariation = variation_element->FindElementValueAsNumber("total_isp");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bindmodel();
|
||||
|
@ -138,7 +150,9 @@ double FGRocket::Calculate(void)
|
|||
}
|
||||
}
|
||||
|
||||
VacThrust = ThrustTable->GetValue(TotalEngineFuelBurned);
|
||||
VacThrust = ThrustTable->GetValue(TotalEngineFuelBurned)
|
||||
* (ThrustVariation + 1)
|
||||
* (TotalIspVariation + 1);
|
||||
if (BurnTime <= BuildupTime && BuildupTime > 0.0) {
|
||||
VacThrust *= sin((BurnTime/BuildupTime)*M_PI/2.0);
|
||||
// VacThrust *= (1-cos((BurnTime/BuildupTime)*M_PI))/2.0; // 1 - cos approach
|
||||
|
@ -241,6 +255,11 @@ void FGRocket::ConsumeFuel(void)
|
|||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
//
|
||||
// The FuelFlowRate can be affected by the TotalIspVariation value (settable
|
||||
// in a config file or via properties). The TotalIspVariation parameter affects
|
||||
// thrust, but the thrust determines fuel flow rate, so it must be adjusted
|
||||
// for Total Isp Variation.
|
||||
|
||||
double FGRocket::CalcFuelNeed(void)
|
||||
{
|
||||
|
@ -248,6 +267,7 @@ double FGRocket::CalcFuelNeed(void)
|
|||
|
||||
if (ThrustTable != 0L) { // Thrust table given - infers solid fuel
|
||||
FuelFlowRate = VacThrust/Isp; // This calculates wdot (weight flow rate in lbs/sec)
|
||||
FuelFlowRate /= (1 + TotalIspVariation);
|
||||
} else {
|
||||
FuelFlowRate = SLFuelFlowMax*PctPower;
|
||||
}
|
||||
|
@ -290,7 +310,7 @@ string FGRocket::GetEngineValues(const string& delimiter)
|
|||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// This funciton should tie properties to rocket engine specific properties
|
||||
// This function should tie properties to rocket engine specific properties
|
||||
// that are not bound in the base class (FGEngine) code.
|
||||
//
|
||||
void FGRocket::bindmodel()
|
||||
|
@ -300,10 +320,20 @@ void FGRocket::bindmodel()
|
|||
|
||||
property_name = base_property_name + "/total-impulse";
|
||||
PropertyManager->Tie( property_name.c_str(), this, &FGRocket::GetTotalImpulse);
|
||||
property_name = base_property_name + "/oxi-flow-rate-pps";
|
||||
PropertyManager->Tie( property_name.c_str(), this, &FGRocket::GetOxiFlowRate);
|
||||
property_name = base_property_name + "/vacuum-thrust_lbs";
|
||||
PropertyManager->Tie( property_name.c_str(), this, &FGRocket::GetVacThrust);
|
||||
|
||||
if (ThrustTable) { // Solid rocket motor
|
||||
property_name = base_property_name + "/thrust-variation_pct";
|
||||
PropertyManager->Tie( property_name.c_str(), this, &FGRocket::GetThrustVariation,
|
||||
&FGRocket::SetThrustVariation);
|
||||
property_name = base_property_name + "/total-isp-variation_pct";
|
||||
PropertyManager->Tie( property_name.c_str(), this, &FGRocket::GetTotalIspVariation,
|
||||
&FGRocket::SetTotalIspVariation);
|
||||
} else { // Liquid rocket motor
|
||||
property_name = base_property_name + "/oxi-flow-rate-pps";
|
||||
PropertyManager->Tie( property_name.c_str(), this, &FGRocket::GetOxiFlowRate);
|
||||
}
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -162,6 +162,32 @@ public:
|
|||
std::string GetEngineLabels(const std::string& delimiter);
|
||||
std::string GetEngineValues(const std::string& delimiter);
|
||||
|
||||
/** Sets the thrust variation for a solid rocket engine.
|
||||
Solid propellant rocket motor thrust characteristics are typically
|
||||
defined at 70 degrees F temperature. At any other temperature,
|
||||
performance will be different. Warmer propellant grain will
|
||||
burn quicker and at higher thrust. Total motor impulse is
|
||||
not changed for change in thrust.
|
||||
@param var the variation in percent. That is, a 2 percent
|
||||
variation would be specified as 0.02. A positive 2% variation
|
||||
in thrust would increase the thrust by 2%, and shorten the burn time. */
|
||||
void SetThrustVariation(double var) {ThrustVariation = var;}
|
||||
|
||||
/** Sets the variation in total motor energy.
|
||||
The total energy present in a solid rocket motor can be modified
|
||||
(such as might happen with manufacturing variations) by setting
|
||||
the total Isp variation.
|
||||
@param var the variation in percent. That is, a 2 percent
|
||||
variation would be specified as 0.02. This variation will
|
||||
affect the total thrust, but not the burn time.*/
|
||||
void SetTotalIspVariation(double var) {TotalIspVariation = var;}
|
||||
|
||||
/** Returns the thrust variation, if any. */
|
||||
double GetThrustVariation(void) const {return ThrustVariation;}
|
||||
|
||||
/** Returns the Total Isp variation, if any. */
|
||||
double GetTotalIspVariation(void) const {return TotalIspVariation;}
|
||||
|
||||
private:
|
||||
/** Reduces the fuel in the active tanks by the amount required.
|
||||
This function should be called from within the
|
||||
|
@ -192,6 +218,8 @@ private:
|
|||
double It;
|
||||
double MxR; // Mixture Ratio
|
||||
double BurnTime;
|
||||
double ThrustVariation;
|
||||
double TotalIspVariation;
|
||||
double VacThrust;
|
||||
double previousFuelNeedPerTank;
|
||||
double previousOxiNeedPerTank;
|
||||
|
|
|
@ -58,7 +58,7 @@ CLASS IMPLEMENTATION
|
|||
FGTank::FGTank(FGFDMExec* exec, Element* el, int tank_number)
|
||||
: TankNumber(tank_number), Exec(exec)
|
||||
{
|
||||
string token;
|
||||
string token, strFuelName;
|
||||
Element* element;
|
||||
Element* element_Grain;
|
||||
Area = 1.0;
|
||||
|
@ -102,6 +102,9 @@ FGTank::FGTank(FGFDMExec* exec, Element* el, int tank_number)
|
|||
InitialPriority = Priority = el->FindElementValueAsNumber("priority");
|
||||
if (el->FindElement("density"))
|
||||
Density = el->FindElementValueAsNumberConvertTo("density", "LBS/GAL");
|
||||
if (el->FindElement("type"))
|
||||
strFuelName = el->FindElementValue("type");
|
||||
|
||||
|
||||
SetPriority( InitialPriority ); // this will also set the Selected flag
|
||||
|
||||
|
@ -162,6 +165,9 @@ FGTank::FGTank(FGFDMExec* exec, Element* el, int tank_number)
|
|||
if (Temperature != -9999.0) InitialTemperature = Temperature = FahrenheitToCelsius(Temperature);
|
||||
Area = 40.0 * pow(Capacity/1975, 0.666666667);
|
||||
|
||||
// A named fuel type will override a previous density value
|
||||
if (!strFuelName.empty()) Density = ProcessFuelName(strFuelName);
|
||||
|
||||
Debug(0);
|
||||
}
|
||||
|
||||
|
@ -313,6 +319,43 @@ void FGTank::CalculateInertias(void)
|
|||
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGTank::ProcessFuelName(std::string const& name)
|
||||
{
|
||||
if (name == "AVGAS") return 6.02;
|
||||
else if (name == "JET-A") return 6.74;
|
||||
else if (name == "JET-A1") return 6.74;
|
||||
else if (name == "JET-B") return 6.48;
|
||||
else if (name == "JP-1") return 6.76;
|
||||
else if (name == "JP-2") return 6.38;
|
||||
else if (name == "JP-3") return 6.34;
|
||||
else if (name == "JP-4") return 6.48;
|
||||
else if (name == "JP-5") return 6.81;
|
||||
else if (name == "JP-6") return 6.55;
|
||||
else if (name == "JP-7") return 6.61;
|
||||
else if (name == "JP-8") return 6.66;
|
||||
else if (name == "JP-8+100") return 6.66;
|
||||
//else if (name == "JP-9") return 6.74;
|
||||
//else if (name == "JPTS") return 6.74;
|
||||
else if (name == "RP-1") return 6.73;
|
||||
else if (name == "T-1") return 6.88;
|
||||
else if (name == "ETHANOL") return 6.58;
|
||||
else if (name == "HYDRAZINE")return 8.61;
|
||||
else if (name == "F-34") return 6.66;
|
||||
else if (name == "F-35") return 6.74;
|
||||
else if (name == "F-40") return 6.48;
|
||||
else if (name == "F-44") return 6.81;
|
||||
else if (name == "AVTAG") return 6.48;
|
||||
else if (name == "AVCAT") return 6.81;
|
||||
else {
|
||||
cerr << "Unknown fuel type specified: "<< name << endl;
|
||||
}
|
||||
|
||||
return 6.6;
|
||||
}
|
||||
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// The bitmasked value choices are as follows:
|
||||
// unset: In this case (the default) JSBSim would only print
|
||||
|
|
|
@ -126,6 +126,7 @@ CLASS DOCUMENTATION
|
|||
<standpipe unit="{LBS | KG"}> {number} </standpipe>
|
||||
<priority> {integer} </priority>
|
||||
<density unit="{KG/L | LBS/GAL}"> {number} </density>
|
||||
<type> {string} </type> <!-- will override previous density setting -->
|
||||
</tank>
|
||||
@endcode
|
||||
|
||||
|
@ -141,6 +142,9 @@ CLASS DOCUMENTATION
|
|||
- \b standpipe - Minimum contents to which tank can dump, defaults to pounds.
|
||||
- \b priority - Establishes feed sequence of tank. "1" is the highest priority.
|
||||
- \b density - Density of liquid tank contents.
|
||||
- \b type - Named fuel type. One of AVGAS, JET-A, JET-A1, JET-B, JP-1, JP-2, JP-3,
|
||||
- \b JP-4, JP-5, JP-6, JP-7, JP-8, JP-8+100, RP-1, T-1, ETHANOL, HYDRAZINE,
|
||||
- \b F-34, F-35, F-40, F-44, AVTAG, AVCAT
|
||||
|
||||
location:
|
||||
- \b x - Location of tank on aircraft's x-axis, defaults to inches.
|
||||
|
@ -252,6 +256,10 @@ public:
|
|||
is given, otherwise 32 degrees F is returned. */
|
||||
double GetTemperature(void) {return CelsiusToFahrenheit(Temperature);}
|
||||
|
||||
/** Returns the density of a named fuel type.
|
||||
@return the density, in lbs/gal, or 6.6 if name cannot be resolved. */
|
||||
double ProcessFuelName(std::string const& name);
|
||||
|
||||
double GetIxx(void) {return Ixx;}
|
||||
double GetIyy(void) {return Iyy;}
|
||||
double GetIzz(void) {return Izz;}
|
||||
|
@ -261,6 +269,9 @@ public:
|
|||
int GetPriority(void) const {return Priority;}
|
||||
void SetPriority(int p) { Priority = p; Selected = p>0 ? true:false; }
|
||||
|
||||
double GetDensity(void) const {return Density;}
|
||||
void SetDensity(double d) { Density = d; }
|
||||
|
||||
const FGColumnVector3 GetXYZ(void);
|
||||
const double GetXYZ(int idx);
|
||||
|
||||
|
|
Loading…
Reference in a new issue