1
0
Fork 0

Sync. withn JSBSim CVS

This commit is contained in:
ehofman 2009-11-27 08:54:33 +00:00 committed by Tim Moore
parent b1eebb21a6
commit 30e535bc7b
29 changed files with 383 additions and 135 deletions

View file

@ -94,7 +94,8 @@ void checkTied ( FGPropertyManager *node )
for (int i=0; i<N; i++) { for (int i=0; i<N; i++) {
if (node->getChild(i)->nChildren() ) { if (node->getChild(i)->nChildren() ) {
checkTied( (FGPropertyManager*)node->getChild(i) ); checkTied( (FGPropertyManager*)node->getChild(i) );
} else if ( node->getChild(i)->isTied() ) { }
if ( node->getChild(i)->isTied() ) {
name = ((FGPropertyManager*)node->getChild(i))->GetFullyQualifiedName(); name = ((FGPropertyManager*)node->getChild(i))->GetFullyQualifiedName();
node->Untie(name); node->Untie(name);
} }
@ -108,7 +109,6 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root) : Root(root)
{ {
Frame = 0; Frame = 0;
FirstModel = 0;
Error = 0; Error = 0;
GroundCallback = 0; GroundCallback = 0;
State = 0; State = 0;
@ -221,30 +221,11 @@ bool FGFDMExec::Allocate(void)
// class needs valid pointers to the above // class needs valid pointers to the above
// model classes // 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 // 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 // instance, the atmosphere model could get executed every fifth pass it is called.
// by the executive. IC and Trim objects are NOT scheduled.
Schedule(Input, 1); Schedule(Input, 1);
Schedule(Atmosphere, 1); Schedule(Atmosphere, 30);
Schedule(FCS, 1); Schedule(FCS, 1);
Schedule(Propulsion, 1); Schedule(Propulsion, 1);
Schedule(MassBalance, 1); Schedule(MassBalance, 1);
@ -257,6 +238,13 @@ bool FGFDMExec::Allocate(void)
Schedule(Propagate, 1); Schedule(Propagate, 1);
Schedule(Auxiliary, 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; modelLoaded = false;
return result; return result;
@ -290,7 +278,6 @@ bool FGFDMExec::DeAllocate(void)
delete GroundCallback; delete GroundCallback;
FirstModel = 0L;
Error = 0; Error = 0;
State = 0; State = 0;
@ -309,35 +296,18 @@ bool FGFDMExec::DeAllocate(void)
Auxiliary = 0; Auxiliary = 0;
Script = 0; Script = 0;
Models.clear();
modelLoaded = false; modelLoaded = false;
return modelLoaded; return modelLoaded;
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
int FGFDMExec::Schedule(FGModel* model, int rate) void FGFDMExec::Schedule(FGModel* model, int rate)
{ {
FGModel* model_iterator; model->SetRate(rate);
Models.push_back(model);
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;
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -345,10 +315,6 @@ int FGFDMExec::Schedule(FGModel* model, int rate)
bool FGFDMExec::Run(void) bool FGFDMExec::Run(void)
{ {
bool success=true; bool success=true;
FGModel* model_iterator;
model_iterator = FirstModel;
if (model_iterator == 0L) return false;
Debug(2); Debug(2);
@ -357,14 +323,11 @@ bool FGFDMExec::Run(void)
ChildFDMList[i]->Run(); ChildFDMList[i]->Run();
} }
// returns true if success // returns true if success, false if complete
// false if complete
if (Script != 0 && !State->IntegrationSuspended()) success = Script->RunScript(); if (Script != 0 && !State->IntegrationSuspended()) success = Script->RunScript();
while (model_iterator != 0L) { vector <FGModel*>::iterator it;
model_iterator->Run(); for (it = Models.begin(); it != Models.end(); ++it) (*it)->Run();
model_iterator = model_iterator->NextModel;
}
Frame++; Frame++;
if (!Holding()) State->IncrTime(); if (!Holding()) State->IncrTime();
@ -406,15 +369,10 @@ void FGFDMExec::ResetToInitialConditions(int mode)
void FGFDMExec::ResetToInitialConditions(void) void FGFDMExec::ResetToInitialConditions(void)
{ {
FGModel* model_iterator; if (Constructing) return;
model_iterator = FirstModel; vector <FGModel*>::iterator it;
if (model_iterator == 0L || Constructing) return; for (it = Models.begin(); it != Models.end(); ++it) (*it)->InitModel();
while (model_iterator != 0L) {
model_iterator->InitModel();
model_iterator = model_iterator->NextModel;
}
RunIC(); RunIC();
if (Script) Script->ResetEvents(); if (Script) Script->ResetEvents();

View file

@ -222,7 +222,7 @@ public:
@param model A pointer to the model being scheduled. @param model A pointer to the model being scheduled.
@param rate The rate at which to execute the model as described above. @param rate The rate at which to execute the model as described above.
@return Currently returns 0 always. */ @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. /** This function executes each scheduled model in succession.
@return true if successful, false if sim should be ended */ @return true if successful, false if sim should be ended */
@ -488,7 +488,6 @@ private:
static FGPropertyManager *master; static FGPropertyManager *master;
FGModel* FirstModel;
FGGroundCallback* GroundCallback; FGGroundCallback* GroundCallback;
FGState* State; FGState* State;
FGAtmosphere* Atmosphere; FGAtmosphere* Atmosphere;
@ -514,6 +513,7 @@ private:
vector <string> PropertyCatalog; vector <string> PropertyCatalog;
vector <FGOutput*> Outputs; vector <FGOutput*> Outputs;
vector <childData*> ChildFDMList; vector <childData*> ChildFDMList;
vector <FGModel*> Models;
bool ReadFileHeader(Element*); bool ReadFileHeader(Element*);
bool ReadChild(Element*); bool ReadChild(Element*);

View file

@ -31,6 +31,7 @@ INCLUDES
#include <sstream> #include <sstream>
#include <iomanip> #include <iomanip>
#include <cstdlib> #include <cstdlib>
#include <cmath>
#include "FGFunction.h" #include "FGFunction.h"
#include "FGTable.h" #include "FGTable.h"
#include "FGPropertyValue.h" #include "FGPropertyValue.h"
@ -56,6 +57,7 @@ FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, const string& pr
string operation, property_name; string operation, property_name;
cached = false; cached = false;
cachedValue = -HUGE_VAL; cachedValue = -HUGE_VAL;
invlog2val = 1.0/log10(2.0);
property_string = "property"; property_string = "property";
value_string = "value"; value_string = "value";
@ -72,6 +74,9 @@ FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, const string& pr
quotient_string = "quotient"; quotient_string = "quotient";
pow_string = "pow"; pow_string = "pow";
exp_string = "exp"; exp_string = "exp";
log2_string = "log2";
ln_string = "ln";
log10_string = "log10";
abs_string = "abs"; abs_string = "abs";
sin_string = "sin"; sin_string = "sin";
cos_string = "cos"; cos_string = "cos";
@ -103,6 +108,12 @@ FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, const string& pr
Type = eQuotient; Type = eQuotient;
} else if (operation == pow_string) { } else if (operation == pow_string) {
Type = ePow; 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) { } else if (operation == abs_string) {
Type = eAbs; Type = eAbs;
} else if (operation == sin_string) { } else if (operation == sin_string) {
@ -174,6 +185,9 @@ FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, const string& pr
operation == quotient_string || operation == quotient_string ||
operation == pow_string || operation == pow_string ||
operation == exp_string || operation == exp_string ||
operation == log2_string ||
operation == ln_string ||
operation == log10_string ||
operation == abs_string || operation == abs_string ||
operation == sin_string || operation == sin_string ||
operation == cos_string || operation == cos_string ||
@ -259,6 +273,18 @@ double FGFunction::GetValue(void) const
case eExp: case eExp:
temp = exp(temp); temp = exp(temp);
break; 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: case eAbs:
temp = fabs(temp); temp = fabs(temp);
break; break;
@ -335,7 +361,12 @@ string FGFunction::GetValueAsString(void) const
void FGFunction::bind(void) void FGFunction::bind(void)
{ {
if ( !Name.empty() ) { 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); PropertyManager->Tie( tmp, this, &FGFunction::GetValue);
} }
} }

View file

@ -70,6 +70,9 @@ A function definition consists of an operation, a value, a table, or a property
- quotient (takes 2 args) - quotient (takes 2 args)
- pow (takes 2 args) - pow (takes 2 args)
- exp (takes 2 args) - exp (takes 2 args)
- log2 (takes 1 arg)
- ln (takes 1 arg)
- log10 (takes 1 arg)
- abs (takes n args) - abs (takes n args)
- sin (takes 1 arg) - sin (takes 1 arg)
- cos (takes 1 arg) - cos (takes 1 arg)
@ -193,6 +196,7 @@ private:
std::vector <FGParameter*> Parameters; std::vector <FGParameter*> Parameters;
FGPropertyManager* const PropertyManager; FGPropertyManager* const PropertyManager;
bool cached; bool cached;
double invlog2val;
std::string Prefix; std::string Prefix;
std::string description_string; std::string description_string;
std::string property_string; std::string property_string;
@ -208,6 +212,9 @@ private:
std::string quotient_string; std::string quotient_string;
std::string pow_string; std::string pow_string;
std::string exp_string; std::string exp_string;
std::string log2_string;
std::string ln_string;
std::string log10_string;
std::string abs_string; std::string abs_string;
std::string sin_string; std::string sin_string;
std::string cos_string; std::string cos_string;
@ -226,7 +233,7 @@ private:
double cachedValue; double cachedValue;
enum functionType {eTopLevel=0, eProduct, eDifference, eSum, eQuotient, ePow, enum functionType {eTopLevel=0, eProduct, eDifference, eSum, eQuotient, ePow,
eExp, eAbs, eSin, eCos, eTan, eASin, eACos, eATan, eATan2, 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; std::string Name;
void bind(void); void bind(void);
void Debug(int from); void Debug(int from);

View file

@ -39,6 +39,8 @@ INCLUDES
#include "FGMatrix33.h" #include "FGMatrix33.h"
#include "FGColumnVector3.h" #include "FGColumnVector3.h"
#include <sstream>
#include <iomanip>
#include <iostream> #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) ostream& operator<<(ostream& os, const FGMatrix33& M)
{ {
for (unsigned int i=1; i<=M.Rows(); i++) { for (unsigned int i=1; i<=M.Rows(); i++) {

View file

@ -158,6 +158,11 @@ public:
*/ */
~FGMatrix33(void) { Debug(1); } ~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. /** Read access the entries of the matrix.
@param row Row index. @param row Row index.
@param col Column index. @param col Column index.

View file

@ -108,9 +108,6 @@ FGAerodynamics::~FGAerodynamics()
delete[] Coeff; delete[] Coeff;
for (i=0; i<variables.size(); i++)
delete variables[i];
delete AeroRPShift; delete AeroRPShift;
Debug(1); Debug(1);
@ -137,12 +134,14 @@ bool FGAerodynamics::InitModel(void)
bool FGAerodynamics::Run(void) bool FGAerodynamics::Run(void)
{ {
unsigned int axis_ctr, ctr, i; unsigned int axis_ctr, ctr;
double alpha, twovel; double alpha, twovel;
if (FGModel::Run()) return true; if (FGModel::Run()) return true;
if (FDMExec->Holding()) return false; // if paused don't execute if (FDMExec->Holding()) return false; // if paused don't execute
RunPreFunctions();
// calculate some oft-used quantities for speed // calculate some oft-used quantities for speed
twovel = 2*Auxiliary->GetVt(); twovel = 2*Auxiliary->GetVt();
@ -173,13 +172,6 @@ bool FGAerodynamics::Run(void)
vFw.InitMatrix(); vFw.InitMatrix();
vFnative.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 (axis_ctr = 0; axis_ctr < 3; axis_ctr++) {
for (ctr=0; ctr < Coeff[axis_ctr].size(); ctr++) { for (ctr=0; ctr < Coeff[axis_ctr].size(); ctr++) {
vFnative(axis_ctr+1) += Coeff[axis_ctr][ctr]->GetValue(); vFnative(axis_ctr+1) += Coeff[axis_ctr][ctr]->GetValue();
@ -233,6 +225,8 @@ bool FGAerodynamics::Run(void)
} }
} }
RunPostFunctions();
return false; return false;
} }
@ -324,7 +318,7 @@ bool FGAerodynamics::Load(Element *element)
document = 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. DetermineAxisSystem(); // Detemine if Lift/Side/Drag, etc. is used.
@ -349,12 +343,6 @@ bool FGAerodynamics::Load(Element *element)
AeroRPShift = new FGFunction(PropertyManager, function_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"); axis_element = document->FindElement("axis");
while (axis_element) { while (axis_element) {
CoeffArray ca; CoeffArray ca;
@ -368,6 +356,8 @@ bool FGAerodynamics::Load(Element *element)
axis_element = document->FindNextElement("axis"); axis_element = document->FindNextElement("axis");
} }
FGModel::PostLoad(element); // Perform base class Post-Load
return true; return true;
} }
@ -427,15 +417,6 @@ string FGAerodynamics::GetCoefficientStrings(const string& delimeter) const
bool firstime = true; bool firstime = true;
unsigned int axis, sd; 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 (axis = 0; axis < 6; axis++) {
for (sd = 0; sd < Coeff[axis].size(); sd++) { for (sd = 0; sd < Coeff[axis].size(); sd++) {
if (firstime) { if (firstime) {
@ -455,12 +436,6 @@ string FGAerodynamics::GetCoefficientValues(const string& delimeter) const
{ {
ostringstream buf; 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 axis = 0; axis < 6; axis++) {
for (unsigned int sd = 0; sd < Coeff[axis].size(); sd++) { for (unsigned int sd = 0; sd < Coeff[axis].size(); sd++) {
if (buf.tellp() > 0) buf << delimeter; if (buf.tellp() > 0) buf << delimeter;

View file

@ -114,6 +114,8 @@ bool FGAircraft::Run(void)
if (FGModel::Run()) return true; if (FGModel::Run()) return true;
if (FDMExec->Holding()) return false; if (FDMExec->Holding()) return false;
RunPreFunctions();
vForces.InitMatrix(); vForces.InitMatrix();
if (!HoldDown) { if (!HoldDown) {
vForces += Aerodynamics->GetForces(); vForces += Aerodynamics->GetForces();
@ -139,6 +141,8 @@ bool FGAircraft::Run(void)
vNwcg = Aerodynamics->GetTb2w() * vNcg; vNwcg = Aerodynamics->GetTb2w() * vNcg;
vNwcg(3) = -1*vNwcg(3) + 1; vNwcg(3) = -1*vNwcg(3) + 1;
RunPostFunctions();
return false; return false;
} }
@ -199,6 +203,8 @@ bool FGAircraft::Load(Element* el)
} }
} }
FGModel::PostLoad(el);
Debug(2); Debug(2);
return true; return true;

View file

@ -139,6 +139,8 @@ bool FGAtmosphere::Run(void)
if (FGModel::Run()) return true; if (FGModel::Run()) return true;
if (FDMExec->Holding()) return false; if (FDMExec->Holding()) return false;
RunPreFunctions();
T_dev = 0.0; T_dev = 0.0;
h = Propagate->GetAltitudeASL(); h = Propagate->GetAltitudeASL();
@ -149,6 +151,8 @@ bool FGAtmosphere::Run(void)
CalculateDerived(); CalculateDerived();
} }
RunPostFunctions();
Debug(2); Debug(2);
return false; return false;
} }

View file

@ -142,6 +142,8 @@ bool FGAuxiliary::Run()
if (FGModel::Run()) return true; // return true if error returned from base class if (FGModel::Run()) return true; // return true if error returned from base class
if (FDMExec->Holding()) return false; if (FDMExec->Holding()) return false;
RunPreFunctions();
const FGColumnVector3& vPQR = Propagate->GetPQR(); const FGColumnVector3& vPQR = Propagate->GetPQR();
const FGColumnVector3& vUVW = Propagate->GetUVW(); const FGColumnVector3& vUVW = Propagate->GetUVW();
const FGColumnVector3& vUVWdot = Propagate->GetUVWdot(); const FGColumnVector3& vUVWdot = Propagate->GetUVWdot();
@ -290,6 +292,8 @@ bool FGAuxiliary::Run()
CalculateRelativePosition(); CalculateRelativePosition();
RunPostFunctions();
return false; return false;
} }

View file

@ -95,6 +95,8 @@ bool FGBuoyantForces::Run(void)
if (FDMExec->Holding()) return false; // if paused don't execute if (FDMExec->Holding()) return false; // if paused don't execute
if (NoneDefined) return true; if (NoneDefined) return true;
RunPreFunctions();
vTotalForces.InitMatrix(); vTotalForces.InitMatrix();
vTotalMoments.InitMatrix(); vTotalMoments.InitMatrix();
@ -104,6 +106,8 @@ bool FGBuoyantForces::Run(void)
vTotalMoments += Cells[i]->GetMoments(); vTotalMoments += Cells[i]->GetMoments();
} }
RunPostFunctions();
return false; return false;
} }
@ -135,6 +139,8 @@ bool FGBuoyantForces::Load(Element *element)
gas_cell_element = document->FindNextElement("gas_cell"); gas_cell_element = document->FindNextElement("gas_cell");
} }
FGModel::PostLoad(element);
return true; return true;
} }

View file

@ -85,6 +85,8 @@ bool FGExternalReactions::Load(Element* el)
force_element = el->FindNextElement("force"); force_element = el->FindNextElement("force");
} }
FGModel::PostLoad(el);
return true; return true;
} }
@ -115,6 +117,8 @@ bool FGExternalReactions::Run()
if (FDMExec->Holding()) return false; // if paused don't execute if (FDMExec->Holding()) return false; // if paused don't execute
if (NoneDefined) return true; if (NoneDefined) return true;
RunPreFunctions();
vTotalForces.InitMatrix(); vTotalForces.InitMatrix();
vTotalMoments.InitMatrix(); vTotalMoments.InitMatrix();
@ -123,6 +127,8 @@ bool FGExternalReactions::Run()
vTotalMoments += Forces[i]->GetMoments(); vTotalMoments += Forces[i]->GetMoments();
} }
RunPostFunctions();
return false; return false;
} }

View file

@ -198,6 +198,8 @@ bool FGFCS::Run(void)
if (FGModel::Run()) return true; // fast exit if nothing to do if (FGModel::Run()) return true; // fast exit if nothing to do
if (FDMExec->Holding()) return false; if (FDMExec->Holding()) return false;
RunPreFunctions();
for (i=0; i<ThrottlePos.size(); i++) ThrottlePos[i] = ThrottleCmd[i]; 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<MixturePos.size(); i++) MixturePos[i] = MixtureCmd[i];
for (i=0; i<PropAdvance.size(); i++) PropAdvance[i] = PropAdvanceCmd[i]; for (i=0; i<PropAdvance.size(); i++) PropAdvance[i] = PropAdvanceCmd[i];
@ -218,6 +220,8 @@ bool FGFCS::Run(void)
// Execute Flight Control System // Execute Flight Control System
for (i=0; i<FCSComponents.size(); i++) FCSComponents[i]->Run(); for (i=0; i<FCSComponents.size(); i++) FCSComponents[i]->Run();
RunPostFunctions();
return false; return false;
} }

View file

@ -89,6 +89,8 @@ bool FGGroundReactions::Run(void)
if (FGModel::Run()) return true; if (FGModel::Run()) return true;
if (FDMExec->Holding()) return false; if (FDMExec->Holding()) return false;
RunPreFunctions();
vForces.InitMatrix(); vForces.InitMatrix();
vMoments.InitMatrix(); vMoments.InitMatrix();
@ -102,6 +104,8 @@ bool FGGroundReactions::Run(void)
vMoments += lGear[i]->GetMoments(); vMoments += lGear[i]->GetMoments();
} }
RunPostFunctions();
return false; return false;
} }
@ -138,6 +142,8 @@ bool FGGroundReactions::Load(Element* el)
for (unsigned int i=0; i<lGear.size();i++) lGear[i]->bind(); for (unsigned int i=0; i<lGear.size();i++) lGear[i]->bind();
FGModel::PostLoad(el);
return true; return true;
} }
@ -185,7 +191,7 @@ string FGGroundReactions::GetGroundReactionValues(string delimeter)
for (unsigned int i=0;i<lGear.size();i++) { for (unsigned int i=0;i<lGear.size();i++) {
if (lGear[i]->IsBogey()) { if (lGear[i]->IsBogey()) {
FGLGear *gear = lGear[i]; FGLGear *gear = lGear[i];
buf << (gear->GetWOW() ? "1, " : "0, ") buf << (gear->GetWOW() ? "1" : "0") << delimeter
<< setprecision(5) << gear->GetCompLen() << delimeter << setprecision(5) << gear->GetCompLen() << delimeter
<< setprecision(6) << gear->GetCompVel() << delimeter << setprecision(6) << gear->GetCompVel() << delimeter
<< setprecision(10) << gear->GetCompForce() << delimeter << setprecision(10) << gear->GetCompForce() << delimeter

View file

@ -114,11 +114,15 @@ bool FGInertial::Run(void)
if (FGModel::Run()) return true; if (FGModel::Run()) return true;
if (FDMExec->Holding()) return false; if (FDMExec->Holding()) return false;
RunPreFunctions();
// Gravitation accel // Gravitation accel
double r = Propagate->GetRadius(); double r = Propagate->GetRadius();
gAccel = GetGAccel(r); gAccel = GetGAccel(r);
earthPosAngle += State->Getdt()*RotationRate; earthPosAngle += State->Getdt()*RotationRate;
RunPostFunctions();
return false; return false;
} }

View file

@ -105,6 +105,8 @@ bool FGInput::Run(void)
// return false if no error // return false if no error
// This model DOES execute if "Exec->Holding" // This model DOES execute if "Exec->Holding"
RunPreFunctions();
data = socket->Receive(); // get socket transmission if present data = socket->Receive(); // get socket transmission if present
if (data.size() > 0) { if (data.size() > 0) {
@ -213,6 +215,8 @@ bool FGInput::Run(void)
} }
} }
RunPostFunctions();
return false; return false;
} }

View file

@ -152,6 +152,8 @@ bool FGMassBalance::Load(Element* el)
Mass = lbtoslug*Weight; Mass = lbtoslug*Weight;
FGModel::PostLoad(el);
Debug(2); Debug(2);
return true; return true;
} }
@ -166,6 +168,8 @@ bool FGMassBalance::Run(void)
if (FGModel::Run()) return true; if (FGModel::Run()) return true;
if (FDMExec->Holding()) return false; if (FDMExec->Holding()) return false;
RunPreFunctions();
double ChildFDMWeight = 0.0; double ChildFDMWeight = 0.0;
for (int fdm=0; fdm<FDMExec->GetFDMCount(); fdm++) { for (int fdm=0; fdm<FDMExec->GetFDMCount(); fdm++) {
if (FDMExec->GetChildFDM(fdm)->mated) ChildFDMWeight += FDMExec->GetChildFDM(fdm)->exec->GetMassBalance()->GetWeight(); if (FDMExec->GetChildFDM(fdm)->mated) ChildFDMWeight += FDMExec->GetChildFDM(fdm)->exec->GetMassBalance()->GetWeight();
@ -226,6 +230,8 @@ bool FGMassBalance::Run(void)
k2, k4, k5, k2, k4, k5,
k3, k5, k6 ); k3, k5, k6 );
RunPostFunctions();
Debug(0); Debug(0);
return false; return false;

View file

@ -105,6 +105,9 @@ FGModel::~FGModel()
for (unsigned int i=0; i<interface_properties.size(); i++) delete interface_properties[i]; for (unsigned int i=0; i<interface_properties.size(); i++) delete interface_properties[i];
interface_properties.clear(); 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; if (debug_lvl & 2) cout << "Destroyed: FGModel" << endl;
} }
@ -146,15 +149,16 @@ bool FGModel::InitModel(void)
bool FGModel::Load(Element* el) bool FGModel::Load(Element* el)
{ {
// Interface properties are all stored in the interface properties array. // Interface properties are all stored in the interface properties array.
string interface_property_string = ""; string interface_property_string = "";
Element *property_element = el->FindElement("property"); 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) { while (property_element) {
interface_property_string = property_element->GetDataLine(); interface_property_string = property_element->GetDataLine();
if (PropertyManager->HasNode(interface_property_string)) { 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 { } else {
double value=0.0; double value=0.0;
if ( ! property_element->GetAttributeValue("value").empty()) if ( ! property_element->GetAttributeValue("value").empty())
@ -162,23 +166,82 @@ bool FGModel::Load(Element* el)
interface_properties.push_back(new double(value)); interface_properties.push_back(new double(value));
PropertyManager->Tie(interface_property_string, interface_properties.back()); PropertyManager->Tie(interface_property_string, interface_properties.back());
if (debug_lvl > 0) 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"); 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; 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() bool FGModel::Run()
{ {
if (debug_lvl & 4) cout << "Entering Run() for model " << Name << endl; 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; else return true;
} }

View file

@ -39,6 +39,7 @@ INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGJSBBase.h" #include "FGJSBBase.h"
#include "math/FGFunction.h"
#include <string> #include <string>
#include <vector> #include <vector>
@ -93,11 +94,6 @@ public:
/// Destructor /// Destructor
~FGModel(); ~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; FGModel* NextModel;
std::string Name; std::string Name;
@ -116,6 +112,16 @@ protected:
int exe_ctr; int exe_ctr;
int rate; 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); virtual void Debug(int from);
FGFDMExec* FDMExec; FGFDMExec* FDMExec;
@ -133,6 +139,8 @@ protected:
FGPropagate* Propagate; FGPropagate* Propagate;
FGAuxiliary* Auxiliary; FGAuxiliary* Auxiliary;
FGPropertyManager* PropertyManager; FGPropertyManager* PropertyManager;
std::vector <FGFunction*> PreFunctions;
std::vector <FGFunction*> PostFunctions;
std::vector <double*> interface_properties; std::vector <double*> interface_properties;
}; };

View file

@ -188,6 +188,7 @@ bool FGOutput::Run(void)
if (FGModel::Run()) return true; if (FGModel::Run()) return true;
if (enabled && !State->IntegrationSuspended()&& !FDMExec->Holding()) { if (enabled && !State->IntegrationSuspended()&& !FDMExec->Holding()) {
RunPreFunctions();
if (Type == otSocket) { if (Type == otSocket) {
SocketOutput(); SocketOutput();
} else if (Type == otFlightGear) { } else if (Type == otFlightGear) {
@ -201,6 +202,7 @@ bool FGOutput::Run(void)
} else { } else {
// Not a valid type of output // Not a valid type of output
} }
RunPostFunctions();
} }
return false; return false;
} }
@ -396,22 +398,22 @@ void FGOutput::DelimitedOutput(const string& fname)
} }
if (SubSystems & ssForces) { if (SubSystems & ssForces) {
outstream << delimeter; outstream << delimeter;
outstream << Aerodynamics->GetvFw() << delimeter; outstream << Aerodynamics->GetvFw().Dump(delimeter) << delimeter;
outstream << Aerodynamics->GetLoD() << delimeter; outstream << Aerodynamics->GetLoD() << delimeter;
outstream << Aerodynamics->GetForces() << delimeter; outstream << Aerodynamics->GetForces().Dump(delimeter) << delimeter;
outstream << Propulsion->GetForces() << delimeter; outstream << Propulsion->GetForces().Dump(delimeter) << delimeter;
outstream << GroundReactions->GetForces() << delimeter; outstream << GroundReactions->GetForces().Dump(delimeter) << delimeter;
outstream << ExternalReactions->GetForces() << delimeter; outstream << ExternalReactions->GetForces().Dump(delimeter) << delimeter;
outstream << BuoyantForces->GetForces() << delimeter; outstream << BuoyantForces->GetForces().Dump(delimeter) << delimeter;
outstream << Aircraft->GetForces().Dump(delimeter); outstream << Aircraft->GetForces().Dump(delimeter);
} }
if (SubSystems & ssMoments) { if (SubSystems & ssMoments) {
outstream << delimeter; outstream << delimeter;
outstream << Aerodynamics->GetMoments() << delimeter; outstream << Aerodynamics->GetMoments().Dump(delimeter) << delimeter;
outstream << Propulsion->GetMoments() << delimeter; outstream << Propulsion->GetMoments().Dump(delimeter) << delimeter;
outstream << GroundReactions->GetMoments() << delimeter; outstream << GroundReactions->GetMoments().Dump(delimeter) << delimeter;
outstream << ExternalReactions->GetMoments() << delimeter; outstream << ExternalReactions->GetMoments().Dump(delimeter) << delimeter;
outstream << BuoyantForces->GetMoments() << delimeter; outstream << BuoyantForces->GetMoments().Dump(delimeter) << delimeter;
outstream << Aircraft->GetMoments().Dump(delimeter); outstream << Aircraft->GetMoments().Dump(delimeter);
} }
if (SubSystems & ssAtmosphere) { if (SubSystems & ssAtmosphere) {
@ -428,9 +430,9 @@ void FGOutput::DelimitedOutput(const string& fname)
} }
if (SubSystems & ssMassProps) { if (SubSystems & ssMassProps) {
outstream << delimeter; outstream << delimeter;
outstream << MassBalance->GetJ() << delimeter; outstream << MassBalance->GetJ().Dump(delimeter) << delimeter;
outstream << MassBalance->GetMass() << delimeter; outstream << MassBalance->GetMass() << delimeter;
outstream << MassBalance->GetXYZcg(); outstream << MassBalance->GetXYZcg().Dump(delimeter);
} }
if (SubSystems & ssPropagate) { if (SubSystems & ssPropagate) {
outstream.precision(14); outstream.precision(14);

View file

@ -233,6 +233,8 @@ bool FGPropagate::Run(void)
if (FGModel::Run()) return true; // Fast return if we have nothing to do ... if (FGModel::Run()) return true; // Fast return if we have nothing to do ...
if (FDMExec->Holding()) return false; if (FDMExec->Holding()) return false;
RunPreFunctions();
RecomputeLocalTerrainRadius(); RecomputeLocalTerrainRadius();
// Calculate current aircraft radius from center of planet // Calculate current aircraft radius from center of planet
@ -344,6 +346,8 @@ bool FGPropagate::Run(void)
last2_vLocationDot = last_vLocationDot; last2_vLocationDot = last_vLocationDot;
last_vLocationDot = vLocationDot; last_vLocationDot = vLocationDot;
RunPreFunctions();
Debug(2); Debug(2);
return false; return false;
} }

View file

@ -147,6 +147,8 @@ bool FGPropulsion::Run(void)
if (FGModel::Run()) return true; if (FGModel::Run()) return true;
if (FDMExec->Holding()) return false; if (FDMExec->Holding()) return false;
RunPreFunctions();
double dt = State->Getdt(); double dt = State->Getdt();
vForces.InitMatrix(); vForces.InitMatrix();
@ -169,6 +171,8 @@ bool FGPropulsion::Run(void)
if (refuel) DoRefuel( dt * rate ); if (refuel) DoRefuel( dt * rate );
if (dump) DumpFuel( dt * rate ); if (dump) DumpFuel( dt * rate );
RunPostFunctions();
return false; return false;
} }
@ -333,6 +337,7 @@ bool FGPropulsion::Load(Element* el)
if (el->FindElement("dump-rate")) if (el->FindElement("dump-rate"))
DumpRate = el->FindElementValueAsNumberConvertTo("dump-rate", "LBS/MIN"); DumpRate = el->FindElementValueAsNumberConvertTo("dump-rate", "LBS/MIN");
FGModel::PostLoad(el);
return true; return true;
} }

View file

@ -148,6 +148,8 @@ bool MSIS::Run(void)
if (FGModel::Run()) return true; if (FGModel::Run()) return true;
if (FDMExec->Holding()) return false; if (FDMExec->Holding()) return false;
RunPreFunctions();
//do temp, pressure, and density first //do temp, pressure, and density first
if (!useExternal) { if (!useExternal) {
// get sea-level values // get sea-level values
@ -180,6 +182,8 @@ bool MSIS::Run(void)
CalculateDerived(); CalculateDerived();
RunPostFunctions();
Debug(2); Debug(2);
return false; return false;

View file

@ -74,6 +74,7 @@ FGEngine::FGEngine(FGFDMExec* exec, Element* engine_element, int engine_number)
SLFuelFlowMax = 0.0; SLFuelFlowMax = 0.0;
MaxThrottle = 1.0; MaxThrottle = 1.0;
MinThrottle = 0.0; MinThrottle = 0.0;
FuelDensity = 6.0;
unsigned int i; unsigned int i;
ResetToIC(); // initialize dynamic terms ResetToIC(); // initialize dynamic terms
@ -122,7 +123,9 @@ FGEngine::FGEngine(FGFDMExec* exec, Element* engine_element, int engine_number)
if (local_element) { if (local_element) {
while (local_element) { while (local_element) {
int tankID = (int)local_element->GetDataAsNumber(); 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"); local_element = engine_element->GetParent()->FindNextElement("feed");
} }
} else { } else {
@ -139,6 +142,8 @@ FGEngine::FGEngine(FGFDMExec* exec, Element* engine_element, int engine_number)
property_name = base_property_name + "/fuel-flow-rate-pps"; property_name = base_property_name + "/fuel-flow-rate-pps";
PropertyManager->Tie( property_name.c_str(), this, &FGEngine::GetFuelFlowRate); PropertyManager->Tie( property_name.c_str(), this, &FGEngine::GetFuelFlowRate);
//cout << "Engine[" << EngineNumber << "] using fuel density: " << FuelDensity << endl;
Debug(0); Debug(0);
} }

View file

@ -113,8 +113,7 @@ CLASS DOCUMENTATION
@endcode @endcode
<pre> <pre>
NOTES: NOTES:
Engines feed from all tanks equally.
Not all thruster types can be matched with a given engine type. See the class Not all thruster types can be matched with a given engine type. See the class
documentation for engine and thruster classes. documentation for engine and thruster classes.
</pre> </pre>
@ -226,6 +225,7 @@ protected:
double FuelFlow_gph; double FuelFlow_gph;
double FuelFlow_pph; double FuelFlow_pph;
double FuelDensity;
FGFDMExec* FDMExec; FGFDMExec* FDMExec;
FGState* State; FGState* State;

View file

@ -71,6 +71,8 @@ FGRocket::FGRocket(FGFDMExec* exec, Element *el, int engine_number)
SLOxiFlowMax = 0.0; SLOxiFlowMax = 0.0;
BuildupTime = 0.0; BuildupTime = 0.0;
It = 0.0; It = 0.0;
ThrustVariation = 0.0;
TotalIspVariation = 0.0;
// Defaults // Defaults
MinThrottle = 0.0; MinThrottle = 0.0;
@ -89,9 +91,19 @@ FGRocket::FGRocket(FGFDMExec* exec, Element *el, int engine_number)
if (el->FindElement("sloxiflowmax")) if (el->FindElement("sloxiflowmax"))
SLOxiFlowMax = el->FindElementValueAsNumberConvertTo("sloxiflowmax", "LBS/SEC"); 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"); thrust_table_element = el->FindElement("thrust_table");
if (thrust_table_element) { if (thrust_table_element) {
ThrustTable = new FGTable(PropertyManager, 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(); 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) { if (BurnTime <= BuildupTime && BuildupTime > 0.0) {
VacThrust *= sin((BurnTime/BuildupTime)*M_PI/2.0); VacThrust *= sin((BurnTime/BuildupTime)*M_PI/2.0);
// VacThrust *= (1-cos((BurnTime/BuildupTime)*M_PI))/2.0; // 1 - cos approach // 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) double FGRocket::CalcFuelNeed(void)
{ {
@ -248,6 +267,7 @@ double FGRocket::CalcFuelNeed(void)
if (ThrustTable != 0L) { // Thrust table given - infers solid fuel if (ThrustTable != 0L) { // Thrust table given - infers solid fuel
FuelFlowRate = VacThrust/Isp; // This calculates wdot (weight flow rate in lbs/sec) FuelFlowRate = VacThrust/Isp; // This calculates wdot (weight flow rate in lbs/sec)
FuelFlowRate /= (1 + TotalIspVariation);
} else { } else {
FuelFlowRate = SLFuelFlowMax*PctPower; 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. // that are not bound in the base class (FGEngine) code.
// //
void FGRocket::bindmodel() void FGRocket::bindmodel()
@ -300,10 +320,20 @@ void FGRocket::bindmodel()
property_name = base_property_name + "/total-impulse"; property_name = base_property_name + "/total-impulse";
PropertyManager->Tie( property_name.c_str(), this, &FGRocket::GetTotalImpulse); 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"; property_name = base_property_name + "/vacuum-thrust_lbs";
PropertyManager->Tie( property_name.c_str(), this, &FGRocket::GetVacThrust); 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);
}
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

View file

@ -162,6 +162,32 @@ public:
std::string GetEngineLabels(const std::string& delimiter); std::string GetEngineLabels(const std::string& delimiter);
std::string GetEngineValues(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: private:
/** Reduces the fuel in the active tanks by the amount required. /** Reduces the fuel in the active tanks by the amount required.
This function should be called from within the This function should be called from within the
@ -192,6 +218,8 @@ private:
double It; double It;
double MxR; // Mixture Ratio double MxR; // Mixture Ratio
double BurnTime; double BurnTime;
double ThrustVariation;
double TotalIspVariation;
double VacThrust; double VacThrust;
double previousFuelNeedPerTank; double previousFuelNeedPerTank;
double previousOxiNeedPerTank; double previousOxiNeedPerTank;

View file

@ -58,7 +58,7 @@ CLASS IMPLEMENTATION
FGTank::FGTank(FGFDMExec* exec, Element* el, int tank_number) FGTank::FGTank(FGFDMExec* exec, Element* el, int tank_number)
: TankNumber(tank_number), Exec(exec) : TankNumber(tank_number), Exec(exec)
{ {
string token; string token, strFuelName;
Element* element; Element* element;
Element* element_Grain; Element* element_Grain;
Area = 1.0; Area = 1.0;
@ -102,6 +102,9 @@ FGTank::FGTank(FGFDMExec* exec, Element* el, int tank_number)
InitialPriority = Priority = el->FindElementValueAsNumber("priority"); InitialPriority = Priority = el->FindElementValueAsNumber("priority");
if (el->FindElement("density")) if (el->FindElement("density"))
Density = el->FindElementValueAsNumberConvertTo("density", "LBS/GAL"); Density = el->FindElementValueAsNumberConvertTo("density", "LBS/GAL");
if (el->FindElement("type"))
strFuelName = el->FindElementValue("type");
SetPriority( InitialPriority ); // this will also set the Selected flag 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); if (Temperature != -9999.0) InitialTemperature = Temperature = FahrenheitToCelsius(Temperature);
Area = 40.0 * pow(Capacity/1975, 0.666666667); 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); 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: // The bitmasked value choices are as follows:
// unset: In this case (the default) JSBSim would only print // unset: In this case (the default) JSBSim would only print

View file

@ -126,6 +126,7 @@ CLASS DOCUMENTATION
<standpipe unit="{LBS | KG"}> {number} </standpipe> <standpipe unit="{LBS | KG"}> {number} </standpipe>
<priority> {integer} </priority> <priority> {integer} </priority>
<density unit="{KG/L | LBS/GAL}"> {number} </density> <density unit="{KG/L | LBS/GAL}"> {number} </density>
<type> {string} </type> <!-- will override previous density setting -->
</tank> </tank>
@endcode @endcode
@ -141,6 +142,9 @@ CLASS DOCUMENTATION
- \b standpipe - Minimum contents to which tank can dump, defaults to pounds. - \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 priority - Establishes feed sequence of tank. "1" is the highest priority.
- \b density - Density of liquid tank contents. - \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: location:
- \b x - Location of tank on aircraft's x-axis, defaults to inches. - \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. */ is given, otherwise 32 degrees F is returned. */
double GetTemperature(void) {return CelsiusToFahrenheit(Temperature);} 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 GetIxx(void) {return Ixx;}
double GetIyy(void) {return Iyy;} double GetIyy(void) {return Iyy;}
double GetIzz(void) {return Izz;} double GetIzz(void) {return Izz;}
@ -261,6 +269,9 @@ public:
int GetPriority(void) const {return Priority;} int GetPriority(void) const {return Priority;}
void SetPriority(int p) { Priority = p; Selected = p>0 ? true:false; } 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 FGColumnVector3 GetXYZ(void);
const double GetXYZ(int idx); const double GetXYZ(int idx);