New version of JSBSim, a big rewrite.
This commit is contained in:
parent
549c5eccb9
commit
7375166c2b
89 changed files with 4428 additions and 3364 deletions
|
@ -1,5 +1,86 @@
|
|||
include(FlightGearComponent)
|
||||
|
||||
set(HEADERS
|
||||
FGFDMExec.h
|
||||
FGJSBBase.h
|
||||
JSBSim.hxx
|
||||
initialization/FGInitialCondition.h
|
||||
initialization/FGTrim.h
|
||||
initialization/FGTrimAxis.h
|
||||
input_output/FGXMLParse.h
|
||||
input_output/FGXMLFileRead.h
|
||||
input_output/FGPropertyManager.h
|
||||
input_output/FGScript.h
|
||||
input_output/FGfdmSocket.h
|
||||
input_output/string_utilities.h
|
||||
input_output/FGXMLElement.h
|
||||
input_output/net_fdm.hxx
|
||||
input_output/FGGroundCallback.h
|
||||
math/FGParameter.h
|
||||
math/LagrangeMultiplier.h
|
||||
math/FGColumnVector3.h
|
||||
math/FGCondition.h
|
||||
math/FGFunction.h
|
||||
math/FGLocation.h
|
||||
math/FGMatrix33.h
|
||||
math/FGModelFunctions.h
|
||||
math/FGPropertyValue.h
|
||||
math/FGQuaternion.h
|
||||
math/FGRealValue.h
|
||||
math/FGRungeKutta.h
|
||||
math/FGTable.h
|
||||
models/FGAccelerations.h
|
||||
models/FGAerodynamics.h
|
||||
models/FGAircraft.h
|
||||
models/FGAtmosphere.h
|
||||
models/FGAuxiliary.h
|
||||
models/FGBuoyantForces.h
|
||||
models/FGExternalForce.h
|
||||
models/FGExternalReactions.h
|
||||
models/FGFCS.h
|
||||
models/FGGasCell.h
|
||||
models/FGGroundReactions.h
|
||||
models/FGInertial.h
|
||||
models/FGInput.h
|
||||
models/FGLGear.h
|
||||
models/FGMassBalance.h
|
||||
models/FGModel.h
|
||||
models/FGOutput.h
|
||||
models/FGPropagate.h
|
||||
models/FGPropulsion.h
|
||||
models/atmosphere/FGMSIS.h
|
||||
models/atmosphere/FGStandardAtmosphere.h
|
||||
models/atmosphere/FGMars.h
|
||||
models/atmosphere/FGWinds.h
|
||||
models/flight_control/FGAccelerometer.h
|
||||
models/flight_control/FGActuator.h
|
||||
models/flight_control/FGDeadBand.h
|
||||
models/flight_control/FGFCSComponent.h
|
||||
models/flight_control/FGFCSFunction.h
|
||||
models/flight_control/FGFilter.h
|
||||
models/flight_control/FGGain.h
|
||||
models/flight_control/FGGyro.h
|
||||
models/flight_control/FGKinemat.h
|
||||
models/flight_control/FGMagnetometer.h
|
||||
models/flight_control/FGPID.h
|
||||
models/flight_control/FGSensor.h
|
||||
models/flight_control/FGSensorOrientation.h
|
||||
models/flight_control/FGSummer.h
|
||||
models/flight_control/FGSwitch.h
|
||||
models/propulsion/FGElectric.h
|
||||
models/propulsion/FGEngine.h
|
||||
models/propulsion/FGForce.h
|
||||
models/propulsion/FGNozzle.h
|
||||
models/propulsion/FGPiston.h
|
||||
models/propulsion/FGPropeller.h
|
||||
models/propulsion/FGRocket.h
|
||||
models/propulsion/FGRotor.h
|
||||
models/propulsion/FGTank.h
|
||||
models/propulsion/FGThruster.h
|
||||
models/propulsion/FGTurbine.h
|
||||
models/propulsion/FGTurboProp.h
|
||||
)
|
||||
|
||||
set(SOURCES
|
||||
FGFDMExec.cpp
|
||||
FGJSBBase.cpp
|
||||
|
@ -24,6 +105,7 @@ set(SOURCES
|
|||
math/FGRealValue.cpp
|
||||
math/FGRungeKutta.cpp
|
||||
math/FGTable.cpp
|
||||
models/FGAccelerations.cpp
|
||||
models/FGAerodynamics.cpp
|
||||
models/FGAircraft.cpp
|
||||
models/FGAtmosphere.cpp
|
||||
|
@ -44,7 +126,9 @@ set(SOURCES
|
|||
models/FGPropulsion.cpp
|
||||
models/atmosphere/FGMSIS.cpp
|
||||
models/atmosphere/FGMSISData.cpp
|
||||
models/atmosphere/FGStandardAtmosphere.cpp
|
||||
models/atmosphere/FGMars.cpp
|
||||
models/atmosphere/FGWinds.cpp
|
||||
models/flight_control/FGAccelerometer.cpp
|
||||
models/flight_control/FGActuator.cpp
|
||||
models/flight_control/FGDeadBand.cpp
|
||||
|
@ -52,7 +136,6 @@ set(SOURCES
|
|||
models/flight_control/FGFCSFunction.cpp
|
||||
models/flight_control/FGFilter.cpp
|
||||
models/flight_control/FGGain.cpp
|
||||
models/flight_control/FGGradient.cpp
|
||||
models/flight_control/FGGyro.cpp
|
||||
models/flight_control/FGKinemat.cpp
|
||||
models/flight_control/FGMagnetometer.cpp
|
||||
|
@ -76,4 +159,4 @@ set(SOURCES
|
|||
|
||||
include_directories(${PROJECT_SOURCE_DIR}/src/FDM/JSBSim)
|
||||
|
||||
flightgear_component(JSBSim "${SOURCES}")
|
||||
flightgear_component(JSBSim "${SOURCES}" "${HEADERS}")
|
||||
|
|
|
@ -41,10 +41,13 @@ COMMENTS, REFERENCES, and NOTES
|
|||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "FGFDMExec.h"
|
||||
#include "models/FGAtmosphere.h"
|
||||
#include "models/atmosphere/FGMSIS.h"
|
||||
#include "models/atmosphere/FGMars.h"
|
||||
#include "models/atmosphere/FGStandardAtmosphere.h"
|
||||
#include "models/atmosphere/FGWinds.h"
|
||||
#include "models/FGFCS.h"
|
||||
#include "models/FGPropulsion.h"
|
||||
#include "models/FGMassBalance.h"
|
||||
|
@ -54,24 +57,20 @@ INCLUDES
|
|||
#include "models/FGAerodynamics.h"
|
||||
#include "models/FGInertial.h"
|
||||
#include "models/FGAircraft.h"
|
||||
#include "models/FGAccelerations.h"
|
||||
#include "models/FGPropagate.h"
|
||||
#include "models/FGAuxiliary.h"
|
||||
#include "models/FGInput.h"
|
||||
#include "models/FGOutput.h"
|
||||
#include "initialization/FGInitialCondition.h"
|
||||
//#include "initialization/FGTrimAnalysis.h" // Remove until later
|
||||
#include "input_output/FGPropertyManager.h"
|
||||
#include "input_output/FGScript.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <cstdlib>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGFDMExec.cpp,v 1.95 2011/05/20 10:35:25 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGFDMExec.cpp,v 1.113 2011/09/07 02:37:04 jberndt Exp $";
|
||||
static const char *IdHdr = ID_FDMEXEC;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -87,19 +86,6 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root, unsigned int* fdmctr) : Root(root)
|
|||
Frame = 0;
|
||||
Error = 0;
|
||||
GroundCallback = 0;
|
||||
Atmosphere = 0;
|
||||
FCS = 0;
|
||||
Propulsion = 0;
|
||||
MassBalance = 0;
|
||||
Aerodynamics = 0;
|
||||
Inertial = 0;
|
||||
GroundReactions = 0;
|
||||
ExternalReactions = 0;
|
||||
BuoyantForces = 0;
|
||||
Aircraft = 0;
|
||||
Propagate = 0;
|
||||
Auxiliary = 0;
|
||||
Input = 0;
|
||||
IC = 0;
|
||||
Trim = 0;
|
||||
Script = 0;
|
||||
|
@ -111,6 +97,7 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root, unsigned int* fdmctr) : Root(root)
|
|||
holding = false;
|
||||
Terminate = false;
|
||||
StandAlone = false;
|
||||
firstPass = true;
|
||||
|
||||
sim_time = 0.0;
|
||||
dT = 1.0/120.0; // a default timestep size. This is needed for when JSBSim is
|
||||
|
@ -197,7 +184,7 @@ FGFDMExec::~FGFDMExec()
|
|||
|
||||
PropertyCatalog.clear();
|
||||
|
||||
FDMctr--;
|
||||
if (FDMctr > 0) (*FDMctr)--;
|
||||
|
||||
Debug(1);
|
||||
}
|
||||
|
@ -208,44 +195,54 @@ bool FGFDMExec::Allocate(void)
|
|||
{
|
||||
bool result=true;
|
||||
|
||||
Atmosphere = new FGAtmosphere(this);
|
||||
FCS = new FGFCS(this);
|
||||
Propulsion = new FGPropulsion(this);
|
||||
MassBalance = new FGMassBalance(this);
|
||||
Aerodynamics = new FGAerodynamics (this);
|
||||
Inertial = new FGInertial(this);
|
||||
Models.resize(eNumStandardModels);
|
||||
|
||||
GroundCallback = new FGGroundCallback(Inertial->GetRefRadius());
|
||||
// See the eModels enum specification in the header file. The order of the enums
|
||||
// specifies the order of execution. The Models[] vector is the primary
|
||||
// storage array for the list of models.
|
||||
Models[ePropagate] = new FGPropagate(this);
|
||||
Models[eInput] = new FGInput(this);
|
||||
Models[eInertial] = new FGInertial(this);
|
||||
Models[eAtmosphere] = new FGStandardAtmosphere(this);
|
||||
Models[eWinds] = new FGWinds(this);
|
||||
Models[eAuxiliary] = new FGAuxiliary(this);
|
||||
Models[eSystems] = new FGFCS(this);
|
||||
Models[ePropulsion] = new FGPropulsion(this);
|
||||
Models[eAerodynamics] = new FGAerodynamics (this);
|
||||
|
||||
GroundReactions = new FGGroundReactions(this);
|
||||
ExternalReactions = new FGExternalReactions(this);
|
||||
BuoyantForces = new FGBuoyantForces(this);
|
||||
Aircraft = new FGAircraft(this);
|
||||
Propagate = new FGPropagate(this);
|
||||
Auxiliary = new FGAuxiliary(this);
|
||||
Input = new FGInput(this);
|
||||
GroundCallback = new FGGroundCallback(((FGInertial*)Models[eInertial])->GetRefRadius());
|
||||
|
||||
// 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.
|
||||
|
||||
Schedule(Input, 1); // Input model is Models[0]
|
||||
Schedule(Atmosphere, 1); // Input model is Models[1]
|
||||
Schedule(FCS, 1); // Input model is Models[2]
|
||||
Schedule(Propulsion, 1); // Input model is Models[3]
|
||||
Schedule(MassBalance, 1); // Input model is Models[4]
|
||||
Schedule(Aerodynamics, 1); // Input model is Models[5]
|
||||
Schedule(Inertial, 1); // Input model is Models[6]
|
||||
Schedule(GroundReactions, 1); // Input model is Models[7]
|
||||
Schedule(ExternalReactions, 1); // Input model is Models[8]
|
||||
Schedule(BuoyantForces, 1); // Input model is Models[9]
|
||||
Schedule(Aircraft, 1); // Input model is Models[10]
|
||||
Schedule(Propagate, 1); // Input model is Models[11]
|
||||
Schedule(Auxiliary, 1); // Input model is Models[12]
|
||||
Models[eGroundReactions] = new FGGroundReactions(this);
|
||||
Models[eExternalReactions] = new FGExternalReactions(this);
|
||||
Models[eBuoyantForces] = new FGBuoyantForces(this);
|
||||
Models[eMassBalance] = new FGMassBalance(this);
|
||||
Models[eAircraft] = new FGAircraft(this);
|
||||
Models[eAccelerations] = new FGAccelerations(this);
|
||||
|
||||
// Initialize models so they can communicate with each other
|
||||
// Assign the Model shortcuts for internal executive use only.
|
||||
Propagate = (FGPropagate*)Models[ePropagate];
|
||||
Inertial = (FGInertial*)Models[eInertial];
|
||||
Atmosphere = (FGAtmosphere*)Models[eAtmosphere];
|
||||
Winds = (FGWinds*)Models[eWinds];
|
||||
Auxiliary = (FGAuxiliary*)Models[eAuxiliary];
|
||||
FCS = (FGFCS*)Models[eSystems];
|
||||
Propulsion = (FGPropulsion*)Models[ePropulsion];
|
||||
Aerodynamics = (FGAerodynamics*)Models[eAerodynamics];
|
||||
GroundReactions = (FGGroundReactions*)Models[eGroundReactions];
|
||||
ExternalReactions = (FGExternalReactions*)Models[eExternalReactions];
|
||||
BuoyantForces = (FGBuoyantForces*)Models[eBuoyantForces];
|
||||
MassBalance = (FGMassBalance*)Models[eMassBalance];
|
||||
Aircraft = (FGAircraft*)Models[eAircraft];
|
||||
Accelerations = (FGAccelerations*)Models[eAccelerations];
|
||||
|
||||
vector <FGModel*>::iterator it;
|
||||
for (it = Models.begin(); it != Models.end(); ++it) (*it)->InitModel();
|
||||
// Initialize planet (environment) constants
|
||||
LoadPlanetConstants();
|
||||
|
||||
// Initialize models
|
||||
for (unsigned int i = 0; i < Models.size(); i++) {
|
||||
LoadInputs(i);
|
||||
Models[i]->InitModel();
|
||||
}
|
||||
|
||||
IC = new FGInitialCondition(this);
|
||||
|
||||
|
@ -258,24 +255,14 @@ bool FGFDMExec::Allocate(void)
|
|||
|
||||
bool FGFDMExec::DeAllocate(void)
|
||||
{
|
||||
delete Input;
|
||||
delete Atmosphere;
|
||||
delete FCS;
|
||||
delete Propulsion;
|
||||
delete MassBalance;
|
||||
delete Aerodynamics;
|
||||
delete Inertial;
|
||||
delete GroundReactions;
|
||||
delete ExternalReactions;
|
||||
delete BuoyantForces;
|
||||
delete Aircraft;
|
||||
delete Propagate;
|
||||
delete Auxiliary;
|
||||
delete Script;
|
||||
|
||||
for (unsigned int i=0; i<eNumStandardModels; i++) delete Models[i];
|
||||
Models.clear();
|
||||
|
||||
for (unsigned i=0; i<Outputs.size(); i++) delete Outputs[i];
|
||||
Outputs.clear();
|
||||
|
||||
delete Script;
|
||||
delete IC;
|
||||
delete Trim;
|
||||
|
||||
|
@ -283,23 +270,6 @@ bool FGFDMExec::DeAllocate(void)
|
|||
|
||||
Error = 0;
|
||||
|
||||
Input = 0;
|
||||
Atmosphere = 0;
|
||||
FCS = 0;
|
||||
Propulsion = 0;
|
||||
MassBalance = 0;
|
||||
Aerodynamics = 0;
|
||||
Inertial = 0;
|
||||
GroundReactions = 0;
|
||||
ExternalReactions = 0;
|
||||
BuoyantForces = 0;
|
||||
Aircraft = 0;
|
||||
Propagate = 0;
|
||||
Auxiliary = 0;
|
||||
Script = 0;
|
||||
|
||||
Models.clear();
|
||||
|
||||
modelLoaded = false;
|
||||
return modelLoaded;
|
||||
}
|
||||
|
@ -321,22 +291,252 @@ bool FGFDMExec::Run(void)
|
|||
Debug(2);
|
||||
|
||||
for (unsigned int i=1; i<ChildFDMList.size(); i++) {
|
||||
ChildFDMList[i]->AssignState(Propagate); // Transfer state to the child FDM
|
||||
ChildFDMList[i]->AssignState( (FGPropagate*)Models[ePropagate] ); // Transfer state to the child FDM
|
||||
ChildFDMList[i]->Run();
|
||||
}
|
||||
|
||||
if (firstPass && !IntegrationSuspended()) {
|
||||
// Outputs the initial conditions
|
||||
for (unsigned int i = 0; i < Outputs.size(); i++)
|
||||
Outputs[i]->Run(holding);
|
||||
|
||||
firstPass = false;
|
||||
}
|
||||
|
||||
// returns true if success, false if complete
|
||||
if (Script != 0 && !IntegrationSuspended()) success = Script->RunScript();
|
||||
|
||||
vector <FGModel*>::iterator it;
|
||||
for (it = Models.begin(); it != Models.end(); ++it) (*it)->Run(holding);
|
||||
|
||||
IncrTime();
|
||||
|
||||
for (unsigned int i = 0; i < Models.size(); i++) {
|
||||
LoadInputs(i);
|
||||
Models[i]->Run(holding);
|
||||
}
|
||||
|
||||
if (Terminate) success = false;
|
||||
|
||||
return (success);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGFDMExec::LoadInputs(unsigned int idx)
|
||||
{
|
||||
switch(idx) {
|
||||
case ePropagate:
|
||||
Propagate->in.vPQRidot = Accelerations->GetPQRidot();
|
||||
Propagate->in.vQtrndot = Accelerations->GetQuaterniondot();
|
||||
Propagate->in.vUVWidot = Accelerations->GetUVWidot();
|
||||
Propagate->in.DeltaT = dT;
|
||||
break;
|
||||
case eInput:
|
||||
break;
|
||||
case eInertial:
|
||||
Inertial->in.Radius = Propagate->GetRadius();
|
||||
Inertial->in.Latitude = Propagate->GetLatitude();
|
||||
break;
|
||||
case eAtmosphere:
|
||||
Atmosphere->in.altitudeASL = Propagate->GetAltitudeASL();
|
||||
break;
|
||||
case eWinds:
|
||||
Winds->in.AltitudeASL = Propagate->GetAltitudeASL();
|
||||
Winds->in.DistanceAGL = Propagate->GetDistanceAGL();
|
||||
Winds->in.Tl2b = Propagate->GetTl2b();
|
||||
Winds->in.Tw2b = Auxiliary->GetTw2b();
|
||||
Winds->in.V = Auxiliary->GetVt();
|
||||
Winds->in.totalDeltaT = dT * Winds->GetRate();
|
||||
break;
|
||||
case eAuxiliary:
|
||||
Auxiliary->in.Pressure = Atmosphere->GetPressure();
|
||||
Auxiliary->in.Density = Atmosphere->GetDensity();
|
||||
Auxiliary->in.DensitySL = Atmosphere->GetDensitySL();
|
||||
Auxiliary->in.PressureSL = Atmosphere->GetPressureSL();
|
||||
Auxiliary->in.Temperature = Atmosphere->GetTemperature();
|
||||
Auxiliary->in.SoundSpeed = Atmosphere->GetSoundSpeed();
|
||||
Auxiliary->in.KinematicViscosity = Atmosphere->GetKinematicViscosity();
|
||||
Auxiliary->in.DistanceAGL = Propagate->GetDistanceAGL();
|
||||
Auxiliary->in.Mass = MassBalance->GetMass();
|
||||
Auxiliary->in.Tl2b = Propagate->GetTl2b();
|
||||
Auxiliary->in.Tb2l = Propagate->GetTb2l();
|
||||
Auxiliary->in.vPQR = Propagate->GetPQR();
|
||||
Auxiliary->in.vPQRdot = Accelerations->GetPQRdot();
|
||||
Auxiliary->in.vUVW = Propagate->GetUVW();
|
||||
Auxiliary->in.vUVWdot = Accelerations->GetUVWdot();
|
||||
Auxiliary->in.vVel = Propagate->GetVel();
|
||||
Auxiliary->in.vBodyAccel = Accelerations->GetBodyAccel();
|
||||
Auxiliary->in.ToEyePt = MassBalance->StructuralToBody(Aircraft->GetXYZep());
|
||||
Auxiliary->in.VRPBody = MassBalance->StructuralToBody(Aircraft->GetXYZvrp());
|
||||
Auxiliary->in.RPBody = MassBalance->StructuralToBody(Aircraft->GetXYZrp());
|
||||
Auxiliary->in.vFw = Aerodynamics->GetvFw();
|
||||
Auxiliary->in.vLocation = Propagate->GetLocation();
|
||||
Auxiliary->in.Latitude = Propagate->GetLatitude();
|
||||
Auxiliary->in.Longitude = Propagate->GetLongitude();
|
||||
Auxiliary->in.CosTht = Propagate->GetCosEuler(eTht);
|
||||
Auxiliary->in.SinTht = Propagate->GetSinEuler(eTht);
|
||||
Auxiliary->in.CosPhi = Propagate->GetCosEuler(ePhi);
|
||||
Auxiliary->in.SinPhi = Propagate->GetSinEuler(ePhi);
|
||||
Auxiliary->in.Psi = Propagate->GetEuler(ePsi);
|
||||
Auxiliary->in.TotalWindNED = Winds->GetTotalWindNED();
|
||||
Auxiliary->in.TurbPQR = Winds->GetTurbPQR();
|
||||
Auxiliary->in.WindPsi = Winds->GetWindPsi();
|
||||
Auxiliary->in.Vwind = Winds->GetTotalWindNED().Magnitude();
|
||||
break;
|
||||
case eSystems:
|
||||
// Dynamic inputs come into the components that FCS manages through properties
|
||||
break;
|
||||
case ePropulsion:
|
||||
Propulsion->in.SLPressure = Atmosphere->GetPressureSL();
|
||||
Propulsion->in.Pressure = Atmosphere->GetPressure();
|
||||
Propulsion->in.PressureRatio = Atmosphere->GetPressureRatio();
|
||||
Propulsion->in.Temperature = Atmosphere->GetTemperature();
|
||||
Propulsion->in.DensityRatio = Atmosphere->GetDensityRatio();
|
||||
Propulsion->in.Density = Atmosphere->GetDensity();
|
||||
Propulsion->in.Soundspeed = Atmosphere->GetSoundSpeed();
|
||||
Propulsion->in.TotalPressure = Auxiliary->GetTotalPressure();
|
||||
Propulsion->in.TotalTempearture = Auxiliary->GetTotalTemperature();
|
||||
Propulsion->in.Vc = Auxiliary->GetVcalibratedKTS();
|
||||
Propulsion->in.Vt = Auxiliary->GetVt();
|
||||
Propulsion->in.qbar = Auxiliary->Getqbar();
|
||||
Propulsion->in.TAT_c = Auxiliary->GetTAT_C();
|
||||
Propulsion->in.AeroUVW = Auxiliary->GetAeroUVW();
|
||||
Propulsion->in.AeroPQR = Auxiliary->GetAeroPQR();
|
||||
Propulsion->in.alpha = Auxiliary->Getalpha();
|
||||
Propulsion->in.beta = Auxiliary->Getbeta();
|
||||
Propulsion->in.TotalDeltaT = dT * Propulsion->GetRate();
|
||||
Propulsion->in.ThrottlePos = FCS->GetThrottlePos();
|
||||
Propulsion->in.MixturePos = FCS->GetMixturePos();
|
||||
Propulsion->in.ThrottleCmd = FCS->GetThrottleCmd();
|
||||
Propulsion->in.MixtureCmd = FCS->GetMixtureCmd();
|
||||
Propulsion->in.PropAdvance = FCS->GetPropAdvance();
|
||||
Propulsion->in.PropFeather = FCS->GetPropFeather();
|
||||
Propulsion->in.H_agl = Propagate->GetDistanceAGL();
|
||||
Propulsion->in.PQR = Propagate->GetPQR();
|
||||
break;
|
||||
case eAerodynamics:
|
||||
Aerodynamics->in.Alpha = Auxiliary->Getalpha();
|
||||
Aerodynamics->in.Beta = Auxiliary->Getbeta();
|
||||
Aerodynamics->in.Qbar = Auxiliary->Getqbar();
|
||||
Aerodynamics->in.Vt = Auxiliary->GetVt();
|
||||
Aerodynamics->in.Tb2w = Auxiliary->GetTb2w();
|
||||
Aerodynamics->in.Tw2b = Auxiliary->GetTw2b();
|
||||
Aerodynamics->in.RPBody = MassBalance->StructuralToBody(Aircraft->GetXYZrp());
|
||||
break;
|
||||
case eGroundReactions:
|
||||
// There are no external inputs to this model.
|
||||
GroundReactions->in.Vground = Auxiliary->GetVground();
|
||||
GroundReactions->in.VcalibratedKts = Auxiliary->GetVcalibratedKTS();
|
||||
GroundReactions->in.Temperature = Atmosphere->GetTemperature();
|
||||
GroundReactions->in.TakeoffThrottle = (FCS->GetThrottlePos().size() > 0) ? (FCS->GetThrottlePos(0) > 0.90) : false;
|
||||
GroundReactions->in.SteerPosDeg = FCS->GetSteerPosDeg();
|
||||
GroundReactions->in.BrakePos = FCS->GetBrakePos();
|
||||
GroundReactions->in.FCSGearPos = FCS->GetGearPos();
|
||||
GroundReactions->in.EmptyWeight = MassBalance->GetEmptyWeight();
|
||||
GroundReactions->in.Tb2l = Propagate->GetTb2l();
|
||||
GroundReactions->in.Tec2l = Propagate->GetTec2l();
|
||||
GroundReactions->in.Tec2b = Propagate->GetTec2b();
|
||||
GroundReactions->in.PQR = Propagate->GetPQR();
|
||||
GroundReactions->in.UVW = Propagate->GetUVW();
|
||||
GroundReactions->in.DistanceAGL = Propagate->GetDistanceAGL();
|
||||
GroundReactions->in.DistanceASL = Propagate->GetAltitudeASL();
|
||||
GroundReactions->in.TotalDeltaT = dT * GroundReactions->GetRate();
|
||||
GroundReactions->in.WOW = GroundReactions->GetWOW();
|
||||
GroundReactions->in.Location = Propagate->GetLocation();
|
||||
for (unsigned int i=0; i<GroundReactions->GetNumGearUnits(); i++) {
|
||||
GroundReactions->in.vWhlBodyVec[i] = MassBalance->StructuralToBody(GroundReactions->GetGearUnit(i)->GetLocation());
|
||||
}
|
||||
break;
|
||||
case eExternalReactions:
|
||||
// There are no external inputs to this model.
|
||||
break;
|
||||
case eBuoyantForces:
|
||||
BuoyantForces->in.Density = Atmosphere->GetDensity();
|
||||
BuoyantForces->in.Pressure = Atmosphere->GetPressure();
|
||||
BuoyantForces->in.Temperature = Atmosphere->GetTemperature();
|
||||
BuoyantForces->in.gravity = Inertial->gravity();
|
||||
break;
|
||||
case eMassBalance:
|
||||
MassBalance->in.GasInertia = BuoyantForces->GetGasMassInertia();
|
||||
MassBalance->in.GasMass = BuoyantForces->GetGasMass();
|
||||
MassBalance->in.GasMoment = BuoyantForces->GetGasMassMoment();
|
||||
MassBalance->in.TanksWeight = Propulsion->GetTanksWeight();
|
||||
MassBalance->in.TanksMoment = Propulsion->GetTanksMoment();
|
||||
MassBalance->in.TankInertia = Propulsion->CalculateTankInertias();
|
||||
break;
|
||||
case eAircraft:
|
||||
Aircraft->in.AeroForce = Aerodynamics->GetForces();
|
||||
Aircraft->in.PropForce = Propulsion->GetForces();
|
||||
Aircraft->in.GroundForce = GroundReactions->GetForces();
|
||||
Aircraft->in.ExternalForce = ExternalReactions->GetForces();
|
||||
Aircraft->in.BuoyantForce = BuoyantForces->GetForces();
|
||||
Aircraft->in.AeroMoment = Aerodynamics->GetMoments();
|
||||
Aircraft->in.PropMoment = Propulsion->GetMoments();
|
||||
Aircraft->in.GroundMoment = GroundReactions->GetMoments();
|
||||
Aircraft->in.ExternalMoment = ExternalReactions->GetMoments();
|
||||
Aircraft->in.BuoyantMoment = BuoyantForces->GetMoments();
|
||||
Aircraft->in.Weight = MassBalance->GetWeight();
|
||||
Aircraft->in.Tl2b = Propagate->GetTl2b();
|
||||
break;
|
||||
case eAccelerations:
|
||||
Accelerations->in.J = MassBalance->GetJ();
|
||||
Accelerations->in.Jinv = MassBalance->GetJinv();
|
||||
Accelerations->in.Ti2b = Propagate->GetTi2b();
|
||||
Accelerations->in.Tb2i = Propagate->GetTb2i();
|
||||
Accelerations->in.Tec2b = Propagate->GetTec2b();
|
||||
Accelerations->in.Tl2b = Propagate->GetTl2b();
|
||||
Accelerations->in.qAttitudeECI = Propagate->GetQuaternionECI();
|
||||
Accelerations->in.Moment = Aircraft->GetMoments();
|
||||
Accelerations->in.GroundMoment = GroundReactions->GetMoments();
|
||||
Accelerations->in.Force = Aircraft->GetForces();
|
||||
Accelerations->in.GroundForce = GroundReactions->GetForces();
|
||||
Accelerations->in.GAccel = Inertial->GetGAccel(Propagate->GetRadius());
|
||||
Accelerations->in.J2Grav = Inertial->GetGravityJ2(Propagate->GetLocation());
|
||||
Accelerations->in.vPQRi = Propagate->GetPQRi();
|
||||
Accelerations->in.vPQR = Propagate->GetPQR();
|
||||
Accelerations->in.vUVW = Propagate->GetUVW();
|
||||
Accelerations->in.vInertialPosition = Propagate->GetInertialPosition();
|
||||
Accelerations->in.DeltaT = dT;
|
||||
Accelerations->in.Mass = MassBalance->GetMass();
|
||||
Accelerations->in.MultipliersList = GroundReactions->GetMultipliersList();
|
||||
Accelerations->in.TerrainVelocity = Propagate->GetTerrainVelocity();
|
||||
Accelerations->in.TerrainAngularVel = Propagate->GetTerrainAngularVelocity();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGFDMExec::LoadPlanetConstants(void)
|
||||
{
|
||||
Propagate->in.vOmegaPlanet = Inertial->GetOmegaPlanet();
|
||||
Accelerations->in.vOmegaPlanet = Inertial->GetOmegaPlanet();
|
||||
Propagate->in.RefRadius = Inertial->GetRefRadius();
|
||||
Propagate->in.SemiMajor = Inertial->GetSemimajor();
|
||||
Propagate->in.SemiMinor = Inertial->GetSemiminor();
|
||||
Auxiliary->in.SLGravity = Inertial->SLgravity();
|
||||
Auxiliary->in.ReferenceRadius = Inertial->GetRefRadius();
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGFDMExec::LoadModelConstants(void)
|
||||
{
|
||||
Winds->in.wingspan = Aircraft->GetWingSpan();
|
||||
FCS->in.NumGear = GroundReactions->GetNumGearUnits();
|
||||
Aerodynamics->in.Wingarea = Aircraft->GetWingArea();
|
||||
Aerodynamics->in.Wingchord = Aircraft->Getcbar();
|
||||
Aerodynamics->in.Wingincidence = Aircraft->GetWingIncidence();
|
||||
Aerodynamics->in.Wingspan = Aircraft->GetWingSpan();
|
||||
Auxiliary->in.Wingspan = Aircraft->GetWingSpan();
|
||||
Auxiliary->in.Wingchord = Aircraft->Getcbar();
|
||||
for (unsigned int i=0; i<GroundReactions->GetNumGearUnits(); i++) {
|
||||
GroundReactions->in.vWhlBodyVec[i] = MassBalance->StructuralToBody(GroundReactions->GetGearUnit(i)->GetLocation());
|
||||
}
|
||||
|
||||
LoadPlanetConstants();
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// This call will cause the sim time to reset to 0.0
|
||||
|
||||
|
@ -357,12 +557,15 @@ void FGFDMExec::Initialize(FGInitialCondition *FGIC)
|
|||
Setsim_time(0.0);
|
||||
|
||||
Propagate->SetInitialState( FGIC );
|
||||
|
||||
LoadInputs(eAccelerations);
|
||||
Accelerations->Run(false);
|
||||
LoadInputs(ePropagate);
|
||||
Propagate->InitializeDerivatives();
|
||||
LoadInputs(eAtmosphere);
|
||||
Atmosphere->Run(false);
|
||||
Atmosphere->SetWindNED( FGIC->GetWindNFpsIC(),
|
||||
Winds->SetWindNED( FGIC->GetWindNFpsIC(),
|
||||
FGIC->GetWindEFpsIC(),
|
||||
FGIC->GetWindDFpsIC() );
|
||||
|
||||
Auxiliary->Run(false);
|
||||
}
|
||||
|
||||
|
@ -397,6 +600,23 @@ void FGFDMExec::ResetToInitialConditions(void)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
bool FGFDMExec::SetOutputFileName(const string& fname)
|
||||
{
|
||||
if (Outputs.size() > 0) Outputs[0]->SetOutputFileName(fname);
|
||||
else return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
string FGFDMExec::GetOutputFileName(void)
|
||||
{
|
||||
if (Outputs.size() > 0) return Outputs[0]->GetOutputFileName();
|
||||
else return string("");
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGFDMExec::SetGroundCallback(FGGroundCallback* p)
|
||||
{
|
||||
delete GroundCallback;
|
||||
|
@ -408,6 +628,7 @@ void FGFDMExec::SetGroundCallback(FGGroundCallback* p)
|
|||
vector <string> FGFDMExec::EnumerateFDMs(void)
|
||||
{
|
||||
vector <string> FDMList;
|
||||
FGAircraft* Aircraft = (FGAircraft*)Models[eAircraft];
|
||||
|
||||
FDMList.push_back(Aircraft->GetAircraftName());
|
||||
|
||||
|
@ -493,7 +714,7 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
|
|||
// Process the metrics element. This element is REQUIRED.
|
||||
element = document->FindElement("metrics");
|
||||
if (element) {
|
||||
result = Aircraft->Load(element);
|
||||
result = ((FGAircraft*)Models[eAircraft])->Load(element);
|
||||
if (!result) {
|
||||
cerr << endl << "Aircraft metrics element has problems in file " << aircraftCfgFileName << endl;
|
||||
return result;
|
||||
|
@ -506,7 +727,7 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
|
|||
// Process the mass_balance element. This element is REQUIRED.
|
||||
element = document->FindElement("mass_balance");
|
||||
if (element) {
|
||||
result = MassBalance->Load(element);
|
||||
result = ((FGMassBalance*)Models[eMassBalance])->Load(element);
|
||||
if (!result) {
|
||||
cerr << endl << "Aircraft mass_balance element has problems in file " << aircraftCfgFileName << endl;
|
||||
return result;
|
||||
|
@ -519,11 +740,12 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
|
|||
// Process the ground_reactions element. This element is REQUIRED.
|
||||
element = document->FindElement("ground_reactions");
|
||||
if (element) {
|
||||
result = GroundReactions->Load(element);
|
||||
result = ((FGGroundReactions*)Models[eGroundReactions])->Load(element);
|
||||
if (!result) {
|
||||
cerr << endl << "Aircraft ground_reactions element has problems in file " << aircraftCfgFileName << endl;
|
||||
return result;
|
||||
}
|
||||
((FGFCS*)Models[eSystems])->AddGear(((FGGroundReactions*)Models[eGroundReactions])->GetNumGearUnits());
|
||||
} else {
|
||||
cerr << endl << "No ground_reactions element was found in the aircraft config file." << endl;
|
||||
return false;
|
||||
|
@ -532,7 +754,7 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
|
|||
// Process the external_reactions element. This element is OPTIONAL.
|
||||
element = document->FindElement("external_reactions");
|
||||
if (element) {
|
||||
result = ExternalReactions->Load(element);
|
||||
result = ((FGExternalReactions*)Models[eExternalReactions])->Load(element);
|
||||
if (!result) {
|
||||
cerr << endl << "Aircraft external_reactions element has problems in file " << aircraftCfgFileName << endl;
|
||||
return result;
|
||||
|
@ -542,7 +764,7 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
|
|||
// Process the buoyant_forces element. This element is OPTIONAL.
|
||||
element = document->FindElement("buoyant_forces");
|
||||
if (element) {
|
||||
result = BuoyantForces->Load(element);
|
||||
result = ((FGBuoyantForces*)Models[eBuoyantForces])->Load(element);
|
||||
if (!result) {
|
||||
cerr << endl << "Aircraft buoyant_forces element has problems in file " << aircraftCfgFileName << endl;
|
||||
return result;
|
||||
|
@ -552,17 +774,19 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
|
|||
// Process the propulsion element. This element is OPTIONAL.
|
||||
element = document->FindElement("propulsion");
|
||||
if (element) {
|
||||
result = Propulsion->Load(element);
|
||||
result = ((FGPropulsion*)Models[ePropulsion])->Load(element);
|
||||
if (!result) {
|
||||
cerr << endl << "Aircraft propulsion element has problems in file " << aircraftCfgFileName << endl;
|
||||
return result;
|
||||
}
|
||||
for (unsigned int i=0; i<((FGPropulsion*)Models[ePropulsion])->GetNumEngines(); i++)
|
||||
((FGFCS*)Models[eSystems])->AddThrottle();
|
||||
}
|
||||
|
||||
// Process the system element[s]. This element is OPTIONAL, and there may be more than one.
|
||||
element = document->FindElement("system");
|
||||
while (element) {
|
||||
result = FCS->Load(element, FGFCS::stSystem);
|
||||
result = ((FGFCS*)Models[eSystems])->Load(element, FGFCS::stSystem);
|
||||
if (!result) {
|
||||
cerr << endl << "Aircraft system element has problems in file " << aircraftCfgFileName << endl;
|
||||
return result;
|
||||
|
@ -573,7 +797,7 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
|
|||
// Process the autopilot element. This element is OPTIONAL.
|
||||
element = document->FindElement("autopilot");
|
||||
if (element) {
|
||||
result = FCS->Load(element, FGFCS::stAutoPilot);
|
||||
result = ((FGFCS*)Models[eSystems])->Load(element, FGFCS::stAutoPilot);
|
||||
if (!result) {
|
||||
cerr << endl << "Aircraft autopilot element has problems in file " << aircraftCfgFileName << endl;
|
||||
return result;
|
||||
|
@ -583,7 +807,7 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
|
|||
// Process the flight_control element. This element is OPTIONAL.
|
||||
element = document->FindElement("flight_control");
|
||||
if (element) {
|
||||
result = FCS->Load(element, FGFCS::stFCS);
|
||||
result = ((FGFCS*)Models[eSystems])->Load(element, FGFCS::stFCS);
|
||||
if (!result) {
|
||||
cerr << endl << "Aircraft flight_control element has problems in file " << aircraftCfgFileName << endl;
|
||||
return result;
|
||||
|
@ -593,7 +817,7 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
|
|||
// Process the aerodynamics element. This element is OPTIONAL, but almost always expected.
|
||||
element = document->FindElement("aerodynamics");
|
||||
if (element) {
|
||||
result = Aerodynamics->Load(element);
|
||||
result = ((FGAerodynamics*)Models[eAerodynamics])->Load(element);
|
||||
if (!result) {
|
||||
cerr << endl << "Aircraft aerodynamics element has problems in file " << aircraftCfgFileName << endl;
|
||||
return result;
|
||||
|
@ -605,7 +829,7 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
|
|||
// Process the input element. This element is OPTIONAL.
|
||||
element = document->FindElement("input");
|
||||
if (element) {
|
||||
result = Input->Load(element);
|
||||
result = ((FGInput*)Models[eInput])->Load(element);
|
||||
if (!result) {
|
||||
cerr << endl << "Aircraft input element has problems in file " << aircraftCfgFileName << endl;
|
||||
return result;
|
||||
|
@ -616,13 +840,12 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
|
|||
unsigned int idx=0;
|
||||
typedef double (FGOutput::*iOPMF)(void) const;
|
||||
typedef int (FGFDMExec::*iOPV)(void) const;
|
||||
typedef void (FGFDMExec::*vOPI)(int) const;
|
||||
element = document->FindElement("output");
|
||||
while (element) {
|
||||
if (debug_lvl > 0) cout << endl << " Output data set: " << idx << " ";
|
||||
FGOutput* Output = new FGOutput(this);
|
||||
Output->InitModel();
|
||||
Schedule(Output, 1);
|
||||
Schedule(Output);
|
||||
result = Output->Load(element);
|
||||
if (!result) {
|
||||
cerr << endl << "Aircraft output element has problems in file " << aircraftCfgFileName << endl;
|
||||
|
@ -647,11 +870,16 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
|
|||
}
|
||||
}
|
||||
|
||||
// Since all vehicle characteristics have been loaded, place the values in the Inputs
|
||||
// structure for the FGModel-derived classes.
|
||||
LoadModelConstants();
|
||||
|
||||
modelLoaded = true;
|
||||
|
||||
if (debug_lvl > 0) {
|
||||
MassBalance->Run(false); // Update all mass properties for the report.
|
||||
MassBalance->GetMassPropertiesReport();
|
||||
LoadInputs(eMassBalance); // Update all input mass properties for the report.
|
||||
Models[eMassBalance]->Run(false); // Update all mass properties for the report.
|
||||
((FGMassBalance*)Models[eMassBalance])->GetMassPropertiesReport();
|
||||
|
||||
cout << endl << fgblue << highint
|
||||
<< "End of vehicle configuration loading." << endl
|
||||
|
@ -667,6 +895,8 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
|
|||
<< fgdef << endl;
|
||||
}
|
||||
|
||||
for (unsigned int i=0; i< Models.size(); i++) LoadInputs(i);
|
||||
|
||||
if (result) {
|
||||
struct PropertyCatalogStructure masterPCS;
|
||||
masterPCS.base_string = "";
|
||||
|
@ -679,6 +909,13 @@ bool FGFDMExec::LoadModel(const string& model, bool addModelToPath)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
string FGFDMExec::GetPropulsionTankReport()
|
||||
{
|
||||
return ((FGPropulsion*)Models[ePropulsion])->GetPropulsionTankReport();
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGFDMExec::BuildPropertyCatalog(struct PropertyCatalogStructure* pcs)
|
||||
{
|
||||
struct PropertyCatalogStructure* pcsNew = new struct PropertyCatalogStructure;
|
||||
|
@ -760,7 +997,7 @@ bool FGFDMExec::ReadPrologue(Element* el) // el for ReadPrologue is the document
|
|||
if (!el) return false;
|
||||
|
||||
string AircraftName = el->GetAttributeValue("name");
|
||||
Aircraft->SetAircraftName(AircraftName);
|
||||
((FGAircraft*)Models[eAircraft])->SetAircraftName(AircraftName);
|
||||
|
||||
if (debug_lvl & 1) cout << underon << "Reading Aircraft Configuration File"
|
||||
<< underoff << ": " << highint << AircraftName << normint << endl;
|
||||
|
@ -899,7 +1136,7 @@ void FGFDMExec::EnableOutput(void)
|
|||
|
||||
void FGFDMExec::ForceOutput(int idx)
|
||||
{
|
||||
if (idx >= 0 && idx < Outputs.size()) Outputs[idx]->Print();
|
||||
if (idx >= (int)0 && idx < (int)Outputs.size()) Outputs[idx]->Print();
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -911,7 +1148,7 @@ bool FGFDMExec::SetOutputDirectives(const string& fname)
|
|||
FGOutput* Output = new FGOutput(this);
|
||||
Output->SetDirectivesFile(RootDir + fname);
|
||||
Output->InitModel();
|
||||
Schedule(Output, 1);
|
||||
Schedule(Output);
|
||||
result = Output->Load(0);
|
||||
|
||||
if (result) {
|
||||
|
@ -943,38 +1180,6 @@ void FGFDMExec::DoTrim(int mode)
|
|||
sim_time = saved_time;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGFDMExec::UseAtmosphereMSIS(void)
|
||||
{
|
||||
FGAtmosphere *oldAtmosphere = Atmosphere;
|
||||
Atmosphere = new MSIS(this);
|
||||
if (!Atmosphere->InitModel()) {
|
||||
cerr << fgred << "MSIS Atmosphere model init failed" << fgdef << endl;
|
||||
Error+=1;
|
||||
}
|
||||
Models[1] = Atmosphere; // Reassign the atmosphere model that has already been scheduled
|
||||
// to the new atmosphere.
|
||||
delete oldAtmosphere;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGFDMExec::UseAtmosphereMars(void)
|
||||
{
|
||||
/*
|
||||
FGAtmosphere *oldAtmosphere = Atmosphere;
|
||||
Atmosphere = new FGMars(this);
|
||||
if (!Atmosphere->InitModel()) {
|
||||
cerr << fgred << "Mars Atmosphere model init failed" << fgdef << endl;
|
||||
Error+=1;
|
||||
}
|
||||
Models[1] = Atmosphere; // Reassign the atmosphere model that has already been scheduled
|
||||
// to the new atmosphere.
|
||||
delete oldAtmosphere;
|
||||
*/
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// The bitmasked value choices are as follows:
|
||||
// unset: In this case (the default) JSBSim would only print
|
||||
|
@ -1000,10 +1205,10 @@ void FGFDMExec::Debug(int from)
|
|||
|
||||
if (debug_lvl & 1 && IdFDM == 0) { // Standard console startup message output
|
||||
if (from == 0) { // Constructor
|
||||
cout << "\n\n " << highint << underon << "JSBSim Flight Dynamics Model v"
|
||||
<< JSBSim_version << underoff << normint << endl;
|
||||
cout << halfint << " [JSBSim-ML v" << needed_cfg_version << "]\n\n";
|
||||
cout << normint << "JSBSim startup beginning ...\n\n";
|
||||
cout << "\n\n "
|
||||
<< "JSBSim Flight Dynamics Model v" << JSBSim_version << endl;
|
||||
cout << " [JSBSim-ML v" << needed_cfg_version << "]\n\n";
|
||||
cout << "JSBSim startup beginning ...\n\n";
|
||||
} else if (from == 3) {
|
||||
cout << "\n\nJSBSim startup complete\n\n";
|
||||
}
|
||||
|
|
|
@ -44,8 +44,6 @@ INCLUDES
|
|||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "models/FGOutput.h"
|
||||
#include "models/FGInput.h"
|
||||
#include "initialization/FGTrim.h"
|
||||
#include "FGJSBBase.h"
|
||||
#include "input_output/FGPropertyManager.h"
|
||||
|
@ -58,7 +56,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_FDMEXEC "$Id: FGFDMExec.h,v 1.64 2011/05/20 03:18:36 jberndt Exp $"
|
||||
#define ID_FDMEXEC "$Id: FGFDMExec.h,v 1.71 2011/09/07 02:37:04 jberndt Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -71,6 +69,8 @@ class FGTrim;
|
|||
class FGAerodynamics;
|
||||
class FGAircraft;
|
||||
class FGAtmosphere;
|
||||
class FGAccelerations;
|
||||
class FGWinds;
|
||||
class FGAuxiliary;
|
||||
class FGBuoyantForces;
|
||||
class FGExternalReactions;
|
||||
|
@ -181,7 +181,7 @@ CLASS DOCUMENTATION
|
|||
property actually maps toa function call of DoTrim().
|
||||
|
||||
@author Jon S. Berndt
|
||||
@version $Revision: 1.64 $
|
||||
@version $Revision: 1.71 $
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -224,6 +224,25 @@ public:
|
|||
/// Default destructor
|
||||
~FGFDMExec();
|
||||
|
||||
// This list of enums is very important! The order in which models are listed here
|
||||
// determines the order of execution of the models.
|
||||
enum eModels { ePropagate=0,
|
||||
eInput,
|
||||
eInertial,
|
||||
eAtmosphere,
|
||||
eWinds,
|
||||
eAuxiliary,
|
||||
eSystems,
|
||||
ePropulsion,
|
||||
eAerodynamics,
|
||||
eGroundReactions,
|
||||
eExternalReactions,
|
||||
eBuoyantForces,
|
||||
eMassBalance,
|
||||
eAircraft,
|
||||
eAccelerations,
|
||||
eNumStandardModels };
|
||||
|
||||
/** Unbind all tied JSBSim properties. */
|
||||
void Unbind(void) {instance->Unbind();}
|
||||
|
||||
|
@ -236,8 +255,9 @@ public:
|
|||
one is at this time not recommended.
|
||||
@param model A pointer to the model being scheduled.
|
||||
@param rate The rate at which to execute the model as described above.
|
||||
Default is every frame (rate=1).
|
||||
@return Currently returns 0 always. */
|
||||
void Schedule(FGModel* model, int rate);
|
||||
void Schedule(FGModel* model, int rate=1);
|
||||
|
||||
/** This function executes each scheduled model in succession.
|
||||
@return true if successful, false if sim should be ended */
|
||||
|
@ -309,31 +329,35 @@ public:
|
|||
/// @name Top-level executive State and Model retrieval mechanism
|
||||
//@{
|
||||
/// Returns the FGAtmosphere pointer.
|
||||
FGAtmosphere* GetAtmosphere(void) {return Atmosphere;}
|
||||
FGAtmosphere* GetAtmosphere(void) {return (FGAtmosphere*)Models[eAtmosphere];}
|
||||
/// Returns the FGAccelerations pointer.
|
||||
FGAccelerations* GetAccelerations(void) {return (FGAccelerations*)Models[eAccelerations];}
|
||||
/// Returns the FGWinds pointer.
|
||||
FGWinds* GetWinds(void) {return (FGWinds*)Models[eWinds];}
|
||||
/// Returns the FGFCS pointer.
|
||||
FGFCS* GetFCS(void) {return FCS;}
|
||||
FGFCS* GetFCS(void) {return (FGFCS*)Models[eSystems];}
|
||||
/// Returns the FGPropulsion pointer.
|
||||
FGPropulsion* GetPropulsion(void) {return Propulsion;}
|
||||
FGPropulsion* GetPropulsion(void) {return (FGPropulsion*)Models[ePropulsion];}
|
||||
/// Returns the FGAircraft pointer.
|
||||
FGMassBalance* GetMassBalance(void) {return MassBalance;}
|
||||
FGMassBalance* GetMassBalance(void) {return (FGMassBalance*)Models[eMassBalance];}
|
||||
/// Returns the FGAerodynamics pointer
|
||||
FGAerodynamics* GetAerodynamics(void){return Aerodynamics;}
|
||||
FGAerodynamics* GetAerodynamics(void){return (FGAerodynamics*)Models[eAerodynamics];}
|
||||
/// Returns the FGInertial pointer.
|
||||
FGInertial* GetInertial(void) {return Inertial;}
|
||||
FGInertial* GetInertial(void) {return (FGInertial*)Models[eInertial];}
|
||||
/// Returns the FGGroundReactions pointer.
|
||||
FGGroundReactions* GetGroundReactions(void) {return GroundReactions;}
|
||||
FGGroundReactions* GetGroundReactions(void) {return (FGGroundReactions*)Models[eGroundReactions];}
|
||||
/// Returns the FGExternalReactions pointer.
|
||||
FGExternalReactions* GetExternalReactions(void) {return ExternalReactions;}
|
||||
FGExternalReactions* GetExternalReactions(void) {return (FGExternalReactions*)Models[eExternalReactions];}
|
||||
/// Returns the FGBuoyantForces pointer.
|
||||
FGBuoyantForces* GetBuoyantForces(void) {return BuoyantForces;}
|
||||
FGBuoyantForces* GetBuoyantForces(void) {return (FGBuoyantForces*)Models[eBuoyantForces];}
|
||||
/// Returns the FGAircraft pointer.
|
||||
FGAircraft* GetAircraft(void) {return Aircraft;}
|
||||
FGAircraft* GetAircraft(void) {return (FGAircraft*)Models[eAircraft];}
|
||||
/// Returns the FGPropagate pointer.
|
||||
FGPropagate* GetPropagate(void) {return Propagate;}
|
||||
FGPropagate* GetPropagate(void) {return (FGPropagate*)Models[ePropagate];}
|
||||
/// Returns the FGAuxiliary pointer.
|
||||
FGAuxiliary* GetAuxiliary(void) {return Auxiliary;}
|
||||
FGAuxiliary* GetAuxiliary(void) {return (FGAuxiliary*)Models[eAuxiliary];}
|
||||
/// Returns the FGInput pointer.
|
||||
FGInput* GetInput(void) {return Input;}
|
||||
FGInput* GetInput(void) {return (FGInput*)Models[eInput];}
|
||||
/// Returns the FGGroundCallback pointer.
|
||||
FGGroundCallback* GetGroundCallback(void) {return GroundCallback;}
|
||||
/// Retrieves the script object
|
||||
|
@ -408,19 +432,12 @@ public:
|
|||
/** Sets (or overrides) the output filename
|
||||
@param fname the name of the file to output data to
|
||||
@return true if successful, false if there is no output specified for the flight model */
|
||||
bool SetOutputFileName(const string& fname) {
|
||||
if (Outputs.size() > 0) Outputs[0]->SetOutputFileName(fname);
|
||||
else return false;
|
||||
return true;
|
||||
}
|
||||
bool SetOutputFileName(const string& fname);
|
||||
|
||||
/** Retrieves the current output filename.
|
||||
@return the name of the output file for the first output specified by the flight model.
|
||||
If none is specified, the empty string is returned. */
|
||||
string GetOutputFileName(void) {
|
||||
if (Outputs.size() > 0) return Outputs[0]->GetOutputFileName();
|
||||
else return string("");
|
||||
}
|
||||
string GetOutputFileName(void);
|
||||
|
||||
/** Executes trimming in the selected mode.
|
||||
* @param mode Specifies how to trim:
|
||||
|
@ -474,17 +491,13 @@ public:
|
|||
|
||||
vector<string>& GetPropertyCatalog(void) {return PropertyCatalog;}
|
||||
|
||||
/// Use the MSIS atmosphere model.
|
||||
void UseAtmosphereMSIS(void);
|
||||
|
||||
/// Use the Mars atmosphere model. (Not operative yet.)
|
||||
void UseAtmosphereMars(void);
|
||||
|
||||
void SetTrimStatus(bool status){ trim_status = status; }
|
||||
bool GetTrimStatus(void) const { return trim_status; }
|
||||
void SetTrimMode(int mode){ ta_mode = mode; }
|
||||
int GetTrimMode(void) const { return ta_mode; }
|
||||
|
||||
string GetPropulsionTankReport();
|
||||
|
||||
/// Returns the cumulative simulation time in seconds.
|
||||
double GetSimTime(void) const { return sim_time; }
|
||||
|
||||
|
@ -545,6 +558,7 @@ private:
|
|||
bool Constructing;
|
||||
bool modelLoaded;
|
||||
bool IsChild;
|
||||
bool firstPass;
|
||||
string modelName;
|
||||
string AircraftPath;
|
||||
string FullAircraftPath;
|
||||
|
@ -554,23 +568,26 @@ private:
|
|||
string Release;
|
||||
string RootDir;
|
||||
|
||||
// Standard Model pointers - shortcuts for internal executive use only.
|
||||
FGPropagate* Propagate;
|
||||
FGInertial* Inertial;
|
||||
FGAtmosphere* Atmosphere;
|
||||
FGWinds* Winds;
|
||||
FGAuxiliary* Auxiliary;
|
||||
FGFCS* FCS;
|
||||
FGPropulsion* Propulsion;
|
||||
FGAerodynamics* Aerodynamics;
|
||||
FGGroundReactions* GroundReactions;
|
||||
FGExternalReactions* ExternalReactions;
|
||||
FGBuoyantForces* BuoyantForces;
|
||||
FGMassBalance* MassBalance;
|
||||
FGAircraft* Aircraft;
|
||||
FGAccelerations* Accelerations;
|
||||
|
||||
bool trim_status;
|
||||
int ta_mode;
|
||||
|
||||
FGGroundCallback* GroundCallback;
|
||||
FGAtmosphere* Atmosphere;
|
||||
FGFCS* FCS;
|
||||
FGPropulsion* Propulsion;
|
||||
FGMassBalance* MassBalance;
|
||||
FGAerodynamics* Aerodynamics;
|
||||
FGInertial* Inertial;
|
||||
FGGroundReactions* GroundReactions;
|
||||
FGExternalReactions* ExternalReactions;
|
||||
FGBuoyantForces* BuoyantForces;
|
||||
FGAircraft* Aircraft;
|
||||
FGPropagate* Propagate;
|
||||
FGAuxiliary* Auxiliary;
|
||||
FGInput* Input;
|
||||
FGScript* Script;
|
||||
FGInitialCondition* IC;
|
||||
FGTrim* Trim;
|
||||
|
@ -591,6 +608,9 @@ private:
|
|||
bool ReadChild(Element*);
|
||||
bool ReadPrologue(Element*);
|
||||
void ResetToInitialConditions(int mode);
|
||||
void LoadInputs(unsigned int idx);
|
||||
void LoadPlanetConstants(void);
|
||||
void LoadModelConstants(void);
|
||||
bool Allocate(void);
|
||||
bool DeAllocate(void);
|
||||
void Initialize(FGInitialCondition *FGIC);
|
||||
|
|
|
@ -44,7 +44,7 @@ INCLUDES
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGJSBBase.cpp,v 1.30 2011/06/13 11:47:04 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGJSBBase.cpp,v 1.31 2011/07/27 03:55:48 jberndt Exp $";
|
||||
static const char *IdHdr = ID_JSBBASE;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -228,7 +228,8 @@ FGJSBBase::Message* FGJSBBase::ProcessNextMessage(void)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGJSBBase::disableHighLighting(void) {
|
||||
void FGJSBBase::disableHighLighting(void)
|
||||
{
|
||||
highint[0]='\0';
|
||||
halfint[0]='\0';
|
||||
normint[0]='\0';
|
||||
|
|
|
@ -43,27 +43,20 @@ INCLUDES
|
|||
#include <string>
|
||||
#include <cmath>
|
||||
|
||||
using std::min;
|
||||
using std::max;
|
||||
|
||||
#include "input_output/string_utilities.h"
|
||||
|
||||
#ifndef M_PI
|
||||
# define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER < 1300)
|
||||
namespace std
|
||||
{
|
||||
template <class T> inline T max(const T& a, const T& b)
|
||||
{
|
||||
return (a > b) ? a : b;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_JSBBASE "$Id: FGJSBBase.h,v 1.32 2011/06/13 11:47:04 jberndt Exp $"
|
||||
#define ID_JSBBASE "$Id: FGJSBBase.h,v 1.33 2011/06/27 03:14:25 jberndt Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -79,7 +72,7 @@ CLASS DOCUMENTATION
|
|||
* This class provides universal constants, utility functions, messaging
|
||||
* functions, and enumerated constants to JSBSim.
|
||||
@author Jon S. Berndt
|
||||
@version $Id: FGJSBBase.h,v 1.32 2011/06/13 11:47:04 jberndt Exp $
|
||||
@version $Id: FGJSBBase.h,v 1.33 2011/06/27 03:14:25 jberndt Exp $
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -269,7 +262,7 @@ public:
|
|||
@return if the two values can be considered equal up to roundoff */
|
||||
static bool EqualToRoundoff(double a, double b) {
|
||||
double eps = 2.0*DBL_EPSILON;
|
||||
return std::fabs(a - b) <= eps*std::max(std::fabs(a), std::fabs(b));
|
||||
return std::fabs(a - b) <= eps * max(std::fabs(a), std::fabs(b));
|
||||
}
|
||||
|
||||
/** Finite precision comparison.
|
||||
|
@ -278,7 +271,7 @@ public:
|
|||
@return if the two values can be considered equal up to roundoff */
|
||||
static bool EqualToRoundoff(float a, float b) {
|
||||
float eps = 2.0*FLT_EPSILON;
|
||||
return std::fabs(a - b) <= eps*std::max(std::fabs(a), std::fabs(b));
|
||||
return std::fabs(a - b) <= eps * max(std::fabs(a), std::fabs(b));
|
||||
}
|
||||
|
||||
/** Finite precision comparison.
|
||||
|
|
|
@ -60,6 +60,8 @@
|
|||
#include <FDM/JSBSim/models/FGLGear.h>
|
||||
#include <FDM/JSBSim/models/FGGroundReactions.h>
|
||||
#include <FDM/JSBSim/models/FGPropulsion.h>
|
||||
#include <FDM/JSBSim/models/FGAccelerations.h>
|
||||
#include <FDM/JSBSim/models/atmosphere/FGWinds.h>
|
||||
#include <FDM/JSBSim/models/propulsion/FGEngine.h>
|
||||
#include <FDM/JSBSim/models/propulsion/FGPiston.h>
|
||||
#include <FDM/JSBSim/models/propulsion/FGTurbine.h>
|
||||
|
@ -138,12 +140,11 @@ FGJSBsim::FGJSBsim( double dt )
|
|||
{
|
||||
bool result;
|
||||
if( TURBULENCE_TYPE_NAMES.empty() ) {
|
||||
TURBULENCE_TYPE_NAMES["ttNone"] = FGAtmosphere::ttNone;
|
||||
TURBULENCE_TYPE_NAMES["ttStandard"] = FGAtmosphere::ttStandard;
|
||||
// TURBULENCE_TYPE_NAMES["ttBerndt"] = FGAtmosphere::ttBerndt;
|
||||
TURBULENCE_TYPE_NAMES["ttCulp"] = FGAtmosphere::ttCulp;
|
||||
TURBULENCE_TYPE_NAMES["ttMilspec"] = FGAtmosphere::ttMilspec;
|
||||
TURBULENCE_TYPE_NAMES["ttTustin"] = FGAtmosphere::ttTustin;
|
||||
TURBULENCE_TYPE_NAMES["ttNone"] = FGWinds::ttNone;
|
||||
TURBULENCE_TYPE_NAMES["ttStandard"] = FGWinds::ttStandard;
|
||||
TURBULENCE_TYPE_NAMES["ttCulp"] = FGWinds::ttCulp;
|
||||
TURBULENCE_TYPE_NAMES["ttMilspec"] = FGWinds::ttMilspec;
|
||||
TURBULENCE_TYPE_NAMES["ttTustin"] = FGWinds::ttTustin;
|
||||
}
|
||||
|
||||
// Set up the debugging level
|
||||
|
@ -177,6 +178,7 @@ FGJSBsim::FGJSBsim( double dt )
|
|||
fdmex->SetGroundCallback( new FGFSGroundCallback(this) );
|
||||
|
||||
Atmosphere = fdmex->GetAtmosphere();
|
||||
Winds = fdmex->GetWinds();
|
||||
FCS = fdmex->GetFCS();
|
||||
MassBalance = fdmex->GetMassBalance();
|
||||
Propulsion = fdmex->GetPropulsion();
|
||||
|
@ -186,6 +188,7 @@ FGJSBsim::FGJSBsim( double dt )
|
|||
Inertial = fdmex->GetInertial();
|
||||
Aerodynamics = fdmex->GetAerodynamics();
|
||||
GroundReactions = fdmex->GetGroundReactions();
|
||||
Accelerations = fdmex->GetAccelerations();
|
||||
|
||||
fgic=fdmex->GetIC();
|
||||
needTrim=true;
|
||||
|
@ -307,6 +310,7 @@ FGJSBsim::FGJSBsim( double dt )
|
|||
|
||||
temperature = fgGetNode("/environment/temperature-degc",true);
|
||||
pressure = fgGetNode("/environment/pressure-inhg",true);
|
||||
pressureSL = fgGetNode("/environment/pressure-sea-level-inhg",true);
|
||||
density = fgGetNode("/environment/density-slugft3",true);
|
||||
ground_wind = fgGetNode("/environment/config/boundary/entry[0]/wind-speed-kt",true);
|
||||
turbulence_gain = fgGetNode("/environment/turbulence/magnitude-norm",true);
|
||||
|
@ -354,21 +358,17 @@ void FGJSBsim::init()
|
|||
// init method first.
|
||||
|
||||
if (fgGetBool("/environment/params/control-fdm-atmosphere")) {
|
||||
Atmosphere->UseExternal();
|
||||
Atmosphere->SetExTemperature(
|
||||
9.0/5.0*(temperature->getDoubleValue()+273.15) );
|
||||
Atmosphere->SetExPressure(pressure->getDoubleValue()*70.726566);
|
||||
Atmosphere->SetExDensity(density->getDoubleValue());
|
||||
Atmosphere->SetTemperature(temperature->getDoubleValue(), get_Altitude(), FGAtmosphere::eCelsius);
|
||||
Atmosphere->SetPressureSL(pressureSL->getDoubleValue(), FGAtmosphere::eInchesHg);
|
||||
// initialize to no turbulence, these values get set in the update loop
|
||||
Atmosphere->SetTurbType(FGAtmosphere::ttNone);
|
||||
Atmosphere->SetTurbGain(0.0);
|
||||
Atmosphere->SetTurbRate(0.0);
|
||||
Atmosphere->SetWindspeed20ft(0.0);
|
||||
Atmosphere->SetProbabilityOfExceedence(0.0);
|
||||
} else {
|
||||
Atmosphere->UseInternal();
|
||||
Winds->SetTurbType(FGWinds::ttNone);
|
||||
Winds->SetTurbGain(0.0);
|
||||
Winds->SetTurbRate(0.0);
|
||||
Winds->SetWindspeed20ft(0.0);
|
||||
Winds->SetProbabilityOfExceedence(0.0);
|
||||
}
|
||||
|
||||
fgic->SetSeaLevelRadiusFtIC( get_Sea_level_radius() );
|
||||
fgic->SetWindNEDFpsIC( -wind_from_north->getDoubleValue(),
|
||||
-wind_from_east->getDoubleValue(),
|
||||
-wind_from_down->getDoubleValue() );
|
||||
|
@ -409,14 +409,14 @@ void FGJSBsim::init()
|
|||
|
||||
if ( startup_trim->getBoolValue() ) {
|
||||
FGLocation cart(fgic->GetLongitudeRadIC(), fgic->GetLatitudeRadIC(),
|
||||
fgic->GetSeaLevelRadiusFtIC() + fgic->GetAltitudeASLFtIC());
|
||||
get_Sea_level_radius() + fgic->GetAltitudeASLFtIC());
|
||||
double cart_pos[3], contact[3], d[3], vel[3], agl;
|
||||
update_ground_cache(cart, cart_pos, 0.01);
|
||||
|
||||
get_agl_ft(fdmex->GetSimTime(), cart_pos, SG_METER_TO_FEET*2, contact,
|
||||
d, vel, d, &agl);
|
||||
double terrain_alt = sqrt(contact[0]*contact[0] + contact[1]*contact[1]
|
||||
+ contact[2]*contact[2]) - fgic->GetSeaLevelRadiusFtIC();
|
||||
+ contact[2]*contact[2]) - get_Sea_level_radius();
|
||||
|
||||
SG_LOG(SG_FLIGHT, SG_INFO, "Ready to trim, terrain elevation is: "
|
||||
<< terrain_alt * SG_METER_TO_FEET );
|
||||
|
@ -664,30 +664,27 @@ bool FGJSBsim::copy_to_JSBsim()
|
|||
|
||||
Propagate->SetSeaLevelRadius( get_Sea_level_radius() );
|
||||
|
||||
Atmosphere->SetExTemperature(
|
||||
9.0/5.0*(temperature->getDoubleValue()+273.15) );
|
||||
Atmosphere->SetExPressure(pressure->getDoubleValue()*70.726566);
|
||||
Atmosphere->SetExDensity(density->getDoubleValue());
|
||||
Atmosphere->SetTemperature(temperature->getDoubleValue(), get_Altitude(), FGAtmosphere::eCelsius);
|
||||
Atmosphere->SetPressureSL(pressureSL->getDoubleValue(), FGAtmosphere::eInchesHg);
|
||||
|
||||
Atmosphere->SetTurbType((FGAtmosphere::tType)TURBULENCE_TYPE_NAMES[turbulence_model->getStringValue()]);
|
||||
switch( Atmosphere->GetTurbType() ) {
|
||||
// case FGAtmosphere::ttBerndt:
|
||||
case FGAtmosphere::ttStandard:
|
||||
case FGAtmosphere::ttCulp: {
|
||||
Winds->SetTurbType((FGWinds::tType)TURBULENCE_TYPE_NAMES[turbulence_model->getStringValue()]);
|
||||
switch( Winds->GetTurbType() ) {
|
||||
case FGWinds::ttStandard:
|
||||
case FGWinds::ttCulp: {
|
||||
double tmp = turbulence_gain->getDoubleValue();
|
||||
Atmosphere->SetTurbGain(tmp * tmp * 100.0);
|
||||
Atmosphere->SetTurbRate(turbulence_rate->getDoubleValue());
|
||||
Winds->SetTurbGain(tmp * tmp * 100.0);
|
||||
Winds->SetTurbRate(turbulence_rate->getDoubleValue());
|
||||
break;
|
||||
}
|
||||
case FGAtmosphere::ttMilspec:
|
||||
case FGAtmosphere::ttTustin: {
|
||||
case FGWinds::ttMilspec:
|
||||
case FGWinds::ttTustin: {
|
||||
// milspec turbulence: 3=light, 4=moderate, 6=severe turbulence
|
||||
// turbulence_gain normalized: 0: none, 1/3: light, 2/3: moderate, 3/3: severe
|
||||
double tmp = turbulence_gain->getDoubleValue();
|
||||
Atmosphere->SetProbabilityOfExceedence(
|
||||
Winds->SetProbabilityOfExceedence(
|
||||
SGMiscd::roundToInt(TurbulenceSeverityTable.GetValue( tmp ) )
|
||||
);
|
||||
Atmosphere->SetWindspeed20ft(ground_wind->getDoubleValue());
|
||||
Winds->SetWindspeed20ft(ground_wind->getDoubleValue());
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -695,9 +692,9 @@ bool FGJSBsim::copy_to_JSBsim()
|
|||
break;
|
||||
}
|
||||
|
||||
Atmosphere->SetWindNED( -wind_from_north->getDoubleValue(),
|
||||
-wind_from_east->getDoubleValue(),
|
||||
-wind_from_down->getDoubleValue() );
|
||||
Winds->SetWindNED( -wind_from_north->getDoubleValue(),
|
||||
-wind_from_east->getDoubleValue(),
|
||||
-wind_from_down->getDoubleValue() );
|
||||
// SG_LOG(SG_FLIGHT,SG_INFO, "Wind NED: "
|
||||
// << get_V_north_airmass() << ", "
|
||||
// << get_V_east_airmass() << ", "
|
||||
|
@ -739,19 +736,19 @@ bool FGJSBsim::copy_from_JSBsim()
|
|||
MassBalance->GetXYZcg(2),
|
||||
MassBalance->GetXYZcg(3) );
|
||||
|
||||
_set_Accels_Body( Aircraft->GetBodyAccel(1),
|
||||
Aircraft->GetBodyAccel(2),
|
||||
Aircraft->GetBodyAccel(3) );
|
||||
_set_Accels_Body( Accelerations->GetBodyAccel(1),
|
||||
Accelerations->GetBodyAccel(2),
|
||||
Accelerations->GetBodyAccel(3) );
|
||||
|
||||
_set_Accels_CG_Body_N ( Aircraft->GetNcg(1),
|
||||
Aircraft->GetNcg(2),
|
||||
Aircraft->GetNcg(3) );
|
||||
_set_Accels_CG_Body_N ( Auxiliary->GetNcg(1),
|
||||
Auxiliary->GetNcg(2),
|
||||
Auxiliary->GetNcg(3) );
|
||||
|
||||
_set_Accels_Pilot_Body( Auxiliary->GetPilotAccel(1),
|
||||
Auxiliary->GetPilotAccel(2),
|
||||
Auxiliary->GetPilotAccel(3) );
|
||||
|
||||
_set_Nlf( Aircraft->GetNlf() );
|
||||
_set_Nlf( Auxiliary->GetNlf() );
|
||||
|
||||
// Velocities
|
||||
|
||||
|
@ -812,7 +809,7 @@ bool FGJSBsim::copy_from_JSBsim()
|
|||
|
||||
_set_Gamma_vert_rad( Auxiliary->GetGamma() );
|
||||
|
||||
_set_Earth_position_angle( Inertial->GetEarthPositionAngle() );
|
||||
_set_Earth_position_angle( Propagate->GetEarthPositionAngle() );
|
||||
|
||||
_set_Climb_Rate( Propagate->Gethdot() );
|
||||
|
||||
|
@ -1349,7 +1346,7 @@ bool FGJSBsim::update_ground_cache(FGLocation cart, double* cart_pos, double dt)
|
|||
<< fgic->GetAltitudeASLFtIC());
|
||||
|
||||
SG_LOG(SG_FLIGHT, SG_WARN, "sea level radius = "
|
||||
<< fgic->GetSeaLevelRadiusFtIC());
|
||||
<< get_Sea_level_radius());
|
||||
|
||||
SG_LOG(SG_FLIGHT, SG_WARN, "latitude = "
|
||||
<< fgic->GetLatitudeRadIC());
|
||||
|
|
|
@ -58,6 +58,7 @@ FORWARD DECLARATIONS
|
|||
|
||||
namespace JSBSim {
|
||||
class FGAtmosphere;
|
||||
class FGWinds;
|
||||
class FGFCS;
|
||||
class FGPropulsion;
|
||||
class FGMassBalance;
|
||||
|
@ -69,6 +70,7 @@ class FGAuxiliary;
|
|||
class FGOutput;
|
||||
class FGInitialCondition;
|
||||
class FGLocation;
|
||||
class FGAccelerations;
|
||||
}
|
||||
|
||||
// Adding it here will cause a namespace clash in FlightGear -EMH-
|
||||
|
@ -221,16 +223,18 @@ private:
|
|||
JSBSim::FGInitialCondition *fgic;
|
||||
bool needTrim;
|
||||
|
||||
JSBSim::FGAtmosphere* Atmosphere;
|
||||
JSBSim::FGFCS* FCS;
|
||||
JSBSim::FGPropulsion* Propulsion;
|
||||
JSBSim::FGMassBalance* MassBalance;
|
||||
JSBSim::FGAircraft* Aircraft;
|
||||
JSBSim::FGPropagate* Propagate;
|
||||
JSBSim::FGAuxiliary* Auxiliary;
|
||||
JSBSim::FGAerodynamics* Aerodynamics;
|
||||
JSBSim::FGAtmosphere* Atmosphere;
|
||||
JSBSim::FGWinds* Winds;
|
||||
JSBSim::FGFCS* FCS;
|
||||
JSBSim::FGPropulsion* Propulsion;
|
||||
JSBSim::FGMassBalance* MassBalance;
|
||||
JSBSim::FGAircraft* Aircraft;
|
||||
JSBSim::FGPropagate* Propagate;
|
||||
JSBSim::FGAuxiliary* Auxiliary;
|
||||
JSBSim::FGAerodynamics* Aerodynamics;
|
||||
JSBSim::FGGroundReactions* GroundReactions;
|
||||
JSBSim::FGInertial* Inertial;
|
||||
JSBSim::FGInertial* Inertial;
|
||||
JSBSim::FGAccelerations* Accelerations;
|
||||
|
||||
int runcount;
|
||||
double trim_elev;
|
||||
|
@ -269,6 +273,7 @@ private:
|
|||
|
||||
SGPropertyNode_ptr temperature;
|
||||
SGPropertyNode_ptr pressure;
|
||||
SGPropertyNode_ptr pressureSL;
|
||||
SGPropertyNode_ptr density;
|
||||
SGPropertyNode_ptr ground_wind;
|
||||
SGPropertyNode_ptr turbulence_gain;
|
||||
|
|
|
@ -44,6 +44,10 @@ you have chosen your IC's wisely) even after setting it up with this class.
|
|||
INCLUDES
|
||||
*******************************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "FGInitialCondition.h"
|
||||
#include "FGFDMExec.h"
|
||||
#include "math/FGQuaternion.h"
|
||||
|
@ -51,17 +55,15 @@ INCLUDES
|
|||
#include "models/FGAtmosphere.h"
|
||||
#include "models/FGPropagate.h"
|
||||
#include "models/FGPropulsion.h"
|
||||
#include "models/FGFCS.h"
|
||||
#include "input_output/FGPropertyManager.h"
|
||||
#include "input_output/string_utilities.h"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <cstdlib>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGInitialCondition.cpp,v 1.63 2011/06/13 10:30:22 bcoconni Exp $";
|
||||
static const char *IdSrc = "$Id: FGInitialCondition.cpp,v 1.69 2011/08/04 12:46:32 jberndt Exp $";
|
||||
static const char *IdHdr = ID_INITIALCONDITION;
|
||||
|
||||
//******************************************************************************
|
||||
|
@ -134,7 +136,7 @@ void FGInitialCondition::InitializeIC(void)
|
|||
terrain_elevation = 0;
|
||||
sea_level_radius = fdmex->GetInertial()->GetRefRadius();
|
||||
position.SetPosition(0., 0., sea_level_radius);
|
||||
position.SetEarthPositionAngle(fdmex->GetInertial()->GetEarthPositionAngle());
|
||||
position.SetEarthPositionAngle(fdmex->GetPropagate()->GetEarthPositionAngle());
|
||||
vUVW_NED.InitMatrix();
|
||||
p=q=r=0;
|
||||
vt=0;
|
||||
|
@ -587,8 +589,9 @@ void FGInitialCondition::SetCrossWindKtsIC(double cross)
|
|||
|
||||
// Gram-Schmidt process is used to remove the existing cross wind component
|
||||
_vWIND_NED -= DotProduct(_vWIND_NED, _vCROSS) * _vCROSS;
|
||||
// which is now replaced by the new value.
|
||||
_vWIND_NED += cross * _vCROSS;
|
||||
// Which is now replaced by the new value. The input cross wind is expected
|
||||
// in knots, so first convert to fps, which is the internal unit used.
|
||||
_vWIND_NED += (cross * ktstofps) * _vCROSS;
|
||||
_vt_NED = vUVW_NED + _vWIND_NED;
|
||||
vt = _vt_NED.Magnitude();
|
||||
|
||||
|
@ -604,13 +607,19 @@ void FGInitialCondition::SetHeadWindKtsIC(double head)
|
|||
{
|
||||
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
||||
FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
|
||||
FGColumnVector3 _vHEAD(cos(psi), sin(psi), 0.);
|
||||
// This is a head wind, so the direction vector for the wind
|
||||
// needs to be set opposite to the heading the aircraft
|
||||
// is taking. So, the cos and sin of the heading (psi)
|
||||
// are negated in the line below.
|
||||
FGColumnVector3 _vHEAD(-cos(psi), -sin(psi), 0.);
|
||||
|
||||
// Gram-Schmidt process is used to remove the existing head wind component
|
||||
_vWIND_NED -= DotProduct(_vWIND_NED, _vHEAD) * _vHEAD;
|
||||
// which is now replaced by the new value.
|
||||
_vWIND_NED += head * _vHEAD;
|
||||
// Which is now replaced by the new value. The input head wind is expected
|
||||
// in knots, so first convert to fps, which is the internal unit used.
|
||||
_vWIND_NED += (head * ktstofps) * _vHEAD;
|
||||
_vt_NED = vUVW_NED + _vWIND_NED;
|
||||
|
||||
vt = _vt_NED.Magnitude();
|
||||
|
||||
calcAeroAngles(_vt_NED);
|
||||
|
@ -644,9 +653,9 @@ void FGInitialCondition::SetWindMagKtsIC(double mag)
|
|||
double windMag = _vHEAD.Magnitude();
|
||||
|
||||
if (windMag > 0.001)
|
||||
_vHEAD *= mag / windMag;
|
||||
_vHEAD *= (mag*ktstofps) / windMag;
|
||||
else
|
||||
_vHEAD = FGColumnVector3(mag, 0., 0.);
|
||||
_vHEAD = FGColumnVector3((mag*ktstofps), 0., 0.);
|
||||
|
||||
_vWIND_NED(eU) = _vHEAD(eU);
|
||||
_vWIND_NED(eV) = _vHEAD(eV);
|
||||
|
@ -1028,7 +1037,7 @@ bool FGInitialCondition::Load_v2(void)
|
|||
{
|
||||
FGColumnVector3 vOrient;
|
||||
bool result = true;
|
||||
FGColumnVector3 vOmegaEarth = FGColumnVector3(0.0, 0.0, fdmex->GetInertial()->omega());
|
||||
FGColumnVector3 vOmegaEarth = fdmex->GetInertial()->GetOmegaPlanet();
|
||||
|
||||
if (document->FindElement("earth_position_angle"))
|
||||
position.SetEarthPositionAngle(document->FindElementValueAsNumberConvertTo("earth_position_angle", "RAD"));
|
||||
|
@ -1325,10 +1334,6 @@ void FGInitialCondition::bind(void)
|
|||
&FGInitialCondition::GetAltitudeAGLFtIC,
|
||||
&FGInitialCondition::SetAltitudeAGLFtIC,
|
||||
true);
|
||||
PropertyManager->Tie("ic/sea-level-radius-ft", this,
|
||||
&FGInitialCondition::GetSeaLevelRadiusFtIC,
|
||||
&FGInitialCondition::SetSeaLevelRadiusFtIC,
|
||||
true);
|
||||
PropertyManager->Tie("ic/terrain-elevation-ft", this,
|
||||
&FGInitialCondition::GetTerrainElevationFtIC,
|
||||
&FGInitialCondition::SetTerrainElevationFtIC,
|
||||
|
|
|
@ -54,7 +54,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_INITIALCONDITION "$Id: FGInitialCondition.h,v 1.27 2011/05/20 00:47:03 bcoconni Exp $"
|
||||
#define ID_INITIALCONDITION "$Id: FGInitialCondition.h,v 1.28 2011/07/10 19:03:49 jberndt Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -213,7 +213,7 @@ CLASS DOCUMENTATION
|
|||
@property ic/r-rad_sec (read/write) Yaw rate initial condition in radians/second
|
||||
|
||||
@author Tony Peden
|
||||
@version "$Id: FGInitialCondition.h,v 1.27 2011/05/20 00:47:03 bcoconni Exp $"
|
||||
@version "$Id: FGInitialCondition.h,v 1.28 2011/07/10 19:03:49 jberndt Exp $"
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -237,7 +237,7 @@ public:
|
|||
void SetVequivalentKtsIC(double ve);
|
||||
|
||||
/** Set true airspeed initial condition in knots.
|
||||
@param vt True airspeed in knots */
|
||||
@param vtrue True airspeed in knots */
|
||||
void SetVtrueKtsIC(double vtrue) { SetVtrueFpsIC(vtrue*ktstofps); }
|
||||
|
||||
/** Set ground speed initial condition in knots.
|
||||
|
@ -375,10 +375,6 @@ public:
|
|||
@return Initial altitude AGL in feet */
|
||||
double GetAltitudeAGLFtIC(void) const { return position.GetRadius() - sea_level_radius - terrain_elevation; }
|
||||
|
||||
/** Gets the initial sea level radius.
|
||||
@return Initial sea level radius */
|
||||
double GetSeaLevelRadiusFtIC(void) const { return sea_level_radius; }
|
||||
|
||||
/** Gets the initial terrain elevation.
|
||||
@return Initial terrain elevation in feet */
|
||||
double GetTerrainElevationFtIC(void) const { return terrain_elevation; }
|
||||
|
|
|
@ -43,19 +43,20 @@ INCLUDES
|
|||
#include "models/FGAtmosphere.h"
|
||||
#include "FGInitialCondition.h"
|
||||
#include "FGTrimAxis.h"
|
||||
#include "models/FGAircraft.h"
|
||||
#include "models/FGPropulsion.h"
|
||||
#include "models/FGAerodynamics.h"
|
||||
#include "models/FGFCS.h"
|
||||
#include "models/propulsion/FGEngine.h"
|
||||
#include "models/FGAuxiliary.h"
|
||||
#include "models/FGGroundReactions.h"
|
||||
#include "models/FGPropagate.h"
|
||||
#include "models/FGAccelerations.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGTrimAxis.cpp,v 1.10 2010/07/08 11:36:28 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGTrimAxis.cpp,v 1.13 2011/07/28 12:48:19 jberndt Exp $";
|
||||
static const char *IdHdr = ID_TRIMAXIS;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
@ -167,14 +168,14 @@ FGTrimAxis::~FGTrimAxis(void)
|
|||
|
||||
void FGTrimAxis::getState(void) {
|
||||
switch(state) {
|
||||
case tUdot: state_value=fdmex->GetPropagate()->GetUVWdot(1)-state_target; break;
|
||||
case tVdot: state_value=fdmex->GetPropagate()->GetUVWdot(2)-state_target; break;
|
||||
case tWdot: state_value=fdmex->GetPropagate()->GetUVWdot(3)-state_target; break;
|
||||
case tQdot: state_value=fdmex->GetPropagate()->GetPQRdot(2)-state_target;break;
|
||||
case tPdot: state_value=fdmex->GetPropagate()->GetPQRdot(1)-state_target; break;
|
||||
case tRdot: state_value=fdmex->GetPropagate()->GetPQRdot(3)-state_target; break;
|
||||
case tUdot: state_value=fdmex->GetAccelerations()->GetUVWdot(1)-state_target; break;
|
||||
case tVdot: state_value=fdmex->GetAccelerations()->GetUVWdot(2)-state_target; break;
|
||||
case tWdot: state_value=fdmex->GetAccelerations()->GetUVWdot(3)-state_target; break;
|
||||
case tQdot: state_value=fdmex->GetAccelerations()->GetPQRdot(2)-state_target;break;
|
||||
case tPdot: state_value=fdmex->GetAccelerations()->GetPQRdot(1)-state_target; break;
|
||||
case tRdot: state_value=fdmex->GetAccelerations()->GetPQRdot(3)-state_target; break;
|
||||
case tHmgt: state_value=computeHmgt()-state_target; break;
|
||||
case tNlf: state_value=fdmex->GetAircraft()->GetNlf()-state_target; break;
|
||||
case tNlf: state_value=fdmex->GetAuxiliary()->GetNlf()-state_target; break;
|
||||
case tAll: break;
|
||||
}
|
||||
}
|
||||
|
@ -423,9 +424,12 @@ void FGTrimAxis::setThrottlesPct(void) {
|
|||
for(unsigned i=0;i<fdmex->GetPropulsion()->GetNumEngines();i++) {
|
||||
tMin=fdmex->GetPropulsion()->GetEngine(i)->GetThrottleMin();
|
||||
tMax=fdmex->GetPropulsion()->GetEngine(i)->GetThrottleMax();
|
||||
//cout << "setThrottlespct: " << i << ", " << control_min << ", " << control_max << ", " << control_value;
|
||||
|
||||
// Both the main throttle setting in FGFCS and the copy of the position
|
||||
// in the Propulsion::Inputs structure need to be set at this time.
|
||||
fdmex->GetFCS()->SetThrottleCmd(i,tMin+control_value*(tMax-tMin));
|
||||
//cout << "setThrottlespct: " << fdmex->GetFCS()->GetThrottleCmd(i) << endl;
|
||||
fdmex->GetPropulsion()->in.ThrottlePos[i] = tMin +control_value*(tMax - tMin);
|
||||
|
||||
fdmex->RunIC(); //apply throttle change
|
||||
fdmex->GetPropulsion()->GetSteadyState();
|
||||
}
|
||||
|
|
|
@ -41,20 +41,21 @@ COMMENTS, REFERENCES, and NOTES
|
|||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
#include <iomanip>
|
||||
|
||||
#include "FGScript.h"
|
||||
#include "input_output/FGXMLElement.h"
|
||||
#include "input_output/FGXMLParse.h"
|
||||
#include "initialization/FGTrim.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
#include <iomanip>
|
||||
#include "models/FGInput.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGScript.cpp,v 1.46 2011/02/18 12:44:16 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGScript.cpp,v 1.48 2011/09/07 02:36:04 jberndt Exp $";
|
||||
static const char *IdHdr = ID_FGSCRIPT;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -379,7 +380,12 @@ bool FGScript::RunScript(void)
|
|||
for (i=0; i<Events[ev_ctr].SetValue.size(); i++) {
|
||||
Events[ev_ctr].OriginalValue[i] = Events[ev_ctr].SetParam[i]->getDoubleValue();
|
||||
if (Events[ev_ctr].Functions[i] != 0) { // Parameter should be set to a function value
|
||||
Events[ev_ctr].SetValue[i] = Events[ev_ctr].Functions[i]->GetValue();
|
||||
try {
|
||||
Events[ev_ctr].SetValue[i] = Events[ev_ctr].Functions[i]->GetValue();
|
||||
} catch (string msg) {
|
||||
std::cerr << std::endl << "A problem occurred in the execution of the script. " << msg << endl;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
switch (Events[ev_ctr].Type[i]) {
|
||||
case FG_VALUE:
|
||||
|
|
|
@ -37,18 +37,19 @@ SENTRY
|
|||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include "FGJSBBase.h"
|
||||
#include <vector>
|
||||
|
||||
#include "FGFDMExec.h"
|
||||
#include "FGJSBBase.h"
|
||||
#include "math/FGFunction.h"
|
||||
#include "math/FGCondition.h"
|
||||
#include <vector>
|
||||
#include "input_output/FGXMLFileRead.h"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_FGSCRIPT "$Id: FGScript.h,v 1.20 2011/02/11 12:43:28 jberndt Exp $"
|
||||
#define ID_FGSCRIPT "$Id: FGScript.h,v 1.21 2011/08/04 12:46:32 jberndt Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -157,7 +158,7 @@ CLASS DOCUMENTATION
|
|||
comes the "run" section, where the conditions are
|
||||
described in "event" clauses.</p>
|
||||
@author Jon S. Berndt
|
||||
@version "$Id: FGScript.h,v 1.20 2011/02/11 12:43:28 jberndt Exp $"
|
||||
@version "$Id: FGScript.h,v 1.21 2011/08/04 12:46:32 jberndt Exp $"
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -42,7 +42,7 @@ FORWARD DECLARATIONS
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGXMLElement.cpp,v 1.32 2011/02/13 00:42:45 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGXMLElement.cpp,v 1.33 2011/08/05 12:28:20 jberndt Exp $";
|
||||
static const char *IdHdr = ID_XMLELEMENT;
|
||||
|
||||
bool Element::converterIsInitialized = false;
|
||||
|
@ -64,6 +64,8 @@ Element::Element(const string& nm)
|
|||
// Length
|
||||
convert["M"]["FT"] = 3.2808399;
|
||||
convert["FT"]["M"] = 1.0/convert["M"]["FT"];
|
||||
convert["CM"]["FT"] = 0.032808399;
|
||||
convert["FT"]["CM"] = 1.0/convert["CM"]["FT"];
|
||||
convert["KM"]["FT"] = 3280.8399;
|
||||
convert["FT"]["KM"] = 1.0/convert["KM"]["FT"];
|
||||
convert["FT"]["IN"] = 12.0;
|
||||
|
@ -73,6 +75,8 @@ Element::Element(const string& nm)
|
|||
// Area
|
||||
convert["M2"]["FT2"] = convert["M"]["FT"]*convert["M"]["FT"];
|
||||
convert["FT2"]["M2"] = 1.0/convert["M2"]["FT2"];
|
||||
convert["CM2"]["FT2"] = convert["CM"]["FT"]*convert["CM"]["FT"];
|
||||
convert["FT2"]["CM2"] = 1.0/convert["CM2"]["FT2"];
|
||||
convert["M2"]["IN2"] = convert["M"]["IN"]*convert["M"]["IN"];
|
||||
convert["IN2"]["M2"] = 1.0/convert["M2"]["IN2"];
|
||||
convert["FT2"]["IN2"] = 144.0;
|
||||
|
|
|
@ -43,13 +43,65 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGFunction.cpp,v 1.36 2011/04/05 20:20:21 andgi Exp $";
|
||||
static const char *IdSrc = "$Id: FGFunction.cpp,v 1.42 2011/09/07 02:36:04 jberndt Exp $";
|
||||
static const char *IdHdr = ID_FUNCTION;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS IMPLEMENTATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
const std::string FGFunction::property_string = "property";
|
||||
const std::string FGFunction::value_string = "value";
|
||||
const std::string FGFunction::table_string = "table";
|
||||
const std::string FGFunction::p_string = "p";
|
||||
const std::string FGFunction::v_string = "v";
|
||||
const std::string FGFunction::t_string = "t";
|
||||
|
||||
const std::string FGFunction::function_string = "function";
|
||||
const std::string FGFunction::description_string = "description";
|
||||
const std::string FGFunction::sum_string = "sum";
|
||||
const std::string FGFunction::difference_string = "difference";
|
||||
const std::string FGFunction::product_string = "product";
|
||||
const std::string FGFunction::quotient_string = "quotient";
|
||||
const std::string FGFunction::pow_string = "pow";
|
||||
const std::string FGFunction::exp_string = "exp";
|
||||
const std::string FGFunction::log2_string = "log2";
|
||||
const std::string FGFunction::ln_string = "ln";
|
||||
const std::string FGFunction::log10_string = "log10";
|
||||
const std::string FGFunction::abs_string = "abs";
|
||||
const std::string FGFunction::sign_string = "sign";
|
||||
const std::string FGFunction::sin_string = "sin";
|
||||
const std::string FGFunction::cos_string = "cos";
|
||||
const std::string FGFunction::tan_string = "tan";
|
||||
const std::string FGFunction::asin_string = "asin";
|
||||
const std::string FGFunction::acos_string = "acos";
|
||||
const std::string FGFunction::atan_string = "atan";
|
||||
const std::string FGFunction::atan2_string = "atan2";
|
||||
const std::string FGFunction::min_string = "min";
|
||||
const std::string FGFunction::max_string = "max";
|
||||
const std::string FGFunction::avg_string = "avg";
|
||||
const std::string FGFunction::fraction_string = "fraction";
|
||||
const std::string FGFunction::mod_string = "mod";
|
||||
const std::string FGFunction::random_string = "random";
|
||||
const std::string FGFunction::integer_string = "integer";
|
||||
const std::string FGFunction::rotation_alpha_local_string = "rotation_alpha_local";
|
||||
const std::string FGFunction::rotation_beta_local_string = "rotation_beta_local";
|
||||
const std::string FGFunction::rotation_gamma_local_string = "rotation_gamma_local";
|
||||
const std::string FGFunction::rotation_bf_to_wf_string = "rotation_bf_to_wf";
|
||||
const std::string FGFunction::rotation_wf_to_bf_string = "rotation_wf_to_bf";
|
||||
|
||||
const std::string FGFunction::lessthan_string = "lt";
|
||||
const std::string FGFunction::lessequal_string = "le";
|
||||
const std::string FGFunction::greatthan_string = "gt";
|
||||
const std::string FGFunction::greatequal_string = "ge";
|
||||
const std::string FGFunction::equal_string = "eq";
|
||||
const std::string FGFunction::notequal_string = "nq";
|
||||
const std::string FGFunction::and_string = "and";
|
||||
const std::string FGFunction::or_string = "or";
|
||||
const std::string FGFunction::not_string = "not";
|
||||
const std::string FGFunction::ifthen_string = "ifthen";
|
||||
const std::string FGFunction::switch_string = "switch";
|
||||
|
||||
FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, const string& prefix)
|
||||
: PropertyManager(propMan), Prefix(prefix)
|
||||
{
|
||||
|
@ -59,40 +111,6 @@ FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, const string& pr
|
|||
cachedValue = -HUGE_VAL;
|
||||
invlog2val = 1.0/log10(2.0);
|
||||
|
||||
property_string = "property";
|
||||
value_string = "value";
|
||||
table_string = "table";
|
||||
p_string = "p";
|
||||
v_string = "v";
|
||||
t_string = "t";
|
||||
|
||||
function_string = "function";
|
||||
description_string = "description";
|
||||
sum_string = "sum";
|
||||
difference_string = "difference";
|
||||
product_string = "product";
|
||||
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";
|
||||
tan_string = "tan";
|
||||
asin_string = "asin";
|
||||
acos_string = "acos";
|
||||
atan_string = "atan";
|
||||
atan2_string = "atan2";
|
||||
min_string = "min";
|
||||
max_string = "max";
|
||||
avg_string = "avg";
|
||||
fraction_string = "fraction";
|
||||
mod_string = "mod";
|
||||
random_string = "random";
|
||||
integer_string = "integer";
|
||||
|
||||
Name = el->GetAttributeValue("name");
|
||||
operation = el->GetName();
|
||||
|
||||
|
@ -116,6 +134,8 @@ FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, const string& pr
|
|||
Type = eLog10;
|
||||
} else if (operation == abs_string) {
|
||||
Type = eAbs;
|
||||
} else if (operation == sign_string) {
|
||||
Type = eSign;
|
||||
} else if (operation == sin_string) {
|
||||
Type = eSin;
|
||||
} else if (operation == exp_string) {
|
||||
|
@ -146,6 +166,38 @@ FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, const string& pr
|
|||
Type = eMod;
|
||||
} else if (operation == random_string) {
|
||||
Type = eRandom;
|
||||
} else if (operation == rotation_alpha_local_string) {
|
||||
Type = eRotation_alpha_local;
|
||||
} else if (operation == rotation_beta_local_string) {
|
||||
Type = eRotation_beta_local;
|
||||
} else if (operation == rotation_gamma_local_string) {
|
||||
Type = eRotation_gamma_local;
|
||||
} else if (operation == rotation_bf_to_wf_string) {
|
||||
Type = eRotation_bf_to_wf;
|
||||
} else if (operation == rotation_wf_to_bf_string) {
|
||||
Type = eRotation_wf_to_bf;
|
||||
} else if (operation == lessthan_string) {
|
||||
Type = eLT;
|
||||
} else if (operation == lessequal_string) {
|
||||
Type = eLE;
|
||||
} else if (operation == greatthan_string) {
|
||||
Type = eGT;
|
||||
} else if (operation == greatequal_string) {
|
||||
Type = eGE;
|
||||
} else if (operation == equal_string) {
|
||||
Type = eEQ;
|
||||
} else if (operation == notequal_string) {
|
||||
Type = eNE;
|
||||
} else if (operation == and_string) {
|
||||
Type = eAND;
|
||||
} else if (operation == or_string) {
|
||||
Type = eOR;
|
||||
} else if (operation == not_string) {
|
||||
Type = eNOT;
|
||||
} else if (operation == ifthen_string) {
|
||||
Type = eIfThen;
|
||||
} else if (operation == switch_string) {
|
||||
Type = eSwitch;
|
||||
} else if (operation != description_string) {
|
||||
cerr << "Bad operation " << operation << " detected in configuration file" << endl;
|
||||
}
|
||||
|
@ -197,6 +249,7 @@ FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, const string& pr
|
|||
operation == ln_string ||
|
||||
operation == log10_string ||
|
||||
operation == abs_string ||
|
||||
operation == sign_string ||
|
||||
operation == sin_string ||
|
||||
operation == cos_string ||
|
||||
operation == tan_string ||
|
||||
|
@ -210,7 +263,23 @@ FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, const string& pr
|
|||
operation == integer_string ||
|
||||
operation == mod_string ||
|
||||
operation == random_string ||
|
||||
operation == avg_string )
|
||||
operation == avg_string ||
|
||||
operation == rotation_alpha_local_string||
|
||||
operation == rotation_beta_local_string||
|
||||
operation == rotation_gamma_local_string||
|
||||
operation == rotation_bf_to_wf_string||
|
||||
operation == rotation_wf_to_bf_string ||
|
||||
operation == lessthan_string ||
|
||||
operation == lessequal_string ||
|
||||
operation == greatthan_string ||
|
||||
operation == greatequal_string ||
|
||||
operation == equal_string ||
|
||||
operation == notequal_string ||
|
||||
operation == and_string ||
|
||||
operation == or_string ||
|
||||
operation == not_string ||
|
||||
operation == ifthen_string ||
|
||||
operation == switch_string)
|
||||
{
|
||||
Parameters.push_back(new FGFunction(PropertyManager, element, Prefix));
|
||||
} else if (operation != description_string) {
|
||||
|
@ -245,6 +314,18 @@ void FGFunction::cacheValue(bool cache)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
unsigned int FGFunction::GetBinary(double val) const
|
||||
{
|
||||
val = fabs(val);
|
||||
if (val < 1E-9) return 0;
|
||||
else if (val-1 < 1E-9) return 1;
|
||||
else {
|
||||
throw("Malformed conditional check in function definition.");
|
||||
}
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGFunction::GetValue(void) const
|
||||
{
|
||||
unsigned int i;
|
||||
|
@ -300,6 +381,9 @@ double FGFunction::GetValue(void) const
|
|||
case eAbs:
|
||||
temp = fabs(temp);
|
||||
break;
|
||||
case eSign:
|
||||
temp = temp < 0 ? -1:1; // 0.0 counts as positive.
|
||||
break;
|
||||
case eSin:
|
||||
temp = sin(temp);
|
||||
break;
|
||||
|
@ -350,6 +434,262 @@ double FGFunction::GetValue(void) const
|
|||
case eRandom:
|
||||
temp = GaussianRandomNumber();
|
||||
break;
|
||||
case eLT:
|
||||
temp = (temp < Parameters[1]->GetValue())?1:0;
|
||||
break;
|
||||
case eLE:
|
||||
temp = (temp <= Parameters[1]->GetValue())?1:0;
|
||||
break;
|
||||
case eGT:
|
||||
temp = (temp > Parameters[1]->GetValue())?1:0;
|
||||
break;
|
||||
case eGE:
|
||||
temp = (temp >= Parameters[1]->GetValue())?1:0;
|
||||
break;
|
||||
case eEQ:
|
||||
temp = (temp == Parameters[1]->GetValue())?1:0;
|
||||
break;
|
||||
case eNE:
|
||||
temp = (temp != Parameters[1]->GetValue())?1:0;
|
||||
break;
|
||||
case eAND:
|
||||
{
|
||||
bool flag = (GetBinary(temp) != 0u);
|
||||
for (i=1; i<Parameters.size() && flag; i++) {
|
||||
flag = (GetBinary(Parameters[i]->GetValue()) != 0);
|
||||
}
|
||||
temp = flag ? 1 : 0;
|
||||
}
|
||||
break;
|
||||
case eOR:
|
||||
{
|
||||
bool flag = (GetBinary(temp) != 0);
|
||||
for (i=1; i<Parameters.size() && !flag; i++) {
|
||||
flag = (GetBinary(Parameters[i]->GetValue()) != 0);
|
||||
}
|
||||
temp = flag ? 1 : 0;
|
||||
}
|
||||
break;
|
||||
case eNOT:
|
||||
temp = (GetBinary(temp) != 0) ? 0 : 1;
|
||||
break;
|
||||
case eIfThen:
|
||||
{
|
||||
i = Parameters.size();
|
||||
if (i != 3) {
|
||||
if (GetBinary(temp) == 1) {
|
||||
temp = Parameters[1]->GetValue();
|
||||
} else {
|
||||
temp = Parameters[2]->GetValue();
|
||||
}
|
||||
} else {
|
||||
throw("Malformed if/then function statement");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case eSwitch:
|
||||
{
|
||||
unsigned int n = Parameters.size()-1;
|
||||
i = int(temp+0.5);
|
||||
if (i >= 0u && i < n) {
|
||||
temp = Parameters[i+1]->GetValue();
|
||||
} else {
|
||||
throw(string("The switch function index selected a value above the range of supplied values"
|
||||
" - not enough values were supplied."));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case eRotation_alpha_local:
|
||||
if (Parameters.size()==6) // calculates local angle of attack for skydiver body component
|
||||
//Euler angles from the intermediate body frame to the local body frame must be from a z-y-x axis rotation order
|
||||
{
|
||||
double alpha = Parameters[0]->GetValue()*degtorad;
|
||||
double beta = Parameters[1]->GetValue()*degtorad;
|
||||
double gamma = Parameters[2]->GetValue()*degtorad;
|
||||
double phi = Parameters[3]->GetValue()*degtorad;
|
||||
double theta = Parameters[4]->GetValue()*degtorad;
|
||||
double psi = Parameters[5]->GetValue()*degtorad;
|
||||
double cphi2 = cos(-phi/2), ctht2 = cos(-theta/2), cpsi2 = cos(-psi/2);
|
||||
double sphi2 = sin(-phi/2), stht2 = sin(-theta/2), spsi2 = sin(-psi/2);
|
||||
double calpha2 = cos(-alpha/2), salpha2 = sin(-alpha/2);
|
||||
double cbeta2 = cos(beta/2), sbeta2 = sin(beta/2);
|
||||
double cgamma2 = cos(-gamma/2), sgamma2 = sin(-gamma/2);
|
||||
//calculate local body frame to the intermediate body frame rotation quaternion
|
||||
double At = cphi2*ctht2*cpsi2 - sphi2*stht2*spsi2;
|
||||
double Ax = cphi2*stht2*spsi2 + sphi2*ctht2*cpsi2;
|
||||
double Ay = cphi2*stht2*cpsi2 - sphi2*ctht2*spsi2;
|
||||
double Az = cphi2*ctht2*spsi2 + sphi2*stht2*cpsi2;
|
||||
//calculate the intermediate body frame to global wind frame rotation quaternion
|
||||
double Bt = calpha2*cbeta2*cgamma2 - salpha2*sbeta2*sgamma2;
|
||||
double Bx = calpha2*cbeta2*sgamma2 + salpha2*sbeta2*cgamma2;
|
||||
double By = calpha2*sbeta2*sgamma2 + salpha2*cbeta2*cgamma2;
|
||||
double Bz = calpha2*sbeta2*cgamma2 - salpha2*cbeta2*sgamma2;
|
||||
//multiply quaternions
|
||||
double Ct = At*Bt - Ax*Bx - Ay*By - Az*Bz;
|
||||
double Cx = At*Bx + Ax*Bt + Ay*Bz - Az*By;
|
||||
double Cy = At*By - Ax*Bz + Ay*Bt + Az*Bx;
|
||||
double Cz = At*Bz + Ax*By - Ay*Bx + Az*Bt;
|
||||
//calculate alpha_local
|
||||
temp = -atan2(2*(Cy*Ct-Cx*Cz),(Ct*Ct+Cx*Cx-Cy*Cy-Cz*Cz));
|
||||
temp *= radtodeg;
|
||||
} else {
|
||||
temp = 1;
|
||||
}
|
||||
break;
|
||||
case eRotation_beta_local:
|
||||
if (Parameters.size()==6) // calculates local angle of sideslip for skydiver body component
|
||||
//Euler angles from the intermediate body frame to the local body frame must be from a z-y-x axis rotation order
|
||||
{
|
||||
double alpha = Parameters[0]->GetValue()*degtorad; //angle of attack of intermediate body frame
|
||||
double beta = Parameters[1]->GetValue()*degtorad; //sideslip angle of intermediate body frame
|
||||
double gamma = Parameters[2]->GetValue()*degtorad; //roll angle of intermediate body frame
|
||||
double phi = Parameters[3]->GetValue()*degtorad; //x-axis Euler angle from the intermediate body frame to the local body frame
|
||||
double theta = Parameters[4]->GetValue()*degtorad; //y-axis Euler angle from the intermediate body frame to the local body frame
|
||||
double psi = Parameters[5]->GetValue()*degtorad; //z-axis Euler angle from the intermediate body frame to the local body frame
|
||||
double cphi2 = cos(-phi/2), ctht2 = cos(-theta/2), cpsi2 = cos(-psi/2);
|
||||
double sphi2 = sin(-phi/2), stht2 = sin(-theta/2), spsi2 = sin(-psi/2);
|
||||
double calpha2 = cos(-alpha/2), salpha2 = sin(-alpha/2);
|
||||
double cbeta2 = cos(beta/2), sbeta2 = sin(beta/2);
|
||||
double cgamma2 = cos(-gamma/2), sgamma2 = sin(-gamma/2);
|
||||
//calculate local body frame to the intermediate body frame rotation quaternion
|
||||
double At = cphi2*ctht2*cpsi2 - sphi2*stht2*spsi2;
|
||||
double Ax = cphi2*stht2*spsi2 + sphi2*ctht2*cpsi2;
|
||||
double Ay = cphi2*stht2*cpsi2 - sphi2*ctht2*spsi2;
|
||||
double Az = cphi2*ctht2*spsi2 + sphi2*stht2*cpsi2;
|
||||
//calculate the intermediate body frame to global wind frame rotation quaternion
|
||||
double Bt = calpha2*cbeta2*cgamma2 - salpha2*sbeta2*sgamma2;
|
||||
double Bx = calpha2*cbeta2*sgamma2 + salpha2*sbeta2*cgamma2;
|
||||
double By = calpha2*sbeta2*sgamma2 + salpha2*cbeta2*cgamma2;
|
||||
double Bz = calpha2*sbeta2*cgamma2 - salpha2*cbeta2*sgamma2;
|
||||
//multiply quaternions
|
||||
double Ct = At*Bt - Ax*Bx - Ay*By - Az*Bz;
|
||||
double Cx = At*Bx + Ax*Bt + Ay*Bz - Az*By;
|
||||
double Cy = At*By - Ax*Bz + Ay*Bt + Az*Bx;
|
||||
double Cz = At*Bz + Ax*By - Ay*Bx + Az*Bt;
|
||||
//calculate beta_local
|
||||
temp = asin(2*(Cx*Cy+Cz*Ct));
|
||||
temp *= radtodeg;
|
||||
}
|
||||
else //
|
||||
{temp = 1;}
|
||||
break;
|
||||
case eRotation_gamma_local:
|
||||
if (Parameters.size()==6) // calculates local angle of attack for skydiver body component
|
||||
//Euler angles from the intermediate body frame to the local body frame must be from a z-y-x axis rotation order
|
||||
{
|
||||
double alpha = Parameters[0]->GetValue()*degtorad; //angle of attack of intermediate body frame
|
||||
double beta = Parameters[1]->GetValue()*degtorad; //sideslip angle of intermediate body frame
|
||||
double gamma = Parameters[2]->GetValue()*degtorad; //roll angle of intermediate body frame
|
||||
double phi = Parameters[3]->GetValue()*degtorad; //x-axis Euler angle from the intermediate body frame to the local body frame
|
||||
double theta = Parameters[4]->GetValue()*degtorad; //y-axis Euler angle from the intermediate body frame to the local body frame
|
||||
double psi = Parameters[5]->GetValue()*degtorad; //z-axis Euler angle from the intermediate body frame to the local body frame
|
||||
double cphi2 = cos(-phi/2), ctht2 = cos(-theta/2), cpsi2 = cos(-psi/2);
|
||||
double sphi2 = sin(-phi/2), stht2 = sin(-theta/2), spsi2 = sin(-psi/2);
|
||||
double calpha2 = cos(-alpha/2), salpha2 = sin(-alpha/2);
|
||||
double cbeta2 = cos(beta/2), sbeta2 = sin(beta/2);
|
||||
double cgamma2 = cos(-gamma/2), sgamma2 = sin(-gamma/2);
|
||||
//calculate local body frame to the intermediate body frame rotation quaternion
|
||||
double At = cphi2*ctht2*cpsi2 - sphi2*stht2*spsi2;
|
||||
double Ax = cphi2*stht2*spsi2 + sphi2*ctht2*cpsi2;
|
||||
double Ay = cphi2*stht2*cpsi2 - sphi2*ctht2*spsi2;
|
||||
double Az = cphi2*ctht2*spsi2 + sphi2*stht2*cpsi2;
|
||||
//calculate the intermediate body frame to global wind frame rotation quaternion
|
||||
double Bt = calpha2*cbeta2*cgamma2 - salpha2*sbeta2*sgamma2;
|
||||
double Bx = calpha2*cbeta2*sgamma2 + salpha2*sbeta2*cgamma2;
|
||||
double By = calpha2*sbeta2*sgamma2 + salpha2*cbeta2*cgamma2;
|
||||
double Bz = calpha2*sbeta2*cgamma2 - salpha2*cbeta2*sgamma2;
|
||||
//multiply quaternions
|
||||
double Ct = At*Bt - Ax*Bx - Ay*By - Az*Bz;
|
||||
double Cx = At*Bx + Ax*Bt + Ay*Bz - Az*By;
|
||||
double Cy = At*By - Ax*Bz + Ay*Bt + Az*Bx;
|
||||
double Cz = At*Bz + Ax*By - Ay*Bx + Az*Bt;
|
||||
//calculate local roll anlge
|
||||
temp = -atan2(2*(Cx*Ct-Cz*Cy),(Ct*Ct-Cx*Cx+Cy*Cy-Cz*Cz));
|
||||
temp *= radtodeg;
|
||||
}
|
||||
else //
|
||||
{temp = 1;}
|
||||
break;
|
||||
case eRotation_bf_to_wf:
|
||||
if (Parameters.size()==7) // transforms the input vector from a body frame to a wind frame. The origin of the vector remains the same.
|
||||
{
|
||||
double rx = Parameters[0]->GetValue(); //x component of input vector
|
||||
double ry = Parameters[1]->GetValue(); //y component of input vector
|
||||
double rz = Parameters[2]->GetValue(); //z component of input vector
|
||||
double alpha = Parameters[3]->GetValue()*degtorad; //angle of attack of the body frame
|
||||
double beta = Parameters[4]->GetValue()*degtorad; //sideslip angle of the body frame
|
||||
double gamma = Parameters[5]->GetValue()*degtorad; //roll angle of the body frame
|
||||
double index = Parameters[6]->GetValue();
|
||||
double calpha2 = cos(-alpha/2), salpha2 = sin(-alpha/2);
|
||||
double cbeta2 = cos(beta/2), sbeta2 = sin(beta/2);
|
||||
double cgamma2 = cos(-gamma/2), sgamma2 = sin(-gamma/2);
|
||||
//calculate the body frame to wind frame quaternion
|
||||
double qt = calpha2*cbeta2*cgamma2 - salpha2*sbeta2*sgamma2;
|
||||
double qx = calpha2*cbeta2*sgamma2 + salpha2*sbeta2*cgamma2;
|
||||
double qy = calpha2*sbeta2*sgamma2 + salpha2*cbeta2*cgamma2;
|
||||
double qz = calpha2*sbeta2*cgamma2 - salpha2*cbeta2*sgamma2;
|
||||
//calculate the quaternion conjugate
|
||||
double qstart = qt;
|
||||
double qstarx = -qx;
|
||||
double qstary = -qy;
|
||||
double qstarz = -qz;
|
||||
//multiply quaternions v*q
|
||||
double vqt = -rx*qx - ry*qy - rz*qz;
|
||||
double vqx = rx*qt + ry*qz - rz*qy;
|
||||
double vqy = -rx*qz + ry*qt + rz*qx;
|
||||
double vqz = rx*qy - ry*qx + rz*qt;
|
||||
//multiply quaternions qstar*vq
|
||||
double Cx = qstart*vqx + qstarx*vqt + qstary*vqz - qstarz*vqy;
|
||||
double Cy = qstart*vqy - qstarx*vqz + qstary*vqt + qstarz*vqx;
|
||||
double Cz = qstart*vqz + qstarx*vqy - qstary*vqx + qstarz*vqt;
|
||||
|
||||
if (index == 1) temp = Cx;
|
||||
else if (index ==2) temp = Cy;
|
||||
else temp = Cz;
|
||||
}
|
||||
else //
|
||||
{temp = 1;}
|
||||
break;
|
||||
case eRotation_wf_to_bf:
|
||||
if (Parameters.size()==7) // transforms the input vector from q wind frame to a body frame. The origin of the vector remains the same.
|
||||
{
|
||||
double rx = Parameters[0]->GetValue(); //x component of input vector
|
||||
double ry = Parameters[1]->GetValue(); //y component of input vector
|
||||
double rz = Parameters[2]->GetValue(); //z component of input vector
|
||||
double alpha = Parameters[3]->GetValue()*degtorad; //angle of attack of the body frame
|
||||
double beta = Parameters[4]->GetValue()*degtorad; //sideslip angle of the body frame
|
||||
double gamma = Parameters[5]->GetValue()*degtorad; //roll angle of the body frame
|
||||
double index = Parameters[6]->GetValue();
|
||||
double calpha2 = cos(alpha/2), salpha2 = sin(alpha/2);
|
||||
double cbeta2 = cos(-beta/2), sbeta2 = sin(-beta/2);
|
||||
double cgamma2 = cos(gamma/2), sgamma2 = sin(gamma/2);
|
||||
//calculate the wind frame to body frame quaternion
|
||||
double qt = cgamma2*cbeta2*calpha2 + sgamma2*sbeta2*salpha2;
|
||||
double qx = -cgamma2*sbeta2*salpha2 + sgamma2*cbeta2*calpha2;
|
||||
double qy = cgamma2*cbeta2*salpha2 - sgamma2*sbeta2*calpha2;
|
||||
double qz = cgamma2*sbeta2*calpha2 + sgamma2*cbeta2*salpha2;
|
||||
//calculate the quaternion conjugate
|
||||
double qstart = qt;
|
||||
double qstarx = -qx;
|
||||
double qstary = -qy;
|
||||
double qstarz = -qz;
|
||||
//multiply quaternions v*q
|
||||
double vqt = -rx*qx - ry*qy - rz*qz;
|
||||
double vqx = rx*qt + ry*qz - rz*qy;
|
||||
double vqy = -rx*qz + ry*qt + rz*qx;
|
||||
double vqz = rx*qy - ry*qx + rz*qt;
|
||||
//multiply quaternions qstar*vq
|
||||
double Cx = qstart*vqx + qstarx*vqt + qstary*vqz - qstarz*vqy;
|
||||
double Cy = qstart*vqy - qstarx*vqz + qstary*vqt + qstarz*vqx;
|
||||
double Cz = qstart*vqz + qstarx*vqy - qstary*vqx + qstarz*vqt;
|
||||
|
||||
if (index == 1) temp = Cx;
|
||||
else if (index ==2) temp = Cy;
|
||||
else temp = Cz;
|
||||
}
|
||||
else //
|
||||
{temp = 1;}
|
||||
break;
|
||||
default:
|
||||
cerr << "Unknown function operation type" << endl;
|
||||
break;
|
||||
|
|
103
src/FDM/JSBSim/math/FGFunction.h
Normal file → Executable file
103
src/FDM/JSBSim/math/FGFunction.h
Normal file → Executable file
|
@ -42,7 +42,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_FUNCTION "$Id: FGFunction.h,v 1.21 2009/11/18 04:49:02 jberndt Exp $"
|
||||
#define ID_FUNCTION "$Id: FGFunction.h,v 1.24 2011/08/06 13:10:00 jberndt Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -86,6 +86,17 @@ A function definition consists of an operation, a value, a table, or a property
|
|||
- avg (takes n args)
|
||||
- fraction
|
||||
- mod
|
||||
- lt (less than, takes 2 args)
|
||||
- le (less equal, takes 2 args)
|
||||
- gt (greater than, takes 2 args)
|
||||
- ge (greater than, takes 2 args)
|
||||
- eq (equal, takes 2 args)
|
||||
- nq (not equal, takes 2 args)
|
||||
- and (takes n args)
|
||||
- or (takes n args)
|
||||
- not (takes 1 args)
|
||||
- if-then (takes 2-3 args)
|
||||
- switch (takes 2 or more args)
|
||||
- random (Gaussian random number)
|
||||
- integer
|
||||
|
||||
|
@ -198,43 +209,65 @@ private:
|
|||
bool cached;
|
||||
double invlog2val;
|
||||
std::string Prefix;
|
||||
std::string description_string;
|
||||
std::string property_string;
|
||||
std::string value_string;
|
||||
std::string table_string;
|
||||
std::string p_string;
|
||||
std::string v_string;
|
||||
std::string t_string;
|
||||
std::string function_string;
|
||||
std::string sum_string;
|
||||
std::string difference_string;
|
||||
std::string product_string;
|
||||
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;
|
||||
std::string tan_string;
|
||||
std::string asin_string;
|
||||
std::string acos_string;
|
||||
std::string atan_string;
|
||||
std::string atan2_string;
|
||||
std::string min_string;
|
||||
std::string max_string;
|
||||
std::string avg_string;
|
||||
std::string fraction_string;
|
||||
std::string mod_string;
|
||||
std::string random_string;
|
||||
std::string integer_string;
|
||||
static const std::string description_string;
|
||||
static const std::string property_string;
|
||||
static const std::string value_string;
|
||||
static const std::string table_string;
|
||||
static const std::string p_string;
|
||||
static const std::string v_string;
|
||||
static const std::string t_string;
|
||||
static const std::string function_string;
|
||||
static const std::string sum_string;
|
||||
static const std::string difference_string;
|
||||
static const std::string product_string;
|
||||
static const std::string quotient_string;
|
||||
static const std::string pow_string;
|
||||
static const std::string exp_string;
|
||||
static const std::string log2_string;
|
||||
static const std::string ln_string;
|
||||
static const std::string log10_string;
|
||||
static const std::string abs_string;
|
||||
static const std::string sign_string;
|
||||
static const std::string sin_string;
|
||||
static const std::string cos_string;
|
||||
static const std::string tan_string;
|
||||
static const std::string asin_string;
|
||||
static const std::string acos_string;
|
||||
static const std::string atan_string;
|
||||
static const std::string atan2_string;
|
||||
static const std::string min_string;
|
||||
static const std::string max_string;
|
||||
static const std::string avg_string;
|
||||
static const std::string fraction_string;
|
||||
static const std::string mod_string;
|
||||
static const std::string random_string;
|
||||
static const std::string integer_string;
|
||||
static const std::string rotation_alpha_local_string;
|
||||
static const std::string rotation_beta_local_string;
|
||||
static const std::string rotation_gamma_local_string;
|
||||
static const std::string rotation_bf_to_wf_string;
|
||||
static const std::string rotation_wf_to_bf_string;
|
||||
static const std::string lessthan_string;
|
||||
static const std::string lessequal_string;
|
||||
static const std::string greatthan_string;
|
||||
static const std::string greatequal_string;
|
||||
static const std::string equal_string;
|
||||
static const std::string notequal_string;
|
||||
static const std::string and_string;
|
||||
static const std::string or_string;
|
||||
static const std::string not_string;
|
||||
static const std::string ifthen_string;
|
||||
static const std::string switch_string;
|
||||
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, eLog2, eLn, eLog10} Type;
|
||||
eExp, eAbs, eSign, eSin, eCos, eTan, eASin, eACos, eATan, eATan2,
|
||||
eMin, eMax, eAvg, eFrac, eInteger, eMod, eRandom, eLog2, eLn,
|
||||
eLog10, eLT, eLE, eGE, eGT, eEQ, eNE, eAND, eOR, eNOT,
|
||||
eIfThen, eSwitch, eRotation_alpha_local, eRotation_beta_local,
|
||||
eRotation_gamma_local, eRotation_bf_to_wf, eRotation_wf_to_bf} Type;
|
||||
std::string Name;
|
||||
|
||||
unsigned int GetBinary(double) const;
|
||||
void bind(void);
|
||||
void Debug(int from);
|
||||
};
|
||||
|
|
|
@ -48,7 +48,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_LOCATION "$Id: FGLocation.h,v 1.27 2010/11/29 12:33:58 jberndt Exp $"
|
||||
#define ID_LOCATION "$Id: FGLocation.h,v 1.28 2011/08/04 12:46:32 jberndt Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -142,7 +142,7 @@ CLASS DOCUMENTATION
|
|||
@see W. C. Durham "Aircraft Dynamics & Control", section 2.2
|
||||
|
||||
@author Mathias Froehlich
|
||||
@version $Id: FGLocation.h,v 1.27 2010/11/29 12:33:58 jberndt Exp $
|
||||
@version $Id: FGLocation.h,v 1.28 2011/08/04 12:46:32 jberndt Exp $
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -229,6 +229,13 @@ public:
|
|||
respect to the Inertial (ECI) frame in radians. */
|
||||
void SetEarthPositionAngle(double EPA) {epa = EPA; mCacheValid = false;}
|
||||
|
||||
/** Increments the Earth position angle.
|
||||
This is the relative orientation of the ECEF frame with respect to the
|
||||
Inertial frame.
|
||||
@param delta delta to the Earth fixed frame (ECEF) rotation offset about the axis with
|
||||
respect to the Inertial (ECI) frame in radians. */
|
||||
void IncrementEarthPositionAngle(double delta) {epa += delta; mCacheValid = false;}
|
||||
|
||||
/** Get the longitude.
|
||||
@return the longitude in rad of the location represented with this
|
||||
class instance. The returned values are in the range between
|
||||
|
@ -290,6 +297,8 @@ public:
|
|||
return -mTec2l(3,3)/cLat;
|
||||
}
|
||||
|
||||
double GetEPA() const {return epa;}
|
||||
|
||||
/** Get the distance from the center of the earth.
|
||||
@return the distance of the location represented with this class
|
||||
instance to the center of the earth in ft. The radius value is
|
||||
|
|
4
src/FDM/JSBSim/math/FGModelFunctions.h
Normal file → Executable file
4
src/FDM/JSBSim/math/FGModelFunctions.h
Normal file → Executable file
|
@ -44,7 +44,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_MODELFUNCTIONS "$Id: FGModelFunctions.h,v 1.3 2010/11/17 03:18:37 jberndt Exp $"
|
||||
#define ID_MODELFUNCTIONS "$Id: FGModelFunctions.h,v 1.4 2011/06/21 04:41:54 jberndt Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -76,7 +76,7 @@ DECLARATION: FGModelFunctions
|
|||
class FGModelFunctions : public FGJSBBase
|
||||
{
|
||||
public:
|
||||
~FGModelFunctions();
|
||||
virtual ~FGModelFunctions();
|
||||
void RunPreFunctions(void);
|
||||
void RunPostFunctions(void);
|
||||
bool Load(Element* el, FGPropertyManager* PropertyManager, std::string prefix="");
|
||||
|
|
67
src/FDM/JSBSim/math/LagrangeMultiplier.h
Executable file
67
src/FDM/JSBSim/math/LagrangeMultiplier.h
Executable file
|
@ -0,0 +1,67 @@
|
|||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
Header: LaGrangeMultiplier.h
|
||||
Author: Bertrand Coconnier
|
||||
Date started: 07/01/11
|
||||
|
||||
------------- Copyright (C) 2011 Bertrand Coconnier -------------
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the Free Software
|
||||
Foundation; either version 2 of the License, or (at your option) any later
|
||||
version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Further information about the GNU Lesser General Public License can also be found on
|
||||
the world wide web at http://www.gnu.org.
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
SENTRY
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#ifndef LAGRANGEMULTIPLIER_H
|
||||
#define LAGRANGEMULTIPLIER_H
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_LAGRANGEMULTIPLIER "$Id: LagrangeMultiplier.h,v 1.2 2011/08/21 15:13:22 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS DOCUMENTATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS DECLARATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
struct LagrangeMultiplier {
|
||||
FGColumnVector3 ForceJacobian;
|
||||
FGColumnVector3 MomentJacobian;
|
||||
double Min;
|
||||
double Max;
|
||||
double value;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif
|
|
@ -6,6 +6,6 @@ libMath_a_SOURCES = FGColumnVector3.cpp FGFunction.cpp FGLocation.cpp FGMatrix33
|
|||
|
||||
noinst_HEADERS = FGColumnVector3.h FGFunction.h FGLocation.h FGMatrix33.h \
|
||||
FGParameter.h FGPropertyValue.h FGQuaternion.h FGRealValue.h FGTable.h \
|
||||
FGCondition.h FGRungeKutta.h FGModelFunctions.h
|
||||
FGCondition.h FGRungeKutta.h FGModelFunctions.h LagrangeMultiplier.h
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/src/FDM/JSBSim
|
||||
|
|
397
src/FDM/JSBSim/models/FGAccelerations.cpp
Normal file
397
src/FDM/JSBSim/models/FGAccelerations.cpp
Normal file
|
@ -0,0 +1,397 @@
|
|||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
Module: FGAccelerations.cpp
|
||||
Author: Jon S. Berndt
|
||||
Date started: 07/12/11
|
||||
Purpose: Calculates derivatives of rotational and translational rates, and
|
||||
of the attitude quaternion.
|
||||
Called by: FGFDMExec
|
||||
|
||||
------------- Copyright (C) 2011 Jon S. Berndt (jon@jsbsim.org) -------------
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the Free Software
|
||||
Foundation; either version 2 of the License, or (at your option) any later
|
||||
version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Further information about the GNU Lesser General Public License can also be found on
|
||||
the world wide web at http://www.gnu.org.
|
||||
|
||||
FUNCTIONAL DESCRIPTION
|
||||
--------------------------------------------------------------------------------
|
||||
This class encapsulates the calculation of the derivatives of the state vectors
|
||||
UVW and PQR - the translational and rotational rates relative to the planet
|
||||
fixed frame. The derivatives relative to the inertial frame are also calculated
|
||||
as a side effect. Also, the derivative of the attitude quaterion is also calculated.
|
||||
|
||||
HISTORY
|
||||
--------------------------------------------------------------------------------
|
||||
07/12/11 JSB Created
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
COMMENTS, REFERENCES, and NOTES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
[1] Stevens and Lewis, "Aircraft Control and Simulation", Second edition (2004)
|
||||
Wiley
|
||||
[2] Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
|
||||
NASA-Ames", NASA CR-2497, January 1975
|
||||
[3] Erin Catto, "Iterative Dynamics with Temporal Coherence", February 22, 2005
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include "FGAccelerations.h"
|
||||
#include "FGFDMExec.h"
|
||||
#include "input_output/FGPropertyManager.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGAccelerations.cpp,v 1.8 2011/08/30 20:49:04 bcoconni Exp $";
|
||||
static const char *IdHdr = ID_ACCELERATIONS;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS IMPLEMENTATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
FGAccelerations::FGAccelerations(FGFDMExec* fdmex)
|
||||
: FGModel(fdmex)
|
||||
{
|
||||
Debug(0);
|
||||
Name = "FGAccelerations";
|
||||
gravType = gtWGS84;
|
||||
|
||||
vPQRidot.InitMatrix();
|
||||
vUVWidot.InitMatrix();
|
||||
vGravAccel.InitMatrix();
|
||||
vBodyAccel.InitMatrix();
|
||||
vQtrndot = FGQuaternion(0,0,0);
|
||||
|
||||
bind();
|
||||
Debug(0);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
FGAccelerations::~FGAccelerations(void)
|
||||
{
|
||||
Debug(1);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
bool FGAccelerations::InitModel(void)
|
||||
{
|
||||
vPQRidot.InitMatrix();
|
||||
vUVWidot.InitMatrix();
|
||||
vGravAccel.InitMatrix();
|
||||
vBodyAccel.InitMatrix();
|
||||
vQtrndot = FGQuaternion(0,0,0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
/*
|
||||
Purpose: Called on a schedule to calculate derivatives.
|
||||
*/
|
||||
|
||||
bool FGAccelerations::Run(bool Holding)
|
||||
{
|
||||
if (FGModel::Run(Holding)) return true; // Fast return if we have nothing to do ...
|
||||
if (Holding) return false;
|
||||
|
||||
RunPreFunctions();
|
||||
|
||||
CalculatePQRdot(); // Angular rate derivative
|
||||
CalculateUVWdot(); // Translational rate derivative
|
||||
CalculateQuatdot(); // Angular orientation derivative
|
||||
|
||||
ResolveFrictionForces(in.DeltaT * rate); // Update rate derivatives with friction forces
|
||||
|
||||
RunPostFunctions();
|
||||
|
||||
Debug(2);
|
||||
return false;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// Compute body frame rotational accelerations based on the current body moments
|
||||
//
|
||||
// vPQRdot is the derivative of the absolute angular velocity of the vehicle
|
||||
// (body rate with respect to the inertial frame), expressed in the body frame,
|
||||
// where the derivative is taken in the body frame.
|
||||
// J is the inertia matrix
|
||||
// Jinv is the inverse inertia matrix
|
||||
// vMoments is the moment vector in the body frame
|
||||
// in.vPQRi is the total inertial angular velocity of the vehicle
|
||||
// expressed in the body frame.
|
||||
// Reference: See Stevens and Lewis, "Aircraft Control and Simulation",
|
||||
// Second edition (2004), eqn 1.5-16e (page 50)
|
||||
|
||||
void FGAccelerations::CalculatePQRdot(void)
|
||||
{
|
||||
// Compute body frame rotational accelerations based on the current body
|
||||
// moments and the total inertial angular velocity expressed in the body
|
||||
// frame.
|
||||
|
||||
vPQRidot = in.Jinv * (in.Moment - in.vPQRi * (in.J * in.vPQRi));
|
||||
vPQRdot = vPQRidot - in.vPQRi * (in.Ti2b * in.vOmegaPlanet);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// Compute the quaternion orientation derivative
|
||||
//
|
||||
// vQtrndot is the quaternion derivative.
|
||||
// Reference: See Stevens and Lewis, "Aircraft Control and Simulation",
|
||||
// Second edition (2004), eqn 1.5-16b (page 50)
|
||||
|
||||
void FGAccelerations::CalculateQuatdot(void)
|
||||
{
|
||||
// Compute quaternion orientation derivative on current body rates
|
||||
vQtrndot = in.qAttitudeECI.GetQDot(in.vPQRi);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// This set of calculations results in the body and inertial frame accelerations
|
||||
// being computed.
|
||||
// Compute body and inertial frames accelerations based on the current body
|
||||
// forces including centripetal and coriolis accelerations for the former.
|
||||
// in.vOmegaPlanet is the Earth angular rate - expressed in the inertial frame -
|
||||
// so it has to be transformed to the body frame. More completely,
|
||||
// in.vOmegaPlanet is the rate of the ECEF frame relative to the Inertial
|
||||
// frame (ECI), expressed in the Inertial frame.
|
||||
// in.Force is the total force on the vehicle in the body frame.
|
||||
// in.vPQR is the vehicle body rate relative to the ECEF frame, expressed
|
||||
// in the body frame.
|
||||
// in.vUVW is the vehicle velocity relative to the ECEF frame, expressed
|
||||
// in the body frame.
|
||||
// Reference: See Stevens and Lewis, "Aircraft Control and Simulation",
|
||||
// Second edition (2004), eqns 1.5-13 (pg 48) and 1.5-16d (page 50)
|
||||
|
||||
void FGAccelerations::CalculateUVWdot(void)
|
||||
{
|
||||
vBodyAccel = in.Force / in.Mass;
|
||||
|
||||
vUVWdot = vBodyAccel - (in.vPQR + 2.0 * (in.Ti2b * in.vOmegaPlanet)) * in.vUVW;
|
||||
|
||||
// Include Centripetal acceleration.
|
||||
vUVWdot -= in.Ti2b * (in.vOmegaPlanet * (in.vOmegaPlanet * in.vInertialPosition));
|
||||
|
||||
// Include Gravitation accel
|
||||
switch (gravType) {
|
||||
case gtStandard:
|
||||
vGravAccel = in.Tl2b * FGColumnVector3( 0.0, 0.0, in.GAccel );
|
||||
break;
|
||||
case gtWGS84:
|
||||
vGravAccel = in.Tec2b * in.J2Grav;
|
||||
break;
|
||||
}
|
||||
|
||||
vUVWdot += vGravAccel;
|
||||
vUVWidot = in.Tb2i * (vBodyAccel + vGravAccel);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// Resolves the contact forces just before integrating the EOM.
|
||||
// This routine is using Lagrange multipliers and the projected Gauss-Seidel
|
||||
// (PGS) method.
|
||||
// Reference: See Erin Catto, "Iterative Dynamics with Temporal Coherence",
|
||||
// February 22, 2005
|
||||
// In JSBSim there is only one rigid body (the aircraft) and there can be
|
||||
// multiple points of contact between the aircraft and the ground. As a
|
||||
// consequence our matrix J*M^-1*J^T is not sparse and the algorithm described
|
||||
// in Catto's paper has been adapted accordingly.
|
||||
// The friction forces are resolved in the body frame relative to the origin
|
||||
// (Earth center).
|
||||
|
||||
void FGAccelerations::ResolveFrictionForces(double dt)
|
||||
{
|
||||
const double invMass = 1.0 / in.Mass;
|
||||
const FGMatrix33& Jinv = in.Jinv;
|
||||
FGColumnVector3 vdot, wdot;
|
||||
vector<LagrangeMultiplier*>& multipliers = *in.MultipliersList;
|
||||
int n = multipliers.size();
|
||||
|
||||
vFrictionForces.InitMatrix();
|
||||
vFrictionMoments.InitMatrix();
|
||||
|
||||
// If no gears are in contact with the ground then return
|
||||
if (!n) return;
|
||||
|
||||
vector<double> a(n*n); // Will contain J*M^-1*J^T
|
||||
vector<double> rhs(n);
|
||||
|
||||
// Assemble the linear system of equations
|
||||
for (int i=0; i < n; i++) {
|
||||
FGColumnVector3 v1 = invMass * multipliers[i]->ForceJacobian;
|
||||
FGColumnVector3 v2 = Jinv * multipliers[i]->MomentJacobian; // Should be J^-T but J is symmetric and so is J^-1
|
||||
|
||||
for (int j=0; j < i; j++)
|
||||
a[i*n+j] = a[j*n+i]; // Takes advantage of the symmetry of J^T*M^-1*J
|
||||
for (int j=i; j < n; j++)
|
||||
a[i*n+j] = DotProduct(v1, multipliers[j]->ForceJacobian)
|
||||
+ DotProduct(v2, multipliers[j]->MomentJacobian);
|
||||
}
|
||||
|
||||
// Assemble the RHS member
|
||||
|
||||
// Translation
|
||||
vdot = vUVWdot;
|
||||
if (dt > 0.) // Zeroes out the relative movement between aircraft and ground
|
||||
vdot += (in.vUVW - in.Tec2b * in.TerrainVelocity) / dt;
|
||||
|
||||
// Rotation
|
||||
wdot = vPQRdot;
|
||||
if (dt > 0.) // Zeroes out the relative movement between aircraft and ground
|
||||
wdot += (in.vPQR - in.Tec2b * in.TerrainAngularVel) / dt;
|
||||
|
||||
// Prepare the linear system for the Gauss-Seidel algorithm :
|
||||
// 1. Compute the right hand side member 'rhs'
|
||||
// 2. Divide every line of 'a' and 'rhs' by a[i,i]. This is in order to save
|
||||
// a division computation at each iteration of Gauss-Seidel.
|
||||
for (int i=0; i < n; i++) {
|
||||
double d = 1.0 / a[i*n+i];
|
||||
|
||||
rhs[i] = -(DotProduct(multipliers[i]->ForceJacobian, vdot)
|
||||
+DotProduct(multipliers[i]->MomentJacobian, wdot))*d;
|
||||
for (int j=0; j < n; j++)
|
||||
a[i*n+j] *= d;
|
||||
}
|
||||
|
||||
// Resolve the Lagrange multipliers with the projected Gauss-Seidel method
|
||||
for (int iter=0; iter < 50; iter++) {
|
||||
double norm = 0.;
|
||||
|
||||
for (int i=0; i < n; i++) {
|
||||
double lambda0 = multipliers[i]->value;
|
||||
double dlambda = rhs[i];
|
||||
|
||||
for (int j=0; j < n; j++)
|
||||
dlambda -= a[i*n+j]*multipliers[j]->value;
|
||||
|
||||
multipliers[i]->value = Constrain(multipliers[i]->Min, lambda0+dlambda, multipliers[i]->Max);
|
||||
dlambda = multipliers[i]->value - lambda0;
|
||||
|
||||
norm += fabs(dlambda);
|
||||
}
|
||||
|
||||
if (norm < 1E-5) break;
|
||||
}
|
||||
|
||||
// Calculate the total friction forces and moments
|
||||
|
||||
for (int i=0; i< n; i++) {
|
||||
double lambda = multipliers[i]->value;
|
||||
vFrictionForces += lambda * multipliers[i]->ForceJacobian;
|
||||
vFrictionMoments += lambda * multipliers[i]->MomentJacobian;
|
||||
}
|
||||
|
||||
FGColumnVector3 accel = invMass * vFrictionForces;
|
||||
FGColumnVector3 omegadot = Jinv * vFrictionMoments;
|
||||
|
||||
vBodyAccel += accel;
|
||||
vUVWdot += accel;
|
||||
vUVWidot += in.Tb2i * accel;
|
||||
vPQRdot += omegadot;
|
||||
vPQRidot += omegadot;
|
||||
}
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGAccelerations::InitializeDerivatives(void)
|
||||
{
|
||||
// Make an initial run and set past values
|
||||
CalculatePQRdot(); // Angular rate derivative
|
||||
CalculateUVWdot(); // Translational rate derivative
|
||||
CalculateQuatdot(); // Angular orientation derivative
|
||||
ResolveFrictionForces(0.); // Update rate derivatives with friction forces
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGAccelerations::bind(void)
|
||||
{
|
||||
typedef double (FGAccelerations::*PMF)(int) const;
|
||||
|
||||
PropertyManager->Tie("accelerations/pdot-rad_sec2", this, eP, (PMF)&FGAccelerations::GetPQRdot);
|
||||
PropertyManager->Tie("accelerations/qdot-rad_sec2", this, eQ, (PMF)&FGAccelerations::GetPQRdot);
|
||||
PropertyManager->Tie("accelerations/rdot-rad_sec2", this, eR, (PMF)&FGAccelerations::GetPQRdot);
|
||||
|
||||
PropertyManager->Tie("accelerations/udot-ft_sec2", this, eU, (PMF)&FGAccelerations::GetUVWdot);
|
||||
PropertyManager->Tie("accelerations/vdot-ft_sec2", this, eV, (PMF)&FGAccelerations::GetUVWdot);
|
||||
PropertyManager->Tie("accelerations/wdot-ft_sec2", this, eW, (PMF)&FGAccelerations::GetUVWdot);
|
||||
|
||||
PropertyManager->Tie("simulation/gravity-model", &gravType);
|
||||
|
||||
PropertyManager->Tie("forces/fbx-total-lbs", this, eX, (PMF)&FGAccelerations::GetForces);
|
||||
PropertyManager->Tie("forces/fby-total-lbs", this, eY, (PMF)&FGAccelerations::GetForces);
|
||||
PropertyManager->Tie("forces/fbz-total-lbs", this, eZ, (PMF)&FGAccelerations::GetForces);
|
||||
PropertyManager->Tie("moments/l-total-lbsft", this, eL, (PMF)&FGAccelerations::GetMoments);
|
||||
PropertyManager->Tie("moments/m-total-lbsft", this, eM, (PMF)&FGAccelerations::GetMoments);
|
||||
PropertyManager->Tie("moments/n-total-lbsft", this, eN, (PMF)&FGAccelerations::GetMoments);
|
||||
|
||||
PropertyManager->Tie("moments/l-gear-lbsft", this, eL, (PMF)&FGAccelerations::GetGroundMoments);
|
||||
PropertyManager->Tie("moments/m-gear-lbsft", this, eM, (PMF)&FGAccelerations::GetGroundMoments);
|
||||
PropertyManager->Tie("moments/n-gear-lbsft", this, eN, (PMF)&FGAccelerations::GetGroundMoments);
|
||||
PropertyManager->Tie("forces/fbx-gear-lbs", this, eX, (PMF)&FGAccelerations::GetGroundForces);
|
||||
PropertyManager->Tie("forces/fby-gear-lbs", this, eY, (PMF)&FGAccelerations::GetGroundForces);
|
||||
PropertyManager->Tie("forces/fbz-gear-lbs", this, eZ, (PMF)&FGAccelerations::GetGroundForces);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// The bitmasked value choices are as follows:
|
||||
// unset: In this case (the default) JSBSim would only print
|
||||
// out the normally expected messages, essentially echoing
|
||||
// the config files as they are read. If the environment
|
||||
// variable is not set, debug_lvl is set to 1 internally
|
||||
// 0: This requests JSBSim not to output any messages
|
||||
// whatsoever.
|
||||
// 1: This value explicity requests the normal JSBSim
|
||||
// startup messages
|
||||
// 2: This value asks for a message to be printed out when
|
||||
// a class is instantiated
|
||||
// 4: When this value is set, a message is displayed when a
|
||||
// FGModel object executes its Run() method
|
||||
// 8: When this value is set, various runtime state variables
|
||||
// are printed out periodically
|
||||
// 16: When set various parameters are sanity checked and
|
||||
// a message is printed out when they go out of bounds
|
||||
|
||||
void FGAccelerations::Debug(int from)
|
||||
{
|
||||
if (debug_lvl <= 0) return;
|
||||
|
||||
if (debug_lvl & 1) { // Standard console startup message output
|
||||
if (from == 0) { // Constructor
|
||||
|
||||
}
|
||||
}
|
||||
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
|
||||
if (from == 0) cout << "Instantiated: FGAccelerations" << endl;
|
||||
if (from == 1) cout << "Destroyed: FGAccelerations" << endl;
|
||||
}
|
||||
if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
|
||||
}
|
||||
if (debug_lvl & 8 && from == 2) { // Runtime state variables
|
||||
}
|
||||
if (debug_lvl & 16) { // Sanity checking
|
||||
}
|
||||
if (debug_lvl & 64) {
|
||||
if (from == 0) { // Constructor
|
||||
cout << IdSrc << endl;
|
||||
cout << IdHdr << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
230
src/FDM/JSBSim/models/FGAccelerations.h
Normal file
230
src/FDM/JSBSim/models/FGAccelerations.h
Normal file
|
@ -0,0 +1,230 @@
|
|||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
Header: FGAccelerations.h
|
||||
Author: Jon S. Berndt
|
||||
Date started: 07/12/11
|
||||
|
||||
------------- Copyright (C) 2011 Jon S. Berndt (jon@jsbsim.org) -------------
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the Free Software
|
||||
Foundation; either version 2 of the License, or (at your option) any later
|
||||
version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Further information about the GNU Lesser General Public License can also be found on
|
||||
the world wide web at http://www.gnu.org.
|
||||
|
||||
HISTORY
|
||||
--------------------------------------------------------------------------------
|
||||
07/12/11 JSB Created
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
SENTRY
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#ifndef FGACCELERATIONS_H
|
||||
#define FGACCELERATIONS_H
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "models/FGModel.h"
|
||||
#include "math/FGColumnVector3.h"
|
||||
#include "math/LagrangeMultiplier.h"
|
||||
#include "math/FGMatrix33.h"
|
||||
#include "math/FGQuaternion.h"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_ACCELERATIONS "$Id: FGAccelerations.h,v 1.7 2011/08/21 15:46:48 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS DOCUMENTATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
/** Handles the calculation of accelerations.
|
||||
|
||||
-Calculate the angular accelerations
|
||||
-Calculate the translational accelerations
|
||||
-Calculate the angular rate
|
||||
-Calculate the translational velocity
|
||||
|
||||
@author Jon S. Berndt, Mathias Froehlich, Bertrand Coconnier
|
||||
@version $Id: FGAccelerations.h,v 1.7 2011/08/21 15:46:48 bcoconni Exp $
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS DECLARATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
class FGAccelerations : public FGModel {
|
||||
public:
|
||||
/** Constructor.
|
||||
@param Executive a pointer to the parent executive object */
|
||||
FGAccelerations(FGFDMExec* Executive);
|
||||
|
||||
/// Destructor
|
||||
~FGAccelerations();
|
||||
|
||||
/// These define the indices use to select the gravitation models.
|
||||
enum eGravType {gtStandard, gtWGS84};
|
||||
|
||||
/** Initializes the FGAccelerations class after instantiation and prior to first execution.
|
||||
The base class FGModel::InitModel is called first, initializing pointers to the
|
||||
other FGModel objects (and others). */
|
||||
bool InitModel(void);
|
||||
|
||||
/** Runs the state propagation model; called by the Executive
|
||||
Can pass in a value indicating if the executive is directing the simulation to Hold.
|
||||
@param Holding if true, the executive has been directed to hold the sim from
|
||||
advancing time. Some models may ignore this flag, such as the Input
|
||||
model, which may need to be active to listen on a socket for the
|
||||
"Resume" command to be given.
|
||||
@return false if no error */
|
||||
bool Run(bool Holding);
|
||||
|
||||
const FGQuaternion& GetQuaterniondot(void) const {return vQtrndot;}
|
||||
|
||||
/** Retrieves the body axis acceleration.
|
||||
Retrieves the computed body axis accelerations based on the
|
||||
applied forces and accounting for a rotating body frame.
|
||||
The vector returned is represented by an FGColumnVector reference. The vector
|
||||
for the acceleration in Body frame is organized (Ax, Ay, Az). The vector
|
||||
is 1-based, so that the first element can be retrieved using the "()" operator.
|
||||
In other words, vUVWdot(1) is Ax. Various convenience enumerators are defined
|
||||
in FGJSBBase. The relevant enumerators for the vector returned by this call are,
|
||||
eX=1, eY=2, eZ=3.
|
||||
units ft/sec^2
|
||||
@return Body axis translational acceleration in ft/sec^2.
|
||||
*/
|
||||
const FGColumnVector3& GetUVWdot(void) const { return vUVWdot; }
|
||||
|
||||
const FGColumnVector3& GetUVWidot(void) const { return vUVWidot; }
|
||||
|
||||
/** Retrieves the body axis angular acceleration vector.
|
||||
Retrieves the body axis angular acceleration vector in rad/sec^2. The
|
||||
angular acceleration vector is determined from the applied forces and
|
||||
accounts for a rotating frame.
|
||||
The vector returned is represented by an FGColumnVector reference. The vector
|
||||
for the angular acceleration in Body frame is organized (Pdot, Qdot, Rdot). The vector
|
||||
is 1-based, so that the first element can be retrieved using the "()" operator.
|
||||
In other words, vPQRdot(1) is Pdot. Various convenience enumerators are defined
|
||||
in FGJSBBase. The relevant enumerators for the vector returned by this call are,
|
||||
eP=1, eQ=2, eR=3.
|
||||
units rad/sec^2
|
||||
@return The angular acceleration vector.
|
||||
*/
|
||||
const FGColumnVector3& GetPQRdot(void) const {return vPQRdot;}
|
||||
|
||||
const FGColumnVector3& GetPQRidot(void) const {return vPQRidot;}
|
||||
|
||||
/** Retrieves a body frame acceleration component.
|
||||
Retrieves a body frame acceleration component. The acceleration returned
|
||||
is extracted from the vUVWdot vector (an FGColumnVector). The vector for
|
||||
the acceleration in Body frame is organized (Ax, Ay, Az). The vector is
|
||||
1-based. In other words, GetUVWdot(1) returns Ax. Various convenience
|
||||
enumerators are defined in FGJSBBase. The relevant enumerators for the
|
||||
acceleration returned by this call are, eX=1, eY=2, eZ=3.
|
||||
units ft/sec^2
|
||||
@param idx the index of the acceleration component desired (1-based).
|
||||
@return The body frame acceleration component.
|
||||
*/
|
||||
double GetUVWdot(int idx) const { return vUVWdot(idx); }
|
||||
|
||||
FGColumnVector3& GetBodyAccel(void) { return vBodyAccel; }
|
||||
|
||||
double GetBodyAccel(int idx) const { return vBodyAccel(idx); }
|
||||
|
||||
/** Retrieves a body frame angular acceleration component.
|
||||
Retrieves a body frame angular acceleration component. The angular
|
||||
acceleration returned is extracted from the vPQRdot vector (an
|
||||
FGColumnVector). The vector for the angular acceleration in Body frame
|
||||
is organized (Pdot, Qdot, Rdot). The vector is 1-based. In other words,
|
||||
GetPQRdot(1) returns Pdot (roll acceleration). Various convenience
|
||||
enumerators are defined in FGJSBBase. The relevant enumerators for the
|
||||
angular acceleration returned by this call are, eP=1, eQ=2, eR=3.
|
||||
units rad/sec^2
|
||||
@param axis the index of the angular acceleration component desired (1-based).
|
||||
@return The body frame angular acceleration component.
|
||||
*/
|
||||
double GetPQRdot(int axis) const {return vPQRdot(axis);}
|
||||
|
||||
double GetMoments(int idx) const { return in.Moment(idx) + vFrictionMoments(idx); }
|
||||
double GetForces(int idx) const { return in.Force(idx) + vFrictionForces(idx); }
|
||||
double GetGroundMoments(int idx) const { return in.GroundMoment(idx) + vFrictionMoments(idx); }
|
||||
double GetGroundForces(int idx) const { return in.GroundForce(idx) + vFrictionForces(idx); }
|
||||
|
||||
void InitializeDerivatives(void);
|
||||
|
||||
void DumpState(void);
|
||||
|
||||
struct Inputs {
|
||||
FGMatrix33 J;
|
||||
FGMatrix33 Jinv;
|
||||
FGMatrix33 Ti2b;
|
||||
FGMatrix33 Tb2i;
|
||||
FGMatrix33 Tec2b;
|
||||
FGMatrix33 Tl2b;
|
||||
FGQuaternion qAttitudeECI;
|
||||
FGColumnVector3 Moment;
|
||||
FGColumnVector3 GroundMoment;
|
||||
FGColumnVector3 Force;
|
||||
FGColumnVector3 GroundForce;
|
||||
FGColumnVector3 J2Grav;
|
||||
FGColumnVector3 vPQRi;
|
||||
FGColumnVector3 vPQR;
|
||||
FGColumnVector3 vUVW;
|
||||
FGColumnVector3 vInertialPosition;
|
||||
FGColumnVector3 vOmegaPlanet;
|
||||
FGColumnVector3 TerrainVelocity;
|
||||
FGColumnVector3 TerrainAngularVel;
|
||||
double DeltaT;
|
||||
double Mass;
|
||||
double GAccel;
|
||||
std::vector<LagrangeMultiplier*> *MultipliersList;
|
||||
} in;
|
||||
|
||||
private:
|
||||
|
||||
FGColumnVector3 vPQRdot, vPQRidot;
|
||||
FGColumnVector3 vUVWdot, vUVWidot;
|
||||
FGQuaternion vQtrndot;
|
||||
FGColumnVector3 vBodyAccel;
|
||||
FGColumnVector3 vGravAccel;
|
||||
FGColumnVector3 vFrictionForces;
|
||||
FGColumnVector3 vFrictionMoments;
|
||||
|
||||
int gravType;
|
||||
|
||||
void CalculatePQRdot(void);
|
||||
void CalculateQuatdot(void);
|
||||
void CalculateUVWdot(void);
|
||||
|
||||
void ResolveFrictionForces(double dt);
|
||||
|
||||
void bind(void);
|
||||
void Debug(int from);
|
||||
};
|
||||
}
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
#endif
|
|
@ -40,19 +40,15 @@ INCLUDES
|
|||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <cstdlib>
|
||||
#include <FGFDMExec.h>
|
||||
#include "FGFDMExec.h"
|
||||
#include "FGAerodynamics.h"
|
||||
#include "FGPropagate.h"
|
||||
#include "FGAircraft.h"
|
||||
#include "FGAuxiliary.h"
|
||||
#include "FGMassBalance.h"
|
||||
#include "input_output/FGPropertyManager.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGAerodynamics.cpp,v 1.38 2011/05/20 03:18:36 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGAerodynamics.cpp,v 1.41 2011/08/04 12:46:32 jberndt Exp $";
|
||||
static const char *IdHdr = ID_AERODYNAMICS;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -139,36 +135,31 @@ bool FGAerodynamics::Run(bool Holding)
|
|||
if (Holding) return false; // if paused don't execute
|
||||
|
||||
unsigned int axis_ctr, ctr;
|
||||
const double alpha=FDMExec->GetAuxiliary()->Getalpha();
|
||||
const double twovel=2*FDMExec->GetAuxiliary()->GetVt();
|
||||
const double qbar = FDMExec->GetAuxiliary()->Getqbar();
|
||||
const double wingarea = FDMExec->GetAircraft()->GetWingArea(); // TODO: Make these constants constant!
|
||||
const double wingspan = FDMExec->GetAircraft()->GetWingSpan();
|
||||
const double wingchord = FDMExec->GetAircraft()->Getcbar();
|
||||
const double wingincidence = FDMExec->GetAircraft()->GetWingIncidence();
|
||||
const double twovel=2*in.Vt;
|
||||
|
||||
RunPreFunctions();
|
||||
|
||||
// calculate some oft-used quantities for speed
|
||||
|
||||
if (twovel != 0) {
|
||||
bi2vel = wingspan / twovel;
|
||||
ci2vel = wingchord / twovel;
|
||||
bi2vel = in.Wingspan / twovel;
|
||||
ci2vel = in.Wingchord / twovel;
|
||||
}
|
||||
alphaw = alpha + wingincidence;
|
||||
qbar_area = wingarea * qbar;
|
||||
alphaw = in.Alpha + in.Wingincidence;
|
||||
qbar_area = in.Wingarea * in.Qbar;
|
||||
|
||||
if (alphaclmax != 0) {
|
||||
if (alpha > 0.85*alphaclmax) {
|
||||
impending_stall = 10*(alpha/alphaclmax - 0.85);
|
||||
if (in.Alpha > 0.85*alphaclmax) {
|
||||
impending_stall = 10*(in.Alpha/alphaclmax - 0.85);
|
||||
} else {
|
||||
impending_stall = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (alphahystmax != 0.0 && alphahystmin != 0.0) {
|
||||
if (alpha > alphahystmax) {
|
||||
if (in.Alpha > alphahystmax) {
|
||||
stall_hyst = 1;
|
||||
} else if (alpha < alphahystmin) {
|
||||
} else if (in.Alpha < alphahystmin) {
|
||||
stall_hyst = 0;
|
||||
}
|
||||
}
|
||||
|
@ -188,16 +179,16 @@ bool FGAerodynamics::Run(bool Holding)
|
|||
|
||||
switch (axisType) {
|
||||
case atBodyXYZ: // Forces already in body axes; no manipulation needed
|
||||
vFw = GetTb2w()*vFnative;
|
||||
vFw = in.Tb2w*vFnative;
|
||||
vForces = vFnative;
|
||||
break;
|
||||
case atLiftDrag: // Copy forces into wind axes
|
||||
vFw = vFnative;
|
||||
vFw(eDrag)*=-1; vFw(eLift)*=-1;
|
||||
vForces = GetTw2b()*vFw;
|
||||
vForces = in.Tw2b*vFw;
|
||||
break;
|
||||
case atAxialNormal: // Convert native forces into Axial|Normal|Side system
|
||||
vFw = GetTb2w()*vFnative;
|
||||
vFw = in.Tb2w*vFnative;
|
||||
vFnative(eX)*=-1; vFnative(eZ)*=-1;
|
||||
vForces = vFnative;
|
||||
break;
|
||||
|
@ -207,19 +198,23 @@ bool FGAerodynamics::Run(bool Holding)
|
|||
exit(-1);
|
||||
}
|
||||
|
||||
// Calculate aerodynamic reference point shift, if any
|
||||
if (AeroRPShift) vDeltaRP(eX) = AeroRPShift->GetValue()*wingchord*12.0;
|
||||
|
||||
// Calculate lift coefficient squared
|
||||
if ( qbar > 0) {
|
||||
clsq = vFw(eLift) / (wingarea*qbar);
|
||||
if ( in.Qbar > 0) {
|
||||
clsq = vFw(eLift) / (in.Wingarea*in.Qbar);
|
||||
clsq *= clsq;
|
||||
}
|
||||
|
||||
// Calculate lift Lift over Drag
|
||||
if ( fabs(vFw(eDrag)) > 0.0) lod = fabs( vFw(eLift) / vFw(eDrag) );
|
||||
|
||||
vDXYZcg = FDMExec->GetMassBalance()->StructuralToBody(FDMExec->GetAircraft()->GetXYZrp() + vDeltaRP);
|
||||
// Calculate aerodynamic reference point shift, if any. The shift
|
||||
// takes place in the body axis. That is, if the shift is negative,
|
||||
// it is towards the back (tail) of the vehicle. The AeroRPShift
|
||||
// function should be non-dimensionalized by the wing chord. The
|
||||
// calculated vDeltaRP will be in feet.
|
||||
if (AeroRPShift) vDeltaRP(eX) = AeroRPShift->GetValue()*in.Wingchord;
|
||||
|
||||
vDXYZcg = in.RPBody + vDeltaRP;
|
||||
|
||||
vMoments = vDXYZcg*vForces; // M = r X F
|
||||
|
||||
|
@ -234,75 +229,6 @@ bool FGAerodynamics::Run(bool Holding)
|
|||
return false;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
//
|
||||
// From Stevens and Lewis, "Aircraft Control and Simulation", 3rd Ed., the
|
||||
// transformation from body to wind axes is defined (where "a" is alpha and "B"
|
||||
// is beta):
|
||||
//
|
||||
// cos(a)*cos(B) sin(B) sin(a)*cos(B)
|
||||
// -cos(a)*sin(B) cos(B) -sin(a)*sin(B)
|
||||
// -sin(a) 0 cos(a)
|
||||
//
|
||||
// The transform from wind to body axes is then,
|
||||
//
|
||||
// cos(a)*cos(B) -cos(a)*sin(B) -sin(a)
|
||||
// sin(B) cos(B) 0
|
||||
// sin(a)*cos(B) -sin(a)*sin(B) cos(a)
|
||||
|
||||
FGMatrix33& FGAerodynamics::GetTw2b(void)
|
||||
{
|
||||
double ca, cb, sa, sb;
|
||||
|
||||
double alpha = FDMExec->GetAuxiliary()->Getalpha();
|
||||
double beta = FDMExec->GetAuxiliary()->Getbeta();
|
||||
|
||||
ca = cos(alpha);
|
||||
sa = sin(alpha);
|
||||
cb = cos(beta);
|
||||
sb = sin(beta);
|
||||
|
||||
mTw2b(1,1) = ca*cb;
|
||||
mTw2b(1,2) = -ca*sb;
|
||||
mTw2b(1,3) = -sa;
|
||||
mTw2b(2,1) = sb;
|
||||
mTw2b(2,2) = cb;
|
||||
mTw2b(2,3) = 0.0;
|
||||
mTw2b(3,1) = sa*cb;
|
||||
mTw2b(3,2) = -sa*sb;
|
||||
mTw2b(3,3) = ca;
|
||||
|
||||
return mTw2b;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
FGMatrix33& FGAerodynamics::GetTb2w(void)
|
||||
{
|
||||
double alpha,beta;
|
||||
double ca, cb, sa, sb;
|
||||
|
||||
alpha = FDMExec->GetAuxiliary()->Getalpha();
|
||||
beta = FDMExec->GetAuxiliary()->Getbeta();
|
||||
|
||||
ca = cos(alpha);
|
||||
sa = sin(alpha);
|
||||
cb = cos(beta);
|
||||
sb = sin(beta);
|
||||
|
||||
mTb2w(1,1) = ca*cb;
|
||||
mTb2w(1,2) = sb;
|
||||
mTb2w(1,3) = sa*cb;
|
||||
mTb2w(2,1) = -ca*sb;
|
||||
mTb2w(2,2) = cb;
|
||||
mTb2w(2,3) = -sa*sb;
|
||||
mTb2w(3,1) = -sa;
|
||||
mTb2w(3,2) = 0.0;
|
||||
mTb2w(3,3) = ca;
|
||||
|
||||
return mTb2w;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
bool FGAerodynamics::Load(Element *element)
|
||||
|
@ -318,6 +244,7 @@ bool FGAerodynamics::Load(Element *element)
|
|||
if (!fname.empty()) {
|
||||
file = FDMExec->GetFullAircraftPath() + separator + fname;
|
||||
document = LoadXMLDocument(file);
|
||||
if (document == 0L) return false;
|
||||
} else {
|
||||
document = element;
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_AERODYNAMICS "$Id: FGAerodynamics.h,v 1.23 2011/05/20 03:18:36 jberndt Exp $"
|
||||
#define ID_AERODYNAMICS "$Id: FGAerodynamics.h,v 1.25 2011/08/04 12:46:32 jberndt Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -109,7 +109,7 @@ CLASS DOCUMENTATION
|
|||
Systems may NOT be combined, or a load error will occur.
|
||||
|
||||
@author Jon S. Berndt, Tony Peden
|
||||
@version $Revision: 1.23 $
|
||||
@version $Revision: 1.25 $
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -202,18 +202,22 @@ public:
|
|||
aero functions */
|
||||
std::string GetAeroFunctionValues(const std::string& delimeter) const;
|
||||
|
||||
/** Calculates and returns the wind-to-body axis transformation matrix.
|
||||
@return a reference to the wind-to-body transformation matrix.
|
||||
*/
|
||||
FGMatrix33& GetTw2b(void);
|
||||
|
||||
/** Calculates and returns the body-to-wind axis transformation matrix.
|
||||
@return a reference to the wind-to-body transformation matrix.
|
||||
*/
|
||||
FGMatrix33& GetTb2w(void);
|
||||
|
||||
std::vector <FGFunction*> * GetAeroFunctions(void) const { return AeroFunctions; }
|
||||
|
||||
struct Inputs {
|
||||
double Alpha;
|
||||
double Beta;
|
||||
double Vt;
|
||||
double Qbar;
|
||||
double Wingarea;
|
||||
double Wingspan;
|
||||
double Wingchord;
|
||||
double Wingincidence;
|
||||
FGColumnVector3 RPBody;
|
||||
FGMatrix33 Tb2w;
|
||||
FGMatrix33 Tw2b;
|
||||
} in;
|
||||
|
||||
private:
|
||||
enum eAxisType {atNone, atLiftDrag, atAxialNormal, atBodyXYZ} axisType;
|
||||
typedef std::map<std::string,int> AxisIndex;
|
||||
|
@ -227,8 +231,6 @@ private:
|
|||
FGColumnVector3 vMoments;
|
||||
FGColumnVector3 vDXYZcg;
|
||||
FGColumnVector3 vDeltaRP;
|
||||
FGMatrix33 mTw2b;
|
||||
FGMatrix33 mTb2w;
|
||||
double alphaclmax, alphaclmin;
|
||||
double alphahystmax, alphahystmin;
|
||||
double impending_stall, stall_hyst;
|
||||
|
|
|
@ -44,15 +44,7 @@ INCLUDES
|
|||
#include <cmath>
|
||||
|
||||
#include "FGAircraft.h"
|
||||
#include "FGMassBalance.h"
|
||||
#include "FGInertial.h"
|
||||
#include "FGGroundReactions.h"
|
||||
#include "FGExternalReactions.h"
|
||||
#include "FGBuoyantForces.h"
|
||||
#include "FGAerodynamics.h"
|
||||
#include "FGFDMExec.h"
|
||||
#include "FGPropagate.h"
|
||||
#include "FGPropulsion.h"
|
||||
#include "input_output/FGPropertyManager.h"
|
||||
|
||||
using namespace std;
|
||||
|
@ -67,7 +59,7 @@ DEFINITIONS
|
|||
GLOBAL DATA
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
static const char *IdSrc = "$Id: FGAircraft.cpp,v 1.31 2011/05/20 03:18:36 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGAircraft.cpp,v 1.33 2011/08/21 15:06:38 bcoconni Exp $";
|
||||
static const char *IdHdr = ID_AIRCRAFT;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -78,6 +70,8 @@ FGAircraft::FGAircraft(FGFDMExec* fdmex) : FGModel(fdmex)
|
|||
{
|
||||
Name = "FGAircraft";
|
||||
WingSpan = 0.0;
|
||||
WingArea = 0.0;
|
||||
cbar = 0.0;
|
||||
HTailArea = VTailArea = 0.0;
|
||||
HTailArm = VTailArm = 0.0;
|
||||
lbarh = lbarv = 0.0;
|
||||
|
@ -115,32 +109,24 @@ bool FGAircraft::Run(bool Holding)
|
|||
|
||||
vForces.InitMatrix();
|
||||
if (!HoldDown) {
|
||||
vForces += FDMExec->GetAerodynamics()->GetForces();
|
||||
vForces += FDMExec->GetPropulsion()->GetForces();
|
||||
vForces += FDMExec->GetGroundReactions()->GetForces();
|
||||
vForces += FDMExec->GetExternalReactions()->GetForces();
|
||||
vForces += FDMExec->GetBuoyantForces()->GetForces();
|
||||
vForces += in.AeroForce;
|
||||
vForces += in.PropForce;
|
||||
vForces += in.GroundForce;
|
||||
vForces += in.ExternalForce;
|
||||
vForces += in.BuoyantForce;
|
||||
} else {
|
||||
const FGMatrix33& mTl2b = FDMExec->GetPropagate()->GetTl2b();
|
||||
vForces = mTl2b * FGColumnVector3(0,0,-FDMExec->GetMassBalance()->GetWeight());
|
||||
vForces = in.Tl2b * FGColumnVector3(0,0,-in.Weight);
|
||||
}
|
||||
|
||||
vMoments.InitMatrix();
|
||||
if (!HoldDown) {
|
||||
vMoments += FDMExec->GetAerodynamics()->GetMoments();
|
||||
vMoments += FDMExec->GetPropulsion()->GetMoments();
|
||||
vMoments += FDMExec->GetGroundReactions()->GetMoments();
|
||||
vMoments += FDMExec->GetExternalReactions()->GetMoments();
|
||||
vMoments += FDMExec->GetBuoyantForces()->GetMoments();
|
||||
vMoments += in.AeroMoment;
|
||||
vMoments += in.PropMoment;
|
||||
vMoments += in.GroundMoment;
|
||||
vMoments += in.ExternalMoment;
|
||||
vMoments += in.BuoyantMoment;
|
||||
}
|
||||
|
||||
vBodyAccel = vForces/FDMExec->GetMassBalance()->GetMass();
|
||||
|
||||
vNcg = vBodyAccel/FDMExec->GetInertial()->SLgravity();
|
||||
|
||||
vNwcg = FDMExec->GetAerodynamics()->GetTb2w() * vNcg;
|
||||
vNwcg(3) = 1.0 - vNwcg(3);
|
||||
|
||||
RunPostFunctions();
|
||||
|
||||
return false;
|
||||
|
@ -148,16 +134,6 @@ bool FGAircraft::Run(bool Holding)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGAircraft::GetNlf(void) const
|
||||
{
|
||||
if (FDMExec->GetMassBalance()->GetWeight() != 0)
|
||||
return (-FDMExec->GetAerodynamics()->GetvFw(3))/FDMExec->GetMassBalance()->GetWeight();
|
||||
else
|
||||
return 0.;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
bool FGAircraft::Load(Element* el)
|
||||
{
|
||||
string element_name;
|
||||
|
@ -240,14 +216,7 @@ void FGAircraft::bind(void)
|
|||
PropertyManager->Tie("metrics/visualrefpoint-x-in", this, eX, (PMF)&FGAircraft::GetXYZvrp);
|
||||
PropertyManager->Tie("metrics/visualrefpoint-y-in", this, eY, (PMF)&FGAircraft::GetXYZvrp);
|
||||
PropertyManager->Tie("metrics/visualrefpoint-z-in", this, eZ, (PMF)&FGAircraft::GetXYZvrp);
|
||||
PropertyManager->Tie("forces/fbx-total-lbs", this, eX, (PMF)&FGAircraft::GetForces);
|
||||
PropertyManager->Tie("forces/fby-total-lbs", this, eY, (PMF)&FGAircraft::GetForces);
|
||||
PropertyManager->Tie("forces/fbz-total-lbs", this, eZ, (PMF)&FGAircraft::GetForces);
|
||||
PropertyManager->Tie("forces/load-factor", this, &FGAircraft::GetNlf);
|
||||
PropertyManager->Tie("forces/hold-down", this, &FGAircraft::GetHoldDown, &FGAircraft::SetHoldDown);
|
||||
PropertyManager->Tie("moments/l-total-lbsft", this, eL, (PMF)&FGAircraft::GetMoments);
|
||||
PropertyManager->Tie("moments/m-total-lbsft", this, eM, (PMF)&FGAircraft::GetMoments);
|
||||
PropertyManager->Tie("moments/n-total-lbsft", this, eN, (PMF)&FGAircraft::GetMoments);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -44,12 +44,13 @@ INCLUDES
|
|||
#include "FGModel.h"
|
||||
#include "input_output/FGXMLElement.h"
|
||||
#include "math/FGColumnVector3.h"
|
||||
#include "math/FGMatrix33.h"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_AIRCRAFT "$Id: FGAircraft.h,v 1.17 2011/05/20 03:18:36 jberndt Exp $"
|
||||
#define ID_AIRCRAFT "$Id: FGAircraft.h,v 1.18 2011/07/10 20:18:14 jberndt Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -90,7 +91,7 @@ CLASS DOCUMENTATION
|
|||
@endcode
|
||||
|
||||
@author Jon S. Berndt
|
||||
@version $Id: FGAircraft.h,v 1.17 2011/05/20 03:18:36 jberndt Exp $
|
||||
@version $Id: FGAircraft.h,v 1.18 2011/07/10 20:18:14 jberndt Exp $
|
||||
@see Cooke, Zyda, Pratt, and McGhee, "NPSNET: Flight Simulation Dynamic Modeling
|
||||
Using Quaternions", Presence, Vol. 1, No. 4, pp. 404-420 Naval Postgraduate
|
||||
School, January 1994
|
||||
|
@ -159,10 +160,6 @@ public:
|
|||
double GetMoments(int idx) const { return vMoments(idx); }
|
||||
const FGColumnVector3& GetForces(void) const { return vForces; }
|
||||
double GetForces(int idx) const { return vForces(idx); }
|
||||
FGColumnVector3& GetBodyAccel(void) { return vBodyAccel; }
|
||||
double GetBodyAccel(int idx) const { return vBodyAccel(idx); }
|
||||
const FGColumnVector3& GetNcg(void) const { return vNcg; }
|
||||
double GetNcg(int idx) const { return vNcg(idx); }
|
||||
const FGColumnVector3& GetXYZrp(void) const { return vXYZrp; }
|
||||
const FGColumnVector3& GetXYZvrp(void) const { return vXYZvrp; }
|
||||
const FGColumnVector3& GetXYZep(void) const { return vXYZep; }
|
||||
|
@ -177,13 +174,24 @@ public:
|
|||
|
||||
void SetWingArea(double S) {WingArea = S;}
|
||||
|
||||
double GetNlf(void) const;
|
||||
|
||||
FGColumnVector3& GetNwcg(void) { return vNwcg; }
|
||||
|
||||
void bind(void);
|
||||
void unbind(void);
|
||||
|
||||
struct Inputs {
|
||||
FGColumnVector3 AeroForce;
|
||||
FGColumnVector3 PropForce;
|
||||
FGColumnVector3 GroundForce;
|
||||
FGColumnVector3 ExternalForce;
|
||||
FGColumnVector3 BuoyantForce;
|
||||
FGColumnVector3 AeroMoment;
|
||||
FGColumnVector3 PropMoment;
|
||||
FGColumnVector3 GroundMoment;
|
||||
FGColumnVector3 ExternalMoment;
|
||||
FGColumnVector3 BuoyantMoment;
|
||||
FGMatrix33 Tl2b;
|
||||
double Weight;
|
||||
} in;
|
||||
|
||||
private:
|
||||
FGColumnVector3 vMoments;
|
||||
FGColumnVector3 vForces;
|
||||
|
@ -191,9 +199,6 @@ private:
|
|||
FGColumnVector3 vXYZvrp;
|
||||
FGColumnVector3 vXYZep;
|
||||
FGColumnVector3 vDXYZcg;
|
||||
FGColumnVector3 vBodyAccel;
|
||||
FGColumnVector3 vNcg;
|
||||
FGColumnVector3 vNwcg;
|
||||
|
||||
double WingArea, WingSpan, cbar, WingIncidence;
|
||||
double HTailArea, VTailArea, HTailArm, VTailArm;
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
Module: FGAtmosphere.cpp
|
||||
Author: Jon Berndt
|
||||
Implementation of 1959 Standard Atmosphere added by Tony Peden
|
||||
Date started: 11/24/98
|
||||
Purpose: Models the atmosphere
|
||||
Called by: FGSimExec
|
||||
Author: Jon Berndt, Tony Peden
|
||||
Date started: 6/2011
|
||||
Purpose: Models an atmosphere interface class
|
||||
Called by: FGFDMExec
|
||||
|
||||
------------- Copyright (C) 1999 Jon S. Berndt (jon@jsbsim.org) -------------
|
||||
------------- Copyright (C) 2011 Jon S. Berndt (jon@jsbsim.org) -------------
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the Free Software
|
||||
|
@ -28,92 +27,43 @@
|
|||
|
||||
FUNCTIONAL DESCRIPTION
|
||||
--------------------------------------------------------------------------------
|
||||
Models the atmosphere. The equation used below was determined by a third order
|
||||
curve fit using Excel. The data is from the ICAO atmosphere model.
|
||||
This models a base atmosphere class to serve as a common interface to any derived
|
||||
atmosphere models.
|
||||
|
||||
HISTORY
|
||||
--------------------------------------------------------------------------------
|
||||
11/24/98 JSB Created
|
||||
07/23/99 TP Added implementation of 1959 Standard Atmosphere
|
||||
Moved calculation of Mach number to FGPropagate
|
||||
Later updated to '76 model
|
||||
6/18/2011 Started Jon S. Berndt
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
COMMENTS, REFERENCES, and NOTES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
[1] Anderson, John D. "Introduction to Flight, Third Edition", McGraw-Hill,
|
||||
1989, ISBN 0-07-001641-0
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include "FGAtmosphere.h"
|
||||
#include "FGAircraft.h"
|
||||
#include "FGPropagate.h"
|
||||
#include "FGInertial.h"
|
||||
#include "FGAuxiliary.h"
|
||||
#include "FGFDMExec.h"
|
||||
#include "input_output/FGPropertyManager.h"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <cstdlib>
|
||||
|
||||
using namespace std;
|
||||
#include "FGFDMExec.h"
|
||||
#include "FGAtmosphere.h"
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGAtmosphere.cpp,v 1.45 2011/05/20 03:18:36 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGAtmosphere.cpp,v 1.48 2011/07/10 20:18:14 jberndt Exp $";
|
||||
static const char *IdHdr = ID_ATMOSPHERE;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS IMPLEMENTATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
FGAtmosphere::FGAtmosphere(FGFDMExec* fdmex) : FGModel(fdmex)
|
||||
FGAtmosphere::FGAtmosphere(FGFDMExec* fdmex) : FGModel(fdmex),
|
||||
PressureAltitude(0.0), // ft
|
||||
DensityAltitude(0.0), // ft
|
||||
SutherlandConstant(198.72), // deg Rankine
|
||||
Beta(2.269690E-08) // slug/(sec ft R^0.5)
|
||||
{
|
||||
Name = "FGAtmosphere";
|
||||
lastIndex = 0;
|
||||
h = 0.0;
|
||||
psiw = 0.0;
|
||||
htab[0]=0;
|
||||
htab[1]= 36089.0;
|
||||
htab[2]= 65617.0;
|
||||
htab[3]=104987.0;
|
||||
htab[4]=154199.0;
|
||||
htab[5]=167322.0;
|
||||
htab[6]=232940.0;
|
||||
htab[7]=278385.0; //ft.
|
||||
|
||||
MagnitudedAccelDt = MagnitudeAccel = Magnitude = 0.0;
|
||||
SetTurbType( ttMilspec );
|
||||
TurbGain = 1.0;
|
||||
TurbRate = 10.0;
|
||||
Rhythmicity = 0.1;
|
||||
spike = target_time = strength = 0.0;
|
||||
wind_from_clockwise = 0.0;
|
||||
SutherlandConstant = 198.72; // deg Rankine
|
||||
Beta = 2.269690E-08; // slug/(sec ft R^0.5)
|
||||
|
||||
T_dev_sl = T_dev = delta_T = 0.0;
|
||||
StandardTempOnly = false;
|
||||
first_pass = true;
|
||||
vGustNED.InitMatrix();
|
||||
vTurbulenceNED.InitMatrix();
|
||||
|
||||
// Milspec turbulence model
|
||||
windspeed_at_20ft = 0.;
|
||||
probability_of_exceedence_index = 0;
|
||||
POE_Table = new FGTable(7,12);
|
||||
// this is Figure 7 from p. 49 of MIL-F-8785C
|
||||
// rows: probability of exceedance curve index, cols: altitude in ft
|
||||
*POE_Table
|
||||
<< 500.0 << 1750.0 << 3750.0 << 7500.0 << 15000.0 << 25000.0 << 35000.0 << 45000.0 << 55000.0 << 65000.0 << 75000.0 << 80000.0
|
||||
<< 1 << 3.2 << 2.2 << 1.5 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0
|
||||
<< 2 << 4.2 << 3.6 << 3.3 << 1.6 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0
|
||||
<< 3 << 6.6 << 6.9 << 7.4 << 6.7 << 4.6 << 2.7 << 0.4 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0
|
||||
<< 4 << 8.6 << 9.6 << 10.6 << 10.1 << 8.0 << 6.6 << 5.0 << 4.2 << 2.7 << 0.0 << 0.0 << 0.0
|
||||
<< 5 << 11.8 << 13.0 << 16.0 << 15.1 << 11.6 << 9.7 << 8.1 << 8.2 << 7.9 << 4.9 << 3.2 << 2.1
|
||||
<< 6 << 15.6 << 17.6 << 23.0 << 23.6 << 22.1 << 20.0 << 16.0 << 15.1 << 12.1 << 7.9 << 6.2 << 5.1
|
||||
<< 7 << 18.7 << 21.5 << 28.4 << 30.2 << 30.7 << 31.0 << 25.2 << 23.1 << 17.5 << 10.7 << 8.4 << 7.2;
|
||||
|
||||
bind();
|
||||
Debug(0);
|
||||
|
@ -123,7 +73,6 @@ FGAtmosphere::FGAtmosphere(FGFDMExec* fdmex) : FGModel(fdmex)
|
|||
|
||||
FGAtmosphere::~FGAtmosphere()
|
||||
{
|
||||
delete(POE_Table);
|
||||
Debug(1);
|
||||
}
|
||||
|
||||
|
@ -131,17 +80,16 @@ FGAtmosphere::~FGAtmosphere()
|
|||
|
||||
bool FGAtmosphere::InitModel(void)
|
||||
{
|
||||
UseInternal(); // this is the default
|
||||
Calculate(0.0);
|
||||
SLtemperature = Temperature = 518.67;
|
||||
SLpressure = Pressure = 2116.22;
|
||||
SLdensity = Density = Pressure/(Reng*Temperature);
|
||||
SLsoundspeed = Soundspeed = sqrt(SHRatio*Reng*(Temperature));
|
||||
|
||||
Calculate(h);
|
||||
StdSLtemperature = SLtemperature = 518.67;
|
||||
StdSLpressure = SLpressure = 2116.22;
|
||||
StdSLdensity = SLdensity = 0.00237767;
|
||||
StdSLsoundspeed = SLsoundspeed = sqrt(SHRatio*Reng*StdSLtemperature);
|
||||
rSLtemperature = 1.0/StdSLtemperature;
|
||||
rSLpressure = 1.0/StdSLpressure;
|
||||
rSLdensity = 1.0/StdSLdensity;
|
||||
rSLsoundspeed = 1.0/StdSLsoundspeed;
|
||||
rSLtemperature = 1/SLtemperature ;
|
||||
rSLpressure = 1/SLpressure ;
|
||||
rSLdensity = 1/SLdensity ;
|
||||
rSLsoundspeed = 1/SLsoundspeed ;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -155,15 +103,7 @@ bool FGAtmosphere::Run(bool Holding)
|
|||
|
||||
RunPreFunctions();
|
||||
|
||||
T_dev = 0.0;
|
||||
h = FDMExec->GetPropagate()->GetAltitudeASL();
|
||||
|
||||
if (!useExternal) {
|
||||
Calculate(h);
|
||||
CalculateDerived();
|
||||
} else {
|
||||
CalculateDerived();
|
||||
}
|
||||
Calculate(in.altitudeASL);
|
||||
|
||||
RunPostFunctions();
|
||||
|
||||
|
@ -172,537 +112,105 @@ bool FGAtmosphere::Run(bool Holding)
|
|||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
//
|
||||
// See reference 1
|
||||
|
||||
void FGAtmosphere::Calculate(double altitude)
|
||||
{
|
||||
double slope, reftemp, refpress;
|
||||
int i = lastIndex;
|
||||
Temperature = GetTemperature(altitude);
|
||||
Pressure = GetPressure(altitude);
|
||||
Density = Pressure/(Reng*Temperature);
|
||||
Soundspeed = sqrt(SHRatio*Reng*(Temperature));
|
||||
PressureAltitude = altitude;
|
||||
DensityAltitude = altitude;
|
||||
|
||||
if (altitude < htab[lastIndex]) {
|
||||
if (altitude <= 0) {
|
||||
i = 0;
|
||||
altitude=0;
|
||||
} else {
|
||||
i = lastIndex-1;
|
||||
while (htab[i] > altitude) i--;
|
||||
}
|
||||
} else if (altitude > htab[lastIndex+1]) {
|
||||
if (altitude >= htab[7]) {
|
||||
i = 7;
|
||||
altitude = htab[7];
|
||||
} else {
|
||||
i = lastIndex+1;
|
||||
while (htab[i+1] < altitude) i++;
|
||||
}
|
||||
}
|
||||
|
||||
switch(i) {
|
||||
case 0: // Sea level
|
||||
slope = -0.00356616; // R/ft.
|
||||
reftemp = 518.67; // in degrees Rankine, 288.15 Kelvin
|
||||
refpress = 2116.22; // psf
|
||||
//refdens = 0.00237767; // slugs/cubic ft.
|
||||
break;
|
||||
case 1: // 36089 ft. or 11 km
|
||||
slope = 0;
|
||||
reftemp = 389.97; // in degrees Rankine, 216.65 Kelvin
|
||||
refpress = 472.763;
|
||||
//refdens = 0.000706032;
|
||||
break;
|
||||
case 2: // 65616 ft. or 20 km
|
||||
slope = 0.00054864;
|
||||
reftemp = 389.97; // in degrees Rankine, 216.65 Kelvin
|
||||
refpress = 114.636;
|
||||
//refdens = 0.000171306;
|
||||
break;
|
||||
case 3: // 104986 ft. or 32 km
|
||||
slope = 0.001536192;
|
||||
reftemp = 411.57; // in degrees Rankine, 228.65 Kelvin
|
||||
refpress = 18.128;
|
||||
//refdens = 1.18422e-05;
|
||||
break;
|
||||
case 4: // 154199 ft. 47 km
|
||||
slope = 0;
|
||||
reftemp = 487.17; // in degrees Rankine, 270.65 Kelvin
|
||||
refpress = 2.316;
|
||||
//refdens = 4.00585e-7;
|
||||
break;
|
||||
case 5: // 167322 ft. or 51 km
|
||||
slope = -0.001536192;
|
||||
reftemp = 487.17; // in degrees Rankine, 270.65 Kelvin
|
||||
refpress = 1.398;
|
||||
//refdens = 8.17102e-7;
|
||||
break;
|
||||
case 6: // 232940 ft. or 71 km
|
||||
slope = -0.00109728;
|
||||
reftemp = 386.368; // in degrees Rankine, 214.649 Kelvin
|
||||
refpress = 0.0826;
|
||||
//refdens = 8.77702e-9;
|
||||
break;
|
||||
case 7: // 278385 ft. or 84.8520 km
|
||||
slope = 0;
|
||||
reftemp = 336.5; // in degrees Rankine, 186.94 Kelvin
|
||||
refpress = 0.00831;
|
||||
//refdens = 2.19541e-10;
|
||||
break;
|
||||
default: // sea level
|
||||
slope = -0.00356616; // R/ft.
|
||||
reftemp = 518.67; // in degrees Rankine, 288.15 Kelvin
|
||||
refpress = 2116.22; // psf
|
||||
//refdens = 0.00237767; // slugs/cubic ft.
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
// If delta_T is set, then that is our temperature deviation at any altitude.
|
||||
// If not, then we'll estimate a deviation based on the sea level deviation (if set).
|
||||
|
||||
if(!StandardTempOnly) {
|
||||
T_dev = 0.0;
|
||||
if (delta_T != 0.0) {
|
||||
T_dev = delta_T;
|
||||
} else {
|
||||
if ((altitude < 36089.239) && (T_dev_sl != 0.0)) {
|
||||
T_dev = T_dev_sl * ( 1.0 - (altitude/36089.239));
|
||||
}
|
||||
}
|
||||
reftemp+=T_dev;
|
||||
}
|
||||
|
||||
if (slope == 0) {
|
||||
intTemperature = reftemp;
|
||||
intPressure = refpress*exp(-FDMExec->GetInertial()->SLgravity()/(reftemp*Reng)*(altitude-htab[i]));
|
||||
intDensity = intPressure/(Reng*intTemperature);
|
||||
} else {
|
||||
intTemperature = reftemp+slope*(altitude-htab[i]);
|
||||
intPressure = refpress*pow(intTemperature/reftemp,-FDMExec->GetInertial()->SLgravity()/(slope*Reng));
|
||||
intDensity = intPressure/(Reng*intTemperature);
|
||||
}
|
||||
|
||||
lastIndex=i;
|
||||
Viscosity = Beta * pow(Temperature, 1.5) / (SutherlandConstant + Temperature);
|
||||
KinematicViscosity = Viscosity / Density;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// Calculate parameters derived from T, P and rho
|
||||
// Sum gust and turbulence values in NED frame into the wind vector.
|
||||
|
||||
void FGAtmosphere::CalculateDerived(void)
|
||||
void FGAtmosphere::SetPressureSL(double pressure, ePressure unit)
|
||||
{
|
||||
T_dev = (*temperature) - GetTemperature(h);
|
||||
double press = ConvertToPSF(pressure, unit);
|
||||
|
||||
if (T_dev == 0.0) density_altitude = h;
|
||||
else density_altitude = 518.67/0.00356616 * (1.0 - pow(GetDensityRatio(),0.235));
|
||||
|
||||
if (turbType != ttNone) Turbulence();
|
||||
|
||||
vTotalWindNED = vWindNED + vGustNED + vTurbulenceNED;
|
||||
|
||||
// psiw (Wind heading) is the direction the wind is blowing towards
|
||||
if (vWindNED(eX) != 0.0) psiw = atan2( vWindNED(eY), vWindNED(eX) );
|
||||
if (psiw < 0) psiw += 2*M_PI;
|
||||
|
||||
soundspeed = sqrt(SHRatio*Reng*(*temperature));
|
||||
|
||||
intViscosity = Beta * pow(intTemperature, 1.5) / (SutherlandConstant + intTemperature);
|
||||
intKinematicViscosity = intViscosity / intDensity;
|
||||
}
|
||||
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// Get the standard atmospheric properties at a specified altitude
|
||||
|
||||
void FGAtmosphere::GetStdAtmosphere(double altitude) {
|
||||
StandardTempOnly = true;
|
||||
Calculate(altitude);
|
||||
StandardTempOnly = false;
|
||||
atmosphere.Temperature = intTemperature;
|
||||
atmosphere.Pressure = intPressure;
|
||||
atmosphere.Density = intDensity;
|
||||
|
||||
// Reset the internal atmospheric state
|
||||
Calculate(h);
|
||||
SLpressure = press;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// Get the standard pressure at a specified altitude
|
||||
// Get the modeled density at a specified altitude
|
||||
|
||||
double FGAtmosphere::GetPressure(double altitude) {
|
||||
GetStdAtmosphere(altitude);
|
||||
return atmosphere.Pressure;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// Get the standard temperature at a specified altitude
|
||||
|
||||
double FGAtmosphere::GetTemperature(double altitude) {
|
||||
GetStdAtmosphere(altitude);
|
||||
return atmosphere.Temperature;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// Get the standard density at a specified altitude
|
||||
|
||||
double FGAtmosphere::GetDensity(double altitude) {
|
||||
GetStdAtmosphere(altitude);
|
||||
return atmosphere.Density;
|
||||
}
|
||||
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// square a value, but preserve the original sign
|
||||
|
||||
static inline double square_signed (double value)
|
||||
double FGAtmosphere::GetDensity(double altitude) const
|
||||
{
|
||||
if (value < 0)
|
||||
return value * value * -1;
|
||||
else
|
||||
return value * value;
|
||||
return GetPressure(altitude)/(Reng * GetTemperature(altitude));
|
||||
}
|
||||
|
||||
/// simply square a value
|
||||
static inline double sqr(double x) { return x*x; }
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
//
|
||||
// psi is the angle that the wind is blowing *towards*
|
||||
// This function sets the sea level temperature.
|
||||
// Internally, the Rankine scale is used for calculations, so any temperature
|
||||
// supplied must be converted to that unit.
|
||||
|
||||
void FGAtmosphere::SetWindspeed(double speed)
|
||||
void FGAtmosphere::SetTemperatureSL(double t, eTemperature unit)
|
||||
{
|
||||
if (vWindNED.Magnitude() == 0.0) {
|
||||
psiw = 0.0;
|
||||
vWindNED(eNorth) = speed;
|
||||
} else {
|
||||
vWindNED(eNorth) = speed * cos(psiw);
|
||||
vWindNED(eEast) = speed * sin(psiw);
|
||||
vWindNED(eDown) = 0.0;
|
||||
}
|
||||
SLtemperature = ConvertToRankine(t, unit);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGAtmosphere::GetWindspeed(void) const
|
||||
double FGAtmosphere::ConvertToRankine(double t, eTemperature unit) const
|
||||
{
|
||||
return vWindNED.Magnitude();
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
//
|
||||
// psi is the angle that the wind is blowing *towards*
|
||||
|
||||
void FGAtmosphere::SetWindPsi(double dir)
|
||||
{
|
||||
double mag = GetWindspeed();
|
||||
psiw = dir;
|
||||
SetWindspeed(mag);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGAtmosphere::Turbulence(void)
|
||||
{
|
||||
const double DeltaT = rate*FDMExec->GetDeltaT();
|
||||
const double wingspan = FDMExec->GetAircraft()->GetWingSpan();
|
||||
const double HOverBMAC = FDMExec->GetAuxiliary()->GetHOverBMAC();
|
||||
const FGMatrix33& Tl2b = FDMExec->GetPropagate()->GetTl2b();
|
||||
const double HTailArm = FDMExec->GetAircraft()->GetHTailArm();
|
||||
const double VTailArm = FDMExec->GetAircraft()->GetVTailArm();
|
||||
|
||||
switch (turbType) {
|
||||
case ttStandard: {
|
||||
// TurbGain = TurbGain * TurbGain * 100.0; // what is this!?
|
||||
|
||||
vDirectiondAccelDt(eX) = 1 - 2.0*(double(rand())/double(RAND_MAX));
|
||||
vDirectiondAccelDt(eY) = 1 - 2.0*(double(rand())/double(RAND_MAX));
|
||||
vDirectiondAccelDt(eZ) = 1 - 2.0*(double(rand())/double(RAND_MAX));
|
||||
|
||||
MagnitudedAccelDt = 1 - 2.0*(double(rand())/double(RAND_MAX)) - Magnitude;
|
||||
// Scale the magnitude so that it moves
|
||||
// away from the peaks
|
||||
MagnitudedAccelDt = ((MagnitudedAccelDt - Magnitude) /
|
||||
(1 + fabs(Magnitude)));
|
||||
MagnitudeAccel += MagnitudedAccelDt*TurbRate*DeltaT;
|
||||
Magnitude += MagnitudeAccel*DeltaT;
|
||||
Magnitude = fabs(Magnitude);
|
||||
|
||||
vDirectiondAccelDt.Normalize();
|
||||
|
||||
// deemphasise non-vertical forces
|
||||
vDirectiondAccelDt(eX) = square_signed(vDirectiondAccelDt(eX));
|
||||
vDirectiondAccelDt(eY) = square_signed(vDirectiondAccelDt(eY));
|
||||
|
||||
vDirectionAccel += vDirectiondAccelDt*TurbRate*DeltaT;
|
||||
vDirectionAccel.Normalize();
|
||||
vDirection += vDirectionAccel*DeltaT;
|
||||
|
||||
vDirection.Normalize();
|
||||
|
||||
// Diminish turbulence within three wingspans
|
||||
// of the ground
|
||||
vTurbulenceNED = TurbGain * Magnitude * vDirection;
|
||||
if (HOverBMAC < 3.0)
|
||||
vTurbulenceNED *= (HOverBMAC / 3.0) * (HOverBMAC / 3.0);
|
||||
|
||||
// I don't believe these next two statements calculate the proper gradient over
|
||||
// the aircraft body. One reason is because this has no relationship with the
|
||||
// orientation or velocity of the aircraft, which it must have. What is vTurbulenceGrad
|
||||
// supposed to represent? And the direction and magnitude of the turbulence can change,
|
||||
// so both accelerations need to be accounted for, no?
|
||||
|
||||
// Need to determine the turbulence change in body axes between two time points.
|
||||
|
||||
vTurbulenceGrad = TurbGain*MagnitudeAccel * vDirection;
|
||||
vBodyTurbGrad = Tl2b*vTurbulenceGrad;
|
||||
|
||||
if (wingspan > 0) {
|
||||
vTurbPQR(eP) = vBodyTurbGrad(eY)/wingspan;
|
||||
} else {
|
||||
vTurbPQR(eP) = vBodyTurbGrad(eY)/30.0;
|
||||
}
|
||||
// if (HTailArm != 0.0)
|
||||
// vTurbPQR(eQ) = vBodyTurbGrad(eZ)/HTailArm;
|
||||
// else
|
||||
// vTurbPQR(eQ) = vBodyTurbGrad(eZ)/10.0;
|
||||
|
||||
if (VTailArm > 0)
|
||||
vTurbPQR(eR) = vBodyTurbGrad(eX)/VTailArm;
|
||||
else
|
||||
vTurbPQR(eR) = vBodyTurbGrad(eX)/10.0;
|
||||
|
||||
// Clear the horizontal forces
|
||||
// actually felt by the plane, now
|
||||
// that we've used them to calculate
|
||||
// moments.
|
||||
// Why? (JSB)
|
||||
// vTurbulenceNED(eX) = 0.0;
|
||||
// vTurbulenceNED(eY) = 0.0;
|
||||
double targetTemp=0; // in degrees Rankine
|
||||
|
||||
switch(unit) {
|
||||
case eFahrenheit:
|
||||
targetTemp = t + 459.67;
|
||||
break;
|
||||
}
|
||||
|
||||
case ttCulp: {
|
||||
|
||||
vTurbPQR(eP) = wind_from_clockwise;
|
||||
if (TurbGain == 0.0) return;
|
||||
|
||||
// keep the inputs within allowable limts for this model
|
||||
if (TurbGain < 0.0) TurbGain = 0.0;
|
||||
if (TurbGain > 1.0) TurbGain = 1.0;
|
||||
if (TurbRate < 0.0) TurbRate = 0.0;
|
||||
if (TurbRate > 30.0) TurbRate = 30.0;
|
||||
if (Rhythmicity < 0.0) Rhythmicity = 0.0;
|
||||
if (Rhythmicity > 1.0) Rhythmicity = 1.0;
|
||||
|
||||
// generate a sine wave corresponding to turbulence rate in hertz
|
||||
double time = FDMExec->GetSimTime();
|
||||
double sinewave = sin( time * TurbRate * 6.283185307 );
|
||||
|
||||
double random = 0.0;
|
||||
if (target_time == 0.0) {
|
||||
strength = random = 1 - 2.0*(double(rand())/double(RAND_MAX));
|
||||
target_time = time + 0.71 + (random * 0.5);
|
||||
}
|
||||
if (time > target_time) {
|
||||
spike = 1.0;
|
||||
target_time = 0.0;
|
||||
}
|
||||
|
||||
// max vertical wind speed in fps, corresponds to TurbGain = 1.0
|
||||
double max_vs = 40;
|
||||
|
||||
vTurbulenceNED(1) = vTurbulenceNED(2) = vTurbulenceNED(3) = 0.0;
|
||||
double delta = strength * max_vs * TurbGain * (1-Rhythmicity) * spike;
|
||||
|
||||
// Vertical component of turbulence.
|
||||
vTurbulenceNED(3) = sinewave * max_vs * TurbGain * Rhythmicity;
|
||||
vTurbulenceNED(3)+= delta;
|
||||
if (HOverBMAC < 3.0)
|
||||
vTurbulenceNED(3) *= HOverBMAC * 0.3333;
|
||||
|
||||
// Yaw component of turbulence.
|
||||
vTurbulenceNED(1) = sin( delta * 3.0 );
|
||||
vTurbulenceNED(2) = cos( delta * 3.0 );
|
||||
|
||||
// Roll component of turbulence. Clockwise vortex causes left roll.
|
||||
vTurbPQR(eP) += delta * 0.04;
|
||||
|
||||
spike = spike * 0.9;
|
||||
case eCelsius:
|
||||
targetTemp = t*9.0/5.0 + 32.0 + 459.67;
|
||||
break;
|
||||
case eRankine:
|
||||
targetTemp = t;
|
||||
break;
|
||||
case eKelvin:
|
||||
targetTemp = t*9.0/5.0;
|
||||
}
|
||||
case ttMilspec:
|
||||
case ttTustin: {
|
||||
double V = FDMExec->GetAuxiliary()->GetVt(); // true airspeed in ft/s
|
||||
|
||||
// an index of zero means turbulence is disabled
|
||||
// airspeed occurs as divisor in the code below
|
||||
if (probability_of_exceedence_index == 0 || V == 0) {
|
||||
vTurbulenceNED(1) = vTurbulenceNED(2) = vTurbulenceNED(3) = 0.0;
|
||||
vTurbPQR(1) = vTurbPQR(2) = vTurbPQR(3) = 0.0;
|
||||
return;
|
||||
}
|
||||
return targetTemp;
|
||||
}
|
||||
|
||||
// Turbulence model according to MIL-F-8785C (Flying Qualities of Piloted Aircraft)
|
||||
double
|
||||
h = FDMExec->GetPropagate()->GetDistanceAGL(),
|
||||
b_w = wingspan,
|
||||
L_u, L_w, sig_u, sig_w;
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
if (b_w == 0.) b_w = 30.;
|
||||
double FGAtmosphere::ConvertToPSF(double p, ePressure unit) const
|
||||
{
|
||||
double targetPressure=0; // Pressure in PSF
|
||||
|
||||
// clip height functions at 10 ft
|
||||
if (h <= 10.) h = 10;
|
||||
|
||||
// Scale lengths L and amplitudes sigma as function of height
|
||||
if (h <= 1000) {
|
||||
L_u = h/pow(0.177 + 0.000823*h, 1.2); // MIL-F-8785c, Fig. 10, p. 55
|
||||
L_w = h;
|
||||
sig_w = 0.1*windspeed_at_20ft;
|
||||
sig_u = sig_w/pow(0.177 + 0.000823*h, 0.4); // MIL-F-8785c, Fig. 11, p. 56
|
||||
} else if (h <= 2000) {
|
||||
// linear interpolation between low altitude and high altitude models
|
||||
L_u = L_w = 1000 + (h-1000.)/1000.*750.;
|
||||
sig_u = sig_w = 0.1*windspeed_at_20ft
|
||||
+ (h-1000.)/1000.*(POE_Table->GetValue(probability_of_exceedence_index, h) - 0.1*windspeed_at_20ft);
|
||||
} else {
|
||||
L_u = L_w = 1750.; // MIL-F-8785c, Sec. 3.7.2.1, p. 48
|
||||
sig_u = sig_w = POE_Table->GetValue(probability_of_exceedence_index, h);
|
||||
}
|
||||
|
||||
// keep values from last timesteps
|
||||
// TODO maybe use deque?
|
||||
static double
|
||||
xi_u_km1 = 0, nu_u_km1 = 0,
|
||||
xi_v_km1 = 0, xi_v_km2 = 0, nu_v_km1 = 0, nu_v_km2 = 0,
|
||||
xi_w_km1 = 0, xi_w_km2 = 0, nu_w_km1 = 0, nu_w_km2 = 0,
|
||||
xi_p_km1 = 0, nu_p_km1 = 0,
|
||||
xi_q_km1 = 0, xi_r_km1 = 0;
|
||||
|
||||
|
||||
double
|
||||
T_V = DeltaT, // for compatibility of nomenclature
|
||||
sig_p = 1.9/sqrt(L_w*b_w)*sig_w, // Yeager1998, eq. (8)
|
||||
sig_q = sqrt(M_PI/2/L_w/b_w), // eq. (14)
|
||||
sig_r = sqrt(2*M_PI/3/L_w/b_w), // eq. (17)
|
||||
L_p = sqrt(L_w*b_w)/2.6, // eq. (10)
|
||||
tau_u = L_u/V, // eq. (6)
|
||||
tau_w = L_w/V, // eq. (3)
|
||||
tau_p = L_p/V, // eq. (9)
|
||||
tau_q = 4*b_w/M_PI/V, // eq. (13)
|
||||
tau_r =3*b_w/M_PI/V, // eq. (17)
|
||||
nu_u = GaussianRandomNumber(),
|
||||
nu_v = GaussianRandomNumber(),
|
||||
nu_w = GaussianRandomNumber(),
|
||||
nu_p = GaussianRandomNumber(),
|
||||
xi_u=0, xi_v=0, xi_w=0, xi_p=0, xi_q=0, xi_r=0;
|
||||
|
||||
// values of turbulence NED velocities
|
||||
|
||||
if (turbType == ttTustin) {
|
||||
// the following is the Tustin formulation of Yeager's report
|
||||
double
|
||||
omega_w = V/L_w, // hidden in nomenclature p. 3
|
||||
omega_v = V/L_u, // this is defined nowhere
|
||||
C_BL = 1/tau_u/tan(T_V/2/tau_u), // eq. (19)
|
||||
C_BLp = 1/tau_p/tan(T_V/2/tau_p), // eq. (22)
|
||||
C_BLq = 1/tau_q/tan(T_V/2/tau_q), // eq. (24)
|
||||
C_BLr = 1/tau_r/tan(T_V/2/tau_r); // eq. (26)
|
||||
|
||||
// all values calculated so far are strictly positive, except for
|
||||
// the random numbers nu_*. This means that in the code below, all
|
||||
// divisors are strictly positive, too, and no floating point
|
||||
// exception should occur.
|
||||
xi_u = -(1 - C_BL*tau_u)/(1 + C_BL*tau_u)*xi_u_km1
|
||||
+ sig_u*sqrt(2*tau_u/T_V)/(1 + C_BL*tau_u)*(nu_u + nu_u_km1); // eq. (18)
|
||||
xi_v = -2*(sqr(omega_v) - sqr(C_BL))/sqr(omega_v + C_BL)*xi_v_km1
|
||||
- sqr(omega_v - C_BL)/sqr(omega_v + C_BL) * xi_v_km2
|
||||
+ sig_u*sqrt(3*omega_v/T_V)/sqr(omega_v + C_BL)*(
|
||||
(C_BL + omega_v/sqrt(3.))*nu_v
|
||||
+ 2/sqrt(3.)*omega_v*nu_v_km1
|
||||
+ (omega_v/sqrt(3.) - C_BL)*nu_v_km2); // eq. (20) for v
|
||||
xi_w = -2*(sqr(omega_w) - sqr(C_BL))/sqr(omega_w + C_BL)*xi_w_km1
|
||||
- sqr(omega_w - C_BL)/sqr(omega_w + C_BL) * xi_w_km2
|
||||
+ sig_w*sqrt(3*omega_w/T_V)/sqr(omega_w + C_BL)*(
|
||||
(C_BL + omega_w/sqrt(3.))*nu_w
|
||||
+ 2/sqrt(3.)*omega_w*nu_w_km1
|
||||
+ (omega_w/sqrt(3.) - C_BL)*nu_w_km2); // eq. (20) for w
|
||||
xi_p = -(1 - C_BLp*tau_p)/(1 + C_BLp*tau_p)*xi_p_km1
|
||||
+ sig_p*sqrt(2*tau_p/T_V)/(1 + C_BLp*tau_p) * (nu_p + nu_p_km1); // eq. (21)
|
||||
xi_q = -(1 - 4*b_w*C_BLq/M_PI/V)/(1 + 4*b_w*C_BLq/M_PI/V) * xi_q_km1
|
||||
+ C_BLq/V/(1 + 4*b_w*C_BLq/M_PI/V) * (xi_w - xi_w_km1); // eq. (23)
|
||||
xi_r = - (1 - 3*b_w*C_BLr/M_PI/V)/(1 + 3*b_w*C_BLr/M_PI/V) * xi_r_km1
|
||||
+ C_BLr/V/(1 + 3*b_w*C_BLr/M_PI/V) * (xi_v - xi_v_km1); // eq. (25)
|
||||
|
||||
} else if (turbType == ttMilspec) {
|
||||
// the following is the MIL-STD-1797A formulation
|
||||
// as cited in Yeager's report
|
||||
xi_u = (1 - T_V/tau_u) *xi_u_km1 + sig_u*sqrt(2*T_V/tau_u)*nu_u; // eq. (30)
|
||||
xi_v = (1 - 2*T_V/tau_u)*xi_v_km1 + sig_u*sqrt(4*T_V/tau_u)*nu_v; // eq. (31)
|
||||
xi_w = (1 - 2*T_V/tau_w)*xi_w_km1 + sig_w*sqrt(4*T_V/tau_w)*nu_w; // eq. (32)
|
||||
xi_p = (1 - T_V/tau_p) *xi_p_km1 + sig_p*sqrt(2*T_V/tau_p)*nu_p; // eq. (33)
|
||||
xi_q = (1 - T_V/tau_q) *xi_q_km1 + M_PI/4/b_w*(xi_w - xi_w_km1); // eq. (34)
|
||||
xi_r = (1 - T_V/tau_r) *xi_r_km1 + M_PI/3/b_w*(xi_v - xi_v_km1); // eq. (35)
|
||||
}
|
||||
|
||||
// rotate by wind azimuth and assign the velocities
|
||||
double cospsi = cos(psiw), sinpsi = sin(psiw);
|
||||
vTurbulenceNED(1) = cospsi*xi_u + sinpsi*xi_v;
|
||||
vTurbulenceNED(2) = -sinpsi*xi_u + cospsi*xi_v;
|
||||
vTurbulenceNED(3) = xi_w;
|
||||
|
||||
vTurbPQR(1) = cospsi*xi_p + sinpsi*xi_q;
|
||||
vTurbPQR(2) = -sinpsi*xi_p + cospsi*xi_q;
|
||||
vTurbPQR(3) = xi_r;
|
||||
|
||||
// vTurbPQR is in the body fixed frame, not NED
|
||||
vTurbPQR = Tl2b*vTurbPQR;
|
||||
|
||||
// hand on the values for the next timestep
|
||||
xi_u_km1 = xi_u; nu_u_km1 = nu_u;
|
||||
xi_v_km2 = xi_v_km1; xi_v_km1 = xi_v; nu_v_km2 = nu_v_km1; nu_v_km1 = nu_v;
|
||||
xi_w_km2 = xi_w_km1; xi_w_km1 = xi_w; nu_w_km2 = nu_w_km1; nu_w_km1 = nu_w;
|
||||
xi_p_km1 = xi_p; nu_p_km1 = nu_p;
|
||||
xi_q_km1 = xi_q;
|
||||
xi_r_km1 = xi_r;
|
||||
|
||||
}
|
||||
switch(unit) {
|
||||
case ePSF:
|
||||
targetPressure = p;
|
||||
break;
|
||||
case eMillibars:
|
||||
targetPressure = p*2.08854342;
|
||||
break;
|
||||
case ePascals:
|
||||
targetPressure = p*0.0208854342;
|
||||
break;
|
||||
case eInchesHg:
|
||||
targetPressure = p*70.7180803;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
throw("Undefined pressure unit given");
|
||||
}
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGAtmosphere::UseExternal(void)
|
||||
{
|
||||
temperature=&exTemperature;
|
||||
pressure=&exPressure;
|
||||
density=&exDensity;
|
||||
useExternal=true;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGAtmosphere::UseInternal(void)
|
||||
{
|
||||
temperature=&intTemperature;
|
||||
pressure=&intPressure;
|
||||
density=&intDensity;
|
||||
useExternal=false;
|
||||
return targetPressure;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGAtmosphere::bind(void)
|
||||
{
|
||||
typedef double (FGAtmosphere::*PMF)(int) const;
|
||||
typedef double (FGAtmosphere::*PMFv)(void) const;
|
||||
typedef int (FGAtmosphere::*PMFt)(void) const;
|
||||
typedef void (FGAtmosphere::*PMFd)(int,double);
|
||||
typedef void (FGAtmosphere::*PMFi)(int);
|
||||
PropertyManager->Tie("atmosphere/T-R", this, (PMFv)&FGAtmosphere::GetTemperature);
|
||||
PropertyManager->Tie("atmosphere/rho-slugs_ft3", this, (PMFv)&FGAtmosphere::GetDensity);
|
||||
PropertyManager->Tie("atmosphere/P-psf", this, (PMFv)&FGAtmosphere::GetPressure);
|
||||
typedef double (FGAtmosphere::*PMFi)(int) const;
|
||||
typedef void (FGAtmosphere::*PMF)(int, double);
|
||||
PropertyManager->Tie("atmosphere/T-R", this, &FGAtmosphere::GetTemperature);
|
||||
PropertyManager->Tie("atmosphere/rho-slugs_ft3", this, &FGAtmosphere::GetDensity);
|
||||
PropertyManager->Tie("atmosphere/P-psf", this, &FGAtmosphere::GetPressure);
|
||||
PropertyManager->Tie("atmosphere/a-fps", this, &FGAtmosphere::GetSoundSpeed);
|
||||
PropertyManager->Tie("atmosphere/T-sl-R", this, &FGAtmosphere::GetTemperatureSL);
|
||||
PropertyManager->Tie("atmosphere/rho-sl-slugs_ft3", this, &FGAtmosphere::GetDensitySL);
|
||||
|
@ -712,53 +220,8 @@ void FGAtmosphere::bind(void)
|
|||
PropertyManager->Tie("atmosphere/sigma", this, &FGAtmosphere::GetDensityRatio);
|
||||
PropertyManager->Tie("atmosphere/delta", this, &FGAtmosphere::GetPressureRatio);
|
||||
PropertyManager->Tie("atmosphere/a-ratio", this, &FGAtmosphere::GetSoundSpeedRatio);
|
||||
PropertyManager->Tie("atmosphere/psiw-rad", this, &FGAtmosphere::GetWindPsi, &FGAtmosphere::SetWindPsi);
|
||||
PropertyManager->Tie("atmosphere/delta-T", this, &FGAtmosphere::GetDeltaT, &FGAtmosphere::SetDeltaT);
|
||||
PropertyManager->Tie("atmosphere/T-sl-dev-F", this, &FGAtmosphere::GetSLTempDev, &FGAtmosphere::SetSLTempDev);
|
||||
PropertyManager->Tie("atmosphere/density-altitude", this, &FGAtmosphere::GetDensityAltitude);
|
||||
|
||||
PropertyManager->Tie("atmosphere/wind-north-fps", this, eNorth, (PMF)&FGAtmosphere::GetWindNED,
|
||||
(PMFd)&FGAtmosphere::SetWindNED);
|
||||
PropertyManager->Tie("atmosphere/wind-east-fps", this, eEast, (PMF)&FGAtmosphere::GetWindNED,
|
||||
(PMFd)&FGAtmosphere::SetWindNED);
|
||||
PropertyManager->Tie("atmosphere/wind-down-fps", this, eDown, (PMF)&FGAtmosphere::GetWindNED,
|
||||
(PMFd)&FGAtmosphere::SetWindNED);
|
||||
PropertyManager->Tie("atmosphere/wind-mag-fps", this, &FGAtmosphere::GetWindspeed,
|
||||
&FGAtmosphere::SetWindspeed);
|
||||
PropertyManager->Tie("atmosphere/total-wind-north-fps", this, eNorth, (PMF)&FGAtmosphere::GetTotalWindNED);
|
||||
PropertyManager->Tie("atmosphere/total-wind-east-fps", this, eEast, (PMF)&FGAtmosphere::GetTotalWindNED);
|
||||
PropertyManager->Tie("atmosphere/total-wind-down-fps", this, eDown, (PMF)&FGAtmosphere::GetTotalWindNED);
|
||||
|
||||
PropertyManager->Tie("atmosphere/gust-north-fps", this, eNorth, (PMF)&FGAtmosphere::GetGustNED,
|
||||
(PMFd)&FGAtmosphere::SetGustNED);
|
||||
PropertyManager->Tie("atmosphere/gust-east-fps", this, eEast, (PMF)&FGAtmosphere::GetGustNED,
|
||||
(PMFd)&FGAtmosphere::SetGustNED);
|
||||
PropertyManager->Tie("atmosphere/gust-down-fps", this, eDown, (PMF)&FGAtmosphere::GetGustNED,
|
||||
(PMFd)&FGAtmosphere::SetGustNED);
|
||||
|
||||
PropertyManager->Tie("atmosphere/turb-north-fps", this, eNorth, (PMF)&FGAtmosphere::GetTurbNED,
|
||||
(PMFd)&FGAtmosphere::SetTurbNED);
|
||||
PropertyManager->Tie("atmosphere/turb-east-fps", this, eEast, (PMF)&FGAtmosphere::GetTurbNED,
|
||||
(PMFd)&FGAtmosphere::SetTurbNED);
|
||||
PropertyManager->Tie("atmosphere/turb-down-fps", this, eDown, (PMF)&FGAtmosphere::GetTurbNED,
|
||||
(PMFd)&FGAtmosphere::SetTurbNED);
|
||||
|
||||
PropertyManager->Tie("atmosphere/p-turb-rad_sec", this,1, (PMF)&FGAtmosphere::GetTurbPQR);
|
||||
PropertyManager->Tie("atmosphere/q-turb-rad_sec", this,2, (PMF)&FGAtmosphere::GetTurbPQR);
|
||||
PropertyManager->Tie("atmosphere/r-turb-rad_sec", this,3, (PMF)&FGAtmosphere::GetTurbPQR);
|
||||
PropertyManager->Tie("atmosphere/turb-type", this, (PMFt)&FGAtmosphere::GetTurbType, (PMFi)&FGAtmosphere::SetTurbType);
|
||||
PropertyManager->Tie("atmosphere/turb-rate", this, &FGAtmosphere::GetTurbRate, &FGAtmosphere::SetTurbRate);
|
||||
PropertyManager->Tie("atmosphere/turb-gain", this, &FGAtmosphere::GetTurbGain, &FGAtmosphere::SetTurbGain);
|
||||
PropertyManager->Tie("atmosphere/turb-rhythmicity", this, &FGAtmosphere::GetRhythmicity,
|
||||
&FGAtmosphere::SetRhythmicity);
|
||||
|
||||
PropertyManager->Tie("atmosphere/turbulence/milspec/windspeed_at_20ft_AGL-fps",
|
||||
this, &FGAtmosphere::GetWindspeed20ft,
|
||||
&FGAtmosphere::SetWindspeed20ft);
|
||||
PropertyManager->Tie("atmosphere/turbulence/milspec/severity",
|
||||
this, &FGAtmosphere::GetProbabilityOfExceedence,
|
||||
&FGAtmosphere::SetProbabilityOfExceedence);
|
||||
|
||||
PropertyManager->Tie("atmosphere/pressure-altitude", this, &FGAtmosphere::GetPressureAltitude);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -789,8 +252,8 @@ void FGAtmosphere::Debug(int from)
|
|||
}
|
||||
}
|
||||
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
|
||||
if (from == 0) cout << "Instantiated: FGAtmosphere" << endl;
|
||||
if (from == 1) cout << "Destroyed: FGAtmosphere" << endl;
|
||||
if (from == 0) std::cout << "Instantiated: FGAtmosphere" << std::endl;
|
||||
if (from == 1) std::cout << "Destroyed: FGAtmosphere" << std::endl;
|
||||
}
|
||||
if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
|
||||
}
|
||||
|
@ -798,23 +261,12 @@ void FGAtmosphere::Debug(int from)
|
|||
}
|
||||
if (debug_lvl & 16) { // Sanity checking
|
||||
}
|
||||
if (debug_lvl & 128) { // Turbulence
|
||||
if (first_pass && from == 2) {
|
||||
first_pass = false;
|
||||
cout << "vTurbulenceNED(X), vTurbulenceNED(Y), vTurbulenceNED(Z), "
|
||||
<< "vTurbulenceGrad(X), vTurbulenceGrad(Y), vTurbulenceGrad(Z), "
|
||||
<< "vDirection(X), vDirection(Y), vDirection(Z), "
|
||||
<< "Magnitude, "
|
||||
<< "vTurbPQR(P), vTurbPQR(Q), vTurbPQR(R), " << endl;
|
||||
}
|
||||
if (from == 2) {
|
||||
cout << vTurbulenceNED << ", " << vTurbulenceGrad << ", " << vDirection << ", " << Magnitude << ", " << vTurbPQR << endl;
|
||||
}
|
||||
if (debug_lvl & 128) { //
|
||||
}
|
||||
if (debug_lvl & 64) {
|
||||
if (from == 0) { // Constructor
|
||||
cout << IdSrc << endl;
|
||||
cout << IdHdr << endl;
|
||||
std::cout << IdSrc << std::endl;
|
||||
std::cout << IdHdr << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,10 +2,9 @@
|
|||
|
||||
Header: FGAtmosphere.h
|
||||
Author: Jon Berndt
|
||||
Implementation of 1959 Standard Atmosphere added by Tony Peden
|
||||
Date started: 11/24/98
|
||||
Date started: 6/2011
|
||||
|
||||
------------- Copyright (C) 1999 Jon S. Berndt (jon@jsbsim.org) -------------
|
||||
------------- Copyright (C) 2011 Jon S. Berndt (jon@jsbsim.org) -------------
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the Free Software
|
||||
|
@ -26,10 +25,7 @@
|
|||
|
||||
HISTORY
|
||||
--------------------------------------------------------------------------------
|
||||
11/24/98 JSB Created
|
||||
07/23/99 TP Added implementation of 1959 Standard Atmosphere
|
||||
Moved calculation of Mach number to FGPropagate
|
||||
Updated to '76 model
|
||||
5/2011 JSB Created
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
SENTRY
|
||||
|
@ -42,15 +38,14 @@ SENTRY
|
|||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include "FGModel.h"
|
||||
#include "math/FGColumnVector3.h"
|
||||
#include "math/FGTable.h"
|
||||
#include <vector>
|
||||
#include "models/FGModel.h"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_ATMOSPHERE "$Id: FGAtmosphere.h,v 1.26 2011/05/20 03:18:36 jberndt Exp $"
|
||||
#define ID_ATMOSPHERE "$Id: FGAtmosphere.h,v 1.29 2011/07/10 20:18:14 jberndt Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -62,62 +57,24 @@ namespace JSBSim {
|
|||
CLASS DOCUMENTATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
/** Models the 1976 Standard Atmosphere.
|
||||
@author Tony Peden, Jon Berndt
|
||||
@version $Id: FGAtmosphere.h,v 1.26 2011/05/20 03:18:36 jberndt Exp $
|
||||
@see Anderson, John D. "Introduction to Flight, Third Edition", McGraw-Hill,
|
||||
1989, ISBN 0-07-001641-0
|
||||
/** Models an empty, abstract base atmosphere class.
|
||||
|
||||
Additionally, various turbulence models are available. They are specified
|
||||
via the property <tt>atmosphere/turb-type</tt>. The following models are
|
||||
available:
|
||||
- 0: ttNone (turbulence disabled)
|
||||
- 1: ttStandard
|
||||
- 2: ttBerndt
|
||||
- 3: ttCulp
|
||||
- 4: ttMilspec (Dryden spectrum)
|
||||
- 5: ttTustin (Dryden spectrum)
|
||||
|
||||
The Milspec and Tustin models are described in the Yeager report cited below.
|
||||
They both use a Dryden spectrum model whose parameters (scale lengths and intensities)
|
||||
are modelled according to MIL-F-8785C. Parameters are modelled differently
|
||||
for altitudes below 1000ft and above 2000ft, for altitudes in between they
|
||||
are interpolated linearly.
|
||||
|
||||
The two models differ in the implementation of the transfer functions
|
||||
described in the milspec.
|
||||
|
||||
To use one of these two models, set <tt>atmosphere/turb-type</tt> to 4 resp. 5,
|
||||
and specify values for <tt>atmosphere/turbulence/milspec/windspeed_at_20ft_AGL-fps<tt>
|
||||
and <tt>atmosphere/turbulence/milspec/severity<tt> (the latter corresponds to
|
||||
the probability of exceedence curves from Fig. 7 of the milspec, allowable
|
||||
range is 0 (disabled) to 7). <tt>atmosphere/psiw-rad</tt> is respected as well;
|
||||
note that you have to specify a positive wind magnitude to prevent psiw from
|
||||
being reset to zero.
|
||||
|
||||
Reference values (cf. figures 7 and 9 from the milspec):
|
||||
<table>
|
||||
<tr><td><b>Intensity</b></td>
|
||||
<td><b><tt>windspeed_at_20ft_AGL-fps</tt></b></td>
|
||||
<td><b><tt>severity</tt></b></td></tr>
|
||||
<tr><td>light</td>
|
||||
<td>25 (15 knots)</td>
|
||||
<td>3</td></tr>
|
||||
<tr><td>moderate</td>
|
||||
<td>50 (30 knots)</td>
|
||||
<td>4</td></tr>
|
||||
<tr><td>severe</td>
|
||||
<td>75 (45 knots)</td>
|
||||
<td>6</td></tr>
|
||||
</table>
|
||||
|
||||
@see Yeager, Jessie C.: "Implementation and Testing of Turbulence Models for
|
||||
the F18-HARV" (<a
|
||||
href="http://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19980028448_1998081596.pdf">
|
||||
pdf</a>), NASA CR-1998-206937, 1998
|
||||
|
||||
@see MIL-F-8785C: Military Specification: Flying Qualities of Piloted Aircraft
|
||||
<h2> Properties </h2>
|
||||
@property atmosphere/T-R The current modeled temperature in degrees Rankine.
|
||||
@property atmosphere/rho-slugs_ft3
|
||||
@property atmosphere/P-psf
|
||||
@property atmosphere/a-fps
|
||||
@property atmosphere/T-sl-R
|
||||
@property atmosphere/rho-sl-slugs_ft3
|
||||
@property atmosphere/P-sl-psf
|
||||
@property atmosphere/a-sl-fps
|
||||
@property atmosphere/theta
|
||||
@property atmosphere/sigma
|
||||
@property atmosphere/delta
|
||||
@property atmosphere/a-ratio
|
||||
|
||||
@author Jon Berndt
|
||||
@version $Id: FGAtmosphere.h,v 1.29 2011/07/10 20:18:14 jberndt Exp $
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -127,11 +84,19 @@ CLASS DECLARATION
|
|||
class FGAtmosphere : public FGModel {
|
||||
public:
|
||||
|
||||
/// Enums for specifying temperature units.
|
||||
enum eTemperature {eNoTempUnit=0, eFahrenheit, eCelsius, eRankine, eKelvin};
|
||||
|
||||
/// Enums for specifying pressure units.
|
||||
enum ePressure {eNoPressUnit=0, ePSF, eMillibars, ePascals, eInchesHg};
|
||||
|
||||
/// Constructor
|
||||
FGAtmosphere(FGFDMExec*);
|
||||
|
||||
/// Destructor
|
||||
~FGAtmosphere();
|
||||
/** Runs the Atmosphere model; called by the Executive
|
||||
virtual ~FGAtmosphere();
|
||||
|
||||
/** Runs the atmosphere forces model; called by the Executive.
|
||||
Can pass in a value indicating if the executive is directing the simulation to Hold.
|
||||
@param Holding if true, the executive has been directed to hold the sim from
|
||||
advancing time. Some models may ignore this flag, such as the Input
|
||||
|
@ -139,210 +104,137 @@ public:
|
|||
"Resume" command to be given.
|
||||
@return false if no error */
|
||||
bool Run(bool Holding);
|
||||
|
||||
bool InitModel(void);
|
||||
enum tType {ttNone, ttStandard, ttCulp, ttMilspec, ttTustin} turbType;
|
||||
|
||||
/// Returns the temperature in degrees Rankine.
|
||||
virtual double GetTemperature(void) const {return *temperature;}
|
||||
/** Returns the density in slugs/ft^3.
|
||||
<i>This function may <b>only</b> be used if Run() is called first.</i> */
|
||||
virtual double GetDensity(void) const {return *density;}
|
||||
// *************************************************************************
|
||||
/// @name Temperature access functions.
|
||||
/// There are several ways to get the temperature, and several modeled temperature
|
||||
/// values that can be retrieved.
|
||||
// @{
|
||||
/// Returns the actual, modeled temperature at the current altitude in degrees Rankine.
|
||||
/// @return Modeled temperature in degrees Rankine.
|
||||
virtual double GetTemperature() const {return Temperature;}
|
||||
|
||||
/// Returns the actual modeled temperature in degrees Rankine at a specified altitude.
|
||||
/// @param altitude The altitude above sea level (ASL) in feet.
|
||||
/// @return Modeled temperature in degrees Rankine at the specified altitude.
|
||||
virtual double GetTemperature(double altitude) const = 0;
|
||||
|
||||
/// Returns the actual, modeled sea level temperature in degrees Rankine.
|
||||
/// @return The modeled temperature in degrees Rankine at sea level.
|
||||
virtual double GetTemperatureSL() const { return GetTemperature(0.0); }
|
||||
|
||||
/// Returns the ratio of the at-current-altitude temperature as modeled
|
||||
/// over the sea level value.
|
||||
virtual double GetTemperatureRatio() const { return GetTemperature()*rSLtemperature; }
|
||||
|
||||
/// Returns the ratio of the temperature as modeled at the supplied altitude
|
||||
/// over the sea level value.
|
||||
virtual double GetTemperatureRatio(double h) const { return GetTemperature(h)*rSLtemperature; }
|
||||
|
||||
/// Sets the Sea Level temperature.
|
||||
/// @param t the temperature value in the unit provided.
|
||||
/// @param unit the unit of the temperature.
|
||||
virtual void SetTemperatureSL(double t, eTemperature unit=eFahrenheit);
|
||||
|
||||
/// Sets the temperature at the supplied altitude.
|
||||
/// @param t The temperature value in the unit provided.
|
||||
/// @param h The altitude in feet above sea level.
|
||||
/// @param unit The unit of the temperature.
|
||||
virtual void SetTemperature(double t, double h, eTemperature unit=eFahrenheit) = 0;
|
||||
//@}
|
||||
|
||||
// *************************************************************************
|
||||
/// @name Pressure access functions.
|
||||
//@{
|
||||
/// Returns the pressure in psf.
|
||||
virtual double GetPressure(void) const {return *pressure;}
|
||||
/// Returns the standard pressure at a specified altitude
|
||||
virtual double GetPressure(double altitude);
|
||||
/// Returns the standard temperature at a specified altitude
|
||||
virtual double GetTemperature(double altitude);
|
||||
/// Returns the standard density at a specified altitude
|
||||
virtual double GetDensity(double altitude);
|
||||
/// Returns the speed of sound in ft/sec.
|
||||
virtual double GetSoundSpeed(void) const {return soundspeed;}
|
||||
/// Returns the absolute viscosity.
|
||||
virtual double GetAbsoluteViscosity(void) const {return intViscosity;}
|
||||
/// Returns the kinematic viscosity.
|
||||
virtual double GetKinematicViscosity(void) const {return intKinematicViscosity;}
|
||||
virtual double GetPressure(void) const {return Pressure;}
|
||||
|
||||
/// Returns the pressure at a specified altitude in psf.
|
||||
virtual double GetPressure(double altitude) const = 0;
|
||||
|
||||
/// Returns the sea level temperature in degrees Rankine.
|
||||
virtual double GetTemperatureSL(void) const { return SLtemperature; }
|
||||
/// Returns the sea level density in slugs/ft^3
|
||||
virtual double GetDensitySL(void) const { return SLdensity; }
|
||||
/// Returns the sea level pressure in psf.
|
||||
virtual double GetPressureSL(void) const { return SLpressure; }
|
||||
|
||||
/// Returns the ratio of at-altitude pressure over the sea level value.
|
||||
virtual double GetPressureRatio(void) const { return Pressure*rSLpressure; }
|
||||
|
||||
/** Sets the sea level pressure for modeling.
|
||||
@param pressure The pressure in the units specified (PSF by default).
|
||||
@param unit the unit of measure that the specified pressure is
|
||||
supplied in.*/
|
||||
virtual void SetPressureSL(double pressure, ePressure unit=ePSF);
|
||||
//@}
|
||||
|
||||
// *************************************************************************
|
||||
/// @name Density access functions.
|
||||
//@{
|
||||
/** Returns the density in slugs/ft^3.
|
||||
This function may only be used if Run() is called first. */
|
||||
virtual double GetDensity(void) const {return Density;}
|
||||
|
||||
/** Returns the density in slugs/ft^3 at a given altitude in ft. */
|
||||
virtual double GetDensity(double altitude) const;
|
||||
|
||||
/// Returns the sea level density in slugs/ft^3
|
||||
virtual double GetDensitySL(void) const { return SLdensity; }
|
||||
|
||||
/// Returns the ratio of at-altitude density over the sea level value.
|
||||
virtual double GetDensityRatio(void) const { return Density*rSLdensity; }
|
||||
//@}
|
||||
|
||||
// *************************************************************************
|
||||
/// @name Speed of sound access functions.
|
||||
//@{
|
||||
/// Returns the speed of sound in ft/sec.
|
||||
virtual double GetSoundSpeed(void) const {return Soundspeed;}
|
||||
|
||||
/// Returns the sea level speed of sound in ft/sec.
|
||||
virtual double GetSoundSpeedSL(void) const { return SLsoundspeed; }
|
||||
|
||||
/// Returns the ratio of at-altitude temperature over the sea level value.
|
||||
virtual double GetTemperatureRatio(void) const { return (*temperature)*rSLtemperature; }
|
||||
/// Returns the ratio of at-altitude density over the sea level value.
|
||||
virtual double GetDensityRatio(void) const { return (*density)*rSLdensity; }
|
||||
/// Returns the ratio of at-altitude pressure over the sea level value.
|
||||
virtual double GetPressureRatio(void) const { return (*pressure)*rSLpressure; }
|
||||
/// Returns the ratio of at-altitude sound speed over the sea level value.
|
||||
virtual double GetSoundSpeedRatio(void) const { return soundspeed*rSLsoundspeed; }
|
||||
virtual double GetSoundSpeedRatio(void) const { return Soundspeed*rSLsoundspeed; }
|
||||
//@}
|
||||
|
||||
/// Tells the simulator to use an externally calculated atmosphere model.
|
||||
virtual void UseExternal(void);
|
||||
/// Tells the simulator to use the internal atmosphere model.
|
||||
virtual void UseInternal(void); //this is the default
|
||||
/// Gets the boolean that tells if the external atmosphere model is being used.
|
||||
virtual bool External(void) { return useExternal; }
|
||||
// *************************************************************************
|
||||
/// @name Viscosity access functions.
|
||||
//@{
|
||||
/// Returns the absolute viscosity.
|
||||
virtual double GetAbsoluteViscosity(void) const {return Viscosity;}
|
||||
|
||||
/// Provides the external atmosphere model with an interface to set the temperature.
|
||||
virtual void SetExTemperature(double t) { exTemperature=t; }
|
||||
/// Provides the external atmosphere model with an interface to set the density.
|
||||
virtual void SetExDensity(double d) { exDensity=d; }
|
||||
/// Provides the external atmosphere model with an interface to set the pressure.
|
||||
virtual void SetExPressure(double p) { exPressure=p; }
|
||||
/// Returns the kinematic viscosity.
|
||||
virtual double GetKinematicViscosity(void) const {return KinematicViscosity;}
|
||||
//@}
|
||||
|
||||
/// Sets the temperature deviation at sea-level in degrees Fahrenheit
|
||||
virtual void SetSLTempDev(double d) { T_dev_sl = d; }
|
||||
/// Gets the temperature deviation at sea-level in degrees Fahrenheit
|
||||
virtual double GetSLTempDev(void) const { return T_dev_sl; }
|
||||
/// Sets the current delta-T in degrees Fahrenheit
|
||||
virtual void SetDeltaT(double d) { delta_T = d; }
|
||||
/// Gets the current delta-T in degrees Fahrenheit
|
||||
virtual double GetDeltaT(void) const { return delta_T; }
|
||||
/// Gets the at-altitude temperature deviation in degrees Fahrenheit
|
||||
virtual double GetTempDev(void) const { return T_dev; }
|
||||
/// Gets the density altitude in feet
|
||||
virtual double GetDensityAltitude(void) const { return density_altitude; }
|
||||
virtual double GetDensityAltitude() const {return DensityAltitude;}
|
||||
|
||||
// TOTAL WIND access functions (wind + gust + turbulence)
|
||||
virtual double GetPressureAltitude() const {return PressureAltitude;}
|
||||
|
||||
/// Retrieves the total wind components in NED frame.
|
||||
virtual const FGColumnVector3& GetTotalWindNED(void) const { return vTotalWindNED; }
|
||||
|
||||
/// Retrieves a total wind component in NED frame.
|
||||
virtual double GetTotalWindNED(int idx) const {return vTotalWindNED(idx);}
|
||||
|
||||
// WIND access functions
|
||||
|
||||
/// Sets the wind components in NED frame.
|
||||
virtual void SetWindNED(double wN, double wE, double wD) { vWindNED(1)=wN; vWindNED(2)=wE; vWindNED(3)=wD;}
|
||||
|
||||
/// Sets a wind component in NED frame.
|
||||
virtual void SetWindNED(int idx, double wind) { vWindNED(idx)=wind;}
|
||||
|
||||
/// Retrieves the wind components in NED frame.
|
||||
virtual FGColumnVector3& GetWindNED(void) { return vWindNED; }
|
||||
|
||||
/// Retrieves a wind component in NED frame.
|
||||
virtual double GetWindNED(int idx) const {return vWindNED(idx);}
|
||||
|
||||
/** Retrieves the direction that the wind is coming from.
|
||||
The direction is defined as north=0 and increases counterclockwise.
|
||||
The wind heading is returned in radians.*/
|
||||
virtual double GetWindPsi(void) const { return psiw; }
|
||||
|
||||
/** Sets the direction that the wind is coming from.
|
||||
The direction is defined as north=0 and increases counterclockwise to 2*pi (radians). The
|
||||
vertical component of wind is assumed to be zero - and is forcibly set to zero. This function
|
||||
sets the vWindNED vector components based on the supplied direction. The magnitude of
|
||||
the wind set in the vector is preserved (assuming the vertical component is non-zero).
|
||||
@param dir wind direction in the horizontal plane, in radians.*/
|
||||
virtual void SetWindPsi(double dir);
|
||||
|
||||
virtual void SetWindspeed(double speed);
|
||||
|
||||
virtual double GetWindspeed(void) const;
|
||||
|
||||
// GUST access functions
|
||||
|
||||
/// Sets a gust component in NED frame.
|
||||
virtual void SetGustNED(int idx, double gust) { vGustNED(idx)=gust;}
|
||||
|
||||
/// Sets a turbulence component in NED frame.
|
||||
virtual void SetTurbNED(int idx, double turb) { vTurbulenceNED(idx)=turb;}
|
||||
|
||||
/// Sets the gust components in NED frame.
|
||||
virtual void SetGustNED(double gN, double gE, double gD) { vGustNED(eNorth)=gN; vGustNED(eEast)=gE; vGustNED(eDown)=gD;}
|
||||
|
||||
/// Retrieves a gust component in NED frame.
|
||||
virtual double GetGustNED(int idx) const {return vGustNED(idx);}
|
||||
|
||||
/// Retrieves a turbulence component in NED frame.
|
||||
virtual double GetTurbNED(int idx) const {return vTurbulenceNED(idx);}
|
||||
|
||||
/// Retrieves the gust components in NED frame.
|
||||
virtual FGColumnVector3& GetGustNED(void) {return vGustNED;}
|
||||
|
||||
/** Turbulence models available: ttNone, ttStandard, ttBerndt, ttCulp, ttMilspec, ttTustin */
|
||||
virtual void SetTurbType(tType tt) {turbType = tt;}
|
||||
virtual tType GetTurbType() const {return turbType;}
|
||||
|
||||
virtual void SetTurbGain(double tg) {TurbGain = tg;}
|
||||
virtual double GetTurbGain() const {return TurbGain;}
|
||||
|
||||
virtual void SetTurbRate(double tr) {TurbRate = tr;}
|
||||
virtual double GetTurbRate() const {return TurbRate;}
|
||||
|
||||
virtual void SetRhythmicity(double r) {Rhythmicity=r;}
|
||||
virtual double GetRhythmicity() const {return Rhythmicity;}
|
||||
|
||||
virtual double GetTurbPQR(int idx) const {return vTurbPQR(idx);}
|
||||
virtual double GetTurbMagnitude(void) const {return Magnitude;}
|
||||
virtual const FGColumnVector3& GetTurbDirection(void) const {return vDirection;}
|
||||
virtual const FGColumnVector3& GetTurbPQR(void) const {return vTurbPQR;}
|
||||
|
||||
virtual void SetWindspeed20ft(double ws) { windspeed_at_20ft = ws;}
|
||||
virtual double GetWindspeed20ft() const { return windspeed_at_20ft;}
|
||||
|
||||
/// allowable range: 0-7, 3=light, 4=moderate, 6=severe turbulence
|
||||
virtual void SetProbabilityOfExceedence( int idx) {probability_of_exceedence_index = idx;}
|
||||
virtual int GetProbabilityOfExceedence() const { return probability_of_exceedence_index;}
|
||||
struct Inputs {
|
||||
double altitudeASL;
|
||||
} in;
|
||||
|
||||
protected:
|
||||
double rho;
|
||||
double SLtemperature, SLdensity, SLpressure, SLsoundspeed; // Sea level conditions
|
||||
double Temperature, Density, Pressure, Soundspeed; // Current actual conditions at altitude
|
||||
double rSLtemperature, rSLdensity, rSLpressure, rSLsoundspeed; // Reciprocal of sea level conditions
|
||||
|
||||
struct atmType {double Temperature; double Pressure; double Density;};
|
||||
int lastIndex;
|
||||
double h;
|
||||
double htab[8];
|
||||
double StdSLtemperature,StdSLdensity,StdSLpressure,StdSLsoundspeed;
|
||||
double rSLtemperature,rSLdensity,rSLpressure,rSLsoundspeed; //reciprocals
|
||||
double SLtemperature,SLdensity,SLpressure,SLsoundspeed;
|
||||
double *temperature, *density, *pressure;
|
||||
double soundspeed;
|
||||
bool useExternal;
|
||||
double exTemperature,exDensity,exPressure;
|
||||
double intTemperature, intDensity, intPressure;
|
||||
double SutherlandConstant, Beta, intViscosity, intKinematicViscosity;
|
||||
double T_dev_sl, T_dev, delta_T, density_altitude;
|
||||
atmType atmosphere;
|
||||
bool StandardTempOnly;
|
||||
bool first_pass;
|
||||
double PressureAltitude;
|
||||
double DensityAltitude;
|
||||
|
||||
double MagnitudedAccelDt, MagnitudeAccel, Magnitude;
|
||||
double TurbGain;
|
||||
double TurbRate;
|
||||
double Rhythmicity;
|
||||
double wind_from_clockwise;
|
||||
double spike, target_time, strength;
|
||||
FGColumnVector3 vDirectiondAccelDt;
|
||||
FGColumnVector3 vDirectionAccel;
|
||||
FGColumnVector3 vDirection;
|
||||
FGColumnVector3 vTurbulenceGrad;
|
||||
FGColumnVector3 vBodyTurbGrad;
|
||||
FGColumnVector3 vTurbPQR;
|
||||
const double SutherlandConstant, Beta;
|
||||
double Viscosity, KinematicViscosity;
|
||||
|
||||
// Dryden turbulence model
|
||||
double windspeed_at_20ft; ///< in ft/s
|
||||
int probability_of_exceedence_index; ///< this is bound as the severity property
|
||||
FGTable *POE_Table; ///< probability of exceedence table
|
||||
|
||||
double psiw;
|
||||
FGColumnVector3 vTotalWindNED;
|
||||
FGColumnVector3 vWindNED;
|
||||
FGColumnVector3 vGustNED;
|
||||
FGColumnVector3 vTurbulenceNED;
|
||||
|
||||
/// Calculate the atmosphere for the given altitude, including effects of temperature deviation.
|
||||
/// Calculate the atmosphere for the given altitude.
|
||||
void Calculate(double altitude);
|
||||
/// Calculate atmospheric properties other than the basic T, P and rho.
|
||||
void CalculateDerived(void);
|
||||
/// Get T, P and rho for a standard atmosphere at the given altitude.
|
||||
void GetStdAtmosphere(double altitude);
|
||||
void Turbulence(void);
|
||||
|
||||
// Converts to Rankine from one of several unit systems.
|
||||
virtual double ConvertToRankine(double t, eTemperature unit) const;
|
||||
|
||||
// Converts to PSF (pounds per square foot) from one of several unit systems.
|
||||
virtual double ConvertToPSF(double t, ePressure unit=ePSF) const;
|
||||
|
||||
virtual void bind(void);
|
||||
void Debug(int from);
|
||||
};
|
||||
|
|
|
@ -40,26 +40,17 @@ HISTORY
|
|||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include "FGAuxiliary.h"
|
||||
#include "FGAerodynamics.h"
|
||||
#include "FGPropagate.h"
|
||||
#include "FGAtmosphere.h"
|
||||
#include "FGFDMExec.h"
|
||||
#include "FGAircraft.h"
|
||||
#include "FGInertial.h"
|
||||
#include "FGExternalReactions.h"
|
||||
#include "FGBuoyantForces.h"
|
||||
#include "FGGroundReactions.h"
|
||||
#include "FGPropulsion.h"
|
||||
#include "FGMassBalance.h"
|
||||
#include "input_output/FGPropertyManager.h"
|
||||
#include <iostream>
|
||||
|
||||
#include "FGAuxiliary.h"
|
||||
#include "FGFDMExec.h"
|
||||
#include "input_output/FGPropertyManager.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGAuxiliary.cpp,v 1.49 2011/05/20 03:18:36 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGAuxiliary.cpp,v 1.53 2011/08/17 23:56:01 jberndt Exp $";
|
||||
static const char *IdHdr = ID_AUXILIARY;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -70,9 +61,8 @@ CLASS IMPLEMENTATION
|
|||
FGAuxiliary::FGAuxiliary(FGFDMExec* fdmex) : FGModel(fdmex)
|
||||
{
|
||||
Name = "FGAuxiliary";
|
||||
pt = p = psl = 1.0;
|
||||
rho = rhosl = 1.0;
|
||||
tat = sat = 1.0;
|
||||
pt = 1.0;
|
||||
tat = 1.0;
|
||||
tatc = RankineToCelsius(tat);
|
||||
|
||||
vcas = veas = 0.0;
|
||||
|
@ -91,13 +81,11 @@ FGAuxiliary::FGAuxiliary(FGFDMExec* fdmex) : FGModel(fdmex)
|
|||
|
||||
vPilotAccel.InitMatrix();
|
||||
vPilotAccelN.InitMatrix();
|
||||
vToEyePt.InitMatrix();
|
||||
vAeroUVW.InitMatrix();
|
||||
vAeroPQR.InitMatrix();
|
||||
vMachUVW.InitMatrix();
|
||||
vEuler.InitMatrix();
|
||||
vEulerRates.InitMatrix();
|
||||
vAircraftAccel.InitMatrix();
|
||||
|
||||
bind();
|
||||
|
||||
|
@ -108,11 +96,8 @@ FGAuxiliary::FGAuxiliary(FGFDMExec* fdmex) : FGModel(fdmex)
|
|||
|
||||
bool FGAuxiliary::InitModel(void)
|
||||
{
|
||||
pt = p = FDMExec->GetAtmosphere()->GetPressure();
|
||||
rho = FDMExec->GetAtmosphere()->GetDensity();
|
||||
rhosl = FDMExec->GetAtmosphere()->GetDensitySL();
|
||||
psl = FDMExec->GetAtmosphere()->GetPressureSL();
|
||||
tat = sat = FDMExec->GetAtmosphere()->GetTemperature();
|
||||
pt = in.Pressure;
|
||||
tat = in.Temperature;
|
||||
tatc = RankineToCelsius(tat);
|
||||
|
||||
vcas = veas = 0.0;
|
||||
|
@ -131,13 +116,11 @@ bool FGAuxiliary::InitModel(void)
|
|||
|
||||
vPilotAccel.InitMatrix();
|
||||
vPilotAccelN.InitMatrix();
|
||||
vToEyePt.InitMatrix();
|
||||
vAeroUVW.InitMatrix();
|
||||
vAeroPQR.InitMatrix();
|
||||
vMachUVW.InitMatrix();
|
||||
vEuler.InitMatrix();
|
||||
vEulerRates.InitMatrix();
|
||||
vAircraftAccel.InitMatrix();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -160,139 +143,118 @@ bool FGAuxiliary::Run(bool Holding)
|
|||
|
||||
RunPreFunctions();
|
||||
|
||||
const double density = FDMExec->GetAtmosphere()->GetDensity();
|
||||
const double soundspeed = FDMExec->GetAtmosphere()->GetSoundSpeed();
|
||||
const double DistanceAGL = FDMExec->GetPropagate()->GetDistanceAGL();
|
||||
const double wingspan = FDMExec->GetAircraft()->GetWingSpan();
|
||||
const FGMatrix33& Tl2b = FDMExec->GetPropagate()->GetTl2b();
|
||||
const FGMatrix33& Tb2l = FDMExec->GetPropagate()->GetTb2l();
|
||||
|
||||
const FGColumnVector3& vPQR = FDMExec->GetPropagate()->GetPQR();
|
||||
const FGColumnVector3& vUVW = FDMExec->GetPropagate()->GetUVW();
|
||||
const FGColumnVector3& vUVWdot = FDMExec->GetPropagate()->GetUVWdot();
|
||||
const FGColumnVector3& vVel = FDMExec->GetPropagate()->GetVel();
|
||||
|
||||
p = FDMExec->GetAtmosphere()->GetPressure();
|
||||
rhosl = FDMExec->GetAtmosphere()->GetDensitySL();
|
||||
psl = FDMExec->GetAtmosphere()->GetPressureSL();
|
||||
sat = FDMExec->GetAtmosphere()->GetTemperature();
|
||||
|
||||
// Rotation
|
||||
|
||||
double cTht = FDMExec->GetPropagate()->GetCosEuler(eTht);
|
||||
double sTht = FDMExec->GetPropagate()->GetSinEuler(eTht);
|
||||
double cPhi = FDMExec->GetPropagate()->GetCosEuler(ePhi);
|
||||
double sPhi = FDMExec->GetPropagate()->GetSinEuler(ePhi);
|
||||
|
||||
vEulerRates(eTht) = vPQR(eQ)*cPhi - vPQR(eR)*sPhi;
|
||||
if (cTht != 0.0) {
|
||||
vEulerRates(ePsi) = (vPQR(eQ)*sPhi + vPQR(eR)*cPhi)/cTht;
|
||||
vEulerRates(ePhi) = vPQR(eP) + vEulerRates(ePsi)*sTht;
|
||||
vEulerRates(eTht) = in.vPQR(eQ)*in.CosPhi - in.vPQR(eR)*in.SinPhi;
|
||||
if (in.CosTht != 0.0) {
|
||||
vEulerRates(ePsi) = (in.vPQR(eQ)*in.SinPhi + in.vPQR(eR)*in.CosPhi)/in.CosTht;
|
||||
vEulerRates(ePhi) = in.vPQR(eP) + vEulerRates(ePsi)*in.SinTht;
|
||||
}
|
||||
|
||||
// Combine the wind speed with aircraft speed to obtain wind relative speed
|
||||
FGColumnVector3 wind = Tl2b*FDMExec->GetAtmosphere()->GetTotalWindNED();
|
||||
vAeroPQR = vPQR - FDMExec->GetAtmosphere()->GetTurbPQR();
|
||||
vAeroUVW = vUVW - wind;
|
||||
vAeroPQR = in.vPQR - in.TurbPQR;
|
||||
vAeroUVW = in.vUVW - in.Tl2b * in.TotalWindNED;
|
||||
|
||||
Vt = vAeroUVW.Magnitude();
|
||||
double Vt2 = Vt*Vt;
|
||||
alpha = beta = adot = bdot = 0;
|
||||
double mUW = (vAeroUVW(eU)*vAeroUVW(eU) + vAeroUVW(eW)*vAeroUVW(eW));
|
||||
double AeroU2 = vAeroUVW(eU)*vAeroUVW(eU);
|
||||
double AeroV2 = vAeroUVW(eV)*vAeroUVW(eV);
|
||||
double AeroW2 = vAeroUVW(eW)*vAeroUVW(eW);
|
||||
double mUW = AeroU2 + AeroW2;
|
||||
|
||||
double Vt2 = Vt*Vt;
|
||||
|
||||
if ( Vt > 1.0 ) {
|
||||
if (vAeroUVW(eW) != 0.0)
|
||||
alpha = vAeroUVW(eU)*vAeroUVW(eU) > 0.0 ? atan2(vAeroUVW(eW), vAeroUVW(eU)) : 0.0;
|
||||
alpha = AeroU2 > 0.0 ? atan2(vAeroUVW(eW), vAeroUVW(eU)) : 0.0;
|
||||
if (vAeroUVW(eV) != 0.0)
|
||||
beta = mUW > 0.0 ? atan2(vAeroUVW(eV), sqrt(mUW)) : 0.0;
|
||||
beta = mUW > 0.0 ? atan2(vAeroUVW(eV), sqrt(mUW)) : 0.0;
|
||||
|
||||
double signU=1;
|
||||
if (vAeroUVW(eU) < 0.0) signU=-1;
|
||||
|
||||
if ( mUW >= 1.0 ) {
|
||||
adot = (vAeroUVW(eU)*vUVWdot(eW) - vAeroUVW(eW)*vUVWdot(eU))/mUW;
|
||||
bdot = (signU*mUW*vUVWdot(eV)
|
||||
- vAeroUVW(eV)*(vAeroUVW(eU)*vUVWdot(eU) + vAeroUVW(eW)*vUVWdot(eW)))/(Vt2*sqrt(mUW));
|
||||
adot = (vAeroUVW(eU)*in.vUVWdot(eW) - vAeroUVW(eW)*in.vUVWdot(eU))/mUW;
|
||||
bdot = (signU*mUW*in.vUVWdot(eV)
|
||||
- vAeroUVW(eV)*(vAeroUVW(eU)*in.vUVWdot(eU) + vAeroUVW(eW)*in.vUVWdot(eW)))/(Vt2*sqrt(mUW));
|
||||
}
|
||||
}
|
||||
|
||||
Re = Vt * FDMExec->GetAircraft()->Getcbar() / FDMExec->GetAtmosphere()->GetKinematicViscosity();
|
||||
Re = Vt * in.Wingchord / in.KinematicViscosity;
|
||||
|
||||
qbar = 0.5*density*Vt2;
|
||||
qbarUW = 0.5*density*(mUW);
|
||||
qbarUV = 0.5*density*(vAeroUVW(eU)*vAeroUVW(eU) + vAeroUVW(eV)*vAeroUVW(eV));
|
||||
Mach = Vt / soundspeed;
|
||||
MachU = vMachUVW(eU) = vAeroUVW(eU) / soundspeed;
|
||||
vMachUVW(eV) = vAeroUVW(eV) / soundspeed;
|
||||
vMachUVW(eW) = vAeroUVW(eW) / soundspeed;
|
||||
double densityD2 = 0.5*in.Density;
|
||||
|
||||
qbar = densityD2 * Vt2;
|
||||
qbarUW = densityD2 * (mUW);
|
||||
qbarUV = densityD2 * (AeroU2 + AeroV2);
|
||||
Mach = Vt / in.SoundSpeed;
|
||||
MachU = vMachUVW(eU) = vAeroUVW(eU) / in.SoundSpeed;
|
||||
vMachUVW(eV) = vAeroUVW(eV) / in.SoundSpeed;
|
||||
vMachUVW(eW) = vAeroUVW(eW) / in.SoundSpeed;
|
||||
double MachU2 = MachU * MachU;
|
||||
|
||||
// Position
|
||||
|
||||
Vground = sqrt( vVel(eNorth)*vVel(eNorth) + vVel(eEast)*vVel(eEast) );
|
||||
Vground = sqrt( in.vVel(eNorth)*in.vVel(eNorth) + in.vVel(eEast)*in.vVel(eEast) );
|
||||
|
||||
psigt = atan2(vVel(eEast), vVel(eNorth));
|
||||
psigt = atan2(in.vVel(eEast), in.vVel(eNorth));
|
||||
if (psigt < 0.0) psigt += 2*M_PI;
|
||||
gamma = atan2(-vVel(eDown), Vground);
|
||||
gamma = atan2(-in.vVel(eDown), Vground);
|
||||
|
||||
tat = sat*(1 + 0.2*Mach*Mach); // Total Temperature, isentropic flow
|
||||
tat = in.Temperature*(1 + 0.2*Mach*Mach); // Total Temperature, isentropic flow
|
||||
tatc = RankineToCelsius(tat);
|
||||
|
||||
if (MachU < 1) { // Calculate total pressure assuming isentropic flow
|
||||
pt = p*pow((1 + 0.2*MachU*MachU),3.5);
|
||||
pt = in.Pressure*pow((1 + 0.2*MachU2),3.5);
|
||||
} else {
|
||||
// Use Rayleigh pitot tube formula for normal shock in front of pitot tube
|
||||
B = 5.76*MachU*MachU/(5.6*MachU*MachU - 0.8);
|
||||
D = (2.8*MachU*MachU-0.4)*0.4167;
|
||||
pt = p*pow(B,3.5)*D;
|
||||
B = 5.76 * MachU2 / (5.6*MachU2 - 0.8);
|
||||
D = (2.8 * MachU2 - 0.4) * 0.4167;
|
||||
pt = in.Pressure*pow(B,3.5)*D;
|
||||
}
|
||||
|
||||
A = pow(((pt-p)/psl+1),0.28571);
|
||||
A = pow(((pt-in.Pressure)/in.PressureSL + 1),0.28571);
|
||||
if (MachU > 0.0) {
|
||||
vcas = sqrt(7*psl/rhosl*(A-1));
|
||||
veas = sqrt(2*qbar/rhosl);
|
||||
vcas = sqrt(7 * in.PressureSL / in.DensitySL * (A-1));
|
||||
veas = sqrt(2 * qbar / in.DensitySL);
|
||||
vtrue = 1116.43559 * MachU * sqrt(in.Temperature / 518.67);
|
||||
} else {
|
||||
vcas = veas = 0.0;
|
||||
vcas = veas = vtrue = 0.0;
|
||||
}
|
||||
|
||||
const double SLgravity = FDMExec->GetInertial()->SLgravity();
|
||||
|
||||
vPilotAccel.InitMatrix();
|
||||
vNcg = in.vBodyAccel/in.SLGravity;
|
||||
if ( Vt > 1.0 ) {
|
||||
vAircraftAccel = FDMExec->GetAircraft()->GetBodyAccel();
|
||||
// Nz is Acceleration in "g's", along normal axis (-Z body axis)
|
||||
Nz = -vAircraftAccel(eZ)/SLgravity;
|
||||
vToEyePt = FDMExec->GetMassBalance()->StructuralToBody(FDMExec->GetAircraft()->GetXYZep());
|
||||
vPilotAccel = vAircraftAccel + FDMExec->GetPropagate()->GetPQRdot() * vToEyePt;
|
||||
vPilotAccel += vPQR * (vPQR * vToEyePt);
|
||||
// Nz is Acceleration in "g's", along normal axis (-Z body axis)
|
||||
Nz = -vNcg(eZ);
|
||||
vPilotAccel = in.vBodyAccel + in.vPQRdot * in.ToEyePt;
|
||||
vPilotAccel += in.vPQR * (in.vPQR * in.ToEyePt);
|
||||
} else {
|
||||
// The line below handles low velocity (and on-ground) cases, basically
|
||||
// representing the opposite of the force that the landing gear would
|
||||
// exert on the ground (which is just the total weight). This eliminates
|
||||
// any jitter that could be introduced by the landing gear. Theoretically,
|
||||
// this branch could be eliminated, with a penalty of having a short
|
||||
// transient at startup (lasting only a fraction of a second).
|
||||
vPilotAccel = Tl2b * FGColumnVector3( 0.0, 0.0, -SLgravity );
|
||||
Nz = -vPilotAccel(eZ)/SLgravity;
|
||||
// The line below handles low velocity (and on-ground) cases, basically
|
||||
// representing the opposite of the force that the landing gear would
|
||||
// exert on the ground (which is just the total weight). This eliminates
|
||||
// any jitter that could be introduced by the landing gear. Theoretically,
|
||||
// this branch could be eliminated, with a penalty of having a short
|
||||
// transient at startup (lasting only a fraction of a second).
|
||||
vPilotAccel = in.Tl2b * FGColumnVector3( 0.0, 0.0, -in.SLGravity );
|
||||
Nz = -vPilotAccel(eZ) / in.SLGravity;
|
||||
}
|
||||
|
||||
vPilotAccelN = vPilotAccel/SLgravity;
|
||||
vNwcg = mTb2w * vNcg;
|
||||
vNwcg(eZ) = 1.0 - vNwcg(eZ);
|
||||
|
||||
vPilotAccelN = vPilotAccel / in.SLGravity;
|
||||
|
||||
// VRP computation
|
||||
const FGLocation& vLocation = FDMExec->GetPropagate()->GetLocation();
|
||||
const FGColumnVector3& vrpStructural = FDMExec->GetAircraft()->GetXYZvrp();
|
||||
const FGColumnVector3 vrpBody = FDMExec->GetMassBalance()->StructuralToBody( vrpStructural );
|
||||
const FGColumnVector3 vrpLocal = Tb2l * vrpBody;
|
||||
vLocationVRP = vLocation.LocalToLocation( vrpLocal );
|
||||
vLocationVRP = in.vLocation.LocalToLocation( in.Tb2l * in.VRPBody );
|
||||
|
||||
// Recompute some derived values now that we know the dependent parameters values ...
|
||||
hoverbcg = DistanceAGL / wingspan;
|
||||
hoverbcg = in.DistanceAGL / in.Wingspan;
|
||||
|
||||
FGColumnVector3 vMac = Tb2l*FDMExec->GetMassBalance()->StructuralToBody(FDMExec->GetAircraft()->GetXYZrp());
|
||||
hoverbmac = (DistanceAGL + vMac(3)) / wingspan;
|
||||
|
||||
// when all model are executed,
|
||||
// please calculate the distance from the initial point
|
||||
FGColumnVector3 vMac = in.Tb2l * in.RPBody;
|
||||
hoverbmac = (in.DistanceAGL + vMac(3)) / in.Wingspan;
|
||||
|
||||
// When all models are executed calculate the distance from the initial point.
|
||||
CalculateRelativePosition();
|
||||
|
||||
RunPostFunctions();
|
||||
|
@ -300,6 +262,68 @@ bool FGAuxiliary::Run(bool Holding)
|
|||
return false;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
//
|
||||
// From Stevens and Lewis, "Aircraft Control and Simulation", 3rd Ed., the
|
||||
// transformation from body to wind axes is defined (where "a" is alpha and "B"
|
||||
// is beta):
|
||||
//
|
||||
// cos(a)*cos(B) sin(B) sin(a)*cos(B)
|
||||
// -cos(a)*sin(B) cos(B) -sin(a)*sin(B)
|
||||
// -sin(a) 0 cos(a)
|
||||
//
|
||||
// The transform from wind to body axes is then,
|
||||
//
|
||||
// cos(a)*cos(B) -cos(a)*sin(B) -sin(a)
|
||||
// sin(B) cos(B) 0
|
||||
// sin(a)*cos(B) -sin(a)*sin(B) cos(a)
|
||||
|
||||
FGMatrix33& FGAuxiliary::GetTw2b(void)
|
||||
{
|
||||
double ca, cb, sa, sb;
|
||||
|
||||
ca = cos(alpha);
|
||||
sa = sin(alpha);
|
||||
cb = cos(beta);
|
||||
sb = sin(beta);
|
||||
|
||||
mTw2b(1,1) = ca*cb;
|
||||
mTw2b(1,2) = -ca*sb;
|
||||
mTw2b(1,3) = -sa;
|
||||
mTw2b(2,1) = sb;
|
||||
mTw2b(2,2) = cb;
|
||||
mTw2b(2,3) = 0.0;
|
||||
mTw2b(3,1) = sa*cb;
|
||||
mTw2b(3,2) = -sa*sb;
|
||||
mTw2b(3,3) = ca;
|
||||
|
||||
return mTw2b;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
FGMatrix33& FGAuxiliary::GetTb2w(void)
|
||||
{
|
||||
double ca, cb, sa, sb;
|
||||
|
||||
ca = cos(alpha);
|
||||
sa = sin(alpha);
|
||||
cb = cos(beta);
|
||||
sb = sin(beta);
|
||||
|
||||
mTb2w(1,1) = ca*cb;
|
||||
mTb2w(1,2) = sb;
|
||||
mTb2w(1,3) = sa*cb;
|
||||
mTb2w(2,1) = -ca*sb;
|
||||
mTb2w(2,2) = cb;
|
||||
mTb2w(2,3) = -sa*sb;
|
||||
mTb2w(3,1) = -sa;
|
||||
mTb2w(3,2) = 0.0;
|
||||
mTb2w(3,3) = ca;
|
||||
|
||||
return mTb2w;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
//
|
||||
// A positive headwind is blowing with you, a negative headwind is blowing against you.
|
||||
|
@ -308,12 +332,7 @@ bool FGAuxiliary::Run(bool Holding)
|
|||
|
||||
double FGAuxiliary::GetHeadWind(void) const
|
||||
{
|
||||
double psiw,vw;
|
||||
|
||||
psiw = FDMExec->GetAtmosphere()->GetWindPsi();
|
||||
vw = FDMExec->GetAtmosphere()->GetTotalWindNED().Magnitude();
|
||||
|
||||
return vw*cos(psiw - FDMExec->GetPropagate()->GetEuler(ePsi));
|
||||
return in.Vwind * cos(in.WindPsi - in.Psi);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -324,23 +343,38 @@ double FGAuxiliary::GetHeadWind(void) const
|
|||
|
||||
double FGAuxiliary::GetCrossWind(void) const
|
||||
{
|
||||
double psiw,vw;
|
||||
|
||||
psiw = FDMExec->GetAtmosphere()->GetWindPsi();
|
||||
vw = FDMExec->GetAtmosphere()->GetTotalWindNED().Magnitude();
|
||||
|
||||
return vw*sin(psiw - FDMExec->GetPropagate()->GetEuler(ePsi));
|
||||
return in.Vwind * sin(in.WindPsi - in.Psi);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGAuxiliary::GethVRP(void) const
|
||||
{
|
||||
return vLocationVRP.GetRadius() - FDMExec->GetPropagate()->GetSeaLevelRadius();
|
||||
return vLocationVRP.GetRadius() - in.ReferenceRadius;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGAuxiliary::GetNlf(void) const
|
||||
{
|
||||
if (in.Mass != 0)
|
||||
return (-in.vFw(3))/(in.Mass*slugtolb);
|
||||
else
|
||||
return 0.;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGAuxiliary::CalculateRelativePosition(void) //ToDo: This belongs elsewhere - perhaps in FGPropagate or Exec
|
||||
{
|
||||
const double earth_radius_mt = in.ReferenceRadius*fttom;
|
||||
lat_relative_position=(in.Latitude - FDMExec->GetIC()->GetLatitudeDegIC() *degtorad)*earth_radius_mt;
|
||||
lon_relative_position=(in.Longitude - FDMExec->GetIC()->GetLongitudeDegIC()*degtorad)*earth_radius_mt;
|
||||
relative_position = sqrt(lat_relative_position*lat_relative_position + lon_relative_position*lon_relative_position);
|
||||
};
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGAuxiliary::bind(void)
|
||||
{
|
||||
typedef double (FGAuxiliary::*PMF)(int) const;
|
||||
|
@ -352,6 +386,8 @@ void FGAuxiliary::bind(void)
|
|||
PropertyManager->Tie("velocities/vc-kts", this, &FGAuxiliary::GetVcalibratedKTS);
|
||||
PropertyManager->Tie("velocities/ve-fps", this, &FGAuxiliary::GetVequivalentFPS);
|
||||
PropertyManager->Tie("velocities/ve-kts", this, &FGAuxiliary::GetVequivalentKTS);
|
||||
PropertyManager->Tie("velocities/vtrue-fps", this, &FGAuxiliary::GetVtrueFPS);
|
||||
PropertyManager->Tie("velocities/vtrue-kts", this, &FGAuxiliary::GetVtrueKTS);
|
||||
PropertyManager->Tie("velocities/machU", this, &FGAuxiliary::GetMachU);
|
||||
PropertyManager->Tie("velocities/p-aero-rad_sec", this, eX, (PMF)&FGAuxiliary::GetAeroPQR);
|
||||
PropertyManager->Tie("velocities/q-aero-rad_sec", this, eY, (PMF)&FGAuxiliary::GetAeroPQR);
|
||||
|
@ -362,8 +398,8 @@ void FGAuxiliary::bind(void)
|
|||
PropertyManager->Tie("velocities/u-aero-fps", this, eU, (PMF)&FGAuxiliary::GetAeroUVW);
|
||||
PropertyManager->Tie("velocities/v-aero-fps", this, eV, (PMF)&FGAuxiliary::GetAeroUVW);
|
||||
PropertyManager->Tie("velocities/w-aero-fps", this, eW, (PMF)&FGAuxiliary::GetAeroUVW);
|
||||
PropertyManager->Tie("velocities/vt-fps", this, &FGAuxiliary::GetVt, &FGAuxiliary::SetVt, true);
|
||||
PropertyManager->Tie("velocities/mach", this, &FGAuxiliary::GetMach, &FGAuxiliary::SetMach, true);
|
||||
PropertyManager->Tie("velocities/vt-fps", this, &FGAuxiliary::GetVt);
|
||||
PropertyManager->Tie("velocities/mach", this, &FGAuxiliary::GetMach);
|
||||
PropertyManager->Tie("velocities/vg-fps", this, &FGAuxiliary::GetVground);
|
||||
PropertyManager->Tie("accelerations/a-pilot-x-ft_sec2", this, eX, (PMF)&FGAuxiliary::GetPilotAccel);
|
||||
PropertyManager->Tie("accelerations/a-pilot-y-ft_sec2", this, eY, (PMF)&FGAuxiliary::GetPilotAccel);
|
||||
|
@ -372,25 +408,26 @@ void FGAuxiliary::bind(void)
|
|||
PropertyManager->Tie("accelerations/n-pilot-y-norm", this, eY, (PMF)&FGAuxiliary::GetNpilot);
|
||||
PropertyManager->Tie("accelerations/n-pilot-z-norm", this, eZ, (PMF)&FGAuxiliary::GetNpilot);
|
||||
PropertyManager->Tie("accelerations/Nz", this, &FGAuxiliary::GetNz);
|
||||
PropertyManager->Tie("forces/load-factor", this, &FGAuxiliary::GetNlf);
|
||||
/* PropertyManager->Tie("atmosphere/headwind-fps", this, &FGAuxiliary::GetHeadWind, true);
|
||||
PropertyManager->Tie("atmosphere/crosswind-fps", this, &FGAuxiliary::GetCrossWind, true); */
|
||||
PropertyManager->Tie("aero/alpha-rad", this, (PF)&FGAuxiliary::Getalpha, &FGAuxiliary::Setalpha, true);
|
||||
PropertyManager->Tie("aero/beta-rad", this, (PF)&FGAuxiliary::Getbeta, &FGAuxiliary::Setbeta, true);
|
||||
PropertyManager->Tie("aero/alpha-rad", this, (PF)&FGAuxiliary::Getalpha);
|
||||
PropertyManager->Tie("aero/beta-rad", this, (PF)&FGAuxiliary::Getbeta);
|
||||
PropertyManager->Tie("aero/mag-beta-rad", this, (PF)&FGAuxiliary::GetMagBeta);
|
||||
PropertyManager->Tie("aero/alpha-deg", this, inDegrees, (PMF)&FGAuxiliary::Getalpha);
|
||||
PropertyManager->Tie("aero/beta-deg", this, inDegrees, (PMF)&FGAuxiliary::Getbeta);
|
||||
PropertyManager->Tie("aero/mag-beta-deg", this, inDegrees, (PMF)&FGAuxiliary::GetMagBeta);
|
||||
PropertyManager->Tie("aero/Re", this, &FGAuxiliary::GetReynoldsNumber);
|
||||
PropertyManager->Tie("aero/qbar-psf", this, &FGAuxiliary::Getqbar, &FGAuxiliary::Setqbar, true);
|
||||
PropertyManager->Tie("aero/qbarUW-psf", this, &FGAuxiliary::GetqbarUW, &FGAuxiliary::SetqbarUW, true);
|
||||
PropertyManager->Tie("aero/qbarUV-psf", this, &FGAuxiliary::GetqbarUV, &FGAuxiliary::SetqbarUV, true);
|
||||
PropertyManager->Tie("aero/alphadot-rad_sec", this, (PF)&FGAuxiliary::Getadot, &FGAuxiliary::Setadot, true);
|
||||
PropertyManager->Tie("aero/betadot-rad_sec", this, (PF)&FGAuxiliary::Getbdot, &FGAuxiliary::Setbdot, true);
|
||||
PropertyManager->Tie("aero/qbar-psf", this, &FGAuxiliary::Getqbar);
|
||||
PropertyManager->Tie("aero/qbarUW-psf", this, &FGAuxiliary::GetqbarUW);
|
||||
PropertyManager->Tie("aero/qbarUV-psf", this, &FGAuxiliary::GetqbarUV);
|
||||
PropertyManager->Tie("aero/alphadot-rad_sec", this, (PF)&FGAuxiliary::Getadot);
|
||||
PropertyManager->Tie("aero/betadot-rad_sec", this, (PF)&FGAuxiliary::Getbdot);
|
||||
PropertyManager->Tie("aero/alphadot-deg_sec", this, inDegrees, (PMF)&FGAuxiliary::Getadot);
|
||||
PropertyManager->Tie("aero/betadot-deg_sec", this, inDegrees, (PMF)&FGAuxiliary::Getbdot);
|
||||
PropertyManager->Tie("aero/h_b-cg-ft", this, &FGAuxiliary::GetHOverBCG);
|
||||
PropertyManager->Tie("aero/h_b-mac-ft", this, &FGAuxiliary::GetHOverBMAC);
|
||||
PropertyManager->Tie("flight-path/gamma-rad", this, &FGAuxiliary::GetGamma, &FGAuxiliary::SetGamma);
|
||||
PropertyManager->Tie("flight-path/gamma-rad", this, &FGAuxiliary::GetGamma);
|
||||
PropertyManager->Tie("flight-path/psi-gt-rad", this, &FGAuxiliary::GetGroundTrack);
|
||||
|
||||
PropertyManager->Tie("position/distance-from-start-lon-mt", this, &FGAuxiliary::GetLongitudeRelativePosition);
|
||||
|
@ -403,16 +440,6 @@ void FGAuxiliary::bind(void)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGAuxiliary::CalculateRelativePosition(void)
|
||||
{
|
||||
const double earth_radius_mt = FDMExec->GetInertial()->GetRefRadius()*fttom;
|
||||
lat_relative_position=(FDMExec->GetPropagate()->GetLatitude() - FDMExec->GetIC()->GetLatitudeDegIC() *degtorad)*earth_radius_mt;
|
||||
lon_relative_position=(FDMExec->GetPropagate()->GetLongitude() - FDMExec->GetIC()->GetLongitudeDegIC()*degtorad)*earth_radius_mt;
|
||||
relative_position = sqrt(lat_relative_position*lat_relative_position + lon_relative_position*lon_relative_position);
|
||||
};
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGAuxiliary::BadUnits(void) const
|
||||
{
|
||||
cerr << "Bad units" << endl; return 0.0;
|
||||
|
|
|
@ -41,13 +41,14 @@ INCLUDES
|
|||
|
||||
#include "FGModel.h"
|
||||
#include "math/FGColumnVector3.h"
|
||||
#include "math/FGMatrix33.h"
|
||||
#include "math/FGLocation.h"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_AUXILIARY "$Id: FGAuxiliary.h,v 1.20 2011/05/20 03:18:36 jberndt Exp $"
|
||||
#define ID_AUXILIARY "$Id: FGAuxiliary.h,v 1.23 2011/08/17 23:56:01 jberndt Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -96,10 +97,9 @@ CLASS DOCUMENTATION
|
|||
by the F = ma relation. If the vForces vector is divided by the aircraft
|
||||
mass, the acceleration vector is calculated. The term wdot is equivalent
|
||||
to the JSBSim vPQRdot vector, and the w parameter is equivalent to vPQR.
|
||||
The radius R is calculated below in the vector vToEyePt.
|
||||
|
||||
@author Tony Peden, Jon Berndt
|
||||
@version $Id: FGAuxiliary.h,v 1.20 2011/05/20 03:18:36 jberndt Exp $
|
||||
@version $Id: FGAuxiliary.h,v 1.23 2011/08/17 23:56:01 jberndt Exp $
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -137,6 +137,10 @@ public:
|
|||
double GetVequivalentFPS(void) const { return veas; }
|
||||
/** Returns equivalent airspeed in knots. */
|
||||
double GetVequivalentKTS(void) const { return veas*fpstokts; }
|
||||
/** Returns the true airspeed in feet per second. */
|
||||
double GetVtrueFPS() const { return vtrue; }
|
||||
/** Returns the true airspeed in knots. */
|
||||
double GetVtrueKTS() const { return vtrue * fpstokts; }
|
||||
|
||||
/** Returns the total pressure.
|
||||
Total pressure is freestream total pressure for
|
||||
|
@ -147,9 +151,9 @@ public:
|
|||
/** Returns the total temperature.
|
||||
The total temperature ("tat", isentropic flow) is calculated:
|
||||
@code
|
||||
tat = sat*(1 + 0.2*Mach*Mach)
|
||||
tat = in.Temperature*(1 + 0.2*Mach*Mach)
|
||||
@endcode
|
||||
(where "sat" is standard temperature) */
|
||||
(where "in.Temperature" is standard temperature calculated by the atmosphere model) */
|
||||
|
||||
double GetTotalTemperature(void) const { return tat; }
|
||||
double GetTAT_C(void) const { return tatc; }
|
||||
|
@ -161,6 +165,9 @@ public:
|
|||
|
||||
const FGColumnVector3& GetPilotAccel (void) const { return vPilotAccel; }
|
||||
const FGColumnVector3& GetNpilot (void) const { return vPilotAccelN; }
|
||||
const FGColumnVector3& GetNcg (void) const { return vNcg; }
|
||||
double GetNcg (int idx) const { return vNcg(idx); }
|
||||
double GetNlf (void) const;
|
||||
const FGColumnVector3& GetAeroPQR (void) const { return vAeroPQR; }
|
||||
const FGColumnVector3& GetEulerRates (void) const { return vEulerRates; }
|
||||
const FGColumnVector3& GetAeroUVW (void) const { return vAeroUVW; }
|
||||
|
@ -185,6 +192,16 @@ public:
|
|||
double GetMagBeta (int unit) const { if (unit == inDegrees) return fabs(beta)*radtodeg;
|
||||
else return BadUnits(); }
|
||||
|
||||
/** Calculates and returns the wind-to-body axis transformation matrix.
|
||||
@return a reference to the wind-to-body transformation matrix.
|
||||
*/
|
||||
FGMatrix33& GetTw2b(void);
|
||||
|
||||
/** Calculates and returns the body-to-wind axis transformation matrix.
|
||||
@return a reference to the wind-to-body transformation matrix.
|
||||
*/
|
||||
FGMatrix33& GetTb2w(void);
|
||||
|
||||
double Getqbar (void) const { return qbar; }
|
||||
double GetqbarUW (void) const { return qbarUW; }
|
||||
double GetqbarUV (void) const { return qbarUV; }
|
||||
|
@ -208,6 +225,8 @@ public:
|
|||
/** The vertical acceleration in g's of the aircraft center of gravity. */
|
||||
double GetNz (void) const { return Nz; }
|
||||
|
||||
FGColumnVector3& GetNwcg(void) { return vNwcg; }
|
||||
|
||||
double GetHOverBCG(void) const { return hoverbcg; }
|
||||
double GetHOverBMAC(void) const { return hoverbmac; }
|
||||
|
||||
|
@ -217,23 +236,6 @@ public:
|
|||
double GetHeadWind(void) const;
|
||||
double GetCrossWind(void) const;
|
||||
|
||||
// SET functions
|
||||
|
||||
void SetAeroUVW(FGColumnVector3 tt) { vAeroUVW = tt; }
|
||||
|
||||
void Setalpha (double tt) { alpha = tt; }
|
||||
void Setbeta (double tt) { beta = tt; }
|
||||
void Setqbar (double tt) { qbar = tt; }
|
||||
void SetqbarUW (double tt) { qbarUW = tt; }
|
||||
void SetqbarUV (double tt) { qbarUV = tt; }
|
||||
void SetVt (double tt) { Vt = tt; }
|
||||
void SetMach (double tt) { Mach=tt; }
|
||||
void Setadot (double tt) { adot = tt; }
|
||||
void Setbdot (double tt) { bdot = tt; }
|
||||
|
||||
void SetAB (double t1, double t2) { alpha=t1; beta=t2; }
|
||||
void SetGamma (double tt) { gamma = tt; }
|
||||
|
||||
// Time routines, SET and GET functions, used by FGMSIS atmosphere
|
||||
|
||||
void SetDayOfYear (int doy) { day_of_year = doy; }
|
||||
|
@ -248,19 +250,65 @@ public:
|
|||
|
||||
void SetAeroPQR(FGColumnVector3 tt) { vAeroPQR = tt; }
|
||||
|
||||
struct Inputs {
|
||||
double Pressure;
|
||||
double Density;
|
||||
double DensitySL;
|
||||
double PressureSL;
|
||||
double Temperature;
|
||||
double SoundSpeed;
|
||||
double KinematicViscosity;
|
||||
double DistanceAGL;
|
||||
double Wingspan;
|
||||
double Wingchord;
|
||||
double SLGravity;
|
||||
double Mass;
|
||||
FGMatrix33 Tl2b;
|
||||
FGMatrix33 Tb2l;
|
||||
FGMatrix33 Tb2w;
|
||||
FGColumnVector3 vPQR;
|
||||
FGColumnVector3 vPQRdot;
|
||||
FGColumnVector3 vUVW;
|
||||
FGColumnVector3 vUVWdot;
|
||||
FGColumnVector3 vVel;
|
||||
FGColumnVector3 vBodyAccel;
|
||||
FGColumnVector3 ToEyePt;
|
||||
FGColumnVector3 RPBody;
|
||||
FGColumnVector3 VRPBody;
|
||||
FGColumnVector3 vFw;
|
||||
FGLocation vLocation;
|
||||
double Latitude;
|
||||
double Longitude;
|
||||
double InitialLatitude;
|
||||
double InitialLongitude;
|
||||
double ReferenceRadius;
|
||||
double CosTht;
|
||||
double SinTht;
|
||||
double CosPhi;
|
||||
double SinPhi;
|
||||
double Psi;
|
||||
FGColumnVector3 TotalWindNED;
|
||||
FGColumnVector3 TurbPQR;
|
||||
double WindPsi;
|
||||
double Vwind;
|
||||
} in;
|
||||
|
||||
private:
|
||||
double vcas, veas;
|
||||
double rhosl, rho, p, psl, pt, tat, sat, tatc; // Don't add a getter for pt!
|
||||
double vcas, veas, vtrue;
|
||||
double pt, tat, tatc; // Don't add a getter for pt!
|
||||
|
||||
FGMatrix33 mTw2b;
|
||||
FGMatrix33 mTb2w;
|
||||
|
||||
FGColumnVector3 vPilotAccel;
|
||||
FGColumnVector3 vPilotAccelN;
|
||||
FGColumnVector3 vToEyePt;
|
||||
FGColumnVector3 vNcg;
|
||||
FGColumnVector3 vNwcg;
|
||||
FGColumnVector3 vAeroPQR;
|
||||
FGColumnVector3 vAeroUVW;
|
||||
FGColumnVector3 vEuler;
|
||||
FGColumnVector3 vEulerRates;
|
||||
FGColumnVector3 vMachUVW;
|
||||
FGColumnVector3 vAircraftAccel;
|
||||
FGLocation vLocationVRP;
|
||||
|
||||
double Vt, Vground, Mach, MachU;
|
||||
|
|
|
@ -45,7 +45,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGBuoyantForces.cpp,v 1.19 2011/07/01 21:22:25 andgi Exp $";
|
||||
static const char *IdSrc = "$Id: FGBuoyantForces.cpp,v 1.20 2011/08/06 13:47:59 jberndt Exp $";
|
||||
static const char *IdHdr = ID_BUOYANTFORCES;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -131,7 +131,7 @@ bool FGBuoyantForces::Load(Element *element)
|
|||
gas_cell_element = document->FindElement("gas_cell");
|
||||
while (gas_cell_element) {
|
||||
NoneDefined = false;
|
||||
Cells.push_back(new FGGasCell(FDMExec, gas_cell_element, Cells.size()));
|
||||
Cells.push_back(new FGGasCell(FDMExec, gas_cell_element, Cells.size(), in));
|
||||
gas_cell_element = document->FindNextElement("gas_cell");
|
||||
}
|
||||
|
||||
|
|
|
@ -32,8 +32,8 @@ HISTORY
|
|||
SENTRY
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#ifndef FGBuoyanTFORCES_H
|
||||
#define FGBuoyanTFORCES_H
|
||||
#ifndef FGBUOYANTFORCES_H
|
||||
#define FGBUOYANTFORCES_H
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
INCLUDES
|
||||
|
@ -51,7 +51,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_BUOYANTFORCES "$Id: FGBuoyantForces.h,v 1.13 2011/07/01 21:22:25 andgi Exp $"
|
||||
#define ID_BUOYANTFORCES "$Id: FGBuoyantForces.h,v 1.15 2011/08/14 20:15:56 jberndt Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -96,7 +96,7 @@ CLASS DOCUMENTATION
|
|||
See FGGasCell for the full configuration file format for gas cells.
|
||||
|
||||
@author Anders Gidenstam, Jon S. Berndt
|
||||
@version $Id: FGBuoyantForces.h,v 1.13 2011/07/01 21:22:25 andgi Exp $
|
||||
@version $Id: FGBuoyantForces.h,v 1.15 2011/08/14 20:15:56 jberndt Exp $
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -172,6 +172,8 @@ public:
|
|||
parameters */
|
||||
string GetBuoyancyValues(string delimeter);
|
||||
|
||||
FGGasCell::Inputs in;
|
||||
|
||||
private:
|
||||
vector <FGGasCell*> Cells;
|
||||
// Buoyant forces and moments. Excluding the gas weight.
|
||||
|
|
|
@ -53,7 +53,7 @@ DEFINITIONS
|
|||
GLOBAL DATA
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
static const char *IdSrc = "$Id: FGExternalReactions.cpp,v 1.10 2011/05/20 03:18:36 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGExternalReactions.cpp,v 1.12 2011/07/20 12:16:34 jberndt Exp $";
|
||||
static const char *IdHdr = ID_EXTERNALREACTIONS;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -63,6 +63,7 @@ CLASS IMPLEMENTATION
|
|||
FGExternalReactions::FGExternalReactions(FGFDMExec* fdmex) : FGModel(fdmex)
|
||||
{
|
||||
NoneDefined = true;
|
||||
|
||||
Debug(0);
|
||||
}
|
||||
|
||||
|
@ -70,6 +71,14 @@ FGExternalReactions::FGExternalReactions(FGFDMExec* fdmex) : FGModel(fdmex)
|
|||
|
||||
bool FGExternalReactions::Load(Element* el)
|
||||
{
|
||||
// check if a file attribute was specified
|
||||
string fname = el->GetAttributeValue("file");
|
||||
if (!fname.empty()) {
|
||||
string file = FDMExec->GetFullAircraftPath() + "/" + fname;
|
||||
el = LoadXMLDocument(file);
|
||||
if (el == 0L) return false;
|
||||
}
|
||||
|
||||
FGModel::Load(el); // Call the base class Load() function to load interface properties.
|
||||
|
||||
Debug(2);
|
||||
|
@ -87,6 +96,8 @@ bool FGExternalReactions::Load(Element* el)
|
|||
|
||||
PostLoad(el, PropertyManager);
|
||||
|
||||
if (!NoneDefined) bind();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -130,6 +141,20 @@ bool FGExternalReactions::Run(bool Holding)
|
|||
return false;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGExternalReactions::bind(void)
|
||||
{
|
||||
typedef double (FGExternalReactions::*PMF)(int) const;
|
||||
PropertyManager->Tie("moments/l-external-lbsft", this, eL, (PMF)&FGExternalReactions::GetMoments);
|
||||
PropertyManager->Tie("moments/m-external-lbsft", this, eM, (PMF)&FGExternalReactions::GetMoments);
|
||||
PropertyManager->Tie("moments/n-external-lbsft", this, eN, (PMF)&FGExternalReactions::GetMoments);
|
||||
PropertyManager->Tie("forces/fbx-external-lbs", this, eX, (PMF)&FGExternalReactions::GetForces);
|
||||
PropertyManager->Tie("forces/fby-external-lbs", this, eY, (PMF)&FGExternalReactions::GetForces);
|
||||
PropertyManager->Tie("forces/fbz-external-lbs", this, eZ, (PMF)&FGExternalReactions::GetForces);
|
||||
}
|
||||
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// The bitmasked value choices are as follows:
|
||||
// unset: In this case (the default) JSBSim would only print
|
||||
|
|
|
@ -41,12 +41,14 @@ INCLUDES
|
|||
#include <vector>
|
||||
#include "FGModel.h"
|
||||
#include "FGExternalForce.h"
|
||||
#include "input_output/FGXMLFileRead.h"
|
||||
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_EXTERNALREACTIONS "$Id: FGExternalReactions.h,v 1.11 2011/05/20 03:18:36 jberndt Exp $"
|
||||
#define ID_EXTERNALREACTIONS "$Id: FGExternalReactions.h,v 1.13 2011/07/20 12:16:34 jberndt Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -115,7 +117,7 @@ CLASS DOCUMENTATION
|
|||
CLASS DECLARATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
class FGExternalReactions : public FGModel
|
||||
class FGExternalReactions : public FGModel, public FGXMLFileRead
|
||||
{
|
||||
public:
|
||||
/** Constructor.
|
||||
|
@ -152,11 +154,13 @@ public:
|
|||
@return the total force in pounds.
|
||||
*/
|
||||
FGColumnVector3 GetForces(void) const {return vTotalForces;}
|
||||
double GetForces(int idx) const {return vTotalForces(idx);}
|
||||
|
||||
/** Retrieves the total moment resulting from the forces defined in the external reactions.
|
||||
@return the total moment in foot-pounds.
|
||||
*/
|
||||
FGColumnVector3 GetMoments(void) const {return vTotalMoments;}
|
||||
double GetMoments(int idx) const {return vTotalMoments(idx);}
|
||||
|
||||
private:
|
||||
|
||||
|
@ -167,6 +171,7 @@ private:
|
|||
|
||||
bool NoneDefined;
|
||||
|
||||
void bind(void);
|
||||
void Debug(int from);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -37,13 +37,14 @@ HISTORY
|
|||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
#include "FGFCS.h"
|
||||
#include "FGFDMExec.h"
|
||||
#include "FGGroundReactions.h"
|
||||
#include "input_output/FGPropertyManager.h"
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
#include "models/flight_control/FGFilter.h"
|
||||
#include "models/flight_control/FGDeadBand.h"
|
||||
|
@ -63,7 +64,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGFCS.cpp,v 1.74 2011/05/20 03:18:36 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGFCS.cpp,v 1.76 2011/08/14 20:15:56 jberndt Exp $";
|
||||
static const char *IdHdr = ID_FCS;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -78,7 +79,7 @@ FGFCS::FGFCS(FGFDMExec* fdmex) : FGModel(fdmex)
|
|||
DaCmd = DeCmd = DrCmd = DsCmd = DfCmd = DsbCmd = DspCmd = 0;
|
||||
PTrimCmd = YTrimCmd = RTrimCmd = 0.0;
|
||||
GearCmd = GearPos = 1; // default to gear down
|
||||
LeftBrake = RightBrake = CenterBrake = 0.0;
|
||||
BrakePos.resize(FGLGear::bgNumBrakeGroups);
|
||||
TailhookPos = WingFoldPos = 0.0;
|
||||
|
||||
bind();
|
||||
|
@ -673,17 +674,7 @@ bool FGFCS::Load(Element* el, SystemType systype)
|
|||
|
||||
double FGFCS::GetBrake(FGLGear::BrakeGroup bg)
|
||||
{
|
||||
switch (bg) {
|
||||
case FGLGear::bgLeft:
|
||||
return LeftBrake;
|
||||
case FGLGear::bgRight:
|
||||
return RightBrake;
|
||||
case FGLGear::bgCenter:
|
||||
return CenterBrake;
|
||||
default:
|
||||
cerr << "GetBrake asked to return a bogus brake value" << endl;
|
||||
}
|
||||
return 0.0;
|
||||
return BrakePos[bg];
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -838,9 +829,10 @@ void FGFCS::AddThrottle(void)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGFCS::AddGear(void)
|
||||
void FGFCS::AddGear(unsigned int NumGear)
|
||||
{
|
||||
SteerPosDeg.push_back(0.0);
|
||||
SteerPosDeg.clear();
|
||||
for (unsigned int i=0; i<NumGear; i++) SteerPosDeg.push_back(0.0);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -51,7 +51,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_FCS "$Id: FGFCS.h,v 1.36 2011/05/20 03:18:36 jberndt Exp $"
|
||||
#define ID_FCS "$Id: FGFCS.h,v 1.39 2011/08/14 20:15:56 jberndt Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -168,7 +168,7 @@ CLASS DOCUMENTATION
|
|||
@property gear/tailhook-pos-norm
|
||||
|
||||
@author Jon S. Berndt
|
||||
@version $Revision: 1.36 $
|
||||
@version $Revision: 1.39 $
|
||||
@see FGActuator
|
||||
@see FGDeadBand
|
||||
@see FGFCSFunction
|
||||
|
@ -243,11 +243,15 @@ public:
|
|||
@return throttle command in range from 0 - 1.0 for the given engine */
|
||||
double GetThrottleCmd(int engine) const;
|
||||
|
||||
vector <double> GetThrottleCmd() const {return ThrottleCmd;}
|
||||
|
||||
/** Gets the mixture command.
|
||||
@param engine engine ID number
|
||||
@return mixture command in range from 0 - 1.0 for the given engine */
|
||||
double GetMixtureCmd(int engine) const { return MixtureCmd[engine]; }
|
||||
|
||||
vector <double> GetMixtureCmd() const {return MixtureCmd;}
|
||||
|
||||
/** Gets the prop pitch command.
|
||||
@param engine engine ID number
|
||||
@return pitch command in range from 0.0 - 1.0 for the given engine */
|
||||
|
@ -318,15 +322,21 @@ public:
|
|||
@return throttle position for the given engine in range from 0 - 1.0 */
|
||||
double GetThrottlePos(int engine) const;
|
||||
|
||||
vector <double> GetThrottlePos() const {return ThrottlePos;}
|
||||
|
||||
/** Gets the mixture position.
|
||||
@param engine engine ID number
|
||||
@return mixture position for the given engine in range from 0 - 1.0 */
|
||||
double GetMixturePos(int engine) const { return MixturePos[engine]; }
|
||||
|
||||
vector <double> GetMixturePos() const {return MixturePos;}
|
||||
|
||||
/** Gets the steering position.
|
||||
@return steering position in degrees */
|
||||
double GetSteerPosDeg(int gear) const { return SteerPosDeg[gear]; }
|
||||
|
||||
vector <double> GetSteerPosDeg() const {return SteerPosDeg;}
|
||||
|
||||
/** Gets the gear position (0 up, 1 down), defaults to down
|
||||
@return gear position (0 up, 1 down) */
|
||||
double GetGearPos(void) const { return GearPos; }
|
||||
|
@ -344,10 +354,14 @@ public:
|
|||
@return prop pitch position for the given engine in range from 0 - 1.0 */
|
||||
double GetPropAdvance(int engine) const { return PropAdvance[engine]; }
|
||||
|
||||
vector <double> GetPropAdvance() const { return PropAdvance; }
|
||||
|
||||
/** Gets the prop feather position.
|
||||
@param engine engine ID number
|
||||
@return prop fether for the given engine (on / off)*/
|
||||
bool GetPropFeather(int engine) const { return PropFeather[engine]; }
|
||||
|
||||
vector <bool> GetPropFeather() const { return PropFeather; }
|
||||
//@}
|
||||
|
||||
/** Retrieves all component names for inclusion in output stream
|
||||
|
@ -499,32 +513,34 @@ public:
|
|||
//@{
|
||||
/** Sets the left brake group
|
||||
@param cmd brake setting in percent (0.0 - 1.0) */
|
||||
void SetLBrake(double cmd) {LeftBrake = cmd;}
|
||||
void SetLBrake(double cmd) {BrakePos[FGLGear::bgLeft] = cmd;}
|
||||
|
||||
/** Sets the right brake group
|
||||
@param cmd brake setting in percent (0.0 - 1.0) */
|
||||
void SetRBrake(double cmd) {RightBrake = cmd;}
|
||||
void SetRBrake(double cmd) {BrakePos[FGLGear::bgRight] = cmd;}
|
||||
|
||||
/** Sets the center brake group
|
||||
@param cmd brake setting in percent (0.0 - 1.0) */
|
||||
void SetCBrake(double cmd) {CenterBrake = cmd;}
|
||||
void SetCBrake(double cmd) {BrakePos[FGLGear::bgCenter] = cmd;}
|
||||
|
||||
/** Gets the brake for a specified group.
|
||||
@param bg which brakegroup to retrieve the command for
|
||||
@return the brake setting for the supplied brake group argument */
|
||||
double GetBrake(FGLGear::BrakeGroup bg);
|
||||
|
||||
vector <double> GetBrakePos() const {return BrakePos;}
|
||||
|
||||
/** Gets the left brake.
|
||||
@return the left brake setting. */
|
||||
double GetLBrake(void) const {return LeftBrake;}
|
||||
double GetLBrake(void) const {return BrakePos[FGLGear::bgLeft];}
|
||||
|
||||
/** Gets the right brake.
|
||||
@return the right brake setting. */
|
||||
double GetRBrake(void) const {return RightBrake;}
|
||||
double GetRBrake(void) const {return BrakePos[FGLGear::bgRight];}
|
||||
|
||||
/** Gets the center brake.
|
||||
@return the center brake setting. */
|
||||
double GetCBrake(void) const {return CenterBrake;}
|
||||
double GetCBrake(void) const {return BrakePos[FGLGear::bgCenter];}
|
||||
//@}
|
||||
|
||||
enum SystemType { stFCS, stSystem, stAutoPilot };
|
||||
|
@ -540,13 +556,17 @@ public:
|
|||
std::string FindSystemFullPathname(const std::string& system_filename);
|
||||
|
||||
void AddThrottle(void);
|
||||
void AddGear(void);
|
||||
void AddGear(unsigned int NumGear);
|
||||
double GetDt(void);
|
||||
|
||||
FGPropertyManager* GetPropertyManager(void) { return PropertyManager; }
|
||||
|
||||
bool GetTrimStatus(void) const { return FDMExec->GetTrimStatus(); }
|
||||
|
||||
struct Inputs {
|
||||
unsigned int NumGear;
|
||||
} in;
|
||||
|
||||
private:
|
||||
double DaCmd, DeCmd, DrCmd, DsCmd, DfCmd, DsbCmd, DspCmd;
|
||||
double DePos[NForms], DaLPos[NForms], DaRPos[NForms], DrPos[NForms];
|
||||
|
@ -562,6 +582,7 @@ private:
|
|||
std::vector <bool> PropFeather;
|
||||
std::vector <double> SteerPosDeg;
|
||||
double LeftBrake, RightBrake, CenterBrake; // Brake settings
|
||||
vector <double> BrakePos; // left, center, right - defined by FGLGear:: enum
|
||||
double GearCmd,GearPos;
|
||||
double TailhookPos, WingFoldPos;
|
||||
|
||||
|
|
|
@ -36,9 +36,6 @@ INCLUDES
|
|||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include "FGFDMExec.h"
|
||||
#include "models/FGAuxiliary.h"
|
||||
#include "models/FGAtmosphere.h"
|
||||
#include "models/FGInertial.h"
|
||||
#include "models/FGMassBalance.h"
|
||||
#include "FGGasCell.h"
|
||||
#include "input_output/FGXMLElement.h"
|
||||
|
@ -53,7 +50,7 @@ using std::max;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGGasCell.cpp,v 1.14 2011/07/01 21:22:25 andgi Exp $";
|
||||
static const char *IdSrc = "$Id: FGGasCell.cpp,v 1.15 2011/08/06 13:47:59 jberndt Exp $";
|
||||
static const char *IdHdr = ID_GASCELL;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -65,15 +62,13 @@ const double FGGasCell::M_air = 0.0019186; // [slug/mol]
|
|||
const double FGGasCell::M_hydrogen = 0.00013841; // [slug/mol]
|
||||
const double FGGasCell::M_helium = 0.00027409; // [slug/mol]
|
||||
|
||||
FGGasCell::FGGasCell(FGFDMExec* exec, Element* el, int num) : FGForce(exec)
|
||||
FGGasCell::FGGasCell(FGFDMExec* exec, Element* el, int num, const struct Inputs& input)
|
||||
: FGForce(exec), in(input)
|
||||
{
|
||||
string token;
|
||||
Element* element;
|
||||
|
||||
Auxiliary = exec->GetAuxiliary();
|
||||
Atmosphere = exec->GetAtmosphere();
|
||||
PropertyManager = exec->GetPropertyManager();
|
||||
Inertial = exec->GetInertial();
|
||||
MassBalance = exec->GetMassBalance();
|
||||
|
||||
gasCellJ = FGMatrix33();
|
||||
|
@ -175,10 +170,10 @@ FGGasCell::FGGasCell(FGFDMExec* exec, Element* el, int num) : FGForce(exec)
|
|||
SetLocation(vXYZ);
|
||||
|
||||
if (Temperature == 0.0) {
|
||||
Temperature = Atmosphere->GetTemperature();
|
||||
Temperature = in.Temperature;
|
||||
}
|
||||
if (Pressure == 0.0) {
|
||||
Pressure = Atmosphere->GetPressure();
|
||||
Pressure = in.Pressure;
|
||||
}
|
||||
if (Volume != 0.0) {
|
||||
// Calculate initial gas content.
|
||||
|
@ -239,7 +234,7 @@ FGGasCell::FGGasCell(FGFDMExec* exec, Element* el, int num) : FGForce(exec)
|
|||
Ballonet.push_back(new FGBallonet(exec,
|
||||
ballonet_element,
|
||||
Ballonet.size(),
|
||||
this));
|
||||
this, in));
|
||||
ballonet_element = el->FindNextElement("ballonet");
|
||||
}
|
||||
}
|
||||
|
@ -265,10 +260,10 @@ FGGasCell::~FGGasCell()
|
|||
|
||||
void FGGasCell::Calculate(double dt)
|
||||
{
|
||||
const double AirTemperature = Atmosphere->GetTemperature(); // [Rankine]
|
||||
const double AirPressure = Atmosphere->GetPressure(); // [lbs/ft²]
|
||||
const double AirDensity = Atmosphere->GetDensity(); // [slug/ft³]
|
||||
const double g = Inertial->gravity(); // [lbs/slug]
|
||||
const double AirTemperature = in.Temperature; // [Rankine]
|
||||
const double AirPressure = in.Pressure; // [lbs/ft²]
|
||||
const double AirDensity = in.Density; // [slug/ft³]
|
||||
const double g = in.gravity; // [lbs/slug]
|
||||
|
||||
const double OldTemperature = Temperature;
|
||||
const double OldPressure = Pressure;
|
||||
|
@ -509,15 +504,13 @@ const double FGBallonet::R = 3.4071; // [lbs ft/(mol Rankine)]
|
|||
const double FGBallonet::M_air = 0.0019186; // [slug/mol]
|
||||
const double FGBallonet::Cv_air = 5.0/2.0; // [??]
|
||||
|
||||
FGBallonet::FGBallonet(FGFDMExec* exec, Element* el, int num, FGGasCell* parent)
|
||||
FGBallonet::FGBallonet(FGFDMExec* exec, Element* el, int num, FGGasCell* parent, const struct FGGasCell::Inputs& input)
|
||||
: in(input)
|
||||
{
|
||||
string token;
|
||||
Element* element;
|
||||
|
||||
Auxiliary = exec->GetAuxiliary();
|
||||
Atmosphere = exec->GetAtmosphere();
|
||||
PropertyManager = exec->GetPropertyManager();
|
||||
Inertial = exec->GetInertial();
|
||||
MassBalance = exec->GetMassBalance();
|
||||
|
||||
ballonetJ = FGMatrix33();
|
||||
|
@ -696,8 +689,8 @@ FGBallonet::~FGBallonet()
|
|||
|
||||
void FGBallonet::Calculate(double dt)
|
||||
{
|
||||
const double ParentPressure = Parent->GetPressure(); // [lbs/ft²]
|
||||
const double AirPressure = Atmosphere->GetPressure(); // [lbs/ft²]
|
||||
const double ParentPressure = Parent->GetPressure(); // [lbs/ft²]
|
||||
const double AirPressure = Pressure; // [lbs/ft²]
|
||||
|
||||
const double OldTemperature = Temperature;
|
||||
const double OldPressure = Pressure;
|
||||
|
|
|
@ -32,8 +32,8 @@ This class simulates a generic gas cell for static buoyancy.
|
|||
SENTRY
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#ifndef FGGasCell_H
|
||||
#define FGGasCell_H
|
||||
#ifndef FGGASCELL_H
|
||||
#define FGGASCELL_H
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
INCLUDES
|
||||
|
@ -50,7 +50,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_GASCELL "$Id: FGGasCell.h,v 1.11 2011/07/01 21:22:25 andgi Exp $"
|
||||
#define ID_GASCELL "$Id: FGGasCell.h,v 1.12 2011/08/06 13:47:59 jberndt Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -172,11 +172,18 @@ CLASS DECLARATION
|
|||
class FGGasCell : public FGForce
|
||||
{
|
||||
public:
|
||||
struct Inputs {
|
||||
double Pressure;
|
||||
double Temperature;
|
||||
double Density;
|
||||
double gravity;
|
||||
};
|
||||
|
||||
/** Constructor
|
||||
@param exec Executive a pointer to the parent executive object
|
||||
@param el Pointer to configuration file XML node
|
||||
@param num Gas cell index number. */
|
||||
FGGasCell(FGFDMExec* exec, Element* el, int num);
|
||||
FGGasCell(FGFDMExec* exec, Element* el, int num, const struct Inputs& input);
|
||||
~FGGasCell();
|
||||
|
||||
/** Runs the gas cell model; called by BuoyantForces
|
||||
|
@ -221,6 +228,8 @@ public:
|
|||
@return gas pressure in lbs / ft<sup>2</sup>. */
|
||||
double GetPressure(void) const {return Pressure;}
|
||||
|
||||
const struct Inputs& in;
|
||||
|
||||
private:
|
||||
|
||||
enum GasType {ttUNKNOWN, ttHYDROGEN, ttHELIUM, ttAIR};
|
||||
|
@ -252,10 +261,7 @@ private:
|
|||
FGMatrix33 gasCellJ; // [slug foot^2]
|
||||
FGColumnVector3 gasCellM; // [lbs in]
|
||||
|
||||
FGAuxiliary* Auxiliary;
|
||||
FGAtmosphere* Atmosphere;
|
||||
FGPropertyManager* PropertyManager;
|
||||
FGInertial* Inertial;
|
||||
FGMassBalance* MassBalance;
|
||||
void Debug(int from);
|
||||
|
||||
|
@ -302,7 +308,7 @@ private:
|
|||
class FGBallonet : public FGJSBBase
|
||||
{
|
||||
public:
|
||||
FGBallonet(FGFDMExec* exec, Element* el, int num, FGGasCell* parent);
|
||||
FGBallonet(FGFDMExec* exec, Element* el, int num, FGGasCell* parent, const struct FGGasCell::Inputs& input);
|
||||
~FGBallonet();
|
||||
|
||||
/** Runs the ballonet model; called by FGGasCell
|
||||
|
@ -333,6 +339,8 @@ public:
|
|||
@return heat flow in lbs ft / sec. */
|
||||
double GetHeatFlow(void) const {return dU;} // [lbs ft / sec]
|
||||
|
||||
const struct FGGasCell::Inputs& in;
|
||||
|
||||
private:
|
||||
int CellNum;
|
||||
// Structural constants
|
||||
|
@ -356,10 +364,7 @@ private:
|
|||
double ValveOpen; // 0 <= ValveOpen <= 1 (or higher).
|
||||
FGMatrix33 ballonetJ; // [slug foot^2]
|
||||
|
||||
FGAuxiliary* Auxiliary;
|
||||
FGAtmosphere* Atmosphere;
|
||||
FGPropertyManager* PropertyManager;
|
||||
FGInertial* Inertial;
|
||||
FGMassBalance* MassBalance;
|
||||
void Debug(int from);
|
||||
|
||||
|
|
|
@ -39,56 +39,16 @@ INCLUDES
|
|||
#include <iomanip>
|
||||
|
||||
#include "FGGroundReactions.h"
|
||||
#include "FGFCS.h"
|
||||
#include "FGLGear.h"
|
||||
#include "input_output/FGPropertyManager.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGGroundReactions.cpp,v 1.32 2011/05/20 03:18:36 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGGroundReactions.cpp,v 1.36 2011/08/21 15:13:22 bcoconni Exp $";
|
||||
static const char *IdHdr = ID_GROUNDREACTIONS;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS IMPLEMENTATION for MultiplierIterator (See below for FGGroundReactions)
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
MultiplierIterator::MultiplierIterator(FGGroundReactions* GndReactions)
|
||||
: GroundReactions(GndReactions),
|
||||
multiplier(NULL),
|
||||
gearNum(0),
|
||||
entry(0)
|
||||
{
|
||||
for (int i=0; i < GroundReactions->GetNumGearUnits(); i++) {
|
||||
FGLGear* gear = GroundReactions->GetGearUnit(i);
|
||||
|
||||
if (!gear->GetWOW()) continue;
|
||||
|
||||
gearNum = i;
|
||||
multiplier = gear->GetMultiplierEntry(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
MultiplierIterator& MultiplierIterator::operator++()
|
||||
{
|
||||
for (int i=gearNum; i < GroundReactions->GetNumGearUnits(); i++) {
|
||||
FGLGear* gear = GroundReactions->GetGearUnit(i);
|
||||
|
||||
if (!gear->GetWOW()) continue;
|
||||
|
||||
multiplier = gear->GetMultiplierEntry(++entry);
|
||||
if (multiplier) {
|
||||
gearNum = i;
|
||||
break;
|
||||
}
|
||||
else
|
||||
entry = -1;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS IMPLEMENTATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
@ -131,6 +91,8 @@ bool FGGroundReactions::Run(bool Holding)
|
|||
vForces.InitMatrix();
|
||||
vMoments.InitMatrix();
|
||||
|
||||
multipliers.clear();
|
||||
|
||||
// Sum forces and moments for all gear, here.
|
||||
// Some optimizations may be made here - or rather in the gear code itself.
|
||||
// The gear ::Run() method is called several times - once for each gear.
|
||||
|
@ -160,20 +122,6 @@ bool FGGroundReactions::GetWOW(void) const
|
|||
return result;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// This function must be called after friction forces are resolved in order to
|
||||
// include them in the ground reactions total force and moment.
|
||||
void FGGroundReactions::UpdateForcesAndMoments(void)
|
||||
{
|
||||
vForces.InitMatrix();
|
||||
vMoments.InitMatrix();
|
||||
|
||||
for (unsigned int i=0; i<lGear.size(); i++) {
|
||||
vForces += lGear[i]->UpdateForces();
|
||||
vMoments += lGear[i]->GetMoments();
|
||||
}
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
bool FGGroundReactions::Load(Element* el)
|
||||
|
@ -182,15 +130,18 @@ bool FGGroundReactions::Load(Element* el)
|
|||
|
||||
Debug(2);
|
||||
|
||||
unsigned int numContacts = el->GetNumElements("contact");
|
||||
lGear.resize(numContacts);
|
||||
Element* contact_element = el->FindElement("contact");
|
||||
while (contact_element) {
|
||||
lGear.push_back(new FGLGear(contact_element, FDMExec, num++));
|
||||
FDMExec->GetFCS()->AddGear(); // make the FCS aware of the landing gear
|
||||
for (unsigned int idx=0; idx<numContacts; idx++) {
|
||||
lGear[idx] = new FGLGear(contact_element, FDMExec, num++, in);
|
||||
contact_element = el->FindNextElement("contact");
|
||||
}
|
||||
|
||||
|
||||
FGModel::Load(el); // Perform base class Load
|
||||
|
||||
in.vWhlBodyVec.resize(lGear.size());
|
||||
|
||||
for (unsigned int i=0; i<lGear.size();i++) lGear[i]->bind();
|
||||
|
||||
PostLoad(el, PropertyManager);
|
||||
|
@ -275,12 +226,6 @@ void FGGroundReactions::bind(void)
|
|||
typedef double (FGGroundReactions::*PMF)(int) const;
|
||||
PropertyManager->Tie("gear/num-units", this, &FGGroundReactions::GetNumGearUnits);
|
||||
PropertyManager->Tie("gear/wow", this, &FGGroundReactions::GetWOW);
|
||||
PropertyManager->Tie("moments/l-gear-lbsft", this, eL, (PMF)&FGGroundReactions::GetMoments);
|
||||
PropertyManager->Tie("moments/m-gear-lbsft", this, eM, (PMF)&FGGroundReactions::GetMoments);
|
||||
PropertyManager->Tie("moments/n-gear-lbsft", this, eN, (PMF)&FGGroundReactions::GetMoments);
|
||||
PropertyManager->Tie("forces/fbx-gear-lbs", this, eX, (PMF)&FGGroundReactions::GetForces);
|
||||
PropertyManager->Tie("forces/fby-gear-lbs", this, eY, (PMF)&FGGroundReactions::GetForces);
|
||||
PropertyManager->Tie("forces/fbz-gear-lbs", this, eZ, (PMF)&FGGroundReactions::GetForces);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -45,7 +45,7 @@ INCLUDES
|
|||
#include "math/FGColumnVector3.h"
|
||||
#include "input_output/FGXMLElement.h"
|
||||
|
||||
#define ID_GROUNDREACTIONS "$Id: FGGroundReactions.h,v 1.20 2011/05/20 03:18:36 jberndt Exp $"
|
||||
#define ID_GROUNDREACTIONS "$Id: FGGroundReactions.h,v 1.24 2011/08/21 15:13:22 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -78,19 +78,6 @@ CLASS DOCUMENTATION
|
|||
CLASS DECLARATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
class MultiplierIterator
|
||||
{
|
||||
public:
|
||||
MultiplierIterator(FGGroundReactions* GndReactions);
|
||||
MultiplierIterator& operator++();
|
||||
FGPropagate::LagrangeMultiplier* operator*() { return multiplier; }
|
||||
private:
|
||||
FGGroundReactions* GroundReactions;
|
||||
FGPropagate::LagrangeMultiplier* multiplier;
|
||||
int gearNum;
|
||||
int entry;
|
||||
};
|
||||
|
||||
class FGGroundReactions : public FGModel
|
||||
{
|
||||
public:
|
||||
|
@ -114,7 +101,6 @@ public:
|
|||
string GetGroundReactionStrings(string delimeter) const;
|
||||
string GetGroundReactionValues(string delimeter) const;
|
||||
bool GetWOW(void) const;
|
||||
void UpdateForcesAndMoments(void);
|
||||
|
||||
int GetNumGearUnits(void) const { return (int)lGear.size(); }
|
||||
|
||||
|
@ -123,10 +109,16 @@ public:
|
|||
@return a pointer to the FGLGear instance of the gear unit requested */
|
||||
FGLGear* GetGearUnit(int gear) const { return lGear[gear]; }
|
||||
|
||||
void RegisterLagrangeMultiplier(LagrangeMultiplier* lmult) { multipliers.push_back(lmult); }
|
||||
vector <LagrangeMultiplier*>* GetMultipliersList(void) { return &multipliers; }
|
||||
|
||||
FGLGear::Inputs in;
|
||||
|
||||
private:
|
||||
vector <FGLGear*> lGear;
|
||||
FGColumnVector3 vForces;
|
||||
FGColumnVector3 vMoments;
|
||||
vector <LagrangeMultiplier*> multipliers;
|
||||
|
||||
void bind(void);
|
||||
void Debug(int from);
|
||||
|
|
|
@ -37,15 +37,13 @@ INCLUDES
|
|||
|
||||
#include "FGInertial.h"
|
||||
#include "FGFDMExec.h"
|
||||
#include "FGPropagate.h"
|
||||
#include "FGMassBalance.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGInertial.cpp,v 1.21 2011/05/20 03:18:36 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGInertial.cpp,v 1.24 2011/08/04 12:46:32 jberndt Exp $";
|
||||
static const char *IdHdr = ID_INERTIAL;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -65,7 +63,6 @@ FGInertial::FGInertial(FGFDMExec* fgex) : FGModel(fgex)
|
|||
J2 = 1.0826266836E-03; // WGS84 value for J2
|
||||
a = 20925646.3255; // WGS84 semimajor axis length in feet
|
||||
b = 20855486.5951; // WGS84 semiminor axis length in feet
|
||||
earthPosAngle = 0.0;
|
||||
|
||||
// Lunar defaults
|
||||
/*
|
||||
|
@ -76,9 +73,9 @@ FGInertial::FGInertial(FGFDMExec* fgex) : FGModel(fgex)
|
|||
J2 = 2.033542482111609E-4; // value for J2
|
||||
a = 5702559.05; // semimajor axis length in feet
|
||||
b = 5695439.63; // semiminor axis length in feet
|
||||
earthPosAngle = 0.0;
|
||||
*/
|
||||
|
||||
vOmegaPlanet = FGColumnVector3( 0.0, 0.0, RotationRate );
|
||||
gAccelReference = GM/(RadiusReference*RadiusReference);
|
||||
gAccel = GM/(RadiusReference*RadiusReference);
|
||||
|
||||
|
@ -98,8 +95,6 @@ FGInertial::~FGInertial(void)
|
|||
|
||||
bool FGInertial::InitModel(void)
|
||||
{
|
||||
earthPosAngle = 0.0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -114,9 +109,7 @@ bool FGInertial::Run(bool Holding)
|
|||
RunPreFunctions();
|
||||
|
||||
// Gravitation accel
|
||||
double r = FDMExec->GetPropagate()->GetRadius();
|
||||
gAccel = GetGAccel(r);
|
||||
earthPosAngle += FDMExec->GetDeltaT()*RotationRate;
|
||||
gAccel = GetGAccel(in.Radius);
|
||||
|
||||
RunPostFunctions();
|
||||
|
||||
|
@ -143,8 +136,7 @@ FGColumnVector3 FGInertial::GetGravityJ2(FGColumnVector3 position) const
|
|||
|
||||
// Gravitation accel
|
||||
double r = position.Magnitude();
|
||||
double lat = FDMExec->GetPropagate()->GetLatitude();
|
||||
double sinLat = sin(lat);
|
||||
double sinLat = sin(in.Latitude);
|
||||
|
||||
double adivr = a/r;
|
||||
double preCommon = 1.5*J2*adivr*adivr;
|
||||
|
@ -163,7 +155,7 @@ FGColumnVector3 FGInertial::GetGravityJ2(FGColumnVector3 position) const
|
|||
|
||||
void FGInertial::bind(void)
|
||||
{
|
||||
PropertyManager->Tie("position/epa-rad", this, &FGInertial::GetEarthPositionAngle);
|
||||
PropertyManager->Tie("inertial/sea-level-radius_ft", this, &FGInertial::GetRefRadius);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -47,7 +47,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_INERTIAL "$Id: FGInertial.h,v 1.16 2011/05/20 03:18:36 jberndt Exp $"
|
||||
#define ID_INERTIAL "$Id: FGInertial.h,v 1.19 2011/08/04 12:46:32 jberndt Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -86,17 +86,20 @@ public:
|
|||
double SLgravity(void) const {return gAccelReference;}
|
||||
double gravity(void) const {return gAccel;}
|
||||
double omega(void) const {return RotationRate;}
|
||||
double GetEarthPositionAngle(void) const { return earthPosAngle; }
|
||||
double GetEarthPositionAngleDeg(void) const { return earthPosAngle*radtodeg;}
|
||||
FGColumnVector3 GetOmegaPlanet() const {return vOmegaPlanet;}
|
||||
double GetGAccel(double r) const;
|
||||
FGColumnVector3 GetGravityJ2(FGColumnVector3 position) const;
|
||||
double GetRefRadius(void) const {return RadiusReference;}
|
||||
double GetSemimajor(void) const {return a;}
|
||||
double GetSemiminor(void) const {return b;}
|
||||
|
||||
void SetEarthPositionAngle(double epa) {earthPosAngle = epa;}
|
||||
struct Inputs {
|
||||
double Radius;
|
||||
double Latitude;
|
||||
} in;
|
||||
|
||||
private:
|
||||
FGColumnVector3 vOmegaPlanet;
|
||||
double gAccel;
|
||||
double gAccelReference;
|
||||
double RadiusReference;
|
||||
|
|
|
@ -40,16 +40,14 @@ HISTORY
|
|||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include "FGLGear.h"
|
||||
#include "FGGroundReactions.h"
|
||||
#include "FGFCS.h"
|
||||
#include "FGAuxiliary.h"
|
||||
#include "FGAtmosphere.h"
|
||||
#include "FGMassBalance.h"
|
||||
#include "math/FGTable.h"
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include "FGLGear.h"
|
||||
#include "input_output/FGPropertyManager.h"
|
||||
#include "models/FGGroundReactions.h"
|
||||
#include "math/FGTable.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace JSBSim {
|
||||
|
@ -62,7 +60,7 @@ DEFINITIONS
|
|||
GLOBAL DATA
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
static const char *IdSrc = "$Id: FGLGear.cpp,v 1.80 2011/01/24 13:01:56 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGLGear.cpp,v 1.88 2011/08/30 21:05:56 bcoconni Exp $";
|
||||
static const char *IdHdr = ID_LGEAR;
|
||||
|
||||
// Body To Structural (body frame is rotated 180 deg about Y and lengths are given in
|
||||
|
@ -73,12 +71,13 @@ const FGMatrix33 FGLGear::Tb2s(-1./inchtoft, 0., 0., 0., 1./inchtoft, 0., 0., 0.
|
|||
CLASS IMPLEMENTATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
FGLGear::FGLGear(Element* el, FGFDMExec* fdmex, int number) :
|
||||
FGLGear::FGLGear(Element* el, FGFDMExec* fdmex, int number, const struct Inputs& inputs) :
|
||||
FGForce(fdmex),
|
||||
GearNumber(number),
|
||||
SteerAngle(0.0),
|
||||
Castered(false),
|
||||
StaticFriction(false)
|
||||
StaticFriction(false),
|
||||
in(inputs)
|
||||
{
|
||||
Element *force_table=0;
|
||||
Element *dampCoeff=0;
|
||||
|
@ -102,6 +101,15 @@ FGLGear::FGLGear(Element* el, FGFDMExec* fdmex, int number) :
|
|||
eContactType = ctSTRUCTURE;
|
||||
}
|
||||
|
||||
// Default values for structural contact points
|
||||
if (eContactType == ctSTRUCTURE) {
|
||||
kSpring = in.EmptyWeight;
|
||||
bDamp = kSpring;
|
||||
bDampRebound = kSpring * 10;
|
||||
staticFCoeff = 1.0;
|
||||
dynamicFCoeff = 1.0;
|
||||
}
|
||||
|
||||
if (el->FindElement("spring_coeff"))
|
||||
kSpring = el->FindElementValueAsNumberConvertTo("spring_coeff", "LBS/FT");
|
||||
if (el->FindElement("damping_coeff")) {
|
||||
|
@ -138,12 +146,15 @@ FGLGear::FGLGear(Element* el, FGFDMExec* fdmex, int number) :
|
|||
if (el->FindElement("retractable"))
|
||||
isRetractable = ((unsigned int)el->FindElementValueAsNumber("retractable"))>0.0?true:false;
|
||||
|
||||
GroundReactions = fdmex->GetGroundReactions();
|
||||
PropertyManager = fdmex->GetPropertyManager();
|
||||
|
||||
ForceY_Table = 0;
|
||||
force_table = el->FindElement("table");
|
||||
while (force_table) {
|
||||
force_type = force_table->GetAttributeValue("type");
|
||||
if (force_type == "CORNERING_COEFF") {
|
||||
ForceY_Table = new FGTable(fdmex->GetPropertyManager(), force_table);
|
||||
ForceY_Table = new FGTable(PropertyManager, force_table);
|
||||
} else {
|
||||
cerr << "Undefined force table for " << name << " contact point" << endl;
|
||||
}
|
||||
|
@ -212,12 +223,6 @@ FGLGear::FGLGear(Element* el, FGFDMExec* fdmex, int number) :
|
|||
<< sSteerType << " is undefined." << endl;
|
||||
}
|
||||
|
||||
Auxiliary = fdmex->GetAuxiliary();
|
||||
Propagate = fdmex->GetPropagate();
|
||||
FCS = fdmex->GetFCS();
|
||||
MassBalance = fdmex->GetMassBalance();
|
||||
GroundReactions = fdmex->GetGroundReactions();
|
||||
|
||||
GearUp = false;
|
||||
GearDown = true;
|
||||
GearPos = 1.0;
|
||||
|
@ -236,8 +241,6 @@ FGLGear::FGLGear(Element* el, FGFDMExec* fdmex, int number) :
|
|||
MaximumStrutForce = MaximumStrutTravel = 0.0;
|
||||
SinkRate = GroundSpeed = 0.0;
|
||||
|
||||
vWhlBodyVec = MassBalance->StructuralToBody(vXYZn);
|
||||
vLocalGear = Propagate->GetTb2l() * vWhlBodyVec;
|
||||
vWhlVelVec.InitMatrix();
|
||||
|
||||
compressLength = 0.0;
|
||||
|
@ -274,29 +277,27 @@ FGLGear::~FGLGear()
|
|||
FGColumnVector3& FGLGear::GetBodyForces(void)
|
||||
{
|
||||
double t = fdmex->GetSimTime();
|
||||
dT = fdmex->GetDeltaT()*GroundReactions->GetRate();
|
||||
|
||||
vFn.InitMatrix();
|
||||
|
||||
if (isRetractable) ComputeRetractionState();
|
||||
|
||||
if (GearDown) {
|
||||
FGColumnVector3 angularVel;
|
||||
FGColumnVector3 terrainVel, dummy;
|
||||
|
||||
vWhlBodyVec = MassBalance->StructuralToBody(vXYZn); // Get wheel in body frame
|
||||
vLocalGear = Propagate->GetTb2l() * vWhlBodyVec; // Get local frame wheel location
|
||||
vLocalGear = in.Tb2l * in.vWhlBodyVec[GearNumber]; // Get local frame wheel location
|
||||
|
||||
gearLoc = Propagate->GetLocation().LocalToLocation(vLocalGear);
|
||||
gearLoc = in.Location.LocalToLocation(vLocalGear);
|
||||
// Compute the height of the theoretical location of the wheel (if strut is
|
||||
// not compressed) with respect to the ground level
|
||||
double height = fdmex->GetGroundCallback()->GetAGLevel(t, gearLoc, contact, normal, cvel, angularVel);
|
||||
vGroundNormal = Propagate->GetTec2b() * normal;
|
||||
double height = fdmex->GetGroundCallback()->GetAGLevel(t, gearLoc, contact, normal, terrainVel, dummy);
|
||||
vGroundNormal = in.Tec2b * normal;
|
||||
|
||||
// The height returned above is the AGL and is expressed in the Z direction
|
||||
// of the ECEF coordinate frame. We now need to transform this height in
|
||||
// actual compression of the strut (BOGEY) of in the normal direction to the
|
||||
// ground (STRUCTURE)
|
||||
double normalZ = (Propagate->GetTec2l()*normal)(eZ);
|
||||
double normalZ = (in.Tec2l*normal)(eZ);
|
||||
double LGearProj = -(mTGear.Transposed() * vGroundNormal)(eZ);
|
||||
|
||||
switch (eContactType) {
|
||||
|
@ -309,7 +310,6 @@ FGColumnVector3& FGLGear::GetBodyForces(void)
|
|||
}
|
||||
|
||||
if (compressLength > 0.00) {
|
||||
|
||||
WOW = true;
|
||||
|
||||
// The following equations use the vector to the tire contact patch
|
||||
|
@ -325,10 +325,10 @@ FGColumnVector3& FGLGear::GetBodyForces(void)
|
|||
break;
|
||||
}
|
||||
|
||||
FGColumnVector3 vWhlContactVec = vWhlBodyVec + vWhlDisplVec;
|
||||
FGColumnVector3 vWhlContactVec = in.vWhlBodyVec[GearNumber] + vWhlDisplVec;
|
||||
vActingXYZn = vXYZn + Tb2s * vWhlDisplVec;
|
||||
FGColumnVector3 vBodyWhlVel = Propagate->GetPQR() * vWhlContactVec;
|
||||
vBodyWhlVel += Propagate->GetUVW() - Propagate->GetTec2b() * cvel;
|
||||
FGColumnVector3 vBodyWhlVel = in.PQR * vWhlContactVec;
|
||||
vBodyWhlVel += in.UVW - in.Tec2b * terrainVel;
|
||||
|
||||
vWhlVelVec = mTGear.Transposed() * vBodyWhlVel;
|
||||
|
||||
|
@ -338,9 +338,13 @@ FGColumnVector3& FGLGear::GetBodyForces(void)
|
|||
|
||||
vLocalWhlVel = Transform().Transposed() * vBodyWhlVel;
|
||||
|
||||
compressSpeed = -vLocalWhlVel(eX);
|
||||
if (eContactType == ctBOGEY)
|
||||
compressSpeed /= LGearProj;
|
||||
if (fdmex->GetTrimStatus())
|
||||
compressSpeed = 0.0; // Steady state is sought during trimming
|
||||
else {
|
||||
compressSpeed = -vLocalWhlVel(eX);
|
||||
if (eContactType == ctBOGEY)
|
||||
compressSpeed /= LGearProj;
|
||||
}
|
||||
|
||||
ComputeVerticalStrutForce();
|
||||
|
||||
|
@ -364,7 +368,7 @@ FGColumnVector3& FGLGear::GetBodyForces(void)
|
|||
StrutForce = 0.0;
|
||||
|
||||
// Let wheel spin down slowly
|
||||
vWhlVelVec(eX) -= 13.0*dT;
|
||||
vWhlVelVec(eX) -= 13.0 * in.TotalDeltaT;
|
||||
if (vWhlVelVec(eX) < 0.0) vWhlVelVec(eX) = 0.0;
|
||||
|
||||
// Return to neutral position between 1.0 and 0.8 gear pos.
|
||||
|
@ -463,14 +467,14 @@ void FGLGear::ComputeSteeringAngle(void)
|
|||
{
|
||||
switch (eSteerType) {
|
||||
case stSteer:
|
||||
SteerAngle = degtorad * FCS->GetSteerPosDeg(GearNumber);
|
||||
SteerAngle = degtorad * in.SteerPosDeg[GearNumber];
|
||||
break;
|
||||
case stFixed:
|
||||
SteerAngle = 0.0;
|
||||
break;
|
||||
case stCaster:
|
||||
if (!Castered)
|
||||
SteerAngle = degtorad * FCS->GetSteerPosDeg(GearNumber);
|
||||
SteerAngle = degtorad * in.SteerPosDeg[GearNumber];
|
||||
else {
|
||||
// Check that the speed is non-null otherwise use the current angle
|
||||
if (vWhlVelVec.Magnitude(eX,eY) > 0.1)
|
||||
|
@ -488,7 +492,7 @@ void FGLGear::ComputeSteeringAngle(void)
|
|||
|
||||
void FGLGear::ResetReporting(void)
|
||||
{
|
||||
if (Propagate->GetDistanceAGL() > 200.0) {
|
||||
if (in.DistanceAGL > 200.0) {
|
||||
FirstContact = false;
|
||||
StartedGroundRun = false;
|
||||
LandingReported = false;
|
||||
|
@ -508,16 +512,16 @@ void FGLGear::InitializeReporting(void)
|
|||
if (!FirstContact) {
|
||||
FirstContact = true;
|
||||
SinkRate = compressSpeed;
|
||||
GroundSpeed = Propagate->GetVel().Magnitude();
|
||||
GroundSpeed = in.Vground;
|
||||
TakeoffReported = false;
|
||||
}
|
||||
|
||||
// If the takeoff run is starting, initialize.
|
||||
|
||||
if ((Propagate->GetVel().Magnitude() > 0.1) &&
|
||||
(FCS->GetBrake(bgLeft) == 0) &&
|
||||
(FCS->GetBrake(bgRight) == 0) &&
|
||||
(FCS->GetThrottlePos(0) > 0.90) && !StartedGroundRun)
|
||||
if ((in.Vground > 0.1) &&
|
||||
(in.BrakePos[bgLeft] == 0) &&
|
||||
(in.BrakePos[bgRight] == 0) &&
|
||||
(in.TakeoffThrottle && !StartedGroundRun))
|
||||
{
|
||||
TakeoffDistanceTraveled = 0;
|
||||
TakeoffDistanceTraveled50ft = 0;
|
||||
|
@ -531,25 +535,25 @@ void FGLGear::InitializeReporting(void)
|
|||
void FGLGear::ReportTakeoffOrLanding(void)
|
||||
{
|
||||
if (FirstContact)
|
||||
LandingDistanceTraveled += Auxiliary->GetVground()*dT;
|
||||
LandingDistanceTraveled += in.Vground * in.TotalDeltaT;
|
||||
|
||||
if (StartedGroundRun) {
|
||||
TakeoffDistanceTraveled50ft += Auxiliary->GetVground()*dT;
|
||||
if (WOW) TakeoffDistanceTraveled += Auxiliary->GetVground()*dT;
|
||||
TakeoffDistanceTraveled50ft += in.Vground * in.TotalDeltaT;
|
||||
if (WOW) TakeoffDistanceTraveled += in.Vground * in.TotalDeltaT;
|
||||
}
|
||||
|
||||
if ( ReportEnable
|
||||
&& Auxiliary->GetVground() <= 0.05
|
||||
&& in.Vground <= 0.05
|
||||
&& !LandingReported
|
||||
&& GroundReactions->GetWOW())
|
||||
&& in.WOW)
|
||||
{
|
||||
if (debug_lvl > 0) Report(erLand);
|
||||
}
|
||||
|
||||
if ( ReportEnable
|
||||
&& !TakeoffReported
|
||||
&& (Propagate->GetDistanceAGL() - vLocalGear(eZ)) > 50.0
|
||||
&& !GroundReactions->GetWOW())
|
||||
&& (in.DistanceAGL - vLocalGear(eZ)) > 50.0
|
||||
&& !in.WOW)
|
||||
{
|
||||
if (debug_lvl > 0) Report(erTakeoff);
|
||||
}
|
||||
|
@ -584,24 +588,24 @@ void FGLGear::ComputeBrakeForceCoefficient(void)
|
|||
{
|
||||
switch (eBrakeGrp) {
|
||||
case bgLeft:
|
||||
BrakeFCoeff = ( rollingFCoeff*(1.0 - FCS->GetBrake(bgLeft)) +
|
||||
staticFCoeff*FCS->GetBrake(bgLeft) );
|
||||
BrakeFCoeff = ( rollingFCoeff * (1.0 - in.BrakePos[bgLeft]) +
|
||||
staticFCoeff * in.BrakePos[bgLeft] );
|
||||
break;
|
||||
case bgRight:
|
||||
BrakeFCoeff = ( rollingFCoeff*(1.0 - FCS->GetBrake(bgRight)) +
|
||||
staticFCoeff*FCS->GetBrake(bgRight) );
|
||||
BrakeFCoeff = ( rollingFCoeff * (1.0 - in.BrakePos[bgRight]) +
|
||||
staticFCoeff * in.BrakePos[bgRight] );
|
||||
break;
|
||||
case bgCenter:
|
||||
BrakeFCoeff = ( rollingFCoeff*(1.0 - FCS->GetBrake(bgCenter)) +
|
||||
staticFCoeff*FCS->GetBrake(bgCenter) );
|
||||
BrakeFCoeff = ( rollingFCoeff * (1.0 - in.BrakePos[bgCenter]) +
|
||||
staticFCoeff * in.BrakePos[bgCenter] );
|
||||
break;
|
||||
case bgNose:
|
||||
BrakeFCoeff = ( rollingFCoeff*(1.0 - FCS->GetBrake(bgCenter)) +
|
||||
staticFCoeff*FCS->GetBrake(bgCenter) );
|
||||
BrakeFCoeff = ( rollingFCoeff * (1.0 - in.BrakePos[bgCenter]) +
|
||||
staticFCoeff * in.BrakePos[bgCenter] );
|
||||
break;
|
||||
case bgTail:
|
||||
BrakeFCoeff = ( rollingFCoeff*(1.0 - FCS->GetBrake(bgCenter)) +
|
||||
staticFCoeff*FCS->GetBrake(bgCenter) );
|
||||
BrakeFCoeff = ( rollingFCoeff * (1.0 - in.BrakePos[bgCenter]) +
|
||||
staticFCoeff * in.BrakePos[bgCenter] );
|
||||
break;
|
||||
case bgNone:
|
||||
BrakeFCoeff = rollingFCoeff;
|
||||
|
@ -683,9 +687,9 @@ void FGLGear::ComputeVerticalStrutForce(void)
|
|||
double FGLGear::GetGearUnitPos(void)
|
||||
{
|
||||
// hack to provide backward compatibility to gear/gear-pos-norm property
|
||||
if( useFCSGearPos || FCS->GetGearPos() != 1.0 ) {
|
||||
if( useFCSGearPos || in.FCSGearPos != 1.0 ) {
|
||||
useFCSGearPos = true;
|
||||
return FCS->GetGearPos();
|
||||
return in.FCSGearPos;
|
||||
}
|
||||
return GearPos;
|
||||
}
|
||||
|
@ -711,7 +715,14 @@ void FGLGear::ComputeJacobian(const FGColumnVector3& vWhlContactVec)
|
|||
LMultiplier[ftDynamic].MomentJacobian = vWhlContactVec * LMultiplier[ftDynamic].ForceJacobian;
|
||||
LMultiplier[ftDynamic].Max = 0.;
|
||||
LMultiplier[ftDynamic].Min = -fabs(dynamicFCoeff * vFn(eX));
|
||||
|
||||
// The Lagrange multiplier value obtained from the previous iteration is kept
|
||||
// This is supposed to accelerate the convergence of the projected Gauss-Seidel
|
||||
// algorithm. The code just below is to make sure that the initial value
|
||||
// is consistent with the current friction coefficient and normal reaction.
|
||||
LMultiplier[ftDynamic].value = Constrain(LMultiplier[ftDynamic].Min, LMultiplier[ftDynamic].value, LMultiplier[ftDynamic].Max);
|
||||
|
||||
GroundReactions->RegisterLagrangeMultiplier(&LMultiplier[ftDynamic]);
|
||||
}
|
||||
else {
|
||||
// Static friction is used for ctSTRUCTURE when the contact point is not moving.
|
||||
|
@ -738,39 +749,24 @@ void FGLGear::ComputeJacobian(const FGColumnVector3& vWhlContactVec)
|
|||
|
||||
LMultiplier[ftRoll].Min = -LMultiplier[ftRoll].Max;
|
||||
LMultiplier[ftSide].Min = -LMultiplier[ftSide].Max;
|
||||
|
||||
// The Lagrange multiplier value obtained from the previous iteration is kept
|
||||
// This is supposed to accelerate the convergence of the projected Gauss-Seidel
|
||||
// algorithm. The code just below is to make sure that the initial value
|
||||
// is consistent with the current friction coefficient and normal reaction.
|
||||
LMultiplier[ftRoll].value = Constrain(LMultiplier[ftRoll].Min, LMultiplier[ftRoll].value, LMultiplier[ftRoll].Max);
|
||||
LMultiplier[ftSide].value = Constrain(LMultiplier[ftSide].Min, LMultiplier[ftSide].value, LMultiplier[ftSide].Max);
|
||||
|
||||
GroundReactions->RegisterLagrangeMultiplier(&LMultiplier[ftRoll]);
|
||||
GroundReactions->RegisterLagrangeMultiplier(&LMultiplier[ftSide]);
|
||||
}
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// This function is used by the MultiplierIterator class to enumerate the
|
||||
// Lagrange multipliers of a landing gear. This allows to encapsulate the storage
|
||||
// of the multipliers in FGLGear without exposing it. From an outside point of
|
||||
// view, each FGLGear instance has a number of Lagrange multipliers which can be
|
||||
// accessed through this routine without knowing the exact constraint which they
|
||||
// model.
|
||||
|
||||
FGPropagate::LagrangeMultiplier* FGLGear::GetMultiplierEntry(int entry)
|
||||
{
|
||||
switch(entry) {
|
||||
case 0:
|
||||
if (StaticFriction)
|
||||
return &LMultiplier[ftRoll];
|
||||
else
|
||||
return &LMultiplier[ftDynamic];
|
||||
case 1:
|
||||
if (StaticFriction)
|
||||
return &LMultiplier[ftSide];
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// This routine is called after the Lagrange multiplier has been computed. The
|
||||
// friction forces of the landing gear are then updated accordingly.
|
||||
FGColumnVector3& FGLGear::UpdateForces(void)
|
||||
// This routine is called after the Lagrange multiplier has been computed in
|
||||
// the FGAccelerations class. The friction forces of the landing gear are then
|
||||
// updated accordingly.
|
||||
void FGLGear::UpdateForces(void)
|
||||
{
|
||||
if (StaticFriction) {
|
||||
vFn(eY) = LMultiplier[ftRoll].value;
|
||||
|
@ -778,9 +774,6 @@ FGColumnVector3& FGLGear::UpdateForces(void)
|
|||
}
|
||||
else
|
||||
vFn += LMultiplier[ftDynamic].value * (Transform ().Transposed() * LMultiplier[ftDynamic].ForceJacobian);
|
||||
|
||||
// Return the updated force in the body frame
|
||||
return FGForce::GetBodyForces();
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -789,41 +782,52 @@ void FGLGear::bind(void)
|
|||
{
|
||||
string property_name;
|
||||
string base_property_name;
|
||||
base_property_name = CreateIndexedPropertyName("gear/unit", GearNumber);
|
||||
|
||||
switch(eContactType) {
|
||||
case ctBOGEY:
|
||||
base_property_name = CreateIndexedPropertyName("gear/unit", GearNumber);
|
||||
break;
|
||||
case ctSTRUCTURE:
|
||||
base_property_name = CreateIndexedPropertyName("contact/unit", GearNumber);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
property_name = base_property_name + "/WOW";
|
||||
PropertyManager->Tie( property_name.c_str(), &WOW );
|
||||
property_name = base_property_name + "/z-position";
|
||||
PropertyManager->Tie( property_name.c_str(), (FGForce*)this,
|
||||
&FGForce::GetLocationZ, &FGForce::SetLocationZ);
|
||||
property_name = base_property_name + "/compression-ft";
|
||||
PropertyManager->Tie( property_name.c_str(), &compressLength );
|
||||
property_name = base_property_name + "/static_friction_coeff";
|
||||
PropertyManager->Tie( property_name.c_str(), &staticFCoeff );
|
||||
property_name = base_property_name + "/dynamic_friction_coeff";
|
||||
PropertyManager->Tie( property_name.c_str(), &dynamicFCoeff );
|
||||
|
||||
if (eContactType == ctBOGEY) {
|
||||
property_name = base_property_name + "/slip-angle-deg";
|
||||
fdmex->GetPropertyManager()->Tie( property_name.c_str(), &WheelSlip );
|
||||
property_name = base_property_name + "/WOW";
|
||||
fdmex->GetPropertyManager()->Tie( property_name.c_str(), &WOW );
|
||||
PropertyManager->Tie( property_name.c_str(), &WheelSlip );
|
||||
property_name = base_property_name + "/wheel-speed-fps";
|
||||
fdmex->GetPropertyManager()->Tie( property_name.c_str(), (FGLGear*)this,
|
||||
PropertyManager->Tie( property_name.c_str(), (FGLGear*)this,
|
||||
&FGLGear::GetWheelRollVel);
|
||||
property_name = base_property_name + "/z-position";
|
||||
fdmex->GetPropertyManager()->Tie( property_name.c_str(), (FGForce*)this,
|
||||
&FGForce::GetLocationZ, &FGForce::SetLocationZ);
|
||||
property_name = base_property_name + "/compression-ft";
|
||||
fdmex->GetPropertyManager()->Tie( property_name.c_str(), &compressLength );
|
||||
property_name = base_property_name + "/side_friction_coeff";
|
||||
fdmex->GetPropertyManager()->Tie( property_name.c_str(), &FCoeff );
|
||||
|
||||
property_name = base_property_name + "/static_friction_coeff";
|
||||
fdmex->GetPropertyManager()->Tie( property_name.c_str(), &staticFCoeff );
|
||||
PropertyManager->Tie( property_name.c_str(), &FCoeff );
|
||||
property_name = base_property_name + "/rolling_friction_coeff";
|
||||
fdmex->GetPropertyManager()->Tie( property_name.c_str(), &rollingFCoeff );
|
||||
property_name = base_property_name + "/dynamic_friction_coeff";
|
||||
fdmex->GetPropertyManager()->Tie( property_name.c_str(), &dynamicFCoeff );
|
||||
PropertyManager->Tie( property_name.c_str(), &rollingFCoeff );
|
||||
|
||||
if (eSteerType == stCaster) {
|
||||
property_name = base_property_name + "/steering-angle-deg";
|
||||
fdmex->GetPropertyManager()->Tie( property_name.c_str(), this, &FGLGear::GetSteerAngleDeg );
|
||||
PropertyManager->Tie( property_name.c_str(), this, &FGLGear::GetSteerAngleDeg );
|
||||
property_name = base_property_name + "/castered";
|
||||
fdmex->GetPropertyManager()->Tie( property_name.c_str(), &Castered);
|
||||
PropertyManager->Tie( property_name.c_str(), &Castered);
|
||||
}
|
||||
}
|
||||
|
||||
if( isRetractable ) {
|
||||
property_name = base_property_name + "/pos-norm";
|
||||
fdmex->GetPropertyManager()->Tie( property_name.c_str(), &GearPos );
|
||||
PropertyManager->Tie( property_name.c_str(), &GearPos );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -856,11 +860,11 @@ void FGLGear::Report(ReportType repType)
|
|||
<< " ft, " << TakeoffDistanceTraveled*0.3048 << " meters" << endl;
|
||||
cout << " Distance traveled (over 50'): " << TakeoffDistanceTraveled50ft
|
||||
<< " ft, " << TakeoffDistanceTraveled50ft*0.3048 << " meters" << endl;
|
||||
cout << " [Altitude (ASL): " << Propagate->GetAltitudeASL() << " ft. / "
|
||||
<< Propagate->GetAltitudeASLmeters() << " m | Temperature: "
|
||||
<< fdmex->GetAtmosphere()->GetTemperature() - 459.67 << " F / "
|
||||
<< RankineToCelsius(fdmex->GetAtmosphere()->GetTemperature()) << " C]" << endl;
|
||||
cout << " [Velocity (KCAS): " << Auxiliary->GetVcalibratedKTS() << "]" << endl;
|
||||
cout << " [Altitude (ASL): " << in.DistanceASL << " ft. / "
|
||||
<< in.DistanceASL*FGJSBBase::fttom << " m | Temperature: "
|
||||
<< in.Temperature - 459.67 << " F / "
|
||||
<< RankineToCelsius(in.Temperature) << " C]" << endl;
|
||||
cout << " [Velocity (KCAS): " << in.VcalibratedKts << "]" << endl;
|
||||
TakeoffReported = true;
|
||||
break;
|
||||
case erNone:
|
||||
|
|
|
@ -38,16 +38,18 @@ SENTRY
|
|||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include "models/propulsion/FGForce.h"
|
||||
#include "models/FGPropagate.h"
|
||||
#include "math/FGColumnVector3.h"
|
||||
#include <string>
|
||||
|
||||
#include "models/propulsion/FGForce.h"
|
||||
#include "math/FGColumnVector3.h"
|
||||
#include "math/FGMatrix33.h"
|
||||
#include "math/LagrangeMultiplier.h"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_LGEAR "$Id: FGLGear.h,v 1.41 2010/09/22 11:33:40 jberndt Exp $"
|
||||
#define ID_LGEAR "$Id: FGLGear.h,v 1.47 2011/08/30 21:05:56 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -55,13 +57,9 @@ FORWARD DECLARATIONS
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
class FGAircraft;
|
||||
class FGPropagate;
|
||||
class FGFCS;
|
||||
class FGMassBalance;
|
||||
class FGAuxiliary;
|
||||
class FGTable;
|
||||
class Element;
|
||||
class FGPropertyManager;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS DOCUMENTATION
|
||||
|
@ -180,7 +178,7 @@ CLASS DOCUMENTATION
|
|||
</contact>
|
||||
@endcode
|
||||
@author Jon S. Berndt
|
||||
@version $Id: FGLGear.h,v 1.41 2010/09/22 11:33:40 jberndt Exp $
|
||||
@version $Id: FGLGear.h,v 1.47 2011/08/30 21:05:56 bcoconni Exp $
|
||||
@see Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
|
||||
NASA-Ames", NASA CR-2497, January 1975
|
||||
@see Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
|
||||
|
@ -196,8 +194,30 @@ CLASS DECLARATION
|
|||
class FGLGear : public FGForce
|
||||
{
|
||||
public:
|
||||
struct Inputs {
|
||||
double Vground;
|
||||
double VcalibratedKts;
|
||||
double Temperature;
|
||||
double DistanceAGL;
|
||||
double DistanceASL;
|
||||
double TotalDeltaT;
|
||||
bool TakeoffThrottle;
|
||||
bool WOW;
|
||||
FGMatrix33 Tb2l;
|
||||
FGMatrix33 Tec2l;
|
||||
FGMatrix33 Tec2b;
|
||||
FGColumnVector3 PQR;
|
||||
FGColumnVector3 UVW;
|
||||
FGLocation Location;
|
||||
std::vector <double> SteerPosDeg;
|
||||
std::vector <double> BrakePos;
|
||||
std::vector <FGColumnVector3> vWhlBodyVec;
|
||||
double FCSGearPos;
|
||||
double EmptyWeight;
|
||||
};
|
||||
|
||||
/// Brake grouping enumerators
|
||||
enum BrakeGroup {bgNone=0, bgLeft, bgRight, bgCenter, bgNose, bgTail };
|
||||
enum BrakeGroup {bgNone=0, bgLeft, bgRight, bgCenter, bgNose, bgTail, bgNumBrakeGroups };
|
||||
/// Steering group membership enumerators
|
||||
enum SteerType {stSteer, stFixed, stCaster};
|
||||
/// Contact point type
|
||||
|
@ -213,7 +233,7 @@ public:
|
|||
@param Executive a pointer to the parent executive object
|
||||
@param number integer identifier for this instance of FGLGear
|
||||
*/
|
||||
FGLGear(Element* el, FGFDMExec* Executive, int number);
|
||||
FGLGear(Element* el, FGFDMExec* Executive, int number, const struct Inputs& input);
|
||||
/// Destructor
|
||||
~FGLGear();
|
||||
|
||||
|
@ -221,8 +241,8 @@ public:
|
|||
FGColumnVector3& GetBodyForces(void);
|
||||
|
||||
/// Gets the location of the gear in Body axes
|
||||
FGColumnVector3& GetBodyLocation(void) { return vWhlBodyVec; }
|
||||
double GetBodyLocation(int idx) const { return vWhlBodyVec(idx); }
|
||||
FGColumnVector3 GetBodyLocation(void) const { return in.vWhlBodyVec[GearNumber]; }
|
||||
double GetBodyLocation(int idx) const { return in.vWhlBodyVec[GearNumber](idx); }
|
||||
|
||||
FGColumnVector3& GetLocalGear(void) { return vLocalGear; }
|
||||
double GetLocalGear(int idx) const { return vLocalGear(idx); }
|
||||
|
@ -268,9 +288,11 @@ public:
|
|||
bool GetGearUnitUp(void) const { return GearUp; }
|
||||
bool GetGearUnitDown(void) const { return GearDown; }
|
||||
double GetWheelRollForce(void) {
|
||||
UpdateForces();
|
||||
FGColumnVector3 vForce = mTGear.Transposed() * FGForce::GetBodyForces();
|
||||
return vForce(eX)*cos(SteerAngle) + vForce(eY)*sin(SteerAngle); }
|
||||
double GetWheelSideForce(void) {
|
||||
UpdateForces();
|
||||
FGColumnVector3 vForce = mTGear.Transposed() * FGForce::GetBodyForces();
|
||||
return vForce(eY)*cos(SteerAngle) - vForce(eX)*sin(SteerAngle); }
|
||||
double GetWheelRollVel(void) const { return vWhlVelVec(eX)*cos(SteerAngle)
|
||||
|
@ -282,9 +304,8 @@ public:
|
|||
bool IsBogey(void) const { return (eContactType == ctBOGEY);}
|
||||
double GetGearUnitPos(void);
|
||||
double GetSteerAngleDeg(void) const { return radtodeg*SteerAngle; }
|
||||
FGPropagate::LagrangeMultiplier* GetMultiplierEntry(int entry);
|
||||
void SetLagrangeMultiplier(double lambda, int entry);
|
||||
FGColumnVector3& UpdateForces(void);
|
||||
|
||||
const struct Inputs& in;
|
||||
|
||||
void bind(void);
|
||||
|
||||
|
@ -293,13 +314,11 @@ private:
|
|||
static const FGMatrix33 Tb2s;
|
||||
FGMatrix33 mTGear;
|
||||
FGColumnVector3 vGearOrient;
|
||||
FGColumnVector3 vWhlBodyVec;
|
||||
FGColumnVector3 vLocalGear;
|
||||
FGColumnVector3 vWhlVelVec, vLocalWhlVel; // Velocity of this wheel
|
||||
FGColumnVector3 normal, cvel, vGroundNormal;
|
||||
FGColumnVector3 normal, vGroundNormal;
|
||||
FGLocation contact, gearLoc;
|
||||
FGTable *ForceY_Table;
|
||||
double dT;
|
||||
double SteerAngle;
|
||||
double kSpring;
|
||||
double bDamp;
|
||||
|
@ -348,13 +367,10 @@ private:
|
|||
DampType eDampTypeRebound;
|
||||
double maxSteerAngle;
|
||||
|
||||
FGPropagate::LagrangeMultiplier LMultiplier[3];
|
||||
LagrangeMultiplier LMultiplier[3];
|
||||
|
||||
FGAuxiliary* Auxiliary;
|
||||
FGPropagate* Propagate;
|
||||
FGFCS* FCS;
|
||||
FGMassBalance* MassBalance;
|
||||
FGGroundReactions* GroundReactions;
|
||||
FGPropertyManager* PropertyManager;
|
||||
|
||||
void ComputeRetractionState(void);
|
||||
void ComputeBrakeForceCoefficient(void);
|
||||
|
@ -364,6 +380,7 @@ private:
|
|||
void ComputeVerticalStrutForce(void);
|
||||
void ComputeGroundCoordSys(void);
|
||||
void ComputeJacobian(const FGColumnVector3& vWhlContactVec);
|
||||
void UpdateForces(void);
|
||||
void CrashDetect(void);
|
||||
void InitializeReporting(void);
|
||||
void ResetReporting(void);
|
||||
|
|
|
@ -38,20 +38,18 @@ HISTORY
|
|||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include "FGMassBalance.h"
|
||||
#include "FGPropulsion.h"
|
||||
#include "propulsion/FGTank.h"
|
||||
#include "FGBuoyantForces.h"
|
||||
#include "input_output/FGPropertyManager.h"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <cstdlib>
|
||||
#include "FGMassBalance.h"
|
||||
#include "FGFDMExec.h"
|
||||
#include "input_output/FGPropertyManager.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGMassBalance.cpp,v 1.35 2011/05/20 03:18:36 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGMassBalance.cpp,v 1.37 2011/07/12 01:52:49 jberndt Exp $";
|
||||
static const char *IdHdr = ID_MASSBALANCE;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -149,8 +147,8 @@ bool FGMassBalance::Load(Element* el)
|
|||
if (FDMExec->GetChildFDM(fdm)->mated) ChildFDMWeight += FDMExec->GetChildFDM(fdm)->exec->GetMassBalance()->GetWeight();
|
||||
}
|
||||
|
||||
Weight = EmptyWeight + FDMExec->GetPropulsion()->GetTanksWeight() + GetTotalPointMassWeight()
|
||||
+ FDMExec->GetBuoyantForces()->GetGasMass()*slugtolb + ChildFDMWeight;
|
||||
Weight = EmptyWeight + in.TanksWeight + GetTotalPointMassWeight()
|
||||
+ in.GasMass*slugtolb + ChildFDMWeight;
|
||||
|
||||
Mass = lbtoslug*Weight;
|
||||
|
||||
|
@ -177,16 +175,17 @@ bool FGMassBalance::Run(bool Holding)
|
|||
if (FDMExec->GetChildFDM(fdm)->mated) ChildFDMWeight += FDMExec->GetChildFDM(fdm)->exec->GetMassBalance()->GetWeight();
|
||||
}
|
||||
|
||||
Weight = EmptyWeight + FDMExec->GetPropulsion()->GetTanksWeight() + GetTotalPointMassWeight()
|
||||
+ FDMExec->GetBuoyantForces()->GetGasMass()*slugtolb + ChildFDMWeight;
|
||||
Weight = EmptyWeight + in.TanksWeight + GetTotalPointMassWeight()
|
||||
+ in.GasMass*slugtolb + ChildFDMWeight;
|
||||
|
||||
Mass = lbtoslug*Weight;
|
||||
|
||||
// Calculate new CG
|
||||
|
||||
vXYZcg = (FDMExec->GetPropulsion()->GetTanksMoment() + EmptyWeight*vbaseXYZcg
|
||||
vXYZcg = (EmptyWeight*vbaseXYZcg
|
||||
+ GetPointMassMoment()
|
||||
+ FDMExec->GetBuoyantForces()->GetGasMassMoment()) / Weight;
|
||||
+ in.TanksMoment
|
||||
+ in.GasMoment) / Weight;
|
||||
|
||||
// Track frame-by-frame delta CG, and move the EOM-tracked location
|
||||
// by this amount.
|
||||
|
@ -204,8 +203,8 @@ bool FGMassBalance::Run(bool Holding)
|
|||
mJ += GetPointmassInertia( lbtoslug * EmptyWeight, vbaseXYZcg );
|
||||
// Then add the contributions from the additional pointmasses.
|
||||
mJ += CalculatePMInertias();
|
||||
mJ += FDMExec->GetPropulsion()->CalculateTankInertias();
|
||||
mJ += FDMExec->GetBuoyantForces()->GetGasMassInertia();
|
||||
mJ += in.TankInertia;
|
||||
mJ += in.GasInertia;
|
||||
|
||||
Ixx = mJ(1,1);
|
||||
Iyy = mJ(2,2);
|
||||
|
@ -430,24 +429,7 @@ void FGMassBalance::GetMassPropertiesReport(void) const
|
|||
<< setw(12) << pm->GetPointMassMoI(3,3) << endl;
|
||||
}
|
||||
|
||||
for (unsigned int i=0;i<FDMExec->GetPropulsion()->GetNumTanks() ;i++) {
|
||||
FGTank* tank = FDMExec->GetPropulsion()->GetTank(i);
|
||||
string tankname="";
|
||||
if (tank->GetType() == FGTank::ttFUEL && tank->GetGrainType() != FGTank::gtUNKNOWN) {
|
||||
tankname = "Solid Fuel";
|
||||
} else if (tank->GetType() == FGTank::ttFUEL) {
|
||||
tankname = "Fuel";
|
||||
} else if (tank->GetType() == FGTank::ttOXIDIZER) {
|
||||
tankname = "Oxidizer";
|
||||
} else {
|
||||
tankname = "(Unknown tank type)";
|
||||
}
|
||||
cout << highint << left << setw(4) << i << setw(30) << tankname << normint
|
||||
<< right << setw(10) << tank->GetContents() << setw(8) << tank->GetXYZ(eX)
|
||||
<< setw(8) << tank->GetXYZ(eY) << setw(8) << tank->GetXYZ(eZ)
|
||||
<< setw(12) << "*" << setw(12) << "*"
|
||||
<< setw(12) << "*" << endl;
|
||||
}
|
||||
cout << FDMExec->GetPropulsionTankReport();
|
||||
|
||||
cout << underon << setw(104) << " " << underoff << endl;
|
||||
cout << highint << left << setw(30) << " Total: " << right << setw(14) << Weight
|
||||
|
|
|
@ -49,7 +49,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_MASSBALANCE "$Id: FGMassBalance.h,v 1.23 2011/05/20 03:18:36 jberndt Exp $"
|
||||
#define ID_MASSBALANCE "$Id: FGMassBalance.h,v 1.25 2011/07/28 12:48:19 jberndt Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONSS
|
||||
|
@ -138,13 +138,13 @@ public:
|
|||
slugs at the given vector r in the structural frame. The units
|
||||
should be for the mass in slug and the vector in the structural
|
||||
frame as usual in inches.
|
||||
@param slugs the mass of this single pointmass given in slugs
|
||||
@param mass_sl the mass of this single pointmass given in slugs
|
||||
@param r the location of this single pointmass in the structural frame
|
||||
*/
|
||||
FGMatrix33 GetPointmassInertia(double slugs, const FGColumnVector3& r) const
|
||||
FGMatrix33 GetPointmassInertia(double mass_sl, const FGColumnVector3& r) const
|
||||
{
|
||||
FGColumnVector3 v = StructuralToBody( r );
|
||||
FGColumnVector3 sv = slugs*v;
|
||||
FGColumnVector3 sv = mass_sl*v;
|
||||
double xx = sv(1)*v(1);
|
||||
double yy = sv(2)*v(2);
|
||||
double zz = sv(3)*v(3);
|
||||
|
@ -179,6 +179,15 @@ public:
|
|||
void SetAircraftBaseInertias(FGMatrix33 BaseJ) {baseJ = BaseJ;}
|
||||
void GetMassPropertiesReport(void) const;
|
||||
|
||||
struct Inputs {
|
||||
double GasMass;
|
||||
double TanksWeight;
|
||||
FGColumnVector3 GasMoment;
|
||||
FGMatrix33 GasInertia;
|
||||
FGColumnVector3 TanksMoment;
|
||||
FGMatrix33 TankInertia;
|
||||
} in;
|
||||
|
||||
private:
|
||||
double Weight;
|
||||
double EmptyWeight;
|
||||
|
|
|
@ -48,7 +48,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_MODEL "$Id: FGModel.h,v 1.19 2011/05/20 03:18:36 jberndt Exp $"
|
||||
#define ID_MODEL "$Id: FGModel.h,v 1.20 2011/06/21 04:41:54 jberndt Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -79,7 +79,7 @@ public:
|
|||
/// Constructor
|
||||
FGModel(FGFDMExec*);
|
||||
/// Destructor
|
||||
~FGModel();
|
||||
virtual ~FGModel();
|
||||
|
||||
std::string Name;
|
||||
|
||||
|
|
|
@ -39,9 +39,16 @@ HISTORY
|
|||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "FGOutput.h"
|
||||
#include "FGFDMExec.h"
|
||||
#include "FGAtmosphere.h"
|
||||
#include "FGAccelerations.h"
|
||||
#include "atmosphere/FGWinds.h"
|
||||
#include "FGFCS.h"
|
||||
#include "FGAerodynamics.h"
|
||||
#include "FGGroundReactions.h"
|
||||
|
@ -56,10 +63,6 @@ INCLUDES
|
|||
#include "models/propulsion/FGEngine.h"
|
||||
#include "models/propulsion/FGTank.h"
|
||||
#include "models/propulsion/FGPiston.h"
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
|
||||
#if defined(WIN32) && !defined(__CYGWIN__)
|
||||
# include <windows.h>
|
||||
|
@ -74,7 +77,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGOutput.cpp,v 1.55 2011/05/20 03:18:36 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGOutput.cpp,v 1.59 2011/08/14 20:15:56 jberndt Exp $";
|
||||
static const char *IdHdr = ID_OUTPUT;
|
||||
|
||||
// (stolen from FGFS native_fdm.cxx)
|
||||
|
@ -246,9 +249,11 @@ void FGOutput::DelimitedOutput(const string& fname)
|
|||
const FGAuxiliary* Auxiliary = FDMExec->GetAuxiliary();
|
||||
const FGAircraft* Aircraft = FDMExec->GetAircraft();
|
||||
const FGAtmosphere* Atmosphere = FDMExec->GetAtmosphere();
|
||||
const FGWinds* Winds = FDMExec->GetWinds();
|
||||
const FGPropulsion* Propulsion = FDMExec->GetPropulsion();
|
||||
const FGMassBalance* MassBalance = FDMExec->GetMassBalance();
|
||||
const FGPropagate* Propagate = FDMExec->GetPropagate();
|
||||
const FGAccelerations* Accelerations = FDMExec->GetAccelerations();
|
||||
const FGFCS* FCS = FDMExec->GetFCS();
|
||||
const FGInertial* Inertial = FDMExec->GetInertial();
|
||||
const FGGroundReactions* GroundReactions = FDMExec->GetGroundReactions();
|
||||
|
@ -409,7 +414,7 @@ void FGOutput::DelimitedOutput(const string& fname)
|
|||
if (SubSystems & ssRates) {
|
||||
outstream << delimeter;
|
||||
outstream << (radtodeg*Propagate->GetPQR()).Dump(delimeter) << delimeter;
|
||||
outstream << (radtodeg*Propagate->GetPQRdot()).Dump(delimeter) << delimeter;
|
||||
outstream << (radtodeg*Accelerations->GetPQRdot()).Dump(delimeter) << delimeter;
|
||||
outstream << (radtodeg*Propagate->GetPQRi()).Dump(delimeter);
|
||||
}
|
||||
if (SubSystems & ssVelocities) {
|
||||
|
@ -453,9 +458,9 @@ void FGOutput::DelimitedOutput(const string& fname)
|
|||
outstream << Atmosphere->GetTemperature() << delimeter;
|
||||
outstream << Atmosphere->GetPressureSL() << delimeter;
|
||||
outstream << Atmosphere->GetPressure() << delimeter;
|
||||
outstream << Atmosphere->GetTurbMagnitude() << delimeter;
|
||||
outstream << Atmosphere->GetTurbDirection().Dump(delimeter) << delimeter;
|
||||
outstream << Atmosphere->GetTotalWindNED().Dump(delimeter);
|
||||
outstream << Winds->GetTurbMagnitude() << delimeter;
|
||||
outstream << Winds->GetTurbDirection().Dump(delimeter) << delimeter;
|
||||
outstream << Winds->GetTotalWindNED().Dump(delimeter);
|
||||
}
|
||||
if (SubSystems & ssMassProps) {
|
||||
outstream << delimeter;
|
||||
|
@ -477,7 +482,7 @@ void FGOutput::DelimitedOutput(const string& fname)
|
|||
outstream << ((FGColumnVector3)Propagate->GetInertialPosition()).Dump(delimeter) << delimeter;
|
||||
outstream << ((FGColumnVector3)Propagate->GetLocation()).Dump(delimeter) << delimeter;
|
||||
outstream.precision(14);
|
||||
outstream << Inertial->GetEarthPositionAngleDeg() << delimeter;
|
||||
outstream << Propagate->GetEarthPositionAngleDeg() << delimeter;
|
||||
outstream << Propagate->GetDistanceAGL() << delimeter;
|
||||
outstream << Propagate->GetTerrainElevation();
|
||||
outstream.precision(10);
|
||||
|
@ -733,8 +738,10 @@ void FGOutput::SocketOutput(void)
|
|||
const FGPropulsion* Propulsion = FDMExec->GetPropulsion();
|
||||
const FGMassBalance* MassBalance = FDMExec->GetMassBalance();
|
||||
const FGPropagate* Propagate = FDMExec->GetPropagate();
|
||||
const FGAccelerations* Accelerations = FDMExec->GetAccelerations();
|
||||
const FGFCS* FCS = FDMExec->GetFCS();
|
||||
const FGAtmosphere* Atmosphere = FDMExec->GetAtmosphere();
|
||||
const FGWinds* Winds = FDMExec->GetWinds();
|
||||
const FGAircraft* Aircraft = FDMExec->GetAircraft();
|
||||
const FGGroundReactions* GroundReactions = FDMExec->GetGroundReactions();
|
||||
|
||||
|
@ -875,9 +882,9 @@ void FGOutput::SocketOutput(void)
|
|||
socket->Append(radtodeg*Propagate->GetPQR(eP));
|
||||
socket->Append(radtodeg*Propagate->GetPQR(eQ));
|
||||
socket->Append(radtodeg*Propagate->GetPQR(eR));
|
||||
socket->Append(radtodeg*Propagate->GetPQRdot(eP));
|
||||
socket->Append(radtodeg*Propagate->GetPQRdot(eQ));
|
||||
socket->Append(radtodeg*Propagate->GetPQRdot(eR));
|
||||
socket->Append(radtodeg*Accelerations->GetPQRdot(eP));
|
||||
socket->Append(radtodeg*Accelerations->GetPQRdot(eQ));
|
||||
socket->Append(radtodeg*Accelerations->GetPQRdot(eR));
|
||||
}
|
||||
if (SubSystems & ssVelocities) {
|
||||
socket->Append(Auxiliary->Getqbar());
|
||||
|
@ -910,9 +917,9 @@ void FGOutput::SocketOutput(void)
|
|||
socket->Append(Atmosphere->GetDensity());
|
||||
socket->Append(Atmosphere->GetPressureSL());
|
||||
socket->Append(Atmosphere->GetPressure());
|
||||
socket->Append(Atmosphere->GetTurbMagnitude());
|
||||
socket->Append(Atmosphere->GetTurbDirection().Dump(","));
|
||||
socket->Append(Atmosphere->GetTotalWindNED().Dump(","));
|
||||
socket->Append(Winds->GetTurbMagnitude());
|
||||
socket->Append(Winds->GetTurbDirection().Dump(","));
|
||||
socket->Append(Winds->GetTotalWindNED().Dump(","));
|
||||
}
|
||||
if (SubSystems & ssMassProps) {
|
||||
socket->Append(MassBalance->GetJ()(1,1));
|
||||
|
|
|
@ -62,16 +62,13 @@ INCLUDES
|
|||
#include "FGPropagate.h"
|
||||
#include "FGGroundReactions.h"
|
||||
#include "FGFDMExec.h"
|
||||
#include "FGAircraft.h"
|
||||
#include "FGMassBalance.h"
|
||||
#include "FGInertial.h"
|
||||
#include "input_output/FGPropertyManager.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGPropagate.cpp,v 1.88 2011/05/20 03:18:36 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGPropagate.cpp,v 1.95 2011/08/21 16:11:25 bcoconni Exp $";
|
||||
static const char *IdHdr = ID_PROPAGATE;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -86,11 +83,7 @@ FGPropagate::FGPropagate(FGFDMExec* fdmex)
|
|||
{
|
||||
Debug(0);
|
||||
Name = "FGPropagate";
|
||||
gravType = gtWGS84;
|
||||
|
||||
vPQRidot.InitMatrix();
|
||||
vQtrndot = FGQuaternion(0,0,0);
|
||||
vUVWidot.InitMatrix();
|
||||
vInertialVelocity.InitMatrix();
|
||||
|
||||
/// These define the indices use to select the various integrators.
|
||||
|
@ -122,15 +115,12 @@ FGPropagate::~FGPropagate(void)
|
|||
bool FGPropagate::InitModel(void)
|
||||
{
|
||||
// For initialization ONLY:
|
||||
SeaLevelRadius = LocalTerrainRadius = FDMExec->GetInertial()->GetRefRadius();
|
||||
SeaLevelRadius = LocalTerrainRadius = in.RefRadius;
|
||||
FDMExec->GetGroundCallback()->SetTerrainGeoCentRadius(LocalTerrainRadius);
|
||||
|
||||
VState.vLocation.SetRadius( LocalTerrainRadius + 4.0 );
|
||||
VState.vLocation.SetEllipse(FDMExec->GetInertial()->GetSemimajor(), FDMExec->GetInertial()->GetSemiminor());
|
||||
vOmegaEarth = FGColumnVector3( 0.0, 0.0, FDMExec->GetInertial()->omega() ); // Earth rotation vector
|
||||
VState.vLocation.SetEllipse(in.SemiMajor, in.SemiMinor);
|
||||
|
||||
vPQRidot.InitMatrix();
|
||||
vQtrndot = FGQuaternion(0,0,0);
|
||||
vUVWidot.InitMatrix();
|
||||
vInertialVelocity.InitMatrix();
|
||||
|
||||
VState.dqPQRidot.resize(4, FGColumnVector3(0.0,0.0,0.0));
|
||||
|
@ -150,7 +140,6 @@ bool FGPropagate::InitModel(void)
|
|||
|
||||
void FGPropagate::SetInitialState(const FGInitialCondition *FGIC)
|
||||
{
|
||||
SetSeaLevelRadius(FGIC->GetSeaLevelRadiusFtIC());
|
||||
SetTerrainElevation(FGIC->GetTerrainElevationFtIC());
|
||||
|
||||
// Initialize the State Vector elements and the transformation matrices
|
||||
|
@ -158,9 +147,9 @@ void FGPropagate::SetInitialState(const FGInitialCondition *FGIC)
|
|||
// Set the position lat/lon/radius
|
||||
VState.vLocation.SetPosition( FGIC->GetLongitudeRadIC(),
|
||||
FGIC->GetLatitudeRadIC(),
|
||||
FGIC->GetAltitudeASLFtIC() + FGIC->GetSeaLevelRadiusFtIC() );
|
||||
FGIC->GetAltitudeASLFtIC() + SeaLevelRadius);
|
||||
|
||||
VState.vLocation.SetEarthPositionAngle(FDMExec->GetInertial()->GetEarthPositionAngle());
|
||||
VState.vLocation.SetEarthPositionAngle(0.0);
|
||||
|
||||
Ti2ec = VState.vLocation.GetTi2ec(); // ECI to ECEF transform
|
||||
Tec2i = Ti2ec.Transposed(); // ECEF to ECI frame transform
|
||||
|
@ -198,10 +187,22 @@ void FGPropagate::SetInitialState(const FGInitialCondition *FGIC)
|
|||
FGIC->GetQRadpsIC(),
|
||||
FGIC->GetRRadpsIC() );
|
||||
|
||||
VState.vPQRi = VState.vPQR + Ti2b * vOmegaEarth;
|
||||
VState.vPQRi = VState.vPQR + Ti2b * in.vOmegaPlanet;
|
||||
|
||||
// Make an initial run and set past values
|
||||
InitializeDerivatives();
|
||||
CalculateInertialVelocity(); // Translational position derivative
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// Initialize the past value deques
|
||||
|
||||
void FGPropagate::InitializeDerivatives()
|
||||
{
|
||||
for (int i=0; i<4; i++) {
|
||||
VState.dqPQRidot[i] = in.vPQRidot;
|
||||
VState.dqUVWidot[i] = in.vUVWidot;
|
||||
VState.dqInertialVelocity[i] = VState.vInertialVelocity;
|
||||
VState.dqQtrndot[i] = in.vQtrndot;
|
||||
}
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -229,28 +230,22 @@ bool FGPropagate::Run(bool Holding)
|
|||
if (FGModel::Run(Holding)) return true; // Fast return if we have nothing to do ...
|
||||
if (Holding) return false;
|
||||
|
||||
double dt = FDMExec->GetDeltaT()*rate; // The 'stepsize'
|
||||
double dt = in.DeltaT * rate; // The 'stepsize'
|
||||
|
||||
RunPreFunctions();
|
||||
|
||||
// Calculate state derivatives
|
||||
CalculatePQRdot(); // Angular rate derivative
|
||||
CalculateUVWdot(); // Translational rate derivative
|
||||
ResolveFrictionForces(dt); // Update rate derivatives with friction forces
|
||||
CalculateQuatdot(); // Angular orientation derivative
|
||||
|
||||
// Propagate rotational / translational velocity, angular /translational position, respectively.
|
||||
|
||||
Integrate(VState.vPQRi, vPQRidot, VState.dqPQRidot, dt, integrator_rotational_rate);
|
||||
Integrate(VState.qAttitudeECI, vQtrndot, VState.dqQtrndot, dt, integrator_rotational_position);
|
||||
Integrate(VState.vPQRi, in.vPQRidot, VState.dqPQRidot, dt, integrator_rotational_rate);
|
||||
Integrate(VState.qAttitudeECI, in.vQtrndot, VState.dqQtrndot, dt, integrator_rotational_position);
|
||||
Integrate(VState.vInertialPosition, VState.vInertialVelocity, VState.dqInertialVelocity, dt, integrator_translational_position);
|
||||
Integrate(VState.vInertialVelocity, vUVWidot, VState.dqUVWidot, dt, integrator_translational_rate);
|
||||
Integrate(VState.vInertialVelocity, in.vUVWidot, VState.dqUVWidot, dt, integrator_translational_rate);
|
||||
|
||||
// CAUTION : the order of the operations below is very important to get transformation
|
||||
// matrices that are consistent with the new state of the vehicle
|
||||
|
||||
// 1. Update the Earth position angle (EPA)
|
||||
VState.vLocation.SetEarthPositionAngle(FDMExec->GetInertial()->GetEarthPositionAngle());
|
||||
VState.vLocation.IncrementEarthPositionAngle(in.vOmegaPlanet(eZ)*(in.DeltaT*rate));
|
||||
|
||||
// 2. Update the Ti2ec and Tec2i transforms from the updated EPA
|
||||
Ti2ec = VState.vLocation.GetTi2ec(); // ECI to ECEF transform
|
||||
|
@ -278,7 +273,7 @@ bool FGPropagate::Run(bool Holding)
|
|||
|
||||
VehicleRadius = GetRadius(); // Calculate current aircraft radius from center of planet
|
||||
|
||||
VState.vPQR = VState.vPQRi - Ti2b * vOmegaEarth;
|
||||
VState.vPQR = VState.vPQRi - Ti2b * in.vOmegaPlanet;
|
||||
|
||||
VState.qAttitudeLocal = Tl2b.GetQuaternion();
|
||||
|
||||
|
@ -291,88 +286,6 @@ bool FGPropagate::Run(bool Holding)
|
|||
return false;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// Compute body frame rotational accelerations based on the current body moments
|
||||
//
|
||||
// vPQRdot is the derivative of the absolute angular velocity of the vehicle
|
||||
// (body rate with respect to the inertial frame), expressed in the body frame,
|
||||
// where the derivative is taken in the body frame.
|
||||
// J is the inertia matrix
|
||||
// Jinv is the inverse inertia matrix
|
||||
// vMoments is the moment vector in the body frame
|
||||
// VState.vPQRi is the total inertial angular velocity of the vehicle
|
||||
// expressed in the body frame.
|
||||
// Reference: See Stevens and Lewis, "Aircraft Control and Simulation",
|
||||
// Second edition (2004), eqn 1.5-16e (page 50)
|
||||
|
||||
void FGPropagate::CalculatePQRdot(void)
|
||||
{
|
||||
const FGColumnVector3& vMoments = FDMExec->GetAircraft()->GetMoments(); // current moments
|
||||
const FGMatrix33& J = FDMExec->GetMassBalance()->GetJ(); // inertia matrix
|
||||
const FGMatrix33& Jinv = FDMExec->GetMassBalance()->GetJinv(); // inertia matrix inverse
|
||||
|
||||
// Compute body frame rotational accelerations based on the current body
|
||||
// moments and the total inertial angular velocity expressed in the body
|
||||
// frame.
|
||||
|
||||
vPQRidot = Jinv*(vMoments - VState.vPQRi*(J*VState.vPQRi));
|
||||
vPQRdot = vPQRidot - VState.vPQRi * (Ti2b * vOmegaEarth);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// Compute the quaternion orientation derivative
|
||||
//
|
||||
// vQtrndot is the quaternion derivative.
|
||||
// Reference: See Stevens and Lewis, "Aircraft Control and Simulation",
|
||||
// Second edition (2004), eqn 1.5-16b (page 50)
|
||||
|
||||
void FGPropagate::CalculateQuatdot(void)
|
||||
{
|
||||
// Compute quaternion orientation derivative on current body rates
|
||||
vQtrndot = VState.qAttitudeECI.GetQDot( VState.vPQRi);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// This set of calculations results in the body and inertial frame accelerations
|
||||
// being computed.
|
||||
// Compute body and inertial frames accelerations based on the current body
|
||||
// forces including centripetal and coriolis accelerations for the former.
|
||||
// vOmegaEarth is the Earth angular rate - expressed in the inertial frame -
|
||||
// so it has to be transformed to the body frame. More completely,
|
||||
// vOmegaEarth is the rate of the ECEF frame relative to the Inertial
|
||||
// frame (ECI), expressed in the Inertial frame.
|
||||
// vForces is the total force on the vehicle in the body frame.
|
||||
// VState.vPQR is the vehicle body rate relative to the ECEF frame, expressed
|
||||
// in the body frame.
|
||||
// VState.vUVW is the vehicle velocity relative to the ECEF frame, expressed
|
||||
// in the body frame.
|
||||
// Reference: See Stevens and Lewis, "Aircraft Control and Simulation",
|
||||
// Second edition (2004), eqns 1.5-13 (pg 48) and 1.5-16d (page 50)
|
||||
|
||||
void FGPropagate::CalculateUVWdot(void)
|
||||
{
|
||||
double mass = FDMExec->GetMassBalance()->GetMass(); // mass
|
||||
const FGColumnVector3& vForces = FDMExec->GetAircraft()->GetForces(); // current forces
|
||||
|
||||
vUVWdot = vForces/mass - (VState.vPQR + 2.0*(Ti2b *vOmegaEarth)) * VState.vUVW;
|
||||
|
||||
// Include Centripetal acceleration.
|
||||
vUVWdot -= Ti2b * (vOmegaEarth*(vOmegaEarth*VState.vInertialPosition));
|
||||
|
||||
// Include Gravitation accel
|
||||
switch (gravType) {
|
||||
case gtStandard:
|
||||
vGravAccel = Tl2b * FGColumnVector3( 0.0, 0.0, FDMExec->GetInertial()->GetGAccel(VehicleRadius) );
|
||||
break;
|
||||
case gtWGS84:
|
||||
vGravAccel = Tec2b * FDMExec->GetInertial()->GetGravityJ2(VState.vLocation);
|
||||
break;
|
||||
}
|
||||
|
||||
vUVWdot += vGravAccel;
|
||||
vUVWidot = Tb2i * (vForces/mass + vGravAccel);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// Transform the velocity vector of the body relative to the origin (Earth
|
||||
// center) to be expressed in the inertial frame, and add the vehicle velocity
|
||||
|
@ -382,7 +295,7 @@ void FGPropagate::CalculateUVWdot(void)
|
|||
|
||||
void FGPropagate::CalculateInertialVelocity(void)
|
||||
{
|
||||
VState.vInertialVelocity = Tb2i * VState.vUVW + (vOmegaEarth * VState.vInertialPosition);
|
||||
VState.vInertialVelocity = Tb2i * VState.vUVW + (in.vOmegaPlanet * VState.vInertialPosition);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -392,7 +305,7 @@ void FGPropagate::CalculateInertialVelocity(void)
|
|||
|
||||
void FGPropagate::CalculateUVW(void)
|
||||
{
|
||||
VState.vUVW = Ti2b * (VState.vInertialVelocity - (vOmegaEarth * VState.vInertialPosition));
|
||||
VState.vUVW = Ti2b * (VState.vInertialVelocity - (in.vOmegaPlanet * VState.vInertialPosition));
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -449,167 +362,6 @@ void FGPropagate::Integrate( FGQuaternion& Integrand,
|
|||
}
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// Evaluates the rates (translation or rotation) that the friction forces have
|
||||
// to resist to. This includes the external forces and moments as well as the
|
||||
// relative movement between the aircraft and the ground.
|
||||
// Erin Catto's paper (see ref [6]) only supports Euler integration scheme and
|
||||
// this algorithm has been adapted to handle the multistep algorithms that
|
||||
// JSBSim supports (i.e. Trapezoidal, Adams-Bashforth 2, 3 and 4). The capacity
|
||||
// to handle the multistep integration schemes adds some complexity but it
|
||||
// significantly helps stabilizing the friction forces.
|
||||
|
||||
void FGPropagate::EvaluateRateToResistTo(FGColumnVector3& vdot,
|
||||
const FGColumnVector3& Val,
|
||||
const FGColumnVector3& ValDot,
|
||||
const FGColumnVector3& LocalTerrainVal,
|
||||
deque <FGColumnVector3>& dqValDot,
|
||||
const double dt,
|
||||
const eIntegrateType integration_type)
|
||||
{
|
||||
switch(integration_type) {
|
||||
case eAdamsBashforth4:
|
||||
vdot = ValDot + Ti2b * (-59.*dqValDot[0]+37.*dqValDot[1]-9.*dqValDot[2])/55.;
|
||||
if (dt > 0.) // Zeroes out the relative movement between aircraft and ground
|
||||
vdot += 24.*(Val - Tec2b * LocalTerrainVal) / (55.*dt);
|
||||
break;
|
||||
case eAdamsBashforth3:
|
||||
vdot = ValDot + Ti2b * (-16.*dqValDot[0]+5.*dqValDot[1])/23.;
|
||||
if (dt > 0.) // Zeroes out the relative movement between aircraft and ground
|
||||
vdot += 12.*(Val - Tec2b * LocalTerrainVal) / (23.*dt);
|
||||
break;
|
||||
case eAdamsBashforth2:
|
||||
vdot = ValDot - Ti2b * dqValDot[0]/3.;
|
||||
if (dt > 0.) // Zeroes out the relative movement between aircraft and ground
|
||||
vdot += 2.*(Val - Tec2b * LocalTerrainVal) / (3.*dt);
|
||||
break;
|
||||
case eTrapezoidal:
|
||||
vdot = ValDot + Ti2b * dqValDot[0];
|
||||
if (dt > 0.) // Zeroes out the relative movement between aircraft and ground
|
||||
vdot += 2.*(Val - Tec2b * LocalTerrainVal) / dt;
|
||||
break;
|
||||
case eRectEuler:
|
||||
vdot = ValDot;
|
||||
if (dt > 0.) // Zeroes out the relative movement between aircraft and ground
|
||||
vdot += (Val - Tec2b * LocalTerrainVal) / dt;
|
||||
break;
|
||||
case eNone:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// Resolves the contact forces just before integrating the EOM.
|
||||
// This routine is using Lagrange multipliers and the projected Gauss-Seidel
|
||||
// (PGS) method.
|
||||
// Reference: See Erin Catto, "Iterative Dynamics with Temporal Coherence",
|
||||
// February 22, 2005
|
||||
// In JSBSim there is only one rigid body (the aircraft) and there can be
|
||||
// multiple points of contact between the aircraft and the ground. As a
|
||||
// consequence our matrix J*M^-1*J^T is not sparse and the algorithm described
|
||||
// in Catto's paper has been adapted accordingly.
|
||||
// The friction forces are resolved in the body frame relative to the origin
|
||||
// (Earth center).
|
||||
|
||||
void FGPropagate::ResolveFrictionForces(double dt)
|
||||
{
|
||||
const double invMass = 1.0 / FDMExec->GetMassBalance()->GetMass();
|
||||
const FGMatrix33& Jinv = FDMExec->GetMassBalance()->GetJinv();
|
||||
vector <FGColumnVector3> JacF, JacM;
|
||||
vector<double> lambda, lambdaMin, lambdaMax;
|
||||
FGColumnVector3 vdot, wdot;
|
||||
FGColumnVector3 Fc, Mc;
|
||||
int n = 0;
|
||||
|
||||
// Compiles data from the ground reactions to build up the jacobian matrix
|
||||
for (MultiplierIterator it=MultiplierIterator(FDMExec->GetGroundReactions()); *it; ++it, n++) {
|
||||
JacF.push_back((*it)->ForceJacobian);
|
||||
JacM.push_back((*it)->MomentJacobian);
|
||||
lambda.push_back((*it)->value);
|
||||
lambdaMax.push_back((*it)->Max);
|
||||
lambdaMin.push_back((*it)->Min);
|
||||
}
|
||||
|
||||
// If no gears are in contact with the ground then return
|
||||
if (!n) return;
|
||||
|
||||
vector<double> a(n*n); // Will contain J*M^-1*J^T
|
||||
vector<double> rhs(n);
|
||||
|
||||
// Assemble the linear system of equations
|
||||
for (int i=0; i < n; i++) {
|
||||
for (int j=0; j < i; j++)
|
||||
a[i*n+j] = a[j*n+i]; // Takes advantage of the symmetry of J^T*M^-1*J
|
||||
for (int j=i; j < n; j++)
|
||||
a[i*n+j] = DotProduct(JacF[i],invMass*JacF[j])+DotProduct(JacM[i],Jinv*JacM[j]);
|
||||
}
|
||||
|
||||
// Assemble the RHS member
|
||||
|
||||
// Translation
|
||||
EvaluateRateToResistTo(vdot, VState.vUVW, vUVWdot, LocalTerrainVelocity,
|
||||
VState.dqUVWidot, dt, integrator_translational_rate);
|
||||
|
||||
// Rotation
|
||||
EvaluateRateToResistTo(wdot, VState.vPQR, vPQRdot, LocalTerrainAngularVelocity,
|
||||
VState.dqPQRidot, dt, integrator_rotational_rate);
|
||||
|
||||
// Prepare the linear system for the Gauss-Seidel algorithm :
|
||||
// 1. Compute the right hand side member 'rhs'
|
||||
// 2. Divide every line of 'a' and 'rhs' by a[i,i]. This is in order to save
|
||||
// a division computation at each iteration of Gauss-Seidel.
|
||||
for (int i=0; i < n; i++) {
|
||||
double d = 1.0 / a[i*n+i];
|
||||
|
||||
rhs[i] = -(DotProduct(JacF[i],vdot)+DotProduct(JacM[i],wdot))*d;
|
||||
for (int j=0; j < n; j++)
|
||||
a[i*n+j] *= d;
|
||||
}
|
||||
|
||||
// Resolve the Lagrange multipliers with the projected Gauss-Seidel method
|
||||
for (int iter=0; iter < 50; iter++) {
|
||||
double norm = 0.;
|
||||
|
||||
for (int i=0; i < n; i++) {
|
||||
double lambda0 = lambda[i];
|
||||
double dlambda = rhs[i];
|
||||
|
||||
for (int j=0; j < n; j++)
|
||||
dlambda -= a[i*n+j]*lambda[j];
|
||||
|
||||
lambda[i] = Constrain(lambdaMin[i], lambda0+dlambda, lambdaMax[i]);
|
||||
dlambda = lambda[i] - lambda0;
|
||||
|
||||
norm += fabs(dlambda);
|
||||
}
|
||||
|
||||
if (norm < 1E-5) break;
|
||||
}
|
||||
|
||||
// Calculate the total friction forces and moments
|
||||
|
||||
Fc.InitMatrix();
|
||||
Mc.InitMatrix();
|
||||
|
||||
for (int i=0; i< n; i++) {
|
||||
Fc += lambda[i]*JacF[i];
|
||||
Mc += lambda[i]*JacM[i];
|
||||
}
|
||||
|
||||
vUVWdot += invMass * Fc;
|
||||
vUVWidot += invMass * Tb2i * Fc;
|
||||
vPQRdot += Jinv * Mc;
|
||||
vPQRidot += Jinv * Mc;
|
||||
|
||||
// Save the value of the Lagrange multipliers to accelerate the convergence
|
||||
// of the Gauss-Seidel algorithm at next iteration.
|
||||
int i = 0;
|
||||
for (MultiplierIterator it=MultiplierIterator(FDMExec->GetGroundReactions()); *it; ++it)
|
||||
(*it)->value = lambda[i++];
|
||||
|
||||
FDMExec->GetGroundReactions()->UpdateForcesAndMoments();
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGPropagate::UpdateLocationMatrices(void)
|
||||
|
@ -653,31 +405,7 @@ void FGPropagate::SetInertialVelocity(FGColumnVector3 Vi) {
|
|||
|
||||
void FGPropagate::SetInertialRates(FGColumnVector3 vRates) {
|
||||
VState.vPQRi = Ti2b * vRates;
|
||||
VState.vPQR = VState.vPQRi - Ti2b * vOmegaEarth;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGPropagate::InitializeDerivatives(void)
|
||||
{
|
||||
// Make an initial run and set past values
|
||||
CalculatePQRdot(); // Angular rate derivative
|
||||
CalculateUVWdot(); // Translational rate derivative
|
||||
ResolveFrictionForces(0.); // Update rate derivatives with friction forces
|
||||
CalculateQuatdot(); // Angular orientation derivative
|
||||
CalculateInertialVelocity(); // Translational position derivative
|
||||
|
||||
// Initialize past values deques
|
||||
VState.dqPQRidot.clear();
|
||||
VState.dqUVWidot.clear();
|
||||
VState.dqInertialVelocity.clear();
|
||||
VState.dqQtrndot.clear();
|
||||
for (int i=0; i<4; i++) {
|
||||
VState.dqPQRidot.push_front(vPQRidot);
|
||||
VState.dqUVWidot.push_front(vUVWidot);
|
||||
VState.dqInertialVelocity.push_front(VState.vInertialVelocity);
|
||||
VState.dqQtrndot.push_front(vQtrndot);
|
||||
}
|
||||
VState.vPQR = VState.vPQRi - Ti2b * in.vOmegaPlanet;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -685,13 +413,14 @@ void FGPropagate::InitializeDerivatives(void)
|
|||
void FGPropagate::RecomputeLocalTerrainRadius(void)
|
||||
{
|
||||
FGLocation contactloc;
|
||||
FGColumnVector3 dv;
|
||||
FGColumnVector3 dummy;
|
||||
double t = FDMExec->GetSimTime();
|
||||
|
||||
// Get the LocalTerrain radius.
|
||||
FDMExec->GetGroundCallback()->GetAGLevel(t, VState.vLocation, contactloc, dv,
|
||||
LocalTerrainVelocity, LocalTerrainAngularVelocity);
|
||||
LocalTerrainRadius = contactloc.GetRadius();
|
||||
FDMExec->GetGroundCallback()->GetAGLevel(t, VState.vLocation, contactloc,
|
||||
dummy, LocalTerrainVelocity, LocalTerrainAngularVelocity);
|
||||
LocalTerrainRadius = contactloc.GetRadius();
|
||||
FDMExec->GetGroundCallback()->SetTerrainGeoCentRadius(LocalTerrainRadius);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -720,8 +449,9 @@ double FGPropagate::GetDistanceAGL(void) const
|
|||
|
||||
void FGPropagate::SetVState(const VehicleState& vstate)
|
||||
{
|
||||
//ToDo: Shouldn't all of these be set from the vstate vector passed in?
|
||||
VState.vLocation = vstate.vLocation;
|
||||
VState.vLocation.SetEarthPositionAngle(FDMExec->GetInertial()->GetEarthPositionAngle());
|
||||
VState.vLocation.SetEarthPositionAngle(vstate.vLocation.GetEPA());
|
||||
Ti2ec = VState.vLocation.GetTi2ec(); // useless ?
|
||||
Tec2i = Ti2ec.Transposed();
|
||||
UpdateLocationMatrices();
|
||||
|
@ -731,10 +461,8 @@ void FGPropagate::SetVState(const VehicleState& vstate)
|
|||
VState.vUVW = vstate.vUVW;
|
||||
vVel = Tb2l * VState.vUVW;
|
||||
VState.vPQR = vstate.vPQR;
|
||||
VState.vPQRi = VState.vPQR + Ti2b * vOmegaEarth;
|
||||
VState.vPQRi = VState.vPQR + Ti2b * in.vOmegaPlanet;
|
||||
VState.vInertialPosition = vstate.vInertialPosition;
|
||||
|
||||
InitializeDerivatives();
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -755,7 +483,7 @@ void FGPropagate::UpdateVehicleState(void)
|
|||
void FGPropagate::SetLocation(const FGLocation& l)
|
||||
{
|
||||
VState.vLocation = l;
|
||||
VState.vLocation.SetEarthPositionAngle(FDMExec->GetInertial()->GetEarthPositionAngle());
|
||||
VState.vLocation.SetEarthPositionAngle(l.GetEPA());
|
||||
Ti2ec = VState.vLocation.GetTi2ec(); // useless ?
|
||||
Tec2i = Ti2ec.Transposed();
|
||||
UpdateVehicleState();
|
||||
|
@ -822,14 +550,6 @@ void FGPropagate::bind(void)
|
|||
|
||||
PropertyManager->Tie("velocities/eci-velocity-mag-fps", this, &FGPropagate::GetInertialVelocityMagnitude);
|
||||
|
||||
PropertyManager->Tie("accelerations/pdot-rad_sec2", this, eP, (PMF)&FGPropagate::GetPQRdot);
|
||||
PropertyManager->Tie("accelerations/qdot-rad_sec2", this, eQ, (PMF)&FGPropagate::GetPQRdot);
|
||||
PropertyManager->Tie("accelerations/rdot-rad_sec2", this, eR, (PMF)&FGPropagate::GetPQRdot);
|
||||
|
||||
PropertyManager->Tie("accelerations/udot-ft_sec2", this, eU, (PMF)&FGPropagate::GetUVWdot);
|
||||
PropertyManager->Tie("accelerations/vdot-ft_sec2", this, eV, (PMF)&FGPropagate::GetUVWdot);
|
||||
PropertyManager->Tie("accelerations/wdot-ft_sec2", this, eW, (PMF)&FGPropagate::GetUVWdot);
|
||||
|
||||
PropertyManager->Tie("position/h-sl-ft", this, &FGPropagate::GetAltitudeASL, &FGPropagate::SetAltitudeASL, true);
|
||||
PropertyManager->Tie("position/h-sl-meters", this, &FGPropagate::GetAltitudeASLmeters, &FGPropagate::SetAltitudeASLmeters, true);
|
||||
PropertyManager->Tie("position/lat-gc-rad", this, &FGPropagate::GetLatitude, &FGPropagate::SetLatitude);
|
||||
|
@ -845,6 +565,7 @@ void FGPropagate::bind(void)
|
|||
&FGPropagate::GetTerrainElevation,
|
||||
&FGPropagate::SetTerrainElevation, false);
|
||||
|
||||
PropertyManager->Tie("position/epa-rad", this, &FGPropagate::GetEarthPositionAngle);
|
||||
PropertyManager->Tie("metrics/terrain-radius", this, &FGPropagate::GetLocalTerrainRadius);
|
||||
|
||||
PropertyManager->Tie("attitude/phi-rad", this, (int)ePhi, (PMF)&FGPropagate::GetEuler);
|
||||
|
@ -859,7 +580,6 @@ void FGPropagate::bind(void)
|
|||
PropertyManager->Tie("simulation/integrator/rate/translational", (int*)&integrator_translational_rate);
|
||||
PropertyManager->Tie("simulation/integrator/position/rotational", (int*)&integrator_rotational_position);
|
||||
PropertyManager->Tie("simulation/integrator/position/translational", (int*)&integrator_translational_position);
|
||||
PropertyManager->Tie("simulation/gravity-model", &gravType);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -902,7 +622,7 @@ void FGPropagate::Debug(int from)
|
|||
<< reset << endl;
|
||||
cout << endl;
|
||||
cout << highint << " Earth Position Angle (deg): " << setw(8) << setprecision(3) << reset
|
||||
<< FDMExec->GetInertial()->GetEarthPositionAngleDeg() << endl;
|
||||
<< GetEarthPositionAngleDeg() << endl;
|
||||
cout << endl;
|
||||
cout << highint << " Body velocity (ft/sec): " << setw(8) << setprecision(3) << reset << VState.vUVW << endl;
|
||||
cout << highint << " Local velocity (ft/sec): " << setw(8) << setprecision(3) << reset << vVel << endl;
|
||||
|
@ -911,7 +631,7 @@ void FGPropagate::Debug(int from)
|
|||
cout << highint << " Latitude (deg): " << setw(8) << setprecision(3) << reset << VState.vLocation.GetLatitudeDeg() << endl;
|
||||
cout << highint << " Longitude (deg): " << setw(8) << setprecision(3) << reset << VState.vLocation.GetLongitudeDeg() << endl;
|
||||
cout << highint << " Altitude ASL (ft): " << setw(8) << setprecision(3) << reset << GetAltitudeASL() << endl;
|
||||
cout << highint << " Acceleration (NED, ft/sec^2): " << setw(8) << setprecision(3) << reset << Tb2l*GetUVWdot() << endl;
|
||||
// cout << highint << " Acceleration (NED, ft/sec^2): " << setw(8) << setprecision(3) << reset << Tb2l*GetUVWdot() << endl;
|
||||
cout << endl;
|
||||
cout << highint << " Matrix ECEF to Body (Orientation of Body with respect to ECEF): "
|
||||
<< reset << endl << Tec2b.Dump("\t", " ") << endl;
|
||||
|
|
|
@ -49,7 +49,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_PROPAGATE "$Id: FGPropagate.h,v 1.59 2011/05/20 03:18:36 jberndt Exp $"
|
||||
#define ID_PROPAGATE "$Id: FGPropagate.h,v 1.63 2011/08/21 15:35:39 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -69,15 +69,6 @@ CLASS DOCUMENTATION
|
|||
state of the vehicle given the forces and moments that act on it. The
|
||||
integration accounts for a rotating Earth.
|
||||
|
||||
The general execution of this model follows this process:
|
||||
|
||||
-Calculate the angular accelerations
|
||||
-Calculate the translational accelerations
|
||||
-Calculate the angular rate
|
||||
-Calculate the translational velocity
|
||||
|
||||
-Integrate accelerations and rates
|
||||
|
||||
Integration of rotational and translation position and rate can be
|
||||
customized as needed or frozen by the selection of no integrator. The
|
||||
selection of which integrator to use is done through the setting of
|
||||
|
@ -101,8 +92,8 @@ CLASS DOCUMENTATION
|
|||
5: Adams Bashforth 4
|
||||
@endcode
|
||||
|
||||
@author Jon S. Berndt, Mathias Froehlich
|
||||
@version $Id: FGPropagate.h,v 1.59 2011/05/20 03:18:36 jberndt Exp $
|
||||
@author Jon S. Berndt, Mathias Froehlich, Bertrand Coconnier
|
||||
@version $Id: FGPropagate.h,v 1.63 2011/08/21 15:35:39 bcoconni Exp $
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -169,14 +160,13 @@ public:
|
|||
/// These define the indices use to select the various integrators.
|
||||
enum eIntegrateType {eNone = 0, eRectEuler, eTrapezoidal, eAdamsBashforth2, eAdamsBashforth3, eAdamsBashforth4};
|
||||
|
||||
/// These define the indices use to select the gravitation models.
|
||||
enum eGravType {gtStandard, gtWGS84};
|
||||
|
||||
/** Initializes the FGPropagate class after instantiation and prior to first execution.
|
||||
The base class FGModel::InitModel is called first, initializing pointers to the
|
||||
other FGModel objects (and others). */
|
||||
bool InitModel(void);
|
||||
|
||||
void InitializeDerivatives();
|
||||
|
||||
/** Runs the state propagation model; called by the Executive
|
||||
Can pass in a value indicating if the executive is directing the simulation to Hold.
|
||||
@param Holding if true, the executive has been directed to hold the sim from
|
||||
|
@ -186,8 +176,6 @@ public:
|
|||
@return false if no error */
|
||||
bool Run(bool Holding);
|
||||
|
||||
const FGQuaternion& GetQuaterniondot(void) const {return vQtrndot;}
|
||||
|
||||
/** Retrieves the velocity vector.
|
||||
The vector returned is represented by an FGColumnVector reference. The vector
|
||||
for the velocity in Local frame is organized (Vnorth, Veast, Vdown). The vector
|
||||
|
@ -213,20 +201,6 @@ public:
|
|||
*/
|
||||
const FGColumnVector3& GetUVW(void) const { return VState.vUVW; }
|
||||
|
||||
/** Retrieves the body axis acceleration.
|
||||
Retrieves the computed body axis accelerations based on the
|
||||
applied forces and accounting for a rotating body frame.
|
||||
The vector returned is represented by an FGColumnVector reference. The vector
|
||||
for the acceleration in Body frame is organized (Ax, Ay, Az). The vector
|
||||
is 1-based, so that the first element can be retrieved using the "()" operator.
|
||||
In other words, vUVWdot(1) is Ax. Various convenience enumerators are defined
|
||||
in FGJSBBase. The relevant enumerators for the vector returned by this call are,
|
||||
eX=1, eY=2, eZ=3.
|
||||
units ft/sec^2
|
||||
@return Body axis translational acceleration in ft/sec^2.
|
||||
*/
|
||||
const FGColumnVector3& GetUVWdot(void) const { return vUVWdot; }
|
||||
|
||||
/** Retrieves the body angular rates vector, relative to the ECEF frame.
|
||||
Retrieves the body angular rates (p, q, r), which are calculated by integration
|
||||
of the angular acceleration.
|
||||
|
@ -255,21 +229,6 @@ public:
|
|||
*/
|
||||
const FGColumnVector3& GetPQRi(void) const {return VState.vPQRi;}
|
||||
|
||||
/** Retrieves the body axis angular acceleration vector.
|
||||
Retrieves the body axis angular acceleration vector in rad/sec^2. The
|
||||
angular acceleration vector is determined from the applied forces and
|
||||
accounts for a rotating frame.
|
||||
The vector returned is represented by an FGColumnVector reference. The vector
|
||||
for the angular acceleration in Body frame is organized (Pdot, Qdot, Rdot). The vector
|
||||
is 1-based, so that the first element can be retrieved using the "()" operator.
|
||||
In other words, vPQRdot(1) is Pdot. Various convenience enumerators are defined
|
||||
in FGJSBBase. The relevant enumerators for the vector returned by this call are,
|
||||
eP=1, eQ=2, eR=3.
|
||||
units rad/sec^2
|
||||
@return The angular acceleration vector.
|
||||
*/
|
||||
const FGColumnVector3& GetPQRdot(void) const {return vPQRdot;}
|
||||
|
||||
/** Retrieves the Euler angles that define the vehicle orientation.
|
||||
Extracts the Euler angles from the quaternion that stores the orientation
|
||||
in the Local frame. The order of rotation used is Yaw-Pitch-Roll. The
|
||||
|
@ -300,19 +259,6 @@ public:
|
|||
*/
|
||||
double GetUVW (int idx) const { return VState.vUVW(idx); }
|
||||
|
||||
/** Retrieves a body frame acceleration component.
|
||||
Retrieves a body frame acceleration component. The acceleration returned
|
||||
is extracted from the vUVWdot vector (an FGColumnVector). The vector for
|
||||
the acceleration in Body frame is organized (Ax, Ay, Az). The vector is
|
||||
1-based. In other words, GetUVWdot(1) returns Ax. Various convenience
|
||||
enumerators are defined in FGJSBBase. The relevant enumerators for the
|
||||
acceleration returned by this call are, eX=1, eY=2, eZ=3.
|
||||
units ft/sec^2
|
||||
@param idx the index of the acceleration component desired (1-based).
|
||||
@return The body frame acceleration component.
|
||||
*/
|
||||
double GetUVWdot(int idx) const { return vUVWdot(idx); }
|
||||
|
||||
/** Retrieves a Local frame velocity component.
|
||||
Retrieves a Local frame velocity component. The velocity returned is
|
||||
extracted from the vVel vector (an FGColumnVector). The vector for the
|
||||
|
@ -382,20 +328,6 @@ public:
|
|||
*/
|
||||
double GetPQRi(int axis) const {return VState.vPQRi(axis);}
|
||||
|
||||
/** Retrieves a body frame angular acceleration component.
|
||||
Retrieves a body frame angular acceleration component. The angular
|
||||
acceleration returned is extracted from the vPQRdot vector (an
|
||||
FGColumnVector). The vector for the angular acceleration in Body frame
|
||||
is organized (Pdot, Qdot, Rdot). The vector is 1-based. In other words,
|
||||
GetPQRdot(1) returns Pdot (roll acceleration). Various convenience
|
||||
enumerators are defined in FGJSBBase. The relevant enumerators for the
|
||||
angular acceleration returned by this call are, eP=1, eQ=2, eR=3.
|
||||
units rad/sec^2
|
||||
@param axis the index of the angular acceleration component desired (1-based).
|
||||
@return The body frame angular acceleration component.
|
||||
*/
|
||||
double GetPQRdot(int axis) const {return vPQRdot(axis);}
|
||||
|
||||
/** Retrieves a vehicle Euler angle component.
|
||||
Retrieves an Euler angle (Phi, Theta, or Psi) from the quaternion that
|
||||
stores the vehicle orientation relative to the Local frame. The order of
|
||||
|
@ -447,7 +379,12 @@ public:
|
|||
*/
|
||||
double GetLocalTerrainRadius(void) const { return LocalTerrainRadius; }
|
||||
|
||||
double GetSeaLevelRadius(void) const { return SeaLevelRadius; }
|
||||
double GetEarthPositionAngle(void) const { return VState.vLocation.GetEPA(); }
|
||||
|
||||
double GetEarthPositionAngleDeg(void) const { return GetEarthPositionAngle()*radtodeg;}
|
||||
|
||||
const FGColumnVector3& GetTerrainVelocity(void) const { return LocalTerrainVelocity; }
|
||||
const FGColumnVector3& GetTerrainAngularVelocity(void) const { return LocalTerrainAngularVelocity; }
|
||||
double GetTerrainElevation(void) const;
|
||||
double GetDistanceAGL(void) const;
|
||||
double GetRadius(void) const {
|
||||
|
@ -526,13 +463,14 @@ public:
|
|||
|
||||
void SetVState(const VehicleState& vstate);
|
||||
|
||||
void InitializeDerivatives(void);
|
||||
void SetEarthPositionAngle(double epa) {VState.vLocation.SetEarthPositionAngle(epa);}
|
||||
|
||||
void SetInertialOrientation(FGQuaternion Qi);
|
||||
void SetInertialVelocity(FGColumnVector3 Vi);
|
||||
void SetInertialRates(FGColumnVector3 vRates);
|
||||
|
||||
const FGQuaternion GetQuaternion(void) const { return VState.qAttitudeLocal; }
|
||||
const FGQuaternion GetQuaternionECI(void) const { return VState.qAttitudeECI; }
|
||||
|
||||
void SetPQR(unsigned int i, double val) {
|
||||
if ((i>=1) && (i<=3) )
|
||||
|
@ -589,16 +527,19 @@ public:
|
|||
VState.vLocation -= Tb2ec*deltaLoc;
|
||||
}
|
||||
|
||||
struct LagrangeMultiplier {
|
||||
FGColumnVector3 ForceJacobian;
|
||||
FGColumnVector3 MomentJacobian;
|
||||
double Min;
|
||||
double Max;
|
||||
double value;
|
||||
};
|
||||
|
||||
void DumpState(void);
|
||||
|
||||
struct Inputs {
|
||||
FGColumnVector3 vPQRidot;
|
||||
FGQuaternion vQtrndot;
|
||||
FGColumnVector3 vUVWidot;
|
||||
FGColumnVector3 vOmegaPlanet;
|
||||
double RefRadius;
|
||||
double SemiMajor;
|
||||
double SemiMinor;
|
||||
double DeltaT;
|
||||
} in;
|
||||
|
||||
private:
|
||||
|
||||
// state vector
|
||||
|
@ -606,14 +547,9 @@ private:
|
|||
struct VehicleState VState;
|
||||
|
||||
FGColumnVector3 vVel;
|
||||
FGColumnVector3 vPQRdot, vPQRidot;
|
||||
FGColumnVector3 vUVWdot, vUVWidot;
|
||||
FGColumnVector3 vInertialVelocity;
|
||||
FGColumnVector3 vLocation;
|
||||
FGColumnVector3 vDeltaXYZEC;
|
||||
FGColumnVector3 vGravAccel;
|
||||
FGColumnVector3 vOmegaEarth; // The Earth angular velocity vector
|
||||
FGQuaternion vQtrndot;
|
||||
FGMatrix33 Tec2b;
|
||||
FGMatrix33 Tb2ec;
|
||||
FGMatrix33 Tl2b; // local to body frame matrix copy for immediate local use
|
||||
|
@ -633,13 +569,9 @@ private:
|
|||
eIntegrateType integrator_translational_rate;
|
||||
eIntegrateType integrator_rotational_position;
|
||||
eIntegrateType integrator_translational_position;
|
||||
int gravType;
|
||||
|
||||
void CalculatePQRdot(void);
|
||||
void CalculateQuatdot(void);
|
||||
void CalculateInertialVelocity(void);
|
||||
void CalculateUVW(void);
|
||||
void CalculateUVWdot(void);
|
||||
|
||||
void Integrate( FGColumnVector3& Integrand,
|
||||
FGColumnVector3& Val,
|
||||
|
@ -653,16 +585,6 @@ private:
|
|||
double dt,
|
||||
eIntegrateType integration_type);
|
||||
|
||||
void EvaluateRateToResistTo(FGColumnVector3& vdot,
|
||||
const FGColumnVector3& Val,
|
||||
const FGColumnVector3& ValDot,
|
||||
const FGColumnVector3& LocalTerrainVal,
|
||||
deque <FGColumnVector3>& dqValDot,
|
||||
const double dt,
|
||||
const eIntegrateType integration_type);
|
||||
|
||||
void ResolveFrictionForces(double dt);
|
||||
|
||||
void UpdateLocationMatrices(void);
|
||||
void UpdateBodyMatrices(void);
|
||||
void UpdateVehicleState(void);
|
||||
|
|
|
@ -44,10 +44,14 @@ HISTORY
|
|||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <cstdlib>
|
||||
#include <iomanip>
|
||||
|
||||
#include "FGFDMExec.h"
|
||||
#include "FGPropulsion.h"
|
||||
#include "models/FGFCS.h"
|
||||
#include "models/FGMassBalance.h"
|
||||
#include "models/propulsion/FGThruster.h"
|
||||
#include "models/propulsion/FGRocket.h"
|
||||
#include "models/propulsion/FGTurbine.h"
|
||||
#include "models/propulsion/FGPiston.h"
|
||||
|
@ -57,15 +61,12 @@ INCLUDES
|
|||
#include "input_output/FGPropertyManager.h"
|
||||
#include "input_output/FGXMLParse.h"
|
||||
#include "math/FGColumnVector3.h"
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <cstdlib>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGPropulsion.cpp,v 1.46 2011/05/20 03:18:36 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGPropulsion.cpp,v 1.50 2011/08/03 03:21:06 jberndt Exp $";
|
||||
static const char *IdHdr = ID_PROPULSION;
|
||||
|
||||
extern short debug_lvl;
|
||||
|
@ -87,7 +88,7 @@ FGPropulsion::FGPropulsion(FGFDMExec* exec) : FGModel(exec)
|
|||
tankJ.InitMatrix();
|
||||
refuel = dump = false;
|
||||
DumpRate = 0.0;
|
||||
fuel_freeze = false;
|
||||
FuelFreeze = false;
|
||||
TotalFuelQuantity = 0.0;
|
||||
IsBound =
|
||||
HavePistonEngine =
|
||||
|
@ -158,33 +159,132 @@ bool FGPropulsion::Run(bool Holding)
|
|||
|
||||
RunPreFunctions();
|
||||
|
||||
double dt = FDMExec->GetDeltaT();
|
||||
|
||||
vForces.InitMatrix();
|
||||
vMoments.InitMatrix();
|
||||
|
||||
for (i=0; i<numEngines; i++) {
|
||||
Engines[i]->Calculate();
|
||||
ConsumeFuel(Engines[i]);
|
||||
vForces += Engines[i]->GetBodyForces(); // sum body frame forces
|
||||
vMoments += Engines[i]->GetMoments(); // sum body frame moments
|
||||
}
|
||||
|
||||
TotalFuelQuantity = 0.0;
|
||||
for (i=0; i<numTanks; i++) {
|
||||
Tanks[i]->Calculate( dt * rate );
|
||||
Tanks[i]->Calculate( in.TotalDeltaT, in.TAT_c);
|
||||
if (Tanks[i]->GetType() == FGTank::ttFUEL) {
|
||||
TotalFuelQuantity += Tanks[i]->GetContents();
|
||||
}
|
||||
}
|
||||
|
||||
if (refuel) DoRefuel( dt * rate );
|
||||
if (dump) DumpFuel( dt * rate );
|
||||
if (refuel) DoRefuel( in.TotalDeltaT );
|
||||
if (dump) DumpFuel( in.TotalDeltaT );
|
||||
|
||||
RunPostFunctions();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
//
|
||||
// The engine can tell us how much fuel it needs, but it is up to the propulsion
|
||||
// subsystem manager class FGPropulsion to manage fuel flow amongst tanks. Engines
|
||||
// May burn fuel from more than one tank at a time, and may burn from one tank
|
||||
// before another - that is, may burn from one tank until the tank is depleted,
|
||||
// then burn from the next highest priority tank. This can be accompished
|
||||
// by defining a fuel management system, but this way of specifying priorities
|
||||
// is more automatic from a user perspective.
|
||||
|
||||
void FGPropulsion::ConsumeFuel(FGEngine* engine)
|
||||
{
|
||||
if (FuelFreeze) return;
|
||||
if (FDMExec->GetTrimStatus()) return;
|
||||
|
||||
unsigned int TanksWithFuel=0, CurrentFuelTankPriority=1;
|
||||
unsigned int TanksWithOxidizer=0, CurrentOxidizerTankPriority=1;
|
||||
vector <int> FeedListFuel, FeedListOxi;
|
||||
bool Starved = true; // Initially set Starved to true. Set to false in code below.
|
||||
// bool hasOxTanks = false;
|
||||
|
||||
// For this engine,
|
||||
// 1) Count how many fuel tanks with the current priority level have fuel
|
||||
// 2) If there none, then try next lower priority (higher number) - that is,
|
||||
// increment CurrentPriority.
|
||||
// 3) Build the feed list.
|
||||
// 4) Do the same for oxidizer tanks, if needed.
|
||||
|
||||
// Process fuel tanks, if any
|
||||
while ((TanksWithFuel == 0) && (CurrentFuelTankPriority <= numTanks)) {
|
||||
for (unsigned int i=0; i<engine->GetNumSourceTanks(); i++) {
|
||||
unsigned int TankId = engine->GetSourceTank(i);
|
||||
FGTank* Tank = Tanks[TankId];
|
||||
unsigned int TankPriority = Tank->GetPriority();
|
||||
if (TankPriority != 0) {
|
||||
switch(Tank->GetType()) {
|
||||
case FGTank::ttFUEL:
|
||||
if ((Tank->GetContents() > 0.0) && Tank->GetSelected() && (TankPriority == CurrentFuelTankPriority)) {
|
||||
TanksWithFuel++;
|
||||
Starved = false;
|
||||
FeedListFuel.push_back(TankId);
|
||||
}
|
||||
break;
|
||||
case FGTank::ttOXIDIZER:
|
||||
// Skip this here (done below)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (TanksWithFuel == 0) CurrentFuelTankPriority++; // No tanks at this priority, try next priority
|
||||
}
|
||||
|
||||
// Process Oxidizer tanks, if any
|
||||
if (engine->GetType() == FGEngine::etRocket) {
|
||||
while ((TanksWithOxidizer == 0) && (CurrentOxidizerTankPriority <= numTanks)) {
|
||||
for (unsigned int i=0; i<engine->GetNumSourceTanks(); i++) {
|
||||
unsigned int TankId = engine->GetSourceTank(i);
|
||||
FGTank* Tank = Tanks[TankId];
|
||||
unsigned int TankPriority = Tank->GetPriority();
|
||||
if (TankPriority != 0) {
|
||||
switch(Tank->GetType()) {
|
||||
case FGTank::ttFUEL:
|
||||
// Skip this here (done above)
|
||||
break;
|
||||
case FGTank::ttOXIDIZER:
|
||||
// hasOxTanks = true;
|
||||
if (Tank->GetContents() > 0.0 && Tank->GetSelected() && TankPriority == CurrentOxidizerTankPriority) {
|
||||
TanksWithOxidizer++;
|
||||
if (TanksWithFuel > 0) Starved = false;
|
||||
FeedListOxi.push_back(TankId);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (TanksWithOxidizer == 0) CurrentOxidizerTankPriority++; // No tanks at this priority, try next priority
|
||||
}
|
||||
}
|
||||
|
||||
engine->SetStarved(Starved); // Tanks can be refilled, so be sure to reset engine Starved flag here.
|
||||
|
||||
// No fuel or fuel/oxidizer found at any priority!
|
||||
if (Starved) return;
|
||||
|
||||
double FuelToBurn = engine->CalcFuelNeed(); // How much fuel does this engine need?
|
||||
double FuelNeededPerTank = FuelToBurn / TanksWithFuel; // Determine fuel needed per tank.
|
||||
for (unsigned int i=0; i<FeedListFuel.size(); i++) {
|
||||
Tanks[FeedListFuel[i]]->Drain(FuelNeededPerTank);
|
||||
}
|
||||
|
||||
if (engine->GetType() == FGEngine::etRocket) {
|
||||
double OxidizerToBurn = engine->CalcOxidizerNeed(); // How much fuel does this engine need?
|
||||
double OxidizerNeededPerTank = OxidizerToBurn / TanksWithOxidizer; // Determine fuel needed per tank.
|
||||
for (unsigned int i=0; i<FeedListOxi.size(); i++) {
|
||||
Tanks[FeedListOxi[i]]->Drain(OxidizerNeededPerTank);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
bool FGPropulsion::GetSteadyState(void)
|
||||
|
@ -201,28 +301,23 @@ bool FGPropulsion::GetSteadyState(void)
|
|||
FDMExec->SetTrimStatus(true);
|
||||
|
||||
for (unsigned int i=0; i<numEngines; i++) {
|
||||
// cout << " Finding steady state for engine " << i << endl;
|
||||
steady=false;
|
||||
steady_count=0;
|
||||
j=0;
|
||||
while (!steady && j < 6000) {
|
||||
Engines[i]->Calculate();
|
||||
lastThrust = currentThrust;
|
||||
currentThrust = Engines[i]->GetThruster()->GetThrust();
|
||||
currentThrust = Engines[i]->GetThrust();
|
||||
if (fabs(lastThrust-currentThrust) < 0.0001) {
|
||||
steady_count++;
|
||||
if (steady_count > 120) {
|
||||
steady=true;
|
||||
// cout << " Steady state found at thrust: " << currentThrust << " lbs." << endl;
|
||||
}
|
||||
} else {
|
||||
steady_count=0;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
// if (j >= 6000) {
|
||||
// cout << " Could not find a steady state for this engine." << endl;
|
||||
// }
|
||||
vForces += Engines[i]->GetBodyForces(); // sum body frame forces
|
||||
vMoments += Engines[i]->GetMoments(); // sum body frame moments
|
||||
}
|
||||
|
@ -244,8 +339,10 @@ void FGPropulsion::InitRunning(int n)
|
|||
if (n >= (int)GetNumEngines() ) {
|
||||
throw(string("Tried to initialize a non-existent engine!"));
|
||||
}
|
||||
FDMExec->GetFCS()->SetThrottleCmd(n,1);
|
||||
FDMExec->GetFCS()->SetMixtureCmd(n,1);
|
||||
|
||||
in.ThrottleCmd[n] = in.ThrottlePos[n] = 1; // Set the throttle command and position
|
||||
in.MixtureCmd[n] = in.MixturePos[n] = 1; // Set the mixture command and position
|
||||
|
||||
GetEngine(n)->InitRunning();
|
||||
GetSteadyState();
|
||||
|
||||
|
@ -255,14 +352,14 @@ void FGPropulsion::InitRunning(int n)
|
|||
} else if (n < 0) { // -1 refers to "All Engines"
|
||||
|
||||
for (unsigned int i=0; i<GetNumEngines(); i++) {
|
||||
FDMExec->GetFCS()->SetThrottleCmd(i,1);
|
||||
FDMExec->GetFCS()->SetMixtureCmd(i,1);
|
||||
in.ThrottleCmd[i] = in.ThrottlePos[i] = 1; // Set the throttle command and position
|
||||
in.MixtureCmd[i] = in.MixturePos[i] = 1; // Set the mixture command and position
|
||||
GetEngine(i)->InitRunning();
|
||||
}
|
||||
|
||||
GetSteadyState();
|
||||
InitializedEngines = -1;
|
||||
HasInitializedEngines = true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -301,6 +398,11 @@ bool FGPropulsion::Load(Element* el)
|
|||
}
|
||||
|
||||
engine_filename = FindEngineFullPathname(engine_filename);
|
||||
if (engine_filename.empty()) {
|
||||
// error message already printed by FindEngineFullPathname()
|
||||
return false;
|
||||
}
|
||||
|
||||
document = LoadXMLDocument(engine_filename);
|
||||
document->SetParent(engine_element);
|
||||
|
||||
|
@ -309,23 +411,23 @@ bool FGPropulsion::Load(Element* el)
|
|||
if (type == "piston_engine") {
|
||||
HavePistonEngine = true;
|
||||
if (!IsBound) bind();
|
||||
Engines.push_back(new FGPiston(FDMExec, document, numEngines));
|
||||
Engines.push_back(new FGPiston(FDMExec, document, numEngines, in));
|
||||
} else if (type == "turbine_engine") {
|
||||
HaveTurbineEngine = true;
|
||||
if (!IsBound) bind();
|
||||
Engines.push_back(new FGTurbine(FDMExec, document, numEngines));
|
||||
Engines.push_back(new FGTurbine(FDMExec, document, numEngines, in));
|
||||
} else if (type == "turboprop_engine") {
|
||||
HaveTurboPropEngine = true;
|
||||
if (!IsBound) bind();
|
||||
Engines.push_back(new FGTurboProp(FDMExec, document, numEngines));
|
||||
Engines.push_back(new FGTurboProp(FDMExec, document, numEngines, in));
|
||||
} else if (type == "rocket_engine") {
|
||||
HaveRocketEngine = true;
|
||||
if (!IsBound) bind();
|
||||
Engines.push_back(new FGRocket(FDMExec, document, numEngines));
|
||||
Engines.push_back(new FGRocket(FDMExec, document, numEngines, in));
|
||||
} else if (type == "electric_engine") {
|
||||
HaveElectricEngine = true;
|
||||
if (!IsBound) bind();
|
||||
Engines.push_back(new FGElectric(FDMExec, document, numEngines));
|
||||
Engines.push_back(new FGElectric(FDMExec, document, numEngines, in));
|
||||
} else {
|
||||
cerr << "Unknown engine type: " << type << endl;
|
||||
exit(-5);
|
||||
|
@ -335,9 +437,6 @@ bool FGPropulsion::Load(Element* el)
|
|||
return false;
|
||||
}
|
||||
|
||||
FDMExec->GetFCS()->AddThrottle();
|
||||
ThrottleAdded = true;
|
||||
|
||||
numEngines++;
|
||||
|
||||
engine_element = el->FindNextElement("engine");
|
||||
|
@ -345,7 +444,6 @@ bool FGPropulsion::Load(Element* el)
|
|||
}
|
||||
|
||||
CalculateTankInertias();
|
||||
if (!ThrottleAdded) FDMExec->GetFCS()->AddThrottle(); // need to have at least one throttle
|
||||
|
||||
// Process fuel dump rate
|
||||
if (el->FindElement("dump-rate"))
|
||||
|
@ -459,6 +557,34 @@ string FGPropulsion::GetPropulsionValues(const string& delimiter) const
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
string FGPropulsion::GetPropulsionTankReport()
|
||||
{
|
||||
string out="";
|
||||
stringstream outstream;
|
||||
for (unsigned int i=0; i<numTanks; i++)
|
||||
{
|
||||
FGTank* tank = Tanks[i];
|
||||
string tankname="";
|
||||
if (tank->GetType() == FGTank::ttFUEL && tank->GetGrainType() != FGTank::gtUNKNOWN) {
|
||||
tankname = "Solid Fuel";
|
||||
} else if (tank->GetType() == FGTank::ttFUEL) {
|
||||
tankname = "Fuel";
|
||||
} else if (tank->GetType() == FGTank::ttOXIDIZER) {
|
||||
tankname = "Oxidizer";
|
||||
} else {
|
||||
tankname = "(Unknown tank type)";
|
||||
}
|
||||
outstream << highint << left << setw(4) << i << setw(30) << tankname << normint
|
||||
<< right << setw(10) << tank->GetContents() << setw(8) << tank->GetXYZ(eX)
|
||||
<< setw(8) << tank->GetXYZ(eY) << setw(8) << tank->GetXYZ(eZ)
|
||||
<< setw(12) << "*" << setw(12) << "*"
|
||||
<< setw(12) << "*" << endl;
|
||||
}
|
||||
return outstream.str();
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
FGColumnVector3& FGPropulsion::GetTanksMoment(void)
|
||||
{
|
||||
vXYZtank_arm.InitMatrix();
|
||||
|
@ -633,7 +759,7 @@ void FGPropulsion::DumpFuel(double time_slice)
|
|||
|
||||
void FGPropulsion::SetFuelFreeze(bool f)
|
||||
{
|
||||
fuel_freeze = f;
|
||||
FuelFreeze = f;
|
||||
for (unsigned int i=0; i<numEngines; i++) {
|
||||
Engines[i]->SetFuelFreeze(f);
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ INCLUDES
|
|||
#include <iosfwd>
|
||||
|
||||
#include "FGModel.h"
|
||||
#include "propulsion/FGEngine.h"
|
||||
#include "math/FGMatrix33.h"
|
||||
#include "input_output/FGXMLFileRead.h"
|
||||
|
||||
|
@ -49,7 +50,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_PROPULSION "$Id: FGPropulsion.h,v 1.27 2011/05/20 03:18:36 jberndt Exp $"
|
||||
#define ID_PROPULSION "$Id: FGPropulsion.h,v 1.30 2011/08/03 03:21:06 jberndt Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -91,7 +92,7 @@ CLASS DOCUMENTATION
|
|||
@endcode
|
||||
|
||||
@author Jon S. Berndt
|
||||
@version $Id: FGPropulsion.h,v 1.27 2011/05/20 03:18:36 jberndt Exp $
|
||||
@version $Id: FGPropulsion.h,v 1.30 2011/08/03 03:21:06 jberndt Exp $
|
||||
@see
|
||||
FGEngine
|
||||
FGTank
|
||||
|
@ -164,6 +165,7 @@ public:
|
|||
|
||||
std::string GetPropulsionStrings(const std::string& delimiter) const;
|
||||
std::string GetPropulsionValues(const std::string& delimiter) const;
|
||||
std::string GetPropulsionTankReport();
|
||||
|
||||
const FGColumnVector3& GetForces(void) const {return vForces; }
|
||||
double GetForces(int n) const { return vForces(n);}
|
||||
|
@ -184,7 +186,7 @@ public:
|
|||
std::ifstream* FindEngineFile(const std::string& filename);
|
||||
std::string FindEngineFullPathname(const std::string& engine_filename);
|
||||
inline int GetActiveEngine(void) const {return ActiveEngine;}
|
||||
inline bool GetFuelFreeze(void) {return fuel_freeze;}
|
||||
inline bool GetFuelFreeze(void) {return FuelFreeze;}
|
||||
double GetTotalFuelQuantity(void) const {return TotalFuelQuantity;}
|
||||
|
||||
void SetMagnetos(int setting);
|
||||
|
@ -194,6 +196,8 @@ public:
|
|||
void SetFuelFreeze(bool f);
|
||||
FGMatrix33& CalculateTankInertias(void);
|
||||
|
||||
struct FGEngine::Inputs in;
|
||||
|
||||
private:
|
||||
std::vector <FGEngine*> Engines;
|
||||
std::vector <FGTank*> Tanks;
|
||||
|
@ -211,7 +215,7 @@ private:
|
|||
FGMatrix33 tankJ;
|
||||
bool refuel;
|
||||
bool dump;
|
||||
bool fuel_freeze;
|
||||
bool FuelFreeze;
|
||||
double TotalFuelQuantity;
|
||||
double DumpRate;
|
||||
bool IsBound;
|
||||
|
@ -220,6 +224,7 @@ private:
|
|||
bool HaveTurboPropEngine;
|
||||
bool HaveRocketEngine;
|
||||
bool HaveElectricEngine;
|
||||
void ConsumeFuel(FGEngine* engine);
|
||||
|
||||
int InitializedEngines;
|
||||
bool HasInitializedEngines;
|
||||
|
|
|
@ -7,12 +7,12 @@ libModels_a_SOURCES = FGAerodynamics.cpp FGAircraft.cpp FGAtmosphere.cpp \
|
|||
FGInertial.cpp FGBuoyantForces.cpp FGExternalForce.cpp \
|
||||
FGLGear.cpp FGMassBalance.cpp FGModel.cpp FGOutput.cpp \
|
||||
FGPropagate.cpp FGPropulsion.cpp FGInput.cpp \
|
||||
FGExternalReactions.cpp FGGasCell.cpp
|
||||
FGExternalReactions.cpp FGGasCell.cpp FGAccelerations.cpp
|
||||
|
||||
noinst_HEADERS = FGAerodynamics.h FGAircraft.h FGAtmosphere.h FGAuxiliary.h \
|
||||
FGFCS.h FGGroundReactions.h FGInertial.h FGLGear.h \
|
||||
FGMassBalance.h FGBuoyantForces.h FGExternalForce.h \
|
||||
FGModel.h FGOutput.h FGPropagate.h FGPropulsion.h FGInput.h \
|
||||
FGExternalReactions.h FGGasCell.h
|
||||
FGExternalReactions.h FGGasCell.h FGAccelerations.h
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/src/FDM/JSBSim
|
||||
|
|
|
@ -66,7 +66,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGMSIS.cpp,v 1.17 2011/05/20 03:18:36 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGMSIS.cpp,v 1.18 2011/06/21 13:54:40 jberndt Exp $";
|
||||
static const char *IdHdr = ID_MSIS;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -140,16 +140,16 @@ bool MSIS::InitModel(void)
|
|||
input.f107 = 150.0;
|
||||
input.ap = 4.0;
|
||||
|
||||
UseInternal();
|
||||
// UseInternal();
|
||||
|
||||
SLtemperature = intTemperature = 518.0;
|
||||
SLpressure = intPressure = 2116.7;
|
||||
SLdensity = intDensity = 0.002378;
|
||||
SLsoundspeed = sqrt(2403.0832 * SLtemperature);
|
||||
rSLtemperature = 1.0/intTemperature;
|
||||
rSLpressure = 1.0/intPressure;
|
||||
rSLdensity = 1.0/intDensity;
|
||||
rSLsoundspeed = 1.0/SLsoundspeed;
|
||||
// SLtemperature = intTemperature = 518.0;
|
||||
// SLpressure = intPressure = 2116.7;
|
||||
// SLdensity = intDensity = 0.002378;
|
||||
// SLsoundspeed = sqrt(2403.0832 * SLtemperature);
|
||||
// rSLtemperature = 1.0/intTemperature;
|
||||
// rSLpressure = 1.0/intPressure;
|
||||
// rSLdensity = 1.0/intDensity;
|
||||
// rSLsoundspeed = 1.0/SLsoundspeed;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -163,10 +163,10 @@ bool MSIS::Run(bool Holding)
|
|||
|
||||
RunPreFunctions();
|
||||
|
||||
h = FDMExec->GetPropagate()->GetAltitudeASL();
|
||||
double h = FDMExec->GetPropagate()->GetAltitudeASL();
|
||||
|
||||
//do temp, pressure, and density first
|
||||
if (!useExternal) {
|
||||
// if (!useExternal) {
|
||||
// get sea-level values
|
||||
Calculate(FDMExec->GetAuxiliary()->GetDayOfYear(),
|
||||
FDMExec->GetAuxiliary()->GetSecondsInDay(),
|
||||
|
@ -188,14 +188,12 @@ bool MSIS::Run(bool Holding)
|
|||
h,
|
||||
FDMExec->GetPropagate()->GetLocation().GetLatitudeDeg(),
|
||||
FDMExec->GetPropagate()->GetLocation().GetLongitudeDeg());
|
||||
intTemperature = output.t[1] * 1.8;
|
||||
intDensity = output.d[5] * 1.940321;
|
||||
intPressure = 1716.488 * intDensity * intTemperature;
|
||||
// intTemperature = output.t[1] * 1.8;
|
||||
// intDensity = output.d[5] * 1.940321;
|
||||
// intPressure = 1716.488 * intDensity * intTemperature;
|
||||
//cout << "T=" << intTemperature << " D=" << intDensity << " P=";
|
||||
//cout << intPressure << " a=" << soundspeed << endl;
|
||||
}
|
||||
|
||||
CalculateDerived();
|
||||
// }
|
||||
|
||||
RunPostFunctions();
|
||||
|
||||
|
@ -1660,16 +1658,6 @@ void MSIS::Debug(int from)
|
|||
if (debug_lvl & 16) { // Sanity checking
|
||||
}
|
||||
if (debug_lvl & 32) { // Turbulence
|
||||
if (first_pass && from == 2) {
|
||||
cout << "vTurbulenceNED(X), vTurbulenceNED(Y), vTurbulenceNED(Z), "
|
||||
<< "vTurbulenceGrad(X), vTurbulenceGrad(Y), vTurbulenceGrad(Z), "
|
||||
<< "vDirection(X), vDirection(Y), vDirection(Z), "
|
||||
<< "Magnitude, "
|
||||
<< "vTurbPQR(P), vTurbPQR(Q), vTurbPQR(R), " << endl;
|
||||
}
|
||||
if (from == 2) {
|
||||
cout << vTurbulenceNED << ", " << vTurbulenceGrad << ", " << vDirection << ", " << Magnitude << ", " << vTurbPQR << endl;
|
||||
}
|
||||
}
|
||||
if (debug_lvl & 64) {
|
||||
if (from == 0) { // Constructor
|
||||
|
|
19
src/FDM/JSBSim/models/atmosphere/FGMars.cpp
Normal file → Executable file
19
src/FDM/JSBSim/models/atmosphere/FGMars.cpp
Normal file → Executable file
|
@ -48,7 +48,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGMars.cpp,v 1.10 2010/02/25 05:21:36 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGMars.cpp,v 1.11 2011/06/21 13:54:40 jberndt Exp $";
|
||||
static const char *IdHdr = ID_MARS;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -74,12 +74,12 @@ void FGMars::Calculate(double altitude)
|
|||
// LIMIT the temperatures so they do not descend below absolute zero.
|
||||
|
||||
if (altitude < 22960.0) {
|
||||
intTemperature = -25.68 - 0.000548*altitude; // Deg Fahrenheit
|
||||
Temperature = -25.68 - 0.000548*altitude; // Deg Fahrenheit
|
||||
} else {
|
||||
intTemperature = -10.34 - 0.001217*altitude; // Deg Fahrenheit
|
||||
Temperature = -10.34 - 0.001217*altitude; // Deg Fahrenheit
|
||||
}
|
||||
intPressure = 14.62*exp(-0.00003*altitude); // psf - 14.62 psf =~ 7 millibars
|
||||
intDensity = intPressure/(Reng*intTemperature); // slugs/ft^3 (needs deg R. as input
|
||||
Pressure = 14.62*exp(-0.00003*altitude); // psf - 14.62 psf =~ 7 millibars
|
||||
Density = Pressure/(Reng*Temperature); // slugs/ft^3 (needs deg R. as input
|
||||
|
||||
//cout << "Atmosphere: h=" << altitude << " rho= " << intDensity << endl;
|
||||
}
|
||||
|
@ -122,15 +122,6 @@ void FGMars::Debug(int from)
|
|||
if (debug_lvl & 16) { // Sanity checking
|
||||
}
|
||||
if (debug_lvl & 32) { // Turbulence
|
||||
if (first_pass && from == 2) {
|
||||
cout << "vTurbulenceNED(X), vTurbulenceNED(Y), vTurbulenceNED(Z), "
|
||||
<< "vTurbulenceGrad(X), vTurbulenceGrad(Y), vTurbulenceGrad(Z), "
|
||||
<< "vDirection(X), vDirection(Y), vDirection(Z), "
|
||||
<< "Magnitude, "
|
||||
<< "vTurbPQR(P), vTurbPQR(Q), vTurbPQR(R), " << endl;
|
||||
} else if (from == 2) {
|
||||
cout << vTurbulenceNED << ", " << vTurbulenceGrad << ", " << vDirection << ", " << Magnitude << ", " << vTurbPQR << endl;
|
||||
}
|
||||
}
|
||||
if (debug_lvl & 64) {
|
||||
if (from == 0) { // Constructor
|
||||
|
|
|
@ -50,20 +50,16 @@ INCLUDES
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGStandardAtmosphere.cpp,v 1.9 2011/06/13 12:06:29 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGStandardAtmosphere.cpp,v 1.18 2011/08/17 23:56:01 jberndt Exp $";
|
||||
static const char *IdHdr = ID_STANDARDATMOSPHERE;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS IMPLEMENTATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
FGStandardAtmosphere::FGStandardAtmosphere(FGFDMExec* fdmex) : FGModel(fdmex),
|
||||
FGStandardAtmosphere::FGStandardAtmosphere(FGFDMExec* fdmex) : FGAtmosphere(fdmex),
|
||||
TemperatureDeltaGradient(0.0),
|
||||
TemperatureBias(0.0),
|
||||
PressureAltitude(0.0), // ft
|
||||
DensityAltitude(0.0), // ft
|
||||
SutherlandConstant(198.72), // deg Rankine
|
||||
Beta(2.269690E-08) // slug/(sec ft R^0.5)
|
||||
TemperatureBias(0.0)
|
||||
{
|
||||
Name = "FGStandardAtmosphere";
|
||||
|
||||
|
@ -102,6 +98,7 @@ FGStandardAtmosphere::FGStandardAtmosphere(FGFDMExec* fdmex) : FGModel(fdmex),
|
|||
|
||||
FGStandardAtmosphere::~FGStandardAtmosphere()
|
||||
{
|
||||
delete StdAtmosTemperatureTable;
|
||||
LapseRateVector.clear();
|
||||
Debug(1);
|
||||
}
|
||||
|
@ -131,38 +128,6 @@ bool FGStandardAtmosphere::InitModel(void)
|
|||
return true;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
bool FGStandardAtmosphere::Run(bool Holding)
|
||||
{
|
||||
if (FGModel::Run(Holding)) return true;
|
||||
if (Holding) return false;
|
||||
|
||||
RunPreFunctions();
|
||||
|
||||
double altitude = FDMExec->GetPropagate()->GetAltitudeASL();
|
||||
|
||||
Calculate(altitude);
|
||||
|
||||
RunPostFunctions();
|
||||
|
||||
Debug(2);
|
||||
return false;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGStandardAtmosphere::Calculate(double altitude)
|
||||
{
|
||||
Temperature = GetTemperature(altitude);
|
||||
Pressure = GetPressure(altitude);
|
||||
Density = Pressure/(Reng*Temperature);
|
||||
Soundspeed = sqrt(SHRatio*Reng*(Temperature));
|
||||
|
||||
Viscosity = Beta * pow(Temperature, 1.5) / (SutherlandConstant + Temperature);
|
||||
KinematicViscosity = Viscosity / Density;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// Get the actual pressure as modeled at a specified altitude
|
||||
// These calculations are from equations 33a and 33b in the U.S. Standard Atmosphere
|
||||
|
@ -173,6 +138,7 @@ double FGStandardAtmosphere::GetPressure(double altitude) const
|
|||
unsigned int b=0;
|
||||
double pressure = 0.0;
|
||||
double Lmb, Exp, Tmb, deltaH, factor;
|
||||
double numRows = StdAtmosTemperatureTable->GetNumRows();
|
||||
|
||||
// Iterate through the altitudes to find the current Base Altitude
|
||||
// in the table. That is, if the current altitude (the argument passed in)
|
||||
|
@ -180,9 +146,8 @@ double FGStandardAtmosphere::GetPressure(double altitude) const
|
|||
// passed-in altitude is 40000 ft, the base altitude is 36151.6 ft (and
|
||||
// the index "b" is 2 - the second entry in the table).
|
||||
double testAlt = (*StdAtmosTemperatureTable)(b+1,0);
|
||||
while (altitude >= testAlt) {
|
||||
while ((altitude >= testAlt) && (b <= numRows-2)) {
|
||||
b++;
|
||||
if (b+1 > StdAtmosTemperatureTable->GetNumRows()) break;
|
||||
testAlt = (*StdAtmosTemperatureTable)(b+1,0);
|
||||
}
|
||||
if (b>0) b--;
|
||||
|
@ -205,7 +170,7 @@ double FGStandardAtmosphere::GetPressure(double altitude) const
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGStandardAtmosphere::SetSeaLevelPressure(double pressure, ePressure unit)
|
||||
void FGStandardAtmosphere::SetPressureSL(double pressure, ePressure unit)
|
||||
{
|
||||
double press = ConvertToPSF(pressure, unit);
|
||||
|
||||
|
@ -285,30 +250,21 @@ double FGStandardAtmosphere::GetStdPressure100K(double altitude) const
|
|||
// Limit this equation to input altitudes of 100000 ft.
|
||||
if (altitude > 100000.0) altitude = 100000.0;
|
||||
|
||||
double alt[6];
|
||||
double coef[6] = { 2116.22,
|
||||
-7.583514352598E-02,
|
||||
1.045494405501E-06,
|
||||
-5.881341527124E-12,
|
||||
3.482031690718E-18,
|
||||
5.683922549284E-23 };
|
||||
double alt[5];
|
||||
const double coef[5] = { 2116.217,
|
||||
-7.648932746E-2,
|
||||
1.0925498604E-6,
|
||||
-7.1135726027E-12,
|
||||
1.7470331356E-17 };
|
||||
|
||||
alt[0] = 1;
|
||||
for (int pwr=1; pwr<=5; pwr++) alt[pwr] = alt[pwr-1]*altitude;
|
||||
for (int pwr=1; pwr<=4; pwr++) alt[pwr] = alt[pwr-1]*altitude;
|
||||
|
||||
double press = 0.0;
|
||||
for (int ctr=0; ctr<=5; ctr++) press += coef[ctr]*alt[ctr];
|
||||
for (int ctr=0; ctr<=4; ctr++) press += coef[ctr]*alt[ctr];
|
||||
return press;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// Get the modeled density at a specified altitude
|
||||
|
||||
double FGStandardAtmosphere::GetDensity(double altitude) const
|
||||
{
|
||||
return GetPressure(altitude)/(Reng * GetTemperature(altitude));
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// Get the standard density at a specified altitude
|
||||
|
||||
|
@ -319,9 +275,23 @@ double FGStandardAtmosphere::GetStdDensity(double altitude) const
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGStandardAtmosphere::SetTemperatureBias(double t, eTemperature unit)
|
||||
void FGStandardAtmosphere::SetTemperature(double t, double h, eTemperature unit)
|
||||
{
|
||||
TemperatureBias = ConvertToRankine(t, unit);
|
||||
double targetSLtemp = ConvertToRankine(t, unit);
|
||||
|
||||
TemperatureBias = 0.0;
|
||||
TemperatureBias = targetSLtemp - GetTemperature(h);
|
||||
CalculatePressureBreakpoints();
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGStandardAtmosphere::SetTemperatureBias(eTemperature unit, double t)
|
||||
{
|
||||
if (unit == eCelsius || unit == eKelvin)
|
||||
t *= 1.80; // If temp delta "t" is given in metric, scale up to English
|
||||
|
||||
TemperatureBias = t;
|
||||
CalculatePressureBreakpoints();
|
||||
}
|
||||
|
||||
|
@ -331,18 +301,15 @@ void FGStandardAtmosphere::SetTemperatureBias(double t, eTemperature unit)
|
|||
// Internally, the Rankine scale is used for calculations, so any temperature
|
||||
// supplied must be converted to that unit.
|
||||
|
||||
void FGStandardAtmosphere::SetSLTemperature(double t, eTemperature unit)
|
||||
void FGStandardAtmosphere::SetTemperatureSL(double t, eTemperature unit)
|
||||
{
|
||||
double targetSLtemp = ConvertToRankine(t, unit);
|
||||
|
||||
TemperatureBias = targetSLtemp - GetStdTemperatureSL();
|
||||
CalculatePressureBreakpoints();
|
||||
SetTemperature(t, 0.0, unit);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// Sets a Sea Level temperature delta that is ramped out by 86 km (282,152 ft).
|
||||
|
||||
void FGStandardAtmosphere::SetSLTemperatureGradedDelta(double deltemp, eTemperature unit)
|
||||
void FGStandardAtmosphere::SetSLTemperatureGradedDelta(eTemperature unit, double deltemp)
|
||||
{
|
||||
SetTemperatureGradedDelta(deltemp, 0.0, unit);
|
||||
}
|
||||
|
@ -356,12 +323,9 @@ void FGStandardAtmosphere::SetSLTemperatureGradedDelta(double deltemp, eTemperat
|
|||
|
||||
void FGStandardAtmosphere::SetTemperatureGradedDelta(double deltemp, double h, eTemperature unit)
|
||||
{
|
||||
switch(unit) {
|
||||
case eCelsius:
|
||||
case eKelvin:
|
||||
deltemp *= 9.0/5.0; // If temp delta is given in metric, scale up to English
|
||||
break;
|
||||
}
|
||||
if (unit == eCelsius || unit == eKelvin)
|
||||
deltemp *= 1.80; // If temp delta "t" is given in metric, scale up to English
|
||||
|
||||
TemperatureDeltaGradient = deltemp/(GradientFadeoutAltitude - h);
|
||||
CalculateLapseRates();
|
||||
CalculatePressureBreakpoints();
|
||||
|
@ -376,7 +340,7 @@ void FGStandardAtmosphere::SetTemperatureGradedDelta(double deltemp, double h, e
|
|||
for (int i=0; i<280000; i+=1000) {
|
||||
Calculate(i);
|
||||
std::cout << std::setw(12) << std::setprecision(2) << i
|
||||
<< " " << std::setw(9) << std::setprecision(2) << Temperature-459.67
|
||||
<< " " << std::setw(9) << std::setprecision(2) << Temperature - 459.67
|
||||
<< " " << std::setw(13) << std::setprecision(4) << Pressure
|
||||
<< " " << std::setw(18) << std::setprecision(8) << Density
|
||||
<< std::endl;
|
||||
|
@ -447,75 +411,16 @@ void FGStandardAtmosphere::ResetSLPressure()
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGStandardAtmosphere::ConvertToRankine(double t, eTemperature unit) const
|
||||
{
|
||||
double targetTemp=0; // in degrees Rankine
|
||||
|
||||
switch(unit) {
|
||||
case eFahrenheit:
|
||||
targetTemp = t + 459.67;
|
||||
break;
|
||||
case eCelsius:
|
||||
targetTemp = t*9.0/5.0 + 32.0 + 459.67;
|
||||
break;
|
||||
case eRankine:
|
||||
targetTemp = t;
|
||||
break;
|
||||
case eKelvin:
|
||||
targetTemp = t*9.0/5.0;
|
||||
}
|
||||
|
||||
return targetTemp;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGStandardAtmosphere::ConvertToPSF(double p, ePressure unit) const
|
||||
{
|
||||
double targetPressure=0; // Pressure in PSF
|
||||
|
||||
switch(unit) {
|
||||
case ePSF:
|
||||
targetPressure = p;
|
||||
break;
|
||||
case eMillibars:
|
||||
targetPressure = p*2.08854342;
|
||||
break;
|
||||
case ePascals:
|
||||
targetPressure = p*0.0208854342;
|
||||
break;
|
||||
case eInchesHg:
|
||||
targetPressure = p*70.7180803;
|
||||
break;
|
||||
default:
|
||||
throw("Undefined pressure unit given");
|
||||
}
|
||||
|
||||
return targetPressure;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGStandardAtmosphere::bind(void)
|
||||
{
|
||||
typedef double (FGStandardAtmosphere::*PMFi)(int) const;
|
||||
typedef void (FGStandardAtmosphere::*PMF)(int, double);
|
||||
PropertyManager->Tie("stdatmosphere/T-R", this, &FGStandardAtmosphere::GetTemperature);
|
||||
PropertyManager->Tie("stdatmosphere/rho-slugs_ft3", this, &FGStandardAtmosphere::GetDensity);
|
||||
PropertyManager->Tie("stdatmosphere/P-psf", this, &FGStandardAtmosphere::GetPressure);
|
||||
PropertyManager->Tie("stdatmosphere/a-fps", this, &FGStandardAtmosphere::GetSoundSpeed);
|
||||
PropertyManager->Tie("stdatmosphere/T-sl-R", this, &FGStandardAtmosphere::GetTemperatureSL);
|
||||
PropertyManager->Tie("stdatmosphere/rho-sl-slugs_ft3", this, &FGStandardAtmosphere::GetDensitySL);
|
||||
PropertyManager->Tie("stdatmosphere/P-sl-psf", this, &FGStandardAtmosphere::GetPressureSL);
|
||||
PropertyManager->Tie("stdatmosphere/a-sl-fps", this, &FGStandardAtmosphere::GetSoundSpeedSL);
|
||||
PropertyManager->Tie("stdatmosphere/theta", this, &FGStandardAtmosphere::GetTemperatureRatio);
|
||||
PropertyManager->Tie("stdatmosphere/sigma", this, &FGStandardAtmosphere::GetDensityRatio);
|
||||
PropertyManager->Tie("stdatmosphere/delta", this, &FGStandardAtmosphere::GetPressureRatio);
|
||||
PropertyManager->Tie("stdatmosphere/a-ratio", this, &FGStandardAtmosphere::GetSoundSpeedRatio);
|
||||
PropertyManager->Tie("stdatmosphere/delta-T", this, eRankine,
|
||||
PropertyManager->Tie("atmosphere/delta-T", this, eRankine,
|
||||
(PMFi)&FGStandardAtmosphere::GetTemperatureBias,
|
||||
(PMF)&FGStandardAtmosphere::SetTemperatureBias);
|
||||
// PropertyManager->Tie("atmosphere/density-altitude", this, &FGStandardAtmosphere::GetDensityAltitude);
|
||||
PropertyManager->Tie("atmosphere/SL-graded-delta-T", this, eRankine,
|
||||
(PMFi)&FGStandardAtmosphere::GetTemperatureDeltaGradient,
|
||||
(PMF)&FGStandardAtmosphere::SetSLTemperatureGradedDelta);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -39,14 +39,14 @@ INCLUDES
|
|||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include <vector>
|
||||
#include "models/FGModel.h"
|
||||
#include "math/FGTable.h"
|
||||
#include "models/FGAtmosphere.h"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_STANDARDATMOSPHERE "$Id: FGStandardAtmosphere.h,v 1.9 2011/06/13 12:06:21 jberndt Exp $"
|
||||
#define ID_STANDARDATMOSPHERE "$Id: FGStandardAtmosphere.h,v 1.15 2011/08/17 23:56:01 jberndt Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -88,51 +88,26 @@ and/or the sea level standard pressure, so that the entire profile will be
|
|||
consistently and accurately calculated.
|
||||
|
||||
<h2> Properties </h2>
|
||||
@property atmosphere/T-R The current modeled temperature in degrees Rankine.
|
||||
@property atmosphere/rho-slugs_ft3
|
||||
@property atmosphere/P-psf
|
||||
@property atmosphere/a-fps
|
||||
@property atmosphere/T-sl-R
|
||||
@property atmosphere/rho-sl-slugs_ft3
|
||||
@property atmosphere/P-sl-psf
|
||||
@property atmosphere/a-sl-fps
|
||||
@property atmosphere/theta
|
||||
@property atmosphere/sigma
|
||||
@property atmosphere/delta
|
||||
@property atmosphere/a-ratio
|
||||
@property atmosphere/delta-T
|
||||
@property atmosphere/T-sl-dev-F
|
||||
|
||||
@author Jon Berndt
|
||||
@see "U.S. Standard Atmosphere, 1976", NASA TM-X-74335
|
||||
@version $Id: FGStandardAtmosphere.h,v 1.9 2011/06/13 12:06:21 jberndt Exp $
|
||||
@version $Id: FGStandardAtmosphere.h,v 1.15 2011/08/17 23:56:01 jberndt Exp $
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS DECLARATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
class FGStandardAtmosphere : public FGModel {
|
||||
class FGStandardAtmosphere : public FGAtmosphere {
|
||||
public:
|
||||
|
||||
/// Enums for specifying temperature units.
|
||||
enum eTemperature {eNoTempUnit=0, eFahrenheit, eCelsius, eRankine, eKelvin};
|
||||
|
||||
/// Enums for specifying pressure units.
|
||||
enum ePressure {eNoPressUnit=0, ePSF, eMillibars, ePascals, eInchesHg};
|
||||
|
||||
/// Constructor
|
||||
FGStandardAtmosphere(FGFDMExec*);
|
||||
|
||||
/// Destructor
|
||||
~FGStandardAtmosphere();
|
||||
/** Runs the standard atmosphere forces model; called by the Executive.
|
||||
Can pass in a value indicating if the executive is directing the simulation to Hold.
|
||||
@param Holding if true, the executive has been directed to hold the sim from
|
||||
advancing time. Some models may ignore this flag, such as the Input
|
||||
model, which may need to be active to listen on a socket for the
|
||||
"Resume" command to be given.
|
||||
@return false if no error */
|
||||
bool Run(bool Holding);
|
||||
virtual ~FGStandardAtmosphere();
|
||||
|
||||
bool InitModel(void);
|
||||
|
||||
// *************************************************************************
|
||||
|
@ -145,19 +120,11 @@ public:
|
|||
/// at sea level can also be retrieved. These two temperatures DO include the
|
||||
/// effects of an optionally user-supplied bias or delta gradient.
|
||||
// @{
|
||||
/// Returns the actual, modeled temperature at the current altitude in degrees Rankine.
|
||||
/// @return Modeled temperature in degrees Rankine.
|
||||
virtual double GetTemperature() const {return Temperature;}
|
||||
|
||||
/// Returns the actual modeled temperature in degrees Rankine at a specified altitude.
|
||||
/// @param altitude The altitude above sea level (ASL) in feet.
|
||||
/// @return Modeled temperature in degrees Rankine at the specified altitude.
|
||||
virtual double GetTemperature(double altitude) const;
|
||||
|
||||
/// Returns the actual, modeled sea level temperature in degrees Rankine.
|
||||
/// @return The modeled temperature in degrees Rankine at sea level.
|
||||
virtual double GetTemperatureSL() const { return GetTemperature(0.0); }
|
||||
|
||||
/// Returns the standard temperature in degrees Rankine at a specified altitude.
|
||||
/// @param altitude The altitude in feet above sea level (ASL) to get the temperature at.
|
||||
/// @return The STANDARD temperature in degrees Rankine at the specified altitude.
|
||||
|
@ -167,14 +134,6 @@ public:
|
|||
/// @return The STANDARD temperature at sea level in degrees Rankine.
|
||||
virtual double GetStdTemperatureSL() const { return GetStdTemperature(0.0); }
|
||||
|
||||
/// Returns the ratio of the at-current-altitude temperature as modeled
|
||||
/// over the standard sea level value.
|
||||
virtual double GetTemperatureRatio() const { return GetTemperature()*rSLtemperature; }
|
||||
|
||||
/// Returns the ratio of the temperature as modeled at the supplied altitude
|
||||
/// over the standard sea level value.
|
||||
virtual double GetTemperatureRatio(double h) const { return GetTemperature(h)*rSLtemperature; }
|
||||
|
||||
/// Returns the ratio of the standard temperature at the supplied altitude
|
||||
/// over the standard sea level temperature.
|
||||
virtual double GetStdTemperatureRatio(double h) const { return GetStdTemperature(h)*rSLtemperature; }
|
||||
|
@ -194,17 +153,20 @@ public:
|
|||
/// this function.
|
||||
/// @param t the temperature value in the unit provided.
|
||||
/// @param unit the unit of the temperature.
|
||||
virtual void SetSLTemperature(double t, eTemperature unit=eFahrenheit);
|
||||
virtual void SetTemperatureSL(double t, eTemperature unit=eFahrenheit);
|
||||
|
||||
/// Sets the temperature at the supplied altitude, if it is to be different
|
||||
/// than the standard temperature.
|
||||
/// This function will calculate a bias - a difference - from the standard
|
||||
/// atmosphere temperature at the supplied altitude and will apply that
|
||||
/// calculated bias to the entire temperature profile.
|
||||
/// calculated bias to the entire temperature profile. If a graded delta is
|
||||
/// present, that will be included in the calculation - that is, regardless
|
||||
/// of any graded delta present, a temperature bias will be determined so that
|
||||
/// the temperature requested in this function call will be reached.
|
||||
/// @param t The temperature value in the unit provided.
|
||||
/// @param h The altitude in feet above sea level.
|
||||
/// @param unit The unit of the temperature.
|
||||
virtual void SetTemperature(double t, double h, eTemperature unit=eFahrenheit) {};
|
||||
virtual void SetTemperature(double t, double h, eTemperature unit=eFahrenheit);
|
||||
|
||||
/// Sets the temperature bias to be added to the standard temperature at all altitudes.
|
||||
/// This function sets the bias - the difference - from the standard
|
||||
|
@ -214,7 +176,7 @@ public:
|
|||
/// this function with a calculated bias.
|
||||
/// @param t the temperature value in the unit provided.
|
||||
/// @param unit the unit of the temperature.
|
||||
virtual void SetTemperatureBias(double t, eTemperature unit=eFahrenheit);
|
||||
virtual void SetTemperatureBias(eTemperature unit, double t);
|
||||
|
||||
/// Sets a Sea Level temperature delta that is ramped out by 86 km.
|
||||
/// The value of the delta is used to calculate a delta gradient that is
|
||||
|
@ -229,7 +191,7 @@ public:
|
|||
/// temperature profile as desired.
|
||||
/// @param t the sea level temperature delta value in the unit provided.
|
||||
/// @param unit the unit of the temperature.
|
||||
virtual void SetSLTemperatureGradedDelta(double t, eTemperature unit=eFahrenheit);
|
||||
virtual void SetSLTemperatureGradedDelta(eTemperature unit, double t);
|
||||
|
||||
/// Sets the temperature delta value at the supplied altitude/elevation above
|
||||
/// sea level, to be added to the standard temperature and ramped out by
|
||||
|
@ -250,9 +212,6 @@ public:
|
|||
// *************************************************************************
|
||||
/// @name Pressure access functions.
|
||||
//@{
|
||||
/// Returns the pressure in psf.
|
||||
virtual double GetPressure(void) const {return Pressure;}
|
||||
|
||||
/// Returns the pressure at a specified altitude in psf.
|
||||
virtual double GetPressure(double altitude) const;
|
||||
|
||||
|
@ -262,19 +221,13 @@ public:
|
|||
/// Returns the standard pressure at the specified altitude.
|
||||
virtual double GetStdPressure(double altitude) const;
|
||||
|
||||
/// Returns the sea level pressure in psf.
|
||||
virtual double GetPressureSL(void) const { return SLpressure; }
|
||||
|
||||
/// Returns the ratio of at-altitude pressure over the sea level value.
|
||||
virtual double GetPressureRatio(void) const { return Pressure*rSLpressure; }
|
||||
|
||||
/** Sets the sea level pressure for modeling an off-standard pressure
|
||||
profile. This could be useful in the case where the pressure at an
|
||||
airfield is known or set for a particular simulation run.
|
||||
@param pressure The pressure in the units specified (PSF by default).
|
||||
@param unit the unit of measure that the specified pressure is
|
||||
supplied in.*/
|
||||
virtual void SetSeaLevelPressure(double pressure, ePressure unit=ePSF);
|
||||
virtual void SetPressureSL(double pressure, ePressure unit=ePSF);
|
||||
|
||||
/** Resets the sea level to the Standard sea level pressure, and recalculates
|
||||
dependent parameters so that the pressure calculations are standard. */
|
||||
|
@ -284,60 +237,15 @@ public:
|
|||
// *************************************************************************
|
||||
/// @name Density access functions.
|
||||
//@{
|
||||
/** Returns the density in slugs/ft^3.
|
||||
This function may only be used if Run() is called first. */
|
||||
virtual double GetDensity(void) const {return Density;}
|
||||
|
||||
/** Returns the density in slugs/ft^3 at a given altitude in ft. */
|
||||
virtual double GetDensity(double altitude) const;
|
||||
|
||||
/// Returns the standard density at a specified altitude
|
||||
virtual double GetStdDensity(double altitude) const;
|
||||
|
||||
/// Returns the sea level density in slugs/ft^3
|
||||
virtual double GetDensitySL(void) const { return SLdensity; }
|
||||
|
||||
/// Returns the ratio of at-altitude density over the sea level value.
|
||||
virtual double GetDensityRatio(void) const { return Density*rSLdensity; }
|
||||
//@}
|
||||
|
||||
// *************************************************************************
|
||||
/// @name Speed of sound access functions.
|
||||
//@{
|
||||
/// Returns the speed of sound in ft/sec.
|
||||
virtual double GetSoundSpeed(void) const {return Soundspeed;}
|
||||
|
||||
/// Returns the sea level speed of sound in ft/sec.
|
||||
virtual double GetSoundSpeedSL(void) const { return SLsoundspeed; }
|
||||
|
||||
/// Returns the ratio of at-altitude sound speed over the sea level value.
|
||||
virtual double GetSoundSpeedRatio(void) const { return Soundspeed*rSLsoundspeed; }
|
||||
//@}
|
||||
|
||||
// *************************************************************************
|
||||
/// @name Viscosity access functions.
|
||||
//@{
|
||||
/// Returns the absolute viscosity.
|
||||
virtual double GetAbsoluteViscosity(void) const {return Viscosity;}
|
||||
|
||||
/// Returns the kinematic viscosity.
|
||||
virtual double GetKinematicViscosity(void) const {return KinematicViscosity;}
|
||||
//@}
|
||||
|
||||
/* /// Gets the density altitude in feet */
|
||||
// virtual double GetDensityAltitude(void) const { return density_altitude; }
|
||||
|
||||
/// Prints the U.S. Standard Atmosphere table.
|
||||
virtual void PrintStandardAtmosphereTable();
|
||||
|
||||
protected:
|
||||
double StdSLtemperature, StdSLdensity, StdSLpressure, StdSLsoundspeed; // Standard sea level conditions
|
||||
double SLtemperature, SLdensity, SLpressure, SLsoundspeed; // Sea level conditions
|
||||
double Temperature, Density, Pressure, Soundspeed; // Current actual conditions at altitude
|
||||
double rSLtemperature, rSLdensity, rSLpressure, rSLsoundspeed; // Reciprocal of sea level conditions
|
||||
|
||||
double PressureAltitude;
|
||||
double DensityAltitude;
|
||||
|
||||
double TemperatureBias;
|
||||
double TemperatureDeltaGradient;
|
||||
|
@ -347,12 +255,6 @@ protected:
|
|||
std::vector<double> LapseRateVector;
|
||||
std::vector<double> PressureBreakpointVector;
|
||||
|
||||
const double SutherlandConstant, Beta;
|
||||
double Viscosity, KinematicViscosity;
|
||||
|
||||
/// Calculate the atmosphere for the given altitude, including effects of temperature deviation.
|
||||
void Calculate(double altitude);
|
||||
|
||||
/// Recalculate the lapse rate vectors when the temperature profile is altered
|
||||
/// in a way that would change the lapse rates, such as when a gradient is applied.
|
||||
/// This function is also called to initialize the lapse rate vector.
|
||||
|
@ -362,12 +264,6 @@ protected:
|
|||
/// altitudes in the standard temperature table.
|
||||
void CalculatePressureBreakpoints();
|
||||
|
||||
// Converts to Rankine from one of several unit systems.
|
||||
virtual double ConvertToRankine(double t, eTemperature unit) const;
|
||||
|
||||
// Converts to PSF (pounds per square foot) from one of several unit systems.
|
||||
virtual double ConvertToPSF(double t, ePressure unit=ePSF) const;
|
||||
|
||||
virtual void bind(void);
|
||||
void Debug(int from);
|
||||
};
|
||||
|
|
553
src/FDM/JSBSim/models/atmosphere/FGWinds.cpp
Normal file
553
src/FDM/JSBSim/models/atmosphere/FGWinds.cpp
Normal file
|
@ -0,0 +1,553 @@
|
|||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
Module: FGWinds.cpp
|
||||
Author: Jon Berndt, Tony Peden, Andreas Gaeb
|
||||
Date started: Extracted from FGAtmosphere, which originated in 1998
|
||||
5/2011
|
||||
Purpose: Models winds, gusts, turbulence, and other atmospheric disturbances
|
||||
Called by: FGFDMExec
|
||||
|
||||
------------- Copyright (C) 2011 Jon S. Berndt (jon@jsbsim.org) -------------
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the Free Software
|
||||
Foundation; either version 2 of the License, or (at your option) any later
|
||||
version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Further information about the GNU Lesser General Public License can also be found on
|
||||
the world wide web at http://www.gnu.org.
|
||||
|
||||
FUNCTIONAL DESCRIPTION
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
HISTORY
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
COMMENTS, REFERENCES, and NOTES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
[1] Anderson, John D. "Introduction to Flight, Third Edition", McGraw-Hill,
|
||||
1989, ISBN 0-07-001641-0
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
#include "FGWinds.h"
|
||||
#include "FGFDMExec.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGWinds.cpp,v 1.4 2011/09/07 02:37:04 jberndt Exp $";
|
||||
static const char *IdHdr = ID_WINDS;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS IMPLEMENTATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// square a value, but preserve the original sign
|
||||
|
||||
static inline double square_signed (double value)
|
||||
{
|
||||
if (value < 0)
|
||||
return value * value * -1;
|
||||
else
|
||||
return value * value;
|
||||
}
|
||||
|
||||
/// simply square a value
|
||||
static inline double sqr(double x) { return x*x; }
|
||||
|
||||
FGWinds::FGWinds(FGFDMExec* fdmex) : FGModel(fdmex)
|
||||
{
|
||||
Name = "FGWinds";
|
||||
|
||||
MagnitudedAccelDt = MagnitudeAccel = Magnitude = 0.0;
|
||||
SetTurbType( ttMilspec );
|
||||
TurbGain = 1.0;
|
||||
TurbRate = 10.0;
|
||||
Rhythmicity = 0.1;
|
||||
spike = target_time = strength = 0.0;
|
||||
wind_from_clockwise = 0.0;
|
||||
psiw = 0.0;
|
||||
|
||||
vGustNED.InitMatrix();
|
||||
vTurbulenceNED.InitMatrix();
|
||||
|
||||
// Milspec turbulence model
|
||||
windspeed_at_20ft = 0.;
|
||||
probability_of_exceedence_index = 0;
|
||||
POE_Table = new FGTable(7,12);
|
||||
// this is Figure 7 from p. 49 of MIL-F-8785C
|
||||
// rows: probability of exceedance curve index, cols: altitude in ft
|
||||
*POE_Table
|
||||
<< 500.0 << 1750.0 << 3750.0 << 7500.0 << 15000.0 << 25000.0 << 35000.0 << 45000.0 << 55000.0 << 65000.0 << 75000.0 << 80000.0
|
||||
<< 1 << 3.2 << 2.2 << 1.5 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0
|
||||
<< 2 << 4.2 << 3.6 << 3.3 << 1.6 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0
|
||||
<< 3 << 6.6 << 6.9 << 7.4 << 6.7 << 4.6 << 2.7 << 0.4 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0
|
||||
<< 4 << 8.6 << 9.6 << 10.6 << 10.1 << 8.0 << 6.6 << 5.0 << 4.2 << 2.7 << 0.0 << 0.0 << 0.0
|
||||
<< 5 << 11.8 << 13.0 << 16.0 << 15.1 << 11.6 << 9.7 << 8.1 << 8.2 << 7.9 << 4.9 << 3.2 << 2.1
|
||||
<< 6 << 15.6 << 17.6 << 23.0 << 23.6 << 22.1 << 20.0 << 16.0 << 15.1 << 12.1 << 7.9 << 6.2 << 5.1
|
||||
<< 7 << 18.7 << 21.5 << 28.4 << 30.2 << 30.7 << 31.0 << 25.2 << 23.1 << 17.5 << 10.7 << 8.4 << 7.2;
|
||||
|
||||
bind();
|
||||
Debug(0);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
FGWinds::~FGWinds()
|
||||
{
|
||||
delete(POE_Table);
|
||||
Debug(1);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
bool FGWinds::InitModel(void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
bool FGWinds::Run(bool Holding)
|
||||
{
|
||||
if (FGModel::Run(Holding)) return true;
|
||||
if (Holding) return false;
|
||||
|
||||
RunPreFunctions();
|
||||
|
||||
if (turbType != ttNone) Turbulence(in.AltitudeASL);
|
||||
if (oneMinusCosineGust.gustProfile.Running) CosineGust();
|
||||
|
||||
vTotalWindNED = vWindNED + vGustNED + vCosineGust + vTurbulenceNED;
|
||||
|
||||
// psiw (Wind heading) is the direction the wind is blowing towards
|
||||
if (vWindNED(eX) != 0.0) psiw = atan2( vWindNED(eY), vWindNED(eX) );
|
||||
if (psiw < 0) psiw += 2*M_PI;
|
||||
|
||||
RunPostFunctions();
|
||||
|
||||
Debug(2);
|
||||
return false;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
//
|
||||
// psi is the angle that the wind is blowing *towards*
|
||||
|
||||
void FGWinds::SetWindspeed(double speed)
|
||||
{
|
||||
if (vWindNED.Magnitude() == 0.0) {
|
||||
psiw = 0.0;
|
||||
vWindNED(eNorth) = speed;
|
||||
} else {
|
||||
vWindNED(eNorth) = speed * cos(psiw);
|
||||
vWindNED(eEast) = speed * sin(psiw);
|
||||
vWindNED(eDown) = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGWinds::GetWindspeed(void) const
|
||||
{
|
||||
return vWindNED.Magnitude();
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
//
|
||||
// psi is the angle that the wind is blowing *towards*
|
||||
|
||||
void FGWinds::SetWindPsi(double dir)
|
||||
{
|
||||
double mag = GetWindspeed();
|
||||
psiw = dir;
|
||||
SetWindspeed(mag);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGWinds::Turbulence(double h)
|
||||
{
|
||||
switch (turbType) {
|
||||
|
||||
case ttCulp: {
|
||||
|
||||
vTurbPQR(eP) = wind_from_clockwise;
|
||||
if (TurbGain == 0.0) return;
|
||||
|
||||
// keep the inputs within allowable limts for this model
|
||||
if (TurbGain < 0.0) TurbGain = 0.0;
|
||||
if (TurbGain > 1.0) TurbGain = 1.0;
|
||||
if (TurbRate < 0.0) TurbRate = 0.0;
|
||||
if (TurbRate > 30.0) TurbRate = 30.0;
|
||||
if (Rhythmicity < 0.0) Rhythmicity = 0.0;
|
||||
if (Rhythmicity > 1.0) Rhythmicity = 1.0;
|
||||
|
||||
// generate a sine wave corresponding to turbulence rate in hertz
|
||||
double time = FDMExec->GetSimTime();
|
||||
double sinewave = sin( time * TurbRate * 6.283185307 );
|
||||
|
||||
double random = 0.0;
|
||||
if (target_time == 0.0) {
|
||||
strength = random = 1 - 2.0*(double(rand())/double(RAND_MAX));
|
||||
target_time = time + 0.71 + (random * 0.5);
|
||||
}
|
||||
if (time > target_time) {
|
||||
spike = 1.0;
|
||||
target_time = 0.0;
|
||||
}
|
||||
|
||||
// max vertical wind speed in fps, corresponds to TurbGain = 1.0
|
||||
double max_vs = 40;
|
||||
|
||||
vTurbulenceNED(1) = vTurbulenceNED(2) = vTurbulenceNED(3) = 0.0;
|
||||
double delta = strength * max_vs * TurbGain * (1-Rhythmicity) * spike;
|
||||
|
||||
// Vertical component of turbulence.
|
||||
vTurbulenceNED(3) = sinewave * max_vs * TurbGain * Rhythmicity;
|
||||
vTurbulenceNED(3)+= delta;
|
||||
if (in.DistanceAGL/in.wingspan < 3.0)
|
||||
vTurbulenceNED(3) *= in.DistanceAGL/in.wingspan * 0.3333;
|
||||
|
||||
// Yaw component of turbulence.
|
||||
vTurbulenceNED(1) = sin( delta * 3.0 );
|
||||
vTurbulenceNED(2) = cos( delta * 3.0 );
|
||||
|
||||
// Roll component of turbulence. Clockwise vortex causes left roll.
|
||||
vTurbPQR(eP) += delta * 0.04;
|
||||
|
||||
spike = spike * 0.9;
|
||||
break;
|
||||
}
|
||||
case ttMilspec:
|
||||
case ttTustin: {
|
||||
|
||||
// an index of zero means turbulence is disabled
|
||||
// airspeed occurs as divisor in the code below
|
||||
if (probability_of_exceedence_index == 0 || in.V == 0) {
|
||||
vTurbulenceNED(1) = vTurbulenceNED(2) = vTurbulenceNED(3) = 0.0;
|
||||
vTurbPQR(1) = vTurbPQR(2) = vTurbPQR(3) = 0.0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Turbulence model according to MIL-F-8785C (Flying Qualities of Piloted Aircraft)
|
||||
double b_w = in.wingspan, L_u, L_w, sig_u, sig_w;
|
||||
|
||||
if (b_w == 0.) b_w = 30.;
|
||||
|
||||
// clip height functions at 10 ft
|
||||
if (h <= 10.) h = 10;
|
||||
|
||||
// Scale lengths L and amplitudes sigma as function of height
|
||||
if (h <= 1000) {
|
||||
L_u = h/pow(0.177 + 0.000823*h, 1.2); // MIL-F-8785c, Fig. 10, p. 55
|
||||
L_w = h;
|
||||
sig_w = 0.1*windspeed_at_20ft;
|
||||
sig_u = sig_w/pow(0.177 + 0.000823*h, 0.4); // MIL-F-8785c, Fig. 11, p. 56
|
||||
} else if (h <= 2000) {
|
||||
// linear interpolation between low altitude and high altitude models
|
||||
L_u = L_w = 1000 + (h-1000.)/1000.*750.;
|
||||
sig_u = sig_w = 0.1*windspeed_at_20ft
|
||||
+ (h-1000.)/1000.*(POE_Table->GetValue(probability_of_exceedence_index, h) - 0.1*windspeed_at_20ft);
|
||||
} else {
|
||||
L_u = L_w = 1750.; // MIL-F-8785c, Sec. 3.7.2.1, p. 48
|
||||
sig_u = sig_w = POE_Table->GetValue(probability_of_exceedence_index, h);
|
||||
}
|
||||
|
||||
// keep values from last timesteps
|
||||
// TODO maybe use deque?
|
||||
static double
|
||||
xi_u_km1 = 0, nu_u_km1 = 0,
|
||||
xi_v_km1 = 0, xi_v_km2 = 0, nu_v_km1 = 0, nu_v_km2 = 0,
|
||||
xi_w_km1 = 0, xi_w_km2 = 0, nu_w_km1 = 0, nu_w_km2 = 0,
|
||||
xi_p_km1 = 0, nu_p_km1 = 0,
|
||||
xi_q_km1 = 0, xi_r_km1 = 0;
|
||||
|
||||
|
||||
double
|
||||
T_V = in.totalDeltaT, // for compatibility of nomenclature
|
||||
sig_p = 1.9/sqrt(L_w*b_w)*sig_w, // Yeager1998, eq. (8)
|
||||
sig_q = sqrt(M_PI/2/L_w/b_w), // eq. (14)
|
||||
sig_r = sqrt(2*M_PI/3/L_w/b_w), // eq. (17)
|
||||
L_p = sqrt(L_w*b_w)/2.6, // eq. (10)
|
||||
tau_u = L_u/in.V, // eq. (6)
|
||||
tau_w = L_w/in.V, // eq. (3)
|
||||
tau_p = L_p/in.V, // eq. (9)
|
||||
tau_q = 4*b_w/M_PI/in.V, // eq. (13)
|
||||
tau_r =3*b_w/M_PI/in.V, // eq. (17)
|
||||
nu_u = GaussianRandomNumber(),
|
||||
nu_v = GaussianRandomNumber(),
|
||||
nu_w = GaussianRandomNumber(),
|
||||
nu_p = GaussianRandomNumber(),
|
||||
xi_u=0, xi_v=0, xi_w=0, xi_p=0, xi_q=0, xi_r=0;
|
||||
|
||||
// values of turbulence NED velocities
|
||||
|
||||
if (turbType == ttTustin) {
|
||||
// the following is the Tustin formulation of Yeager's report
|
||||
double
|
||||
omega_w = in.V/L_w, // hidden in nomenclature p. 3
|
||||
omega_v = in.V/L_u, // this is defined nowhere
|
||||
C_BL = 1/tau_u/tan(T_V/2/tau_u), // eq. (19)
|
||||
C_BLp = 1/tau_p/tan(T_V/2/tau_p), // eq. (22)
|
||||
C_BLq = 1/tau_q/tan(T_V/2/tau_q), // eq. (24)
|
||||
C_BLr = 1/tau_r/tan(T_V/2/tau_r); // eq. (26)
|
||||
|
||||
// all values calculated so far are strictly positive, except for
|
||||
// the random numbers nu_*. This means that in the code below, all
|
||||
// divisors are strictly positive, too, and no floating point
|
||||
// exception should occur.
|
||||
xi_u = -(1 - C_BL*tau_u)/(1 + C_BL*tau_u)*xi_u_km1
|
||||
+ sig_u*sqrt(2*tau_u/T_V)/(1 + C_BL*tau_u)*(nu_u + nu_u_km1); // eq. (18)
|
||||
xi_v = -2*(sqr(omega_v) - sqr(C_BL))/sqr(omega_v + C_BL)*xi_v_km1
|
||||
- sqr(omega_v - C_BL)/sqr(omega_v + C_BL) * xi_v_km2
|
||||
+ sig_u*sqrt(3*omega_v/T_V)/sqr(omega_v + C_BL)*(
|
||||
(C_BL + omega_v/sqrt(3.))*nu_v
|
||||
+ 2/sqrt(3.)*omega_v*nu_v_km1
|
||||
+ (omega_v/sqrt(3.) - C_BL)*nu_v_km2); // eq. (20) for v
|
||||
xi_w = -2*(sqr(omega_w) - sqr(C_BL))/sqr(omega_w + C_BL)*xi_w_km1
|
||||
- sqr(omega_w - C_BL)/sqr(omega_w + C_BL) * xi_w_km2
|
||||
+ sig_w*sqrt(3*omega_w/T_V)/sqr(omega_w + C_BL)*(
|
||||
(C_BL + omega_w/sqrt(3.))*nu_w
|
||||
+ 2/sqrt(3.)*omega_w*nu_w_km1
|
||||
+ (omega_w/sqrt(3.) - C_BL)*nu_w_km2); // eq. (20) for w
|
||||
xi_p = -(1 - C_BLp*tau_p)/(1 + C_BLp*tau_p)*xi_p_km1
|
||||
+ sig_p*sqrt(2*tau_p/T_V)/(1 + C_BLp*tau_p) * (nu_p + nu_p_km1); // eq. (21)
|
||||
xi_q = -(1 - 4*b_w*C_BLq/M_PI/in.V)/(1 + 4*b_w*C_BLq/M_PI/in.V) * xi_q_km1
|
||||
+ C_BLq/in.V/(1 + 4*b_w*C_BLq/M_PI/in.V) * (xi_w - xi_w_km1); // eq. (23)
|
||||
xi_r = - (1 - 3*b_w*C_BLr/M_PI/in.V)/(1 + 3*b_w*C_BLr/M_PI/in.V) * xi_r_km1
|
||||
+ C_BLr/in.V/(1 + 3*b_w*C_BLr/M_PI/in.V) * (xi_v - xi_v_km1); // eq. (25)
|
||||
|
||||
} else if (turbType == ttMilspec) {
|
||||
// the following is the MIL-STD-1797A formulation
|
||||
// as cited in Yeager's report
|
||||
xi_u = (1 - T_V/tau_u) *xi_u_km1 + sig_u*sqrt(2*T_V/tau_u)*nu_u; // eq. (30)
|
||||
xi_v = (1 - 2*T_V/tau_u)*xi_v_km1 + sig_u*sqrt(4*T_V/tau_u)*nu_v; // eq. (31)
|
||||
xi_w = (1 - 2*T_V/tau_w)*xi_w_km1 + sig_w*sqrt(4*T_V/tau_w)*nu_w; // eq. (32)
|
||||
xi_p = (1 - T_V/tau_p) *xi_p_km1 + sig_p*sqrt(2*T_V/tau_p)*nu_p; // eq. (33)
|
||||
xi_q = (1 - T_V/tau_q) *xi_q_km1 + M_PI/4/b_w*(xi_w - xi_w_km1); // eq. (34)
|
||||
xi_r = (1 - T_V/tau_r) *xi_r_km1 + M_PI/3/b_w*(xi_v - xi_v_km1); // eq. (35)
|
||||
}
|
||||
|
||||
// rotate by wind azimuth and assign the velocities
|
||||
double cospsi = cos(psiw), sinpsi = sin(psiw);
|
||||
vTurbulenceNED(1) = cospsi*xi_u + sinpsi*xi_v;
|
||||
vTurbulenceNED(2) = -sinpsi*xi_u + cospsi*xi_v;
|
||||
vTurbulenceNED(3) = xi_w;
|
||||
|
||||
vTurbPQR(1) = cospsi*xi_p + sinpsi*xi_q;
|
||||
vTurbPQR(2) = -sinpsi*xi_p + cospsi*xi_q;
|
||||
vTurbPQR(3) = xi_r;
|
||||
|
||||
// vTurbPQR is in the body fixed frame, not NED
|
||||
vTurbPQR = in.Tl2b*vTurbPQR;
|
||||
|
||||
// hand on the values for the next timestep
|
||||
xi_u_km1 = xi_u; nu_u_km1 = nu_u;
|
||||
xi_v_km2 = xi_v_km1; xi_v_km1 = xi_v; nu_v_km2 = nu_v_km1; nu_v_km1 = nu_v;
|
||||
xi_w_km2 = xi_w_km1; xi_w_km1 = xi_w; nu_w_km2 = nu_w_km1; nu_w_km1 = nu_w;
|
||||
xi_p_km1 = xi_p; nu_p_km1 = nu_p;
|
||||
xi_q_km1 = xi_q;
|
||||
xi_r_km1 = xi_r;
|
||||
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGWinds::CosineGustProfile(double startDuration, double steadyDuration, double endDuration, double elapsedTime)
|
||||
{
|
||||
double factor = 0.0;
|
||||
if (elapsedTime >= 0 && elapsedTime <= startDuration) {
|
||||
factor = (1.0 - cos(M_PI*elapsedTime/startDuration))/2.0;
|
||||
} else if (elapsedTime > startDuration && (elapsedTime <= (startDuration + steadyDuration))) {
|
||||
factor = 1.0;
|
||||
} else if (elapsedTime > (startDuration + steadyDuration) && elapsedTime <= (startDuration + steadyDuration + endDuration)) {
|
||||
factor = (1-cos(M_PI*(1-(elapsedTime-(startDuration + steadyDuration))/endDuration)))/2.0;
|
||||
} else {
|
||||
factor = 0.0;
|
||||
}
|
||||
|
||||
return factor;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGWinds::CosineGust()
|
||||
{
|
||||
struct OneMinusCosineProfile& profile = oneMinusCosineGust.gustProfile;
|
||||
|
||||
double factor = CosineGustProfile( profile.startupDuration,
|
||||
profile.steadyDuration,
|
||||
profile.endDuration,
|
||||
profile.elapsedTime);
|
||||
// Normalize the gust wind vector
|
||||
oneMinusCosineGust.vWind.Normalize();
|
||||
|
||||
if (oneMinusCosineGust.vWindTransformed.Magnitude() == 0.0) {
|
||||
switch (oneMinusCosineGust.gustFrame) {
|
||||
case gfBody:
|
||||
oneMinusCosineGust.vWindTransformed = in.Tl2b.Inverse() * oneMinusCosineGust.vWind;
|
||||
break;
|
||||
case gfWind:
|
||||
oneMinusCosineGust.vWindTransformed = in.Tl2b.Inverse() * in.Tw2b * oneMinusCosineGust.vWind;
|
||||
break;
|
||||
case gfLocal:
|
||||
// this is the native frame - and the default.
|
||||
oneMinusCosineGust.vWindTransformed = oneMinusCosineGust.vWind;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
vCosineGust = factor * oneMinusCosineGust.vWindTransformed * oneMinusCosineGust.magnitude;
|
||||
|
||||
profile.elapsedTime += in.totalDeltaT;
|
||||
|
||||
if (profile.elapsedTime > (profile.startupDuration + profile.steadyDuration + profile.endDuration)) {
|
||||
profile.Running = false;
|
||||
profile.elapsedTime = 0.0;
|
||||
oneMinusCosineGust.vWindTransformed.InitMatrix(0.0);
|
||||
vCosineGust.InitMatrix(0);
|
||||
}
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGWinds::bind(void)
|
||||
{
|
||||
typedef double (FGWinds::*PMF)(int) const;
|
||||
typedef int (FGWinds::*PMFt)(void) const;
|
||||
typedef void (FGWinds::*PMFd)(int,double);
|
||||
typedef void (FGWinds::*PMFi)(int);
|
||||
typedef double (FGWinds::*Ptr)(void) const;
|
||||
|
||||
// User-specified steady, constant, wind properties (local navigational/geographic frame: N-E-D)
|
||||
PropertyManager->Tie("atmosphere/psiw-rad", this, &FGWinds::GetWindPsi, &FGWinds::SetWindPsi);
|
||||
PropertyManager->Tie("atmosphere/wind-north-fps", this, eNorth, (PMF)&FGWinds::GetWindNED,
|
||||
(PMFd)&FGWinds::SetWindNED);
|
||||
PropertyManager->Tie("atmosphere/wind-east-fps", this, eEast, (PMF)&FGWinds::GetWindNED,
|
||||
(PMFd)&FGWinds::SetWindNED);
|
||||
PropertyManager->Tie("atmosphere/wind-down-fps", this, eDown, (PMF)&FGWinds::GetWindNED,
|
||||
(PMFd)&FGWinds::SetWindNED);
|
||||
PropertyManager->Tie("atmosphere/wind-mag-fps", this, &FGWinds::GetWindspeed,
|
||||
&FGWinds::SetWindspeed);
|
||||
|
||||
// User-specifieded gust (local navigational/geographic frame: N-E-D)
|
||||
PropertyManager->Tie("atmosphere/gust-north-fps", this, eNorth, (PMF)&FGWinds::GetGustNED,
|
||||
(PMFd)&FGWinds::SetGustNED);
|
||||
PropertyManager->Tie("atmosphere/gust-east-fps", this, eEast, (PMF)&FGWinds::GetGustNED,
|
||||
(PMFd)&FGWinds::SetGustNED);
|
||||
PropertyManager->Tie("atmosphere/gust-down-fps", this, eDown, (PMF)&FGWinds::GetGustNED,
|
||||
(PMFd)&FGWinds::SetGustNED);
|
||||
|
||||
// User-specified 1 - cosine gust parameters (in specified frame)
|
||||
PropertyManager->Tie("atmosphere/cosine-gust/startup-duration-sec", this, (Ptr)0L, &FGWinds::StartupGustDuration);
|
||||
PropertyManager->Tie("atmosphere/cosine-gust/steady-duration-sec", this, (Ptr)0L, &FGWinds::SteadyGustDuration);
|
||||
PropertyManager->Tie("atmosphere/cosine-gust/end-duration-sec", this, (Ptr)0L, &FGWinds::EndGustDuration);
|
||||
PropertyManager->Tie("atmosphere/cosine-gust/magnitude-ft_sec", this, (Ptr)0L, &FGWinds::GustMagnitude);
|
||||
PropertyManager->Tie("atmosphere/cosine-gust/frame", this, (PMFt)0L, (PMFi)&FGWinds::GustFrame);
|
||||
PropertyManager->Tie("atmosphere/cosine-gust/X-velocity-ft_sec", this, (Ptr)0L, &FGWinds::GustXComponent);
|
||||
PropertyManager->Tie("atmosphere/cosine-gust/Y-velocity-ft_sec", this, (Ptr)0L, &FGWinds::GustYComponent);
|
||||
PropertyManager->Tie("atmosphere/cosine-gust/Z-velocity-ft_sec", this, (Ptr)0L, &FGWinds::GustZComponent);
|
||||
PropertyManager->Tie("atmosphere/cosine-gust/start", this, (PMFt)0L, (PMFi)&FGWinds::StartGust);
|
||||
|
||||
// User-specified turbulence (local navigational/geographic frame: N-E-D)
|
||||
PropertyManager->Tie("atmosphere/turb-north-fps", this, eNorth, (PMF)&FGWinds::GetTurbNED,
|
||||
(PMFd)&FGWinds::SetTurbNED);
|
||||
PropertyManager->Tie("atmosphere/turb-east-fps", this, eEast, (PMF)&FGWinds::GetTurbNED,
|
||||
(PMFd)&FGWinds::SetTurbNED);
|
||||
PropertyManager->Tie("atmosphere/turb-down-fps", this, eDown, (PMF)&FGWinds::GetTurbNED,
|
||||
(PMFd)&FGWinds::SetTurbNED);
|
||||
// Experimental turbulence parameters
|
||||
PropertyManager->Tie("atmosphere/p-turb-rad_sec", this,1, (PMF)&FGWinds::GetTurbPQR);
|
||||
PropertyManager->Tie("atmosphere/q-turb-rad_sec", this,2, (PMF)&FGWinds::GetTurbPQR);
|
||||
PropertyManager->Tie("atmosphere/r-turb-rad_sec", this,3, (PMF)&FGWinds::GetTurbPQR);
|
||||
PropertyManager->Tie("atmosphere/turb-type", this, (PMFt)&FGWinds::GetTurbType, (PMFi)&FGWinds::SetTurbType);
|
||||
PropertyManager->Tie("atmosphere/turb-rate", this, &FGWinds::GetTurbRate, &FGWinds::SetTurbRate);
|
||||
PropertyManager->Tie("atmosphere/turb-gain", this, &FGWinds::GetTurbGain, &FGWinds::SetTurbGain);
|
||||
PropertyManager->Tie("atmosphere/turb-rhythmicity", this, &FGWinds::GetRhythmicity,
|
||||
&FGWinds::SetRhythmicity);
|
||||
|
||||
// Parameters for milspec turbulence
|
||||
PropertyManager->Tie("atmosphere/turbulence/milspec/windspeed_at_20ft_AGL-fps",
|
||||
this, &FGWinds::GetWindspeed20ft,
|
||||
&FGWinds::SetWindspeed20ft);
|
||||
PropertyManager->Tie("atmosphere/turbulence/milspec/severity",
|
||||
this, &FGWinds::GetProbabilityOfExceedence,
|
||||
&FGWinds::SetProbabilityOfExceedence);
|
||||
|
||||
// Total, calculated winds (local navigational/geographic frame: N-E-D). Read only.
|
||||
PropertyManager->Tie("atmosphere/total-wind-north-fps", this, eNorth, (PMF)&FGWinds::GetTotalWindNED);
|
||||
PropertyManager->Tie("atmosphere/total-wind-east-fps", this, eEast, (PMF)&FGWinds::GetTotalWindNED);
|
||||
PropertyManager->Tie("atmosphere/total-wind-down-fps", this, eDown, (PMF)&FGWinds::GetTotalWindNED);
|
||||
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// The bitmasked value choices are as follows:
|
||||
// unset: In this case (the default) JSBSim would only print
|
||||
// out the normally expected messages, essentially echoing
|
||||
// the config files as they are read. If the environment
|
||||
// variable is not set, debug_lvl is set to 1 internally
|
||||
// 0: This requests JSBSim not to output any messages
|
||||
// whatsoever.
|
||||
// 1: This value explicity requests the normal JSBSim
|
||||
// startup messages
|
||||
// 2: This value asks for a message to be printed out when
|
||||
// a class is instantiated
|
||||
// 4: When this value is set, a message is displayed when a
|
||||
// FGModel object executes its Run() method
|
||||
// 8: When this value is set, various runtime state variables
|
||||
// are printed out periodically
|
||||
// 16: When set various parameters are sanity checked and
|
||||
// a message is printed out when they go out of bounds
|
||||
|
||||
void FGWinds::Debug(int from)
|
||||
{
|
||||
if (debug_lvl <= 0) return;
|
||||
|
||||
if (debug_lvl & 1) { // Standard console startup message output
|
||||
if (from == 0) { // Constructor
|
||||
}
|
||||
}
|
||||
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
|
||||
if (from == 0) cout << "Instantiated: FGWinds" << endl;
|
||||
if (from == 1) cout << "Destroyed: FGWinds" << endl;
|
||||
}
|
||||
if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
|
||||
}
|
||||
if (debug_lvl & 8 ) { // Runtime state variables
|
||||
}
|
||||
if (debug_lvl & 16) { // Sanity checking
|
||||
}
|
||||
if (debug_lvl & 128) { //
|
||||
}
|
||||
if (debug_lvl & 64) {
|
||||
if (from == 0) { // Constructor
|
||||
cout << IdSrc << endl;
|
||||
cout << IdHdr << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace JSBSim
|
349
src/FDM/JSBSim/models/atmosphere/FGWinds.h
Normal file
349
src/FDM/JSBSim/models/atmosphere/FGWinds.h
Normal file
|
@ -0,0 +1,349 @@
|
|||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
Header: FGWinds.h
|
||||
Author: Jon Berndt, Andreas Gaeb, David Culp
|
||||
Date started: 5/2011
|
||||
|
||||
------------- Copyright (C) 2011 Jon S. Berndt (jon@jsbsim.org) -------------
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the Free Software
|
||||
Foundation; either version 2 of the License, or (at your option) any later
|
||||
version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Further information about the GNU Lesser General Public License can also be found on
|
||||
the world wide web at http://www.gnu.org.
|
||||
|
||||
HISTORY
|
||||
--------------------------------------------------------------------------------
|
||||
5/2011 JSB Created
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
SENTRY
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#ifndef FGWINDS_H
|
||||
#define FGWINDS_H
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include "models/FGModel.h"
|
||||
#include "math/FGColumnVector3.h"
|
||||
#include "math/FGMatrix33.h"
|
||||
#include "math/FGTable.h"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_WINDS "$Id: FGWinds.h,v 1.5 2011/09/07 12:21:45 jberndt Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS DOCUMENTATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
/** Models atmospheric disturbances: winds, gusts, turbulence, downbursts, etc.
|
||||
|
||||
Various turbulence models are available. They are specified
|
||||
via the property <tt>atmosphere/turb-type</tt>. The following models are
|
||||
available:
|
||||
- 0: ttNone (turbulence disabled)
|
||||
- 1: ttStandard
|
||||
- 2: ttCulp
|
||||
- 3: ttMilspec (Dryden spectrum)
|
||||
- 4: ttTustin (Dryden spectrum)
|
||||
|
||||
The Milspec and Tustin models are described in the Yeager report cited below.
|
||||
They both use a Dryden spectrum model whose parameters (scale lengths and intensities)
|
||||
are modelled according to MIL-F-8785C. Parameters are modelled differently
|
||||
for altitudes below 1000ft and above 2000ft, for altitudes in between they
|
||||
are interpolated linearly.
|
||||
|
||||
The two models differ in the implementation of the transfer functions
|
||||
described in the milspec.
|
||||
|
||||
To use one of these two models, set <tt>atmosphere/turb-type</tt> to 4 resp. 5,
|
||||
and specify values for <tt>atmosphere/turbulence/milspec/windspeed_at_20ft_AGL-fps<tt>
|
||||
and <tt>atmosphere/turbulence/milspec/severity<tt> (the latter corresponds to
|
||||
the probability of exceedence curves from Fig. 7 of the milspec, allowable
|
||||
range is 0 (disabled) to 7). <tt>atmosphere/psiw-rad</tt> is respected as well;
|
||||
note that you have to specify a positive wind magnitude to prevent psiw from
|
||||
being reset to zero.
|
||||
|
||||
Reference values (cf. figures 7 and 9 from the milspec):
|
||||
<table>
|
||||
<tr><td><b>Intensity</b></td>
|
||||
<td><b><tt>windspeed_at_20ft_AGL-fps</tt></b></td>
|
||||
<td><b><tt>severity</tt></b></td></tr>
|
||||
<tr><td>light</td>
|
||||
<td>25 (15 knots)</td>
|
||||
<td>3</td></tr>
|
||||
<tr><td>moderate</td>
|
||||
<td>50 (30 knots)</td>
|
||||
<td>4</td></tr>
|
||||
<tr><td>severe</td>
|
||||
<td>75 (45 knots)</td>
|
||||
<td>6</td></tr>
|
||||
</table>
|
||||
|
||||
@see Yeager, Jessie C.: "Implementation and Testing of Turbulence Models for
|
||||
the F18-HARV" (<a
|
||||
href="http://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19980028448_1998081596.pdf">
|
||||
pdf</a>), NASA CR-1998-206937, 1998
|
||||
|
||||
@see MIL-F-8785C: Military Specification: Flying Qualities of Piloted Aircraft
|
||||
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS DECLARATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
class FGWinds : public FGModel {
|
||||
public:
|
||||
|
||||
/// Constructor
|
||||
FGWinds(FGFDMExec*);
|
||||
/// Destructor
|
||||
~FGWinds();
|
||||
/** Runs the winds model; called by the Executive
|
||||
Can pass in a value indicating if the executive is directing the simulation to Hold.
|
||||
@param Holding if true, the executive has been directed to hold the sim from
|
||||
advancing time. Some models may ignore this flag, such as the Input
|
||||
model, which may need to be active to listen on a socket for the
|
||||
"Resume" command to be given.
|
||||
@return false if no error */
|
||||
bool Run(bool Holding);
|
||||
bool InitModel(void);
|
||||
enum tType {ttNone, ttStandard, ttCulp, ttMilspec, ttTustin} turbType;
|
||||
|
||||
// TOTAL WIND access functions (wind + gust + turbulence)
|
||||
|
||||
/// Retrieves the total wind components in NED frame.
|
||||
virtual const FGColumnVector3& GetTotalWindNED(void) const { return vTotalWindNED; }
|
||||
|
||||
/// Retrieves a total wind component in NED frame.
|
||||
virtual double GetTotalWindNED(int idx) const {return vTotalWindNED(idx);}
|
||||
|
||||
// WIND access functions
|
||||
|
||||
/// Sets the wind components in NED frame.
|
||||
virtual void SetWindNED(double wN, double wE, double wD) { vWindNED(1)=wN; vWindNED(2)=wE; vWindNED(3)=wD;}
|
||||
|
||||
/// Sets a wind component in NED frame.
|
||||
virtual void SetWindNED(int idx, double wind) { vWindNED(idx)=wind;}
|
||||
|
||||
/// Retrieves the wind components in NED frame.
|
||||
virtual FGColumnVector3& GetWindNED(void) { return vWindNED; }
|
||||
|
||||
/// Retrieves a wind component in NED frame.
|
||||
virtual double GetWindNED(int idx) const {return vWindNED(idx);}
|
||||
|
||||
/** Retrieves the direction that the wind is coming from.
|
||||
The direction is defined as north=0 and increases counterclockwise.
|
||||
The wind heading is returned in radians.*/
|
||||
virtual double GetWindPsi(void) const { return psiw; }
|
||||
|
||||
/** Sets the direction that the wind is coming from.
|
||||
The direction is defined as north=0 and increases counterclockwise to 2*pi (radians). The
|
||||
vertical component of wind is assumed to be zero - and is forcibly set to zero. This function
|
||||
sets the vWindNED vector components based on the supplied direction. The magnitude of
|
||||
the wind set in the vector is preserved (assuming the vertical component is non-zero).
|
||||
@param dir wind direction in the horizontal plane, in radians.*/
|
||||
virtual void SetWindPsi(double dir);
|
||||
|
||||
virtual void SetWindspeed(double speed);
|
||||
|
||||
virtual double GetWindspeed(void) const;
|
||||
|
||||
// GUST access functions
|
||||
|
||||
/// Sets a gust component in NED frame.
|
||||
virtual void SetGustNED(int idx, double gust) { vGustNED(idx)=gust;}
|
||||
|
||||
/// Sets a turbulence component in NED frame.
|
||||
virtual void SetTurbNED(int idx, double turb) { vTurbulenceNED(idx)=turb;}
|
||||
|
||||
/// Sets the gust components in NED frame.
|
||||
virtual void SetGustNED(double gN, double gE, double gD) { vGustNED(eNorth)=gN; vGustNED(eEast)=gE; vGustNED(eDown)=gD;}
|
||||
|
||||
/// Retrieves a gust component in NED frame.
|
||||
virtual double GetGustNED(int idx) const {return vGustNED(idx);}
|
||||
|
||||
/// Retrieves a turbulence component in NED frame.
|
||||
virtual double GetTurbNED(int idx) const {return vTurbulenceNED(idx);}
|
||||
|
||||
/// Retrieves the gust components in NED frame.
|
||||
virtual FGColumnVector3& GetGustNED(void) {return vGustNED;}
|
||||
|
||||
/** Turbulence models available: ttNone, ttStandard, ttBerndt, ttCulp, ttMilspec, ttTustin */
|
||||
virtual void SetTurbType(tType tt) {turbType = tt;}
|
||||
virtual tType GetTurbType() const {return turbType;}
|
||||
|
||||
virtual void SetTurbGain(double tg) {TurbGain = tg;}
|
||||
virtual double GetTurbGain() const {return TurbGain;}
|
||||
|
||||
virtual void SetTurbRate(double tr) {TurbRate = tr;}
|
||||
virtual double GetTurbRate() const {return TurbRate;}
|
||||
|
||||
virtual void SetRhythmicity(double r) {Rhythmicity=r;}
|
||||
virtual double GetRhythmicity() const {return Rhythmicity;}
|
||||
|
||||
virtual double GetTurbPQR(int idx) const {return vTurbPQR(idx);}
|
||||
virtual double GetTurbMagnitude(void) const {return Magnitude;}
|
||||
virtual const FGColumnVector3& GetTurbDirection(void) const {return vDirection;}
|
||||
virtual const FGColumnVector3& GetTurbPQR(void) const {return vTurbPQR;}
|
||||
|
||||
virtual void SetWindspeed20ft(double ws) { windspeed_at_20ft = ws;}
|
||||
virtual double GetWindspeed20ft() const { return windspeed_at_20ft;}
|
||||
|
||||
/// allowable range: 0-7, 3=light, 4=moderate, 6=severe turbulence
|
||||
virtual void SetProbabilityOfExceedence( int idx) {probability_of_exceedence_index = idx;}
|
||||
virtual int GetProbabilityOfExceedence() const { return probability_of_exceedence_index;}
|
||||
|
||||
// Stores data defining a 1 - cosine gust profile that builds up, holds steady
|
||||
// and fades out over specified durations.
|
||||
struct OneMinusCosineProfile {
|
||||
bool Running; ///<- This flag is set true through FGWinds::StartGust().
|
||||
double elapsedTime; ///<- Stores the elapsed time for the ongoing gust.
|
||||
double startupDuration; ///<- Specifies the time it takes for the gust startup transient.
|
||||
double steadyDuration; ///<- Specifies the duration of the steady gust.
|
||||
double endDuration; ///<- Specifies the time it takes for the gust to subsude.
|
||||
OneMinusCosineProfile() ///<- The constructor.
|
||||
{
|
||||
elapsedTime = 0.0;
|
||||
Running = false;
|
||||
startupDuration = 2;
|
||||
steadyDuration = 4;
|
||||
endDuration = 2;
|
||||
}
|
||||
};
|
||||
|
||||
enum eGustFrame {gfNone=0, gfBody, gfWind, gfLocal};
|
||||
|
||||
/// Stores the information about a single one minus cosine gust instance.
|
||||
struct OneMinusCosineGust {
|
||||
FGColumnVector3 vWind; ///<- The input normalized wind vector.
|
||||
FGColumnVector3 vWindTransformed; ///<- The transformed normal vector at the time the gust is started.
|
||||
double magnitude; ///<- The magnitude of the wind vector.
|
||||
eGustFrame gustFrame; ///<- The frame that the wind vector is specified in.
|
||||
struct OneMinusCosineProfile gustProfile; ///<- The gust shape (profile) data for this gust.
|
||||
OneMinusCosineGust() ///<- Constructor.
|
||||
{
|
||||
vWind.InitMatrix(0.0);
|
||||
gustFrame = gfLocal;
|
||||
magnitude = 1.0;
|
||||
};
|
||||
};
|
||||
|
||||
/// Stores information about a specified Up- or Down-burst.
|
||||
struct UpDownBurst {
|
||||
double ringLatitude; ///<- The latitude of the downburst run (radians)
|
||||
double ringLongitude; ///<- The longitude of the downburst run (radians)
|
||||
double ringAltitude; ///<- The altitude of the ring (feet).
|
||||
double ringRadius; ///<- The radius of the ring (feet).
|
||||
double ringCoreRadius; ///<- The cross-section "core" radius of the ring (feet).
|
||||
double circulation; ///<- The circulation (gamma) (feet-squared per second).
|
||||
struct OneMinusCosineProfile oneMCosineProfile;
|
||||
};
|
||||
|
||||
// 1 - Cosine gust setters
|
||||
/// Initiates the execution of the gust.
|
||||
virtual void StartGust(bool running) {oneMinusCosineGust.gustProfile.Running = running;}
|
||||
///Specifies the duration of the startup portion of the gust.
|
||||
virtual void StartupGustDuration(double dur) {oneMinusCosineGust.gustProfile.startupDuration = dur;}
|
||||
///Specifies the length of time that the gust is at a steady, full strength.
|
||||
virtual void SteadyGustDuration(double dur) {oneMinusCosineGust.gustProfile.steadyDuration = dur;}
|
||||
/// Specifies the length of time it takes for the gust to return to zero velocity.
|
||||
virtual void EndGustDuration(double dur) {oneMinusCosineGust.gustProfile.endDuration = dur;}
|
||||
/// Specifies the magnitude of the gust in feet/second.
|
||||
virtual void GustMagnitude(double mag) {oneMinusCosineGust.magnitude = mag;}
|
||||
/** Specifies the frame that the gust direction vector components are specified in. The
|
||||
body frame is defined with the X direction forward, and the Y direction positive out
|
||||
the right wing. The wind frame is defined with the X axis pointing into the velocity
|
||||
vector, the Z axis perpendicular to the X axis, in the aircraft XZ plane, and the Y
|
||||
axis completing the system. The local axis is a navigational frame with X pointing north,
|
||||
Y pointing east, and Z pointing down. This is a locally vertical, locally horizontal
|
||||
frame, with the XY plane tangent to the geocentric surface. */
|
||||
virtual void GustFrame(eGustFrame gFrame) {oneMinusCosineGust.gustFrame = gFrame;}
|
||||
/// Specifies the X component of velocity in the specified gust frame (ft/sec).
|
||||
virtual void GustXComponent(double x) {oneMinusCosineGust.vWind(eX) = x;}
|
||||
/// Specifies the Y component of velocity in the specified gust frame (ft/sec).
|
||||
virtual void GustYComponent(double y) {oneMinusCosineGust.vWind(eY) = y;}
|
||||
/// Specifies the Z component of velocity in the specified gust frame (ft/sec).
|
||||
virtual void GustZComponent(double z) {oneMinusCosineGust.vWind(eZ) = z;}
|
||||
|
||||
struct Inputs {
|
||||
double V;
|
||||
double wingspan;
|
||||
double DistanceAGL;
|
||||
double AltitudeASL;
|
||||
FGMatrix33 Tl2b;
|
||||
FGMatrix33 Tw2b;
|
||||
double totalDeltaT;
|
||||
} in;
|
||||
|
||||
private:
|
||||
|
||||
double MagnitudedAccelDt, MagnitudeAccel, Magnitude;
|
||||
double h;
|
||||
double TurbGain;
|
||||
double TurbRate;
|
||||
double Rhythmicity;
|
||||
double wind_from_clockwise;
|
||||
double spike, target_time, strength;
|
||||
FGColumnVector3 vDirectiondAccelDt;
|
||||
FGColumnVector3 vDirectionAccel;
|
||||
FGColumnVector3 vDirection;
|
||||
FGColumnVector3 vTurbulenceGrad;
|
||||
FGColumnVector3 vBodyTurbGrad;
|
||||
FGColumnVector3 vTurbPQR;
|
||||
|
||||
struct OneMinusCosineGust oneMinusCosineGust;
|
||||
|
||||
// Dryden turbulence model
|
||||
double windspeed_at_20ft; ///< in ft/s
|
||||
int probability_of_exceedence_index; ///< this is bound as the severity property
|
||||
FGTable *POE_Table; ///< probability of exceedence table
|
||||
|
||||
double psiw;
|
||||
FGColumnVector3 vTotalWindNED;
|
||||
FGColumnVector3 vWindNED;
|
||||
FGColumnVector3 vGustNED;
|
||||
FGColumnVector3 vCosineGust;
|
||||
FGColumnVector3 vBurstGust;
|
||||
FGColumnVector3 vTurbulenceNED;
|
||||
|
||||
/// Get T, P and rho for a standard atmosphere at the given altitude.
|
||||
void Turbulence(double h);
|
||||
|
||||
void CosineGust();
|
||||
double CosineGustProfile( double startDuration, double steadyDuration,
|
||||
double endDuration, double elapsedTime);
|
||||
|
||||
virtual void bind(void);
|
||||
void Debug(int from);
|
||||
};
|
||||
|
||||
} // namespace JSBSim
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
#endif
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
noinst_LIBRARIES = libAtmosphere.a
|
||||
|
||||
libAtmosphere_a_SOURCES = FGMSIS.cpp FGMSISData.cpp FGMars.cpp
|
||||
libAtmosphere_a_SOURCES = FGMSIS.cpp FGMSISData.cpp FGMars.cpp FGStandardAtmosphere.cpp FGWinds.cpp
|
||||
|
||||
noinst_HEADERS = FGMSIS.h FGMars.h
|
||||
noinst_HEADERS = FGMSIS.h FGMars.h FGStandardAtmosphere.h FGWinds.h
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/src/FDM/JSBSim
|
||||
|
|
12
src/FDM/JSBSim/models/flight_control/FGAccelerometer.cpp
Normal file → Executable file
12
src/FDM/JSBSim/models/flight_control/FGAccelerometer.cpp
Normal file → Executable file
|
@ -41,11 +41,16 @@ INCLUDES
|
|||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "models/FGPropagate.h"
|
||||
#include "models/FGAccelerations.h"
|
||||
#include "models/FGMassBalance.h"
|
||||
#include "models/FGInertial.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGAccelerometer.cpp,v 1.8 2009/10/24 22:59:30 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGAccelerometer.cpp,v 1.9 2011/07/17 13:51:23 jberndt Exp $";
|
||||
static const char *IdHdr = ID_ACCELEROMETER;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -57,6 +62,7 @@ FGAccelerometer::FGAccelerometer(FGFCS* fcs, Element* element)
|
|||
FGSensorOrientation(element)
|
||||
{
|
||||
Propagate = fcs->GetExec()->GetPropagate();
|
||||
Accelerations = fcs->GetExec()->GetAccelerations();
|
||||
MassBalance = fcs->GetExec()->GetMassBalance();
|
||||
Inertial = fcs->GetExec()->GetInertial();
|
||||
|
||||
|
@ -88,8 +94,8 @@ bool FGAccelerometer::Run(void )
|
|||
vAccel = Propagate->GetTl2b() * FGColumnVector3(0, 0, Inertial->gravity());
|
||||
|
||||
//aircraft forces
|
||||
vAccel += (Propagate->GetUVWdot()
|
||||
+ Propagate->GetPQRdot() * vRadius
|
||||
vAccel += (Accelerations->GetUVWdot()
|
||||
+ Accelerations->GetPQRdot() * vRadius
|
||||
+ Propagate->GetPQR() * (Propagate->GetPQR() * vRadius));
|
||||
|
||||
// transform to the specified orientation
|
||||
|
|
12
src/FDM/JSBSim/models/flight_control/FGAccelerometer.h
Normal file → Executable file
12
src/FDM/JSBSim/models/flight_control/FGAccelerometer.h
Normal file → Executable file
|
@ -39,9 +39,6 @@ INCLUDES
|
|||
|
||||
#include "FGSensor.h"
|
||||
#include "input_output/FGXMLElement.h"
|
||||
#include "models/FGPropagate.h"
|
||||
#include "models/FGMassBalance.h"
|
||||
#include "models/FGInertial.h"
|
||||
#include "math/FGColumnVector3.h"
|
||||
#include "math/FGMatrix33.h"
|
||||
#include "FGSensorOrientation.h"
|
||||
|
@ -50,7 +47,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_ACCELEROMETER "$Id: FGAccelerometer.h,v 1.4 2009/10/02 10:30:09 jberndt Exp $"
|
||||
#define ID_ACCELEROMETER "$Id: FGAccelerometer.h,v 1.5 2011/07/17 13:51:23 jberndt Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -59,6 +56,10 @@ FORWARD DECLARATIONS
|
|||
namespace JSBSim {
|
||||
|
||||
class FGFCS;
|
||||
class FGPropagate;
|
||||
class FGAccelerations;
|
||||
class FGInertial;
|
||||
class FGMassBalance;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS DOCUMENTATION
|
||||
|
@ -110,7 +111,7 @@ even varying all the way from 0.95 to 1.05 in adjacent frames - whatever the del
|
|||
time.
|
||||
|
||||
@author Jon S. Berndt
|
||||
@version $Revision: 1.4 $
|
||||
@version $Revision: 1.5 $
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -127,6 +128,7 @@ public:
|
|||
|
||||
private:
|
||||
FGPropagate* Propagate;
|
||||
FGAccelerations* Accelerations;
|
||||
FGMassBalance* MassBalance;
|
||||
FGInertial* Inertial;
|
||||
FGColumnVector3 vLocation;
|
||||
|
|
|
@ -43,7 +43,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGActuator.cpp,v 1.21 2011/06/30 03:16:10 jentron Exp $";
|
||||
static const char *IdSrc = "$Id: FGActuator.cpp,v 1.22 2011/07/12 21:40:32 jentron Exp $";
|
||||
static const char *IdHdr = ID_ACTUATOR;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -65,6 +65,7 @@ FGActuator::FGActuator(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, eleme
|
|||
rate_limit = 0.0; // no limit
|
||||
fail_zero = fail_hardover = fail_stuck = false;
|
||||
ca = cb = 0.0;
|
||||
initialized = 0;
|
||||
|
||||
if ( element->FindElement("deadband_width") ) {
|
||||
deadband_width = element->FindElementValueAsNumber("deadband_width");
|
||||
|
@ -104,6 +105,8 @@ bool FGActuator::Run(void )
|
|||
{
|
||||
Input = InputNodes[0]->getDoubleValue() * InputSigns[0];
|
||||
|
||||
if( fcs->GetTrimStatus() ) initialized = 0;
|
||||
|
||||
if (fail_zero) Input = 0;
|
||||
if (fail_hardover) Input = clipmax*sign(Input);
|
||||
|
||||
|
@ -125,6 +128,8 @@ bool FGActuator::Run(void )
|
|||
}
|
||||
|
||||
PreviousOutput = Output; // previous value needed for "stuck" malfunction
|
||||
|
||||
initialized = 1;
|
||||
|
||||
Clip();
|
||||
if (IsOutput) SetOutput();
|
||||
|
@ -147,7 +152,7 @@ void FGActuator::Lag(void)
|
|||
// for this Lag filter
|
||||
double input = Output;
|
||||
|
||||
if (!fcs->GetTrimStatus())
|
||||
if ( initialized )
|
||||
Output = ca * (input + PreviousLagInput) + PreviousLagOutput * cb;
|
||||
|
||||
PreviousLagInput = input;
|
||||
|
@ -163,7 +168,7 @@ void FGActuator::Hysteresis(void)
|
|||
// method.
|
||||
double input = Output;
|
||||
|
||||
if (!fcs->GetTrimStatus()) {
|
||||
if ( initialized ) {
|
||||
if (input > PreviousHystOutput)
|
||||
Output = max(PreviousHystOutput, input-0.5*hysteresis_width);
|
||||
else if (input < PreviousHystOutput)
|
||||
|
@ -181,7 +186,7 @@ void FGActuator::RateLimit(void)
|
|||
// is - for the purposes of this RateLimit method - really the input to the
|
||||
// method.
|
||||
double input = Output;
|
||||
if (!fcs->GetTrimStatus()) {
|
||||
if ( initialized ) {
|
||||
double delta = input - PreviousRateLimOutput;
|
||||
if (fabs(delta) > dt * rate_limit) {
|
||||
double signed_rate_limit = delta > 0.0 ? rate_limit : -rate_limit;
|
||||
|
|
|
@ -44,7 +44,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_ACTUATOR "$Id: FGActuator.h,v 1.11 2009/10/02 10:30:09 jberndt Exp $"
|
||||
#define ID_ACTUATOR "$Id: FGActuator.h,v 1.12 2011/07/12 21:40:32 jentron Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -81,7 +81,7 @@ Syntax:
|
|||
<actuator name="name">
|
||||
<input> {[-]property} </input>
|
||||
<lag> number </lag>
|
||||
<rate_limit> number <rate_limit>
|
||||
<rate_limit> number </rate_limit>
|
||||
<bias> number </bias>
|
||||
<deadband_width> number </deadband_width>
|
||||
<hysteresis_width> number </hysteresis_width>
|
||||
|
@ -96,14 +96,14 @@ Syntax:
|
|||
Example:
|
||||
|
||||
@code
|
||||
<actuator name="fcs/gimbal_pitch_position">
|
||||
<actuator name="fcs/gimbal_pitch_position_radians">
|
||||
<input> fcs/gimbal_pitch_command </input>
|
||||
<lag> 60 </lag>
|
||||
<rate_limit> 0.085 <rate_limit> <!-- 5 degrees/sec -->
|
||||
<rate_limit> 0.085 </rate_limit> <!-- 0.085 radians/sec -->
|
||||
<bias> 0.002 </bias>
|
||||
<deadband_width> 0.002 </deadband_width>
|
||||
<hysteresis_width> 0.05 </hysteresis_width>
|
||||
<clipto> <!-- +/- 10 degrees -->
|
||||
<clipto> <!-- +/- 0.17 radians -->
|
||||
<min> -0.17 </min>
|
||||
<max> 0.17 </max>
|
||||
</clipto>
|
||||
|
@ -111,7 +111,7 @@ Example:
|
|||
@endcode
|
||||
|
||||
@author Jon S. Berndt
|
||||
@version $Revision: 1.11 $
|
||||
@version $Revision: 1.12 $
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -160,6 +160,7 @@ private:
|
|||
bool fail_zero;
|
||||
bool fail_hardover;
|
||||
bool fail_stuck;
|
||||
bool initialized;
|
||||
|
||||
void Hysteresis(void);
|
||||
void Lag(void);
|
||||
|
|
8
src/FDM/JSBSim/models/flight_control/FGGyro.cpp
Normal file → Executable file
8
src/FDM/JSBSim/models/flight_control/FGGyro.cpp
Normal file → Executable file
|
@ -40,11 +40,13 @@ INCLUDES
|
|||
#include "FGGyro.h"
|
||||
#include <iostream>
|
||||
|
||||
#include "models/FGAccelerations.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGGyro.cpp,v 1.5 2009/10/24 22:59:30 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGGyro.cpp,v 1.6 2011/07/17 13:51:23 jberndt Exp $";
|
||||
static const char *IdHdr = ID_GYRO;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -54,7 +56,7 @@ CLASS IMPLEMENTATION
|
|||
FGGyro::FGGyro(FGFCS* fcs, Element* element) : FGSensor(fcs, element),
|
||||
FGSensorOrientation(element)
|
||||
{
|
||||
Propagate = fcs->GetExec()->GetPropagate();
|
||||
Accelerations = fcs->GetExec()->GetAccelerations();
|
||||
|
||||
Debug(0);
|
||||
}
|
||||
|
@ -73,7 +75,7 @@ bool FGGyro::Run(void )
|
|||
// There is no input assumed. This is a dedicated angular acceleration sensor.
|
||||
|
||||
//aircraft rates
|
||||
vAccel = mT * Propagate->GetPQRdot();
|
||||
vAccel = mT * Accelerations->GetPQRdot();
|
||||
|
||||
Input = vAccel(axis);
|
||||
|
||||
|
|
10
src/FDM/JSBSim/models/flight_control/FGGyro.h
Normal file → Executable file
10
src/FDM/JSBSim/models/flight_control/FGGyro.h
Normal file → Executable file
|
@ -39,9 +39,6 @@ INCLUDES
|
|||
|
||||
#include "FGSensor.h"
|
||||
#include "input_output/FGXMLElement.h"
|
||||
#include "models/FGPropagate.h"
|
||||
#include "models/FGMassBalance.h"
|
||||
#include "models/FGInertial.h"
|
||||
#include "math/FGColumnVector3.h"
|
||||
#include "math/FGMatrix33.h"
|
||||
#include "FGSensorOrientation.h"
|
||||
|
@ -50,7 +47,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_GYRO "$Id: FGGyro.h,v 1.5 2009/12/11 06:03:06 jberndt Exp $"
|
||||
#define ID_GYRO "$Id: FGGyro.h,v 1.6 2011/07/17 13:51:23 jberndt Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -59,6 +56,7 @@ FORWARD DECLARATIONS
|
|||
namespace JSBSim {
|
||||
|
||||
class FGFCS;
|
||||
class FGAccelerations;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS DOCUMENTATION
|
||||
|
@ -106,7 +104,7 @@ even varying all the way from 0.95 to 1.05 in adjacent frames - whatever the del
|
|||
time.
|
||||
|
||||
@author Jon S. Berndt
|
||||
@version $Revision: 1.5 $
|
||||
@version $Revision: 1.6 $
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -122,7 +120,7 @@ public:
|
|||
bool Run (void);
|
||||
|
||||
private:
|
||||
FGPropagate* Propagate;
|
||||
FGAccelerations* Accelerations;
|
||||
FGColumnVector3 vAccel;
|
||||
void CalculateTransformMatrix(void);
|
||||
|
||||
|
|
4
src/FDM/JSBSim/models/flight_control/FGSensor.cpp
Normal file → Executable file
4
src/FDM/JSBSim/models/flight_control/FGSensor.cpp
Normal file → Executable file
|
@ -46,7 +46,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGSensor.cpp,v 1.20 2009/10/24 22:59:30 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGSensor.cpp,v 1.23 2011/08/18 12:42:17 jberndt Exp $";
|
||||
static const char *IdHdr = ID_SENSOR;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -181,7 +181,7 @@ void FGSensor::Noise(void)
|
|||
double random_value=0.0;
|
||||
|
||||
if (DistributionType == eUniform) {
|
||||
random_value = ((double)rand()/(double)RAND_MAX) - 0.5;
|
||||
random_value = 2.0*(((double)rand()/(double)RAND_MAX) - 0.5);
|
||||
} else {
|
||||
random_value = GaussianRandomNumber();
|
||||
}
|
||||
|
|
34
src/FDM/JSBSim/models/flight_control/FGSensor.h
Normal file → Executable file
34
src/FDM/JSBSim/models/flight_control/FGSensor.h
Normal file → Executable file
|
@ -44,7 +44,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_SENSOR "$Id: FGSensor.h,v 1.19 2009/10/24 22:59:30 jberndt Exp $"
|
||||
#define ID_SENSOR "$Id: FGSensor.h,v 1.20 2011/08/18 12:42:17 jberndt Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -67,7 +67,7 @@ Syntax:
|
|||
<sensor name="name">
|
||||
<input> property </input>
|
||||
<lag> number </lag>
|
||||
<noise variation="PERCENT|ABSOLUTE"> number </noise>
|
||||
<noise [variation="PERCENT|ABSOLUTE"] [distribution="UNIFORM|GAUSSIAN"]> number </noise>
|
||||
<quantization name="name">
|
||||
<bits> number </bits>
|
||||
<min> number </min>
|
||||
|
@ -98,16 +98,32 @@ Example:
|
|||
The only required element in the sensor definition is the input element. In that
|
||||
case, no degradation would be modeled, and the output would simply be the input.
|
||||
|
||||
For noise, if the type is PERCENT, then the value supplied is understood to be a
|
||||
percentage variance. That is, if the number given is 0.05, the the variance is
|
||||
understood to be +/-0.05 percent maximum variance. So, the actual value for the sensor
|
||||
will be *anywhere* from 0.95 to 1.05 of the actual "perfect" value at any time -
|
||||
even varying all the way from 0.95 to 1.05 in adjacent frames - whatever the delta
|
||||
time. The delay element can specify a frame delay. The integer number provided is
|
||||
Noise can be Gaussian or uniform, and the noise can be applied as a factor (PERCENT)
|
||||
or additively (ABSOLUTE). The noise that can be applied at each frame of the
|
||||
simulation execution is calculated as a random factor times a noise value that
|
||||
is specified in the config file. When the noise distribution type is Gaussian,
|
||||
the random number can be between roughly -3 and +3 for a span of six sigma. When
|
||||
the distribution type is UNIFORM, the random value can be between -1.0 and +1.0.
|
||||
This random value is multiplied against the specified noise to arrive at a random
|
||||
noise value for the frame. If the noise type is PERCENT, then random noise value
|
||||
is added to one, and that sum is then multiplied against the input signal for the
|
||||
sensor. In this case, the specified noise value in the config file would be
|
||||
expected to actually be a percent value, such as 0.05 (for a 5% variance). If the
|
||||
noise type is ABSOLUTE, then the random noise value specified in the config file
|
||||
is understood to be an absolute value of noise to be added to the input signal
|
||||
instead of being added to 1.0 and having that sum be multiplied against the input
|
||||
signal as in the PERCENT type. For the ABSOLUTE noise case, the noise number
|
||||
specified in the config file could be any number.
|
||||
|
||||
If the type is ABSOLUTE, then the noise number times the random number is
|
||||
added to the input signal instead of being multiplied against it as with the
|
||||
PERCENT type of noise.
|
||||
|
||||
The delay element can specify a frame delay. The integer number provided is
|
||||
the number of frames to delay the output signal.
|
||||
|
||||
@author Jon S. Berndt
|
||||
@version $Revision: 1.19 $
|
||||
@version $Revision: 1.20 $
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -2,13 +2,13 @@ noinst_LIBRARIES = libFlightControl.a
|
|||
|
||||
libFlightControl_a_SOURCES = \
|
||||
FGPID.cpp FGDeadBand.cpp FGFCSComponent.cpp \
|
||||
FGFilter.cpp FGGain.cpp FGGradient.cpp FGKinemat.cpp \
|
||||
FGFilter.cpp FGGain.cpp FGKinemat.cpp \
|
||||
FGSummer.cpp FGSwitch.cpp FGFCSFunction.cpp FGSensor.cpp \
|
||||
FGActuator.cpp FGAccelerometer.cpp FGGyro.cpp FGMagnetometer.cpp
|
||||
|
||||
noinst_HEADERS = \
|
||||
FGPID.h FGDeadBand.h FGFCSComponent.h FGFilter.h \
|
||||
FGGain.h FGGradient.h FGKinemat.h FGSummer.h FGSwitch.h FGFCSFunction.h\
|
||||
FGGain.h FGKinemat.h FGSummer.h FGSwitch.h FGFCSFunction.h\
|
||||
FGSensor.h FGActuator.h FGAccelerometer.h FGGyro.h FGMagnetometer.h \
|
||||
FGSensorOrientation.h
|
||||
|
||||
|
|
|
@ -39,27 +39,25 @@ HISTORY
|
|||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include "FGElectric.h"
|
||||
#include "models/FGPropulsion.h"
|
||||
#include "models/propulsion/FGThruster.h"
|
||||
#include "FGPropeller.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "FGElectric.h"
|
||||
#include "FGPropeller.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGElectric.cpp,v 1.11 2011/06/06 22:35:08 jentron Exp $";
|
||||
static const char *IdSrc = "$Id: FGElectric.cpp,v 1.13 2011/08/03 03:21:06 jberndt Exp $";
|
||||
static const char *IdHdr = ID_ELECTRIC;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS IMPLEMENTATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
FGElectric::FGElectric(FGFDMExec* exec, Element *el, int engine_number)
|
||||
: FGEngine(exec, el, engine_number)
|
||||
FGElectric::FGElectric(FGFDMExec* exec, Element *el, int engine_number, struct FGEngine::Inputs& input)
|
||||
: FGEngine(exec, el, engine_number, input)
|
||||
{
|
||||
string token;
|
||||
|
||||
|
@ -67,8 +65,6 @@ FGElectric::FGElectric(FGFDMExec* exec, Element *el, int engine_number)
|
|||
PowerWatts = 745.7;
|
||||
hptowatts = 745.7;
|
||||
|
||||
dt = FDMExec->GetDeltaT();
|
||||
|
||||
if (el->FindElement("power"))
|
||||
PowerWatts = el->FindElementValueAsNumberConvertTo("power","WATTS");
|
||||
|
||||
|
@ -93,17 +89,16 @@ void FGElectric::Calculate(void)
|
|||
{
|
||||
RunPreFunctions();
|
||||
|
||||
Throttle = FCS->GetThrottlePos(EngineNumber);
|
||||
|
||||
if (Thruster->GetType() == FGThruster::ttPropeller) {
|
||||
((FGPropeller*)Thruster)->SetAdvance(FCS->GetPropAdvance(EngineNumber));
|
||||
((FGPropeller*)Thruster)->SetFeather(FCS->GetPropFeather(EngineNumber));
|
||||
((FGPropeller*)Thruster)->SetAdvance(in.PropAdvance[EngineNumber]);
|
||||
((FGPropeller*)Thruster)->SetFeather(in.PropFeather[EngineNumber]);
|
||||
}
|
||||
|
||||
RPM = Thruster->GetRPM() * Thruster->GetGearRatio();
|
||||
|
||||
HP = PowerWatts * Throttle / hptowatts;
|
||||
HP = PowerWatts * in.ThrottlePos[EngineNumber] / hptowatts;
|
||||
|
||||
LoadThrusterInputs();
|
||||
Thruster->Calculate(HP * hptoftlbssec);
|
||||
|
||||
RunPostFunctions();
|
||||
|
|
|
@ -45,7 +45,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_ELECTRIC "$Id: FGElectric.h,v 1.10 2011/03/10 01:35:25 dpculp Exp $";
|
||||
#define ID_ELECTRIC "$Id: FGElectric.h,v 1.11 2011/07/28 12:48:19 jberndt Exp $";
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -65,7 +65,7 @@ CLASS DOCUMENTATION
|
|||
there is no battery model available, so this motor does not consume any
|
||||
energy. There is no internal friction.
|
||||
@author David Culp
|
||||
@version "$Id: FGElectric.h,v 1.10 2011/03/10 01:35:25 dpculp Exp $"
|
||||
@version "$Id: FGElectric.h,v 1.11 2011/07/28 12:48:19 jberndt Exp $"
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -76,7 +76,7 @@ class FGElectric : public FGEngine
|
|||
{
|
||||
public:
|
||||
/// Constructor
|
||||
FGElectric(FGFDMExec* exec, Element *el, int engine_number);
|
||||
FGElectric(FGFDMExec* exec, Element *el, int engine_number, FGEngine::Inputs& input);
|
||||
/// Destructor
|
||||
~FGElectric();
|
||||
|
||||
|
@ -92,9 +92,6 @@ private:
|
|||
|
||||
double BrakeHorsePower;
|
||||
|
||||
// timestep
|
||||
double dt;
|
||||
|
||||
// constants
|
||||
double hptowatts;
|
||||
|
||||
|
|
|
@ -37,32 +37,31 @@ HISTORY
|
|||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "FGEngine.h"
|
||||
#include "FGTank.h"
|
||||
#include "FGPropeller.h"
|
||||
#include "FGNozzle.h"
|
||||
#include "FGRotor.h"
|
||||
#include "models/FGPropulsion.h"
|
||||
#include "input_output/FGXMLParse.h"
|
||||
#include "math/FGColumnVector3.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <cstdlib>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGEngine.cpp,v 1.42 2011/03/03 12:16:26 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGEngine.cpp,v 1.46 2011/08/17 23:56:01 jberndt Exp $";
|
||||
static const char *IdHdr = ID_ENGINE;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS IMPLEMENTATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
FGEngine::FGEngine(FGFDMExec* exec, Element* engine_element, int engine_number)
|
||||
: EngineNumber(engine_number)
|
||||
FGEngine::FGEngine(FGFDMExec* exec, Element* engine_element, int engine_number, struct Inputs& input)
|
||||
: EngineNumber(engine_number), in(input)
|
||||
{
|
||||
Element* local_element;
|
||||
FGColumnVector3 location, orientation;
|
||||
|
@ -72,20 +71,13 @@ FGEngine::FGEngine(FGFDMExec* exec, Element* engine_element, int engine_number)
|
|||
X = Y = Z = 0.0;
|
||||
EnginePitch = EngineYaw = 0.0;
|
||||
SLFuelFlowMax = 0.0;
|
||||
FuelExpended = 0.0;
|
||||
MaxThrottle = 1.0;
|
||||
MinThrottle = 0.0;
|
||||
FuelDensity = 6.0;
|
||||
unsigned int i;
|
||||
|
||||
ResetToIC(); // initialize dynamic terms
|
||||
|
||||
FDMExec = exec;
|
||||
Atmosphere = FDMExec->GetAtmosphere();
|
||||
FCS = FDMExec->GetFCS();
|
||||
Propulsion = FDMExec->GetPropulsion();
|
||||
Aircraft = FDMExec->GetAircraft();
|
||||
Propagate = FDMExec->GetPropagate();
|
||||
Auxiliary = FDMExec->GetAuxiliary();
|
||||
|
||||
PropertyManager = FDMExec->GetPropertyManager();
|
||||
|
||||
|
@ -118,28 +110,12 @@ FGEngine::FGEngine(FGFDMExec* exec, Element* engine_element, int engine_number)
|
|||
cerr << "No thruster definition supplied with engine definition." << endl;
|
||||
}
|
||||
|
||||
// Build and initialize the feed tank vector.
|
||||
for (i=0; i<(Propulsion->GetNumTanks()); i++) {
|
||||
SourceTanks.push_back(0);
|
||||
}
|
||||
|
||||
// Load feed tank[s] references
|
||||
local_element = engine_element->GetParent()->FindElement("feed");
|
||||
if (local_element) {
|
||||
while (local_element) {
|
||||
int tankID = (int)local_element->GetDataAsNumber();
|
||||
FGTank* tank = Propulsion->GetTank(tankID);
|
||||
if (tank) {
|
||||
AddFeedTank(tankID, tank->GetPriority());
|
||||
FuelDensity = tank->GetDensity();
|
||||
} else {
|
||||
cerr << "Feed tank " << tankID <<
|
||||
" specified in engine definition does not exist." << endl;
|
||||
}
|
||||
local_element = engine_element->GetParent()->FindNextElement("feed");
|
||||
}
|
||||
} else {
|
||||
cerr << "No feed tank specified in engine definition." << endl;
|
||||
while (local_element) {
|
||||
int tankID = (int)local_element->GetDataAsNumber();
|
||||
SourceTanks.push_back(tankID);
|
||||
local_element = engine_element->GetParent()->FindNextElement("feed");
|
||||
}
|
||||
|
||||
string property_name, base_property_name;
|
||||
|
@ -151,13 +127,13 @@ FGEngine::FGEngine(FGFDMExec* exec, Element* engine_element, int engine_number)
|
|||
PropertyManager->Tie( property_name.c_str(), Thruster, &FGThruster::GetThrust);
|
||||
property_name = base_property_name + "/fuel-flow-rate-pps";
|
||||
PropertyManager->Tie( property_name.c_str(), this, &FGEngine::GetFuelFlowRate);
|
||||
property_name = base_property_name + "/fuel-flow-rate-gph";
|
||||
PropertyManager->Tie( property_name.c_str(), this, &FGEngine::GetFuelFlowRateGPH);
|
||||
property_name = base_property_name + "/fuel-used-lbs";
|
||||
PropertyManager->Tie( property_name.c_str(), this, &FGEngine::GetFuelUsedLbs);
|
||||
|
||||
PostLoad(engine_element, PropertyManager, to_string(EngineNumber));
|
||||
|
||||
//cout << "Engine[" << EngineNumber << "] using fuel density: " << FuelDensity << endl;
|
||||
|
||||
Debug(0);
|
||||
}
|
||||
|
||||
|
@ -173,8 +149,6 @@ FGEngine::~FGEngine()
|
|||
|
||||
void FGEngine::ResetToIC(void)
|
||||
{
|
||||
Throttle = 0.0;
|
||||
Mixture = 1.0;
|
||||
Starter = false;
|
||||
FuelExpended = 0.0;
|
||||
Starved = Running = Cranking = false;
|
||||
|
@ -187,73 +161,24 @@ void FGEngine::ResetToIC(void)
|
|||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// This base class function should be called from within the
|
||||
// derived class' Calculate() function before any other calculations are done.
|
||||
// This base class method removes fuel from the fuel tanks as appropriate,
|
||||
// and sets the starved flag if necessary.
|
||||
// This version of the fuel consumption code should never see an oxidizer tank.
|
||||
|
||||
void FGEngine::ConsumeFuel(void)
|
||||
double FGEngine::CalcFuelNeed(void)
|
||||
{
|
||||
if (FuelFreeze) return;
|
||||
if (FDMExec->GetTrimStatus()) return;
|
||||
|
||||
unsigned int i;
|
||||
double Fshortage, FuelNeeded;
|
||||
FGTank* Tank;
|
||||
unsigned int TanksWithFuel = 0;
|
||||
Fshortage = FuelNeeded = 0.0;
|
||||
double FuelToBurn;
|
||||
unsigned int CurrentPriority = 1;
|
||||
vector <int> FeedList;
|
||||
Starved = false;
|
||||
|
||||
FuelToBurn = CalcFuelNeed();
|
||||
if (FuelToBurn == 0.0) return;
|
||||
|
||||
// Count how many fuel tanks with the current priority level have fuel.
|
||||
// If none, then try next lower priority. Build the feed list.
|
||||
while ((TanksWithFuel == 0) && (CurrentPriority <= Propulsion->GetNumTanks())) {
|
||||
for (i=0; i<Propulsion->GetNumTanks(); i++) {
|
||||
if (SourceTanks[i] != 0) {
|
||||
Tank = Propulsion->GetTank(i);
|
||||
if (Tank->GetType() == FGTank::ttFUEL) {
|
||||
if ((Tank->GetContents() > 0.0) && ((unsigned int)Tank->GetPriority() == CurrentPriority)) {
|
||||
++TanksWithFuel;
|
||||
FeedList.push_back(i);
|
||||
}
|
||||
} else {
|
||||
cerr << "No oxidizer tanks should be used for this engine type." << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (TanksWithFuel == 0) CurrentPriority++;
|
||||
}
|
||||
|
||||
// No fuel found at any priority!
|
||||
if (TanksWithFuel == 0) {
|
||||
Starved = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove equal amount of fuel from each feed tank.
|
||||
FuelNeeded = FuelToBurn/TanksWithFuel;
|
||||
for (i=0; i<FeedList.size(); i++) {
|
||||
Tank = Propulsion->GetTank(FeedList[i]);
|
||||
Tank->Drain(FuelNeeded);
|
||||
}
|
||||
FuelUsedLbs += FuelToBurn;
|
||||
|
||||
FuelFlowRate = SLFuelFlowMax*PctPower;
|
||||
FuelExpended = FuelFlowRate*in.TotalDeltaT;
|
||||
if (!Starved) FuelUsedLbs += FuelExpended;
|
||||
return FuelExpended;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGEngine::CalcFuelNeed(void)
|
||||
unsigned int FGEngine::GetSourceTank(unsigned int i) const
|
||||
{
|
||||
double dT = FDMExec->GetDeltaT()*Propulsion->GetRate();
|
||||
FuelFlowRate = SLFuelFlowMax*PctPower;
|
||||
FuelExpended = FuelFlowRate*dT;
|
||||
return FuelExpended;
|
||||
if (i >= 0 && i < SourceTanks.size()) {
|
||||
return SourceTanks[i];
|
||||
} else {
|
||||
throw("No such source tank is available for this engine");
|
||||
}
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -269,14 +194,14 @@ void FGEngine::SetPlacement(FGColumnVector3& location, FGColumnVector3& orientat
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGEngine::AddFeedTank(int tkID, int priority)
|
||||
double FGEngine::GetThrust(void) const
|
||||
{
|
||||
SourceTanks[tkID] = priority;
|
||||
return Thruster->GetThrust();
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
FGColumnVector3& FGEngine::GetBodyForces(void)
|
||||
FGColumnVector3& FGEngine::GetBodyForces(void)
|
||||
{
|
||||
return Thruster->GetBodyForces();
|
||||
}
|
||||
|
@ -290,6 +215,23 @@ FGColumnVector3& FGEngine::GetMoments(void)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGEngine::LoadThrusterInputs()
|
||||
{
|
||||
Thruster->in.TotalDeltaT = in.TotalDeltaT;
|
||||
Thruster->in.H_agl = in.H_agl;
|
||||
Thruster->in.PQR = in.PQR;
|
||||
Thruster->in.AeroPQR = in.AeroPQR;
|
||||
Thruster->in.AeroUVW = in.AeroUVW;
|
||||
Thruster->in.Density = in.Density;
|
||||
Thruster->in.Pressure = in.Pressure;
|
||||
Thruster->in.Soundspeed = in.Soundspeed;
|
||||
Thruster->in.Alpha = in.alpha;
|
||||
Thruster->in.Beta = in.beta;
|
||||
Thruster->in.Vt = in.Vt;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
bool FGEngine::LoadThruster(Element *thruster_element)
|
||||
{
|
||||
string token, fullpath, localpath;
|
||||
|
@ -339,7 +281,7 @@ bool FGEngine::LoadThruster(Element *thruster_element)
|
|||
Thruster = new FGThruster( FDMExec, document, EngineNumber);
|
||||
}
|
||||
|
||||
Thruster->SetdeltaT(FDMExec->GetDeltaT() * Propulsion->GetRate());
|
||||
Thruster->SetdeltaT(in.TotalDeltaT);
|
||||
|
||||
Debug(2);
|
||||
return true;
|
||||
|
|
|
@ -43,19 +43,19 @@ SENTRY
|
|||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "math/FGModelFunctions.h"
|
||||
#include "input_output/FGXMLFileRead.h"
|
||||
#include "input_output/FGXMLElement.h"
|
||||
#include "models/FGFCS.h"
|
||||
#include "math/FGColumnVector3.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_ENGINE "$Id: FGEngine.h,v 1.23 2011/03/03 12:16:26 jberndt Exp $"
|
||||
#define ID_ENGINE "$Id: FGEngine.h,v 1.27 2011/08/17 23:56:01 jberndt Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -64,11 +64,6 @@ FORWARD DECLARATIONS
|
|||
namespace JSBSim {
|
||||
|
||||
class FGFDMExec;
|
||||
class FGAtmosphere;
|
||||
class FGAircraft;
|
||||
class FGPropagate;
|
||||
class FGPropulsion;
|
||||
class FGAuxiliary;
|
||||
class FGThruster;
|
||||
class Element;
|
||||
class FGPropertyManager;
|
||||
|
@ -118,7 +113,7 @@ CLASS DOCUMENTATION
|
|||
documentation for engine and thruster classes.
|
||||
</pre>
|
||||
@author Jon S. Berndt
|
||||
@version $Id: FGEngine.h,v 1.23 2011/03/03 12:16:26 jberndt Exp $
|
||||
@version $Id: FGEngine.h,v 1.27 2011/08/17 23:56:01 jberndt Exp $
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -128,7 +123,36 @@ CLASS DECLARATION
|
|||
class FGEngine : public FGModelFunctions, public FGXMLFileRead
|
||||
{
|
||||
public:
|
||||
FGEngine(FGFDMExec* exec, Element* el, int engine_number);
|
||||
struct Inputs {
|
||||
double SLPressure;
|
||||
double Pressure;
|
||||
double PressureRatio;
|
||||
double Temperature;
|
||||
double Density;
|
||||
double DensityRatio;
|
||||
double Soundspeed;
|
||||
double TotalPressure;
|
||||
double TotalTempearture;
|
||||
double TAT_c;
|
||||
double Vt;
|
||||
double Vc;
|
||||
double qbar;
|
||||
double alpha;
|
||||
double beta;
|
||||
double H_agl;
|
||||
FGColumnVector3 AeroUVW;
|
||||
FGColumnVector3 AeroPQR;
|
||||
FGColumnVector3 PQR;
|
||||
vector <double> ThrottleCmd;
|
||||
vector <double> MixtureCmd;
|
||||
vector <double> ThrottlePos;
|
||||
vector <double> MixturePos;
|
||||
vector <double> PropAdvance;
|
||||
vector <bool> PropFeather;
|
||||
double TotalDeltaT;
|
||||
};
|
||||
|
||||
FGEngine(FGFDMExec* exec, Element* el, int engine_number, struct Inputs& input);
|
||||
virtual ~FGEngine();
|
||||
|
||||
enum EngineType {etUnknown, etRocket, etPiston, etTurbine, etTurboprop, etElectric};
|
||||
|
@ -139,13 +163,12 @@ public:
|
|||
// Engine controls
|
||||
virtual double GetThrottleMin(void) { return MinThrottle; }
|
||||
virtual double GetThrottleMax(void) { return MaxThrottle; }
|
||||
virtual double GetThrottle(void) { return Throttle; }
|
||||
virtual double GetMixture(void) { return Mixture; }
|
||||
virtual bool GetStarter(void) { return Starter; }
|
||||
|
||||
virtual double getFuelFlow_gph () const {return FuelFlow_gph;}
|
||||
virtual double getFuelFlow_pph () const {return FuelFlow_pph;}
|
||||
virtual double GetFuelFlowRate(void) const {return FuelFlowRate;}
|
||||
virtual double GetFuelFlowRateGPH(void) const {return FuelFlowRate*3600/6.02;}
|
||||
virtual double GetFuelUsedLbs(void) const {return FuelUsedLbs;}
|
||||
virtual bool GetStarved(void) { return Starved; }
|
||||
virtual bool GetRunning(void) const { return Running; }
|
||||
|
@ -156,7 +179,6 @@ public:
|
|||
|
||||
virtual void SetRunning(bool bb) { Running=bb; }
|
||||
virtual void SetName(string name) { Name = name; }
|
||||
virtual void AddFeedTank(int tkID, int priority);
|
||||
virtual void SetFuelFreeze(bool f) { FuelFreeze = f; }
|
||||
|
||||
virtual void SetStarter(bool s) { Starter = s; }
|
||||
|
@ -169,9 +191,19 @@ public:
|
|||
/** Calculates the thrust of the engine, and other engine functions. */
|
||||
virtual void Calculate(void) = 0;
|
||||
|
||||
virtual double GetThrust(void) const;
|
||||
|
||||
/// Sets engine placement information
|
||||
virtual void SetPlacement(FGColumnVector3& location, FGColumnVector3& orientation);
|
||||
|
||||
/** The fuel need is calculated based on power levels and flow rate for that
|
||||
power level. It is also turned from a rate into an actual amount (pounds)
|
||||
by multiplying it by the delta T and the rate.
|
||||
@return Total fuel requirement for this engine in pounds. */
|
||||
virtual double CalcFuelNeed(void);
|
||||
|
||||
virtual double CalcOxidizerNeed(void) {return 0.0;}
|
||||
|
||||
virtual double GetPowerAvailable(void) {return 0.0;};
|
||||
|
||||
virtual FGColumnVector3& GetBodyForces(void);
|
||||
|
@ -180,22 +212,22 @@ public:
|
|||
bool LoadThruster(Element *el);
|
||||
FGThruster* GetThruster(void) {return Thruster;}
|
||||
|
||||
unsigned int GetSourceTank(unsigned int i) const;
|
||||
unsigned int GetNumSourceTanks() const {return SourceTanks.size();}
|
||||
|
||||
virtual std::string GetEngineLabels(const std::string& delimiter) = 0;
|
||||
virtual std::string GetEngineValues(const std::string& delimiter) = 0;
|
||||
|
||||
struct Inputs& in;
|
||||
void LoadThrusterInputs();
|
||||
|
||||
protected:
|
||||
/** Reduces the fuel in the active tanks by the amount required.
|
||||
This function should be called from within the
|
||||
derived class' Calculate() function before any other calculations are
|
||||
done. This base class method removes fuel from the fuel tanks as
|
||||
appropriate, and sets the starved flag if necessary. */
|
||||
virtual void ConsumeFuel(void);
|
||||
|
||||
/** The fuel need is calculated based on power levels and flow rate for that
|
||||
power level. It is also turned from a rate into an actual amount (pounds)
|
||||
by multiplying it by the delta T and the rate.
|
||||
@return Total fuel requirement for this engine in pounds. */
|
||||
virtual double CalcFuelNeed(void);
|
||||
appropriate, and sets the starved flag if necessary. * /
|
||||
virtual void ConsumeFuel(void); */
|
||||
|
||||
FGPropertyManager* PropertyManager;
|
||||
std::string Name;
|
||||
|
@ -208,8 +240,6 @@ protected:
|
|||
double MaxThrottle;
|
||||
double MinThrottle;
|
||||
|
||||
double Throttle;
|
||||
double Mixture;
|
||||
double FuelExpended;
|
||||
double FuelFlowRate;
|
||||
double PctPower;
|
||||
|
@ -221,16 +251,9 @@ protected:
|
|||
|
||||
double FuelFlow_gph;
|
||||
double FuelFlow_pph;
|
||||
double FuelDensity;
|
||||
double FuelUsedLbs;
|
||||
|
||||
FGFDMExec* FDMExec;
|
||||
FGAtmosphere* Atmosphere;
|
||||
FGFCS* FCS;
|
||||
FGPropulsion* Propulsion;
|
||||
FGAircraft* Aircraft;
|
||||
FGPropagate* Propagate;
|
||||
FGAuxiliary* Auxiliary;
|
||||
FGThruster* Thruster;
|
||||
|
||||
std::vector <int> SourceTanks;
|
||||
|
|
|
@ -40,20 +40,20 @@ and the cg.
|
|||
|
||||
*/
|
||||
|
||||
#include "FGForce.h"
|
||||
#include "FGFDMExec.h"
|
||||
#include "models/FGAircraft.h"
|
||||
#include "models/FGPropagate.h"
|
||||
#include "models/FGMassBalance.h"
|
||||
#include "models/FGAerodynamics.h"
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "FGForce.h"
|
||||
#include "FGFDMExec.h"
|
||||
#include "models/FGPropagate.h"
|
||||
#include "models/FGMassBalance.h"
|
||||
#include "models/FGAuxiliary.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGForce.cpp,v 1.15 2011/02/17 00:20:52 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGForce.cpp,v 1.16 2011/08/04 12:46:32 jberndt Exp $";
|
||||
static const char *IdHdr = ID_FORCE;
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -110,7 +110,7 @@ FGMatrix33 FGForce::Transform(void)
|
|||
{
|
||||
switch(ttype) {
|
||||
case tWindBody:
|
||||
return fdmex->GetAerodynamics()->GetTw2b();
|
||||
return fdmex->GetAuxiliary()->GetTw2b();
|
||||
case tLocalBody:
|
||||
return fdmex->GetPropagate()->GetTl2b();
|
||||
case tCustom:
|
||||
|
|
|
@ -40,14 +40,13 @@ INCLUDES
|
|||
#include <cstdlib>
|
||||
|
||||
#include "FGNozzle.h"
|
||||
#include "models/FGAtmosphere.h"
|
||||
#include "input_output/FGXMLElement.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGNozzle.cpp,v 1.13 2009/10/26 03:49:58 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGNozzle.cpp,v 1.14 2011/08/03 03:21:06 jberndt Exp $";
|
||||
static const char *IdHdr = ID_NOZZLE;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -64,14 +63,7 @@ FGNozzle::FGNozzle(FGFDMExec* FDMExec, Element* nozzle_element, int num)
|
|||
cerr << "Fatal Error: Nozzle exit area must be given in nozzle config file." << endl;
|
||||
exit(-1);
|
||||
}
|
||||
/*
|
||||
if (nozzle_element->FindElement("pe"))
|
||||
PE = nozzle_element->FindElementValueAsNumberConvertTo("pe", "PSF");
|
||||
else {
|
||||
cerr << "Fatal Error: Nozzle exit pressure must be given in nozzle config file." << endl;
|
||||
exit(-1);
|
||||
}
|
||||
*/
|
||||
|
||||
Thrust = 0;
|
||||
Type = ttNozzle;
|
||||
|
||||
|
@ -89,8 +81,7 @@ FGNozzle::~FGNozzle()
|
|||
|
||||
double FGNozzle::Calculate(double vacThrust)
|
||||
{
|
||||
double pAtm = fdmex->GetAtmosphere()->GetPressure();
|
||||
Thrust = max((double)0.0, vacThrust - pAtm*Area);
|
||||
Thrust = max((double)0.0, vacThrust - in.Pressure*Area);
|
||||
|
||||
vFn(1) = Thrust * cos(ReverserAngle);
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_NOZZLE "$Id: FGNozzle.h,v 1.8 2009/10/26 03:49:58 jberndt Exp $";
|
||||
#define ID_NOZZLE "$Id: FGNozzle.h,v 1.9 2011/08/03 03:21:06 jberndt Exp $";
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -75,7 +75,7 @@ CLASS DOCUMENTATION
|
|||
|
||||
All parameters MUST be specified.
|
||||
@author Jon S. Berndt
|
||||
@version $Id: FGNozzle.h,v 1.8 2009/10/26 03:49:58 jberndt Exp $
|
||||
@version $Id: FGNozzle.h,v 1.9 2011/08/03 03:21:06 jberndt Exp $
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -83,7 +83,6 @@ CLASS DECLARATION
|
|||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
class FGNozzle : public FGThruster {
|
||||
|
||||
public:
|
||||
/// Constructor
|
||||
FGNozzle(FGFDMExec* exec, Element* el, int num = 0);
|
||||
|
|
|
@ -40,28 +40,25 @@ HISTORY
|
|||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "FGPiston.h"
|
||||
#include "models/FGAtmosphere.h"
|
||||
#include "models/FGAuxiliary.h"
|
||||
#include "models/FGPropulsion.h"
|
||||
#include "FGPropeller.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGPiston.cpp,v 1.58 2011/06/13 15:23:09 jentron Exp $";
|
||||
static const char *IdSrc = "$Id: FGPiston.cpp,v 1.64 2011/08/04 13:45:42 jberndt Exp $";
|
||||
static const char *IdHdr = ID_PISTON;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS IMPLEMENTATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
FGPiston::FGPiston(FGFDMExec* exec, Element* el, int engine_number)
|
||||
: FGEngine(exec, el, engine_number),
|
||||
FGPiston::FGPiston(FGFDMExec* exec, Element* el, int engine_number, struct Inputs& input)
|
||||
: FGEngine(exec, el, engine_number, input),
|
||||
R_air(287.3), // Gas constant for air J/Kg/K
|
||||
rho_fuel(800), // estimate
|
||||
calorific_value_fuel(47.3e6), // J/Kg
|
||||
|
@ -69,12 +66,13 @@ FGPiston::FGPiston(FGFDMExec* exec, Element* el, int engine_number)
|
|||
Cp_fuel(1700),
|
||||
standard_pressure(101320.73)
|
||||
{
|
||||
Element *table_element;
|
||||
string token;
|
||||
string name="";
|
||||
|
||||
// Defaults and initializations
|
||||
|
||||
Type = etPiston;
|
||||
dt = FDMExec->GetDeltaT();
|
||||
|
||||
// These items are read from the configuration file
|
||||
// Defaults are from a Lycoming O-360, more or less
|
||||
|
@ -104,6 +102,8 @@ FGPiston::FGPiston(FGFDMExec* exec, Element* el, int engine_number)
|
|||
|
||||
// These are internal program variables
|
||||
|
||||
Lookup_Combustion_Efficiency = 0;
|
||||
Mixture_Efficiency_Correlation = 0;
|
||||
crank_counter = 0;
|
||||
Magnetos = 0;
|
||||
minMAP = 21950;
|
||||
|
@ -135,39 +135,6 @@ FGPiston::FGPiston(FGFDMExec* exec, Element* el, int engine_number)
|
|||
BoostSwitchPressure[i] = 0.0;
|
||||
}
|
||||
|
||||
// First column is thi, second is neta (combustion efficiency)
|
||||
Lookup_Combustion_Efficiency = new FGTable(12);
|
||||
*Lookup_Combustion_Efficiency << 0.00 << 0.980;
|
||||
*Lookup_Combustion_Efficiency << 0.90 << 0.980;
|
||||
*Lookup_Combustion_Efficiency << 1.00 << 0.970;
|
||||
*Lookup_Combustion_Efficiency << 1.05 << 0.950;
|
||||
*Lookup_Combustion_Efficiency << 1.10 << 0.900;
|
||||
*Lookup_Combustion_Efficiency << 1.15 << 0.850;
|
||||
*Lookup_Combustion_Efficiency << 1.20 << 0.790;
|
||||
*Lookup_Combustion_Efficiency << 1.30 << 0.700;
|
||||
*Lookup_Combustion_Efficiency << 1.40 << 0.630;
|
||||
*Lookup_Combustion_Efficiency << 1.50 << 0.570;
|
||||
*Lookup_Combustion_Efficiency << 1.60 << 0.525;
|
||||
*Lookup_Combustion_Efficiency << 2.00 << 0.345;
|
||||
|
||||
Mixture_Efficiency_Correlation = new FGTable(15);
|
||||
*Mixture_Efficiency_Correlation << 0.05000 << 0.00000;
|
||||
*Mixture_Efficiency_Correlation << 0.05137 << 0.00862;
|
||||
*Mixture_Efficiency_Correlation << 0.05179 << 0.21552;
|
||||
*Mixture_Efficiency_Correlation << 0.05430 << 0.48276;
|
||||
*Mixture_Efficiency_Correlation << 0.05842 << 0.70690;
|
||||
*Mixture_Efficiency_Correlation << 0.06312 << 0.83621;
|
||||
*Mixture_Efficiency_Correlation << 0.06942 << 0.93103;
|
||||
*Mixture_Efficiency_Correlation << 0.07786 << 1.00000;
|
||||
*Mixture_Efficiency_Correlation << 0.08845 << 1.00000;
|
||||
*Mixture_Efficiency_Correlation << 0.09270 << 0.98276;
|
||||
*Mixture_Efficiency_Correlation << 0.10120 << 0.93103;
|
||||
*Mixture_Efficiency_Correlation << 0.11455 << 0.72414;
|
||||
*Mixture_Efficiency_Correlation << 0.12158 << 0.45690;
|
||||
*Mixture_Efficiency_Correlation << 0.12435 << 0.23276;
|
||||
*Mixture_Efficiency_Correlation << 0.12500 << 0.00000;
|
||||
|
||||
|
||||
// Read inputs from engine data file where present.
|
||||
|
||||
if (el->FindElement("minmp")) // Should have ELSE statement telling default value used?
|
||||
|
@ -252,6 +219,21 @@ FGPiston::FGPiston(FGFDMExec* exec, Element* el, int engine_number)
|
|||
RatedAltitude[2] = el->FindElementValueAsNumberConvertTo("ratedaltitude3", "FT");
|
||||
}
|
||||
|
||||
while(table_element = el->FindNextElement("table")) {
|
||||
name = table_element->GetAttributeValue("name");
|
||||
try {
|
||||
if (name == "COMBUSTION") {
|
||||
Lookup_Combustion_Efficiency = new FGTable(PropertyManager, table_element);
|
||||
} else if (name == "MIXTURE") {
|
||||
Mixture_Efficiency_Correlation = new FGTable(PropertyManager, table_element);
|
||||
} else {
|
||||
cerr << "Unknown table type: " << name << " in piston engine definition." << endl;
|
||||
}
|
||||
} catch (std::string str) {
|
||||
throw("Error loading piston engine table:" + name + ". " + str);
|
||||
}
|
||||
}
|
||||
|
||||
StarterHP = sqrt(MaxHP) * 0.4;
|
||||
displacement_SI = Displacement * in3tom3;
|
||||
RatedMeanPistonSpeed_fps = ( MaxRPM * Stroke) / (360); // AKA 2 * (RPM/60) * ( Stroke / 12) or 2NS
|
||||
|
@ -286,7 +268,6 @@ FGPiston::FGPiston(FGFDMExec* exec, Element* el, int engine_number)
|
|||
*
|
||||
*
|
||||
*/
|
||||
|
||||
if(Z_airbox < 0.0){
|
||||
double Ze=PeakMeanPistonSpeed_fps/RatedMeanPistonSpeed_fps; // engine impedence
|
||||
Z_airbox = (standard_pressure *Ze / maxMAP) - Ze; // impedence of airbox
|
||||
|
@ -295,6 +276,44 @@ FGPiston::FGPiston(FGFDMExec* exec, Element* el, int engine_number)
|
|||
Z_throttle=(PeakMeanPistonSpeed_fps/((IdleRPM * Stroke) / 360))*(standard_pressure/minMAP - 1) - Z_airbox;
|
||||
// Z_throttle=(MaxRPM/IdleRPM )*(standard_pressure/minMAP+2); // Constant for Throttle impedence
|
||||
|
||||
// Default tables if not provided in the configuration file
|
||||
if(Lookup_Combustion_Efficiency == 0) {
|
||||
// First column is thi, second is neta (combustion efficiency)
|
||||
Lookup_Combustion_Efficiency = new FGTable(12);
|
||||
*Lookup_Combustion_Efficiency << 0.00 << 0.980;
|
||||
*Lookup_Combustion_Efficiency << 0.90 << 0.980;
|
||||
*Lookup_Combustion_Efficiency << 1.00 << 0.970;
|
||||
*Lookup_Combustion_Efficiency << 1.05 << 0.950;
|
||||
*Lookup_Combustion_Efficiency << 1.10 << 0.900;
|
||||
*Lookup_Combustion_Efficiency << 1.15 << 0.850;
|
||||
*Lookup_Combustion_Efficiency << 1.20 << 0.790;
|
||||
*Lookup_Combustion_Efficiency << 1.30 << 0.700;
|
||||
*Lookup_Combustion_Efficiency << 1.40 << 0.630;
|
||||
*Lookup_Combustion_Efficiency << 1.50 << 0.570;
|
||||
*Lookup_Combustion_Efficiency << 1.60 << 0.525;
|
||||
*Lookup_Combustion_Efficiency << 2.00 << 0.345;
|
||||
}
|
||||
|
||||
// First column is Fuel/Air Ratio, second is neta (mixture efficiency)
|
||||
if( Mixture_Efficiency_Correlation == 0) {
|
||||
Mixture_Efficiency_Correlation = new FGTable(15);
|
||||
*Mixture_Efficiency_Correlation << 0.05000 << 0.00000;
|
||||
*Mixture_Efficiency_Correlation << 0.05137 << 0.00862;
|
||||
*Mixture_Efficiency_Correlation << 0.05179 << 0.21552;
|
||||
*Mixture_Efficiency_Correlation << 0.05430 << 0.48276;
|
||||
*Mixture_Efficiency_Correlation << 0.05842 << 0.70690;
|
||||
*Mixture_Efficiency_Correlation << 0.06312 << 0.83621;
|
||||
*Mixture_Efficiency_Correlation << 0.06942 << 0.93103;
|
||||
*Mixture_Efficiency_Correlation << 0.07786 << 1.00000;
|
||||
*Mixture_Efficiency_Correlation << 0.08845 << 1.00000;
|
||||
*Mixture_Efficiency_Correlation << 0.09270 << 0.98276;
|
||||
*Mixture_Efficiency_Correlation << 0.10120 << 0.93103;
|
||||
*Mixture_Efficiency_Correlation << 0.11455 << 0.72414;
|
||||
*Mixture_Efficiency_Correlation << 0.12158 << 0.45690;
|
||||
*Mixture_Efficiency_Correlation << 0.12435 << 0.23276;
|
||||
*Mixture_Efficiency_Correlation << 0.12500 << 0.00000;
|
||||
}
|
||||
|
||||
string property_name, base_property_name;
|
||||
base_property_name = CreateIndexedPropertyName("propulsion/engine", EngineNumber);
|
||||
property_name = base_property_name + "/power-hp";
|
||||
|
@ -347,13 +366,13 @@ FGPiston::FGPiston(FGFDMExec* exec, Element* el, int engine_number)
|
|||
// But we can also make a reasonable estimate, as below.
|
||||
BoostSwitchAltitude[i] = RatedAltitude[i] + 1000;
|
||||
}
|
||||
BoostSwitchPressure[i] = Atmosphere->GetPressure(BoostSwitchAltitude[i]) * psftopa;
|
||||
BoostSwitchPressure[i] = GetStdPressure100K(BoostSwitchAltitude[i]) * psftopa;
|
||||
//cout << "BoostSwitchAlt = " << BoostSwitchAltitude[i] << ", pressure = " << BoostSwitchPressure[i] << '\n';
|
||||
// Assume there is some hysteresis on the supercharger gear switch, and guess the value for now
|
||||
BoostSwitchHysteresis = 1000;
|
||||
}
|
||||
// Now work out the supercharger pressure multiplier of this speed from the rated boost and altitude.
|
||||
RatedMAP[i] = Atmosphere->GetPressureSL() * psftopa + RatedBoost[i] * 6895; // psi*6895 = Pa.
|
||||
RatedMAP[i] = standard_pressure + RatedBoost[i] * 6895; // psi*6895 = Pa.
|
||||
// Sometimes a separate BCV setting for takeoff or extra power is fitted.
|
||||
if (TakeoffBoost > RatedBoost[0]) {
|
||||
// Assume that the effect on the BCV is the same whichever speed is in use.
|
||||
|
@ -363,7 +382,7 @@ FGPiston::FGPiston(FGFDMExec* exec, Element* el, int engine_number)
|
|||
TakeoffMAP[i] = RatedMAP[i];
|
||||
bTakeoffBoost = false;
|
||||
}
|
||||
BoostMul[i] = RatedMAP[i] / (Atmosphere->GetPressure(RatedAltitude[i]) * psftopa);
|
||||
BoostMul[i] = RatedMAP[i] / (GetStdPressure100K(RatedAltitude[i]) * psftopa);
|
||||
|
||||
}
|
||||
|
||||
|
@ -391,10 +410,10 @@ void FGPiston::ResetToIC(void)
|
|||
{
|
||||
FGEngine::ResetToIC();
|
||||
|
||||
ManifoldPressure_inHg = Atmosphere->GetPressure() * psftoinhg; // psf to in Hg
|
||||
MAP = Atmosphere->GetPressure() * psftopa;
|
||||
ManifoldPressure_inHg = in.Pressure * psftoinhg; // psf to in Hg
|
||||
MAP = in.Pressure * psftopa;
|
||||
TMAP = MAP;
|
||||
double airTemperature_degK = RankineToKelvin(Atmosphere->GetTemperature());
|
||||
double airTemperature_degK = RankineToKelvin(in.Temperature);
|
||||
OilTemp_degK = airTemperature_degK;
|
||||
CylinderHeadTemp_degK = airTemperature_degK;
|
||||
ExhaustGasTemp_degK = airTemperature_degK;
|
||||
|
@ -405,26 +424,22 @@ void FGPiston::ResetToIC(void)
|
|||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGPiston::Calculate(void)
|
||||
{
|
||||
RunPreFunctions();
|
||||
|
||||
if (FuelFlow_gph > 0.0) ConsumeFuel();
|
||||
|
||||
Throttle = FCS->GetThrottlePos(EngineNumber);
|
||||
Mixture = FCS->GetMixturePos(EngineNumber);
|
||||
|
||||
// Input values.
|
||||
|
||||
p_amb = Atmosphere->GetPressure() * psftopa;
|
||||
double p = Auxiliary->GetTotalPressure() * psftopa;
|
||||
p_amb = in.Pressure * psftopa;
|
||||
double p = in.TotalPressure * psftopa;
|
||||
p_ram = (p - p_amb) * Ram_Air_Factor + p_amb;
|
||||
T_amb = RankineToKelvin(Atmosphere->GetTemperature());
|
||||
T_amb = RankineToKelvin(in.Temperature);
|
||||
|
||||
RunPreFunctions();
|
||||
|
||||
RPM = Thruster->GetRPM() * Thruster->GetGearRatio();
|
||||
MeanPistonSpeed_fps = ( RPM * Stroke) / (360); // AKA 2 * (RPM/60) * ( Stroke / 12) or 2NS
|
||||
|
||||
IAS = Auxiliary->GetVcalibratedKTS();
|
||||
IAS = in.Vc;
|
||||
|
||||
doEngineStartup();
|
||||
if (Boosted) doBoostControl();
|
||||
|
@ -449,10 +464,11 @@ void FGPiston::Calculate(void)
|
|||
doOilPressure();
|
||||
|
||||
if (Thruster->GetType() == FGThruster::ttPropeller) {
|
||||
((FGPropeller*)Thruster)->SetAdvance(FCS->GetPropAdvance(EngineNumber));
|
||||
((FGPropeller*)Thruster)->SetFeather(FCS->GetPropFeather(EngineNumber));
|
||||
((FGPropeller*)Thruster)->SetAdvance(in.PropAdvance[EngineNumber]);
|
||||
((FGPropeller*)Thruster)->SetFeather(in.PropFeather[EngineNumber]);
|
||||
}
|
||||
|
||||
LoadThrusterInputs();
|
||||
Thruster->Calculate(HP * hptoftlbssec);
|
||||
|
||||
RunPostFunctions();
|
||||
|
@ -462,22 +478,19 @@ void FGPiston::Calculate(void)
|
|||
|
||||
double FGPiston::CalcFuelNeed(void)
|
||||
{
|
||||
double dT = FDMExec->GetDeltaT() * Propulsion->GetRate();
|
||||
FuelExpended = FuelFlowRate * dT;
|
||||
FuelExpended = FuelFlowRate * in.TotalDeltaT;
|
||||
return FuelExpended;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
int FGPiston::InitRunning(void) {
|
||||
int FGPiston::InitRunning(void)
|
||||
{
|
||||
Magnetos=3;
|
||||
p_amb = Atmosphere->GetPressure() * psftopa;
|
||||
double mix= p_amb / (101325.0*1.3);
|
||||
FCS->SetMixturePos(EngineNumber, mix);
|
||||
Thruster->SetRPM( 2.*IdleRPM/Thruster->GetGearRatio() );
|
||||
//Thruster->SetRPM( 1000 );
|
||||
Running=true;
|
||||
// cout <<"Set Running in FGPiston. RPM:" << Thruster->GetRPM()*Thruster->GetGearRatio() <<" Pressure:"<<p_amb<<" Mixture:"<< mix <<endl;
|
||||
in.MixtureCmd[EngineNumber] = in.PressureRatio/1.3;
|
||||
in.MixturePos[EngineNumber] = in.PressureRatio/1.3;
|
||||
Thruster->SetRPM( 2.0*IdleRPM/Thruster->GetGearRatio() );
|
||||
Running = true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -597,13 +610,18 @@ void FGPiston::doBoostControl(void)
|
|||
|
||||
void FGPiston::doMAP(void)
|
||||
{
|
||||
double Zt = (1-Throttle)*(1-Throttle)*Z_throttle; // throttle impedence
|
||||
double Zt = (1 - in.ThrottlePos[EngineNumber])*(1 - in.ThrottlePos[EngineNumber])*Z_throttle; // throttle impedence
|
||||
double Ze= MeanPistonSpeed_fps > 0 ? PeakMeanPistonSpeed_fps/MeanPistonSpeed_fps : 999999; // engine impedence
|
||||
|
||||
double map_coefficient = Ze/(Ze+Z_airbox+Zt);
|
||||
|
||||
// Add a one second lag to manifold pressure changes
|
||||
double dMAP = (TMAP - p_ram * map_coefficient) * dt;
|
||||
double dMAP=0;
|
||||
if (in.TotalDeltaT > 0.0)
|
||||
dMAP = (TMAP - p_ram * map_coefficient) * in.TotalDeltaT;
|
||||
else
|
||||
dMAP = (TMAP - p_ram * map_coefficient) / 120;
|
||||
|
||||
TMAP -=dMAP;
|
||||
|
||||
// Find the mean effective pressure required to achieve this manifold pressure
|
||||
|
@ -620,7 +638,7 @@ void FGPiston::doMAP(void)
|
|||
|
||||
bool bTakeoffPos = false;
|
||||
if (bTakeoffBoost) {
|
||||
if (Throttle > 0.98) {
|
||||
if (in.ThrottlePos[EngineNumber] > 0.98) {
|
||||
bTakeoffPos = true;
|
||||
}
|
||||
}
|
||||
|
@ -661,7 +679,7 @@ void FGPiston::doAirFlow(void)
|
|||
// loss of volumentric efficiency due to difference between MAP and exhaust pressure
|
||||
// Eq 6-10 from The Internal Combustion Engine - Charles Taylor Vol 1
|
||||
double ve =((gamma-1)/gamma) +( CompressionRatio -(p_amb/MAP))/(gamma*( CompressionRatio - 1));
|
||||
// FGAtmosphere::GetDensity() * FGJSBBase::m3toft3 / FGJSBBase::kgtoslug;
|
||||
|
||||
rho_air = p_amb / (R_air * T_amb);
|
||||
double swept_volume = (displacement_SI * (RPM/60)) / 2;
|
||||
double v_dot_air = swept_volume * volumetric_efficiency *ve;
|
||||
|
@ -682,12 +700,18 @@ void FGPiston::doAirFlow(void)
|
|||
|
||||
void FGPiston::doFuelFlow(void)
|
||||
{
|
||||
double thi_sea_level = 1.3 * Mixture; // Allows an AFR of infinity:1 to 11.3075:1
|
||||
double thi_sea_level = 1.3 * in.MixturePos[EngineNumber]; // Allows an AFR of infinity:1 to 11.3075:1
|
||||
equivalence_ratio = thi_sea_level * 101325.0 / p_amb;
|
||||
// double AFR = 10+(12*(1-Mixture));// mixture 10:1 to 22:1
|
||||
// double AFR = 10+(12*(1-in.Mixture[EngineNumber]));// mixture 10:1 to 22:1
|
||||
// m_dot_fuel = m_dot_air / AFR;
|
||||
m_dot_fuel = (m_dot_air * equivalence_ratio) / 14.7;
|
||||
FuelFlowRate = m_dot_fuel * 2.2046; // kg to lb
|
||||
if(Starved) // There is no fuel, so zero out the flows we've calculated so far
|
||||
{
|
||||
equivalence_ratio = 0.0;
|
||||
FuelFlowRate = 0.0;
|
||||
m_dot_fuel = 0.0;
|
||||
}
|
||||
FuelFlow_pph = FuelFlowRate * 3600; // seconds to hours
|
||||
FuelFlow_gph = FuelFlow_pph / 6.0; // Assumes 6 lbs / gallon
|
||||
}
|
||||
|
@ -773,8 +797,12 @@ void FGPiston::doEGT(void)
|
|||
ExhaustGasTemp_degK = T_amb + delta_T_exhaust;
|
||||
} else { // Drop towards ambient - guess an appropriate time constant for now
|
||||
combustion_efficiency = 0;
|
||||
dEGTdt = (RankineToKelvin(Atmosphere->GetTemperature()) - ExhaustGasTemp_degK) / 100.0;
|
||||
delta_T_exhaust = dEGTdt * dt;
|
||||
dEGTdt = (RankineToKelvin(in.Temperature) - ExhaustGasTemp_degK) / 100.0;
|
||||
if (in.TotalDeltaT > 0.0)
|
||||
delta_T_exhaust = dEGTdt * in.TotalDeltaT;
|
||||
else
|
||||
delta_T_exhaust = dEGTdt / 120;
|
||||
|
||||
ExhaustGasTemp_degK += delta_T_exhaust;
|
||||
}
|
||||
}
|
||||
|
@ -812,8 +840,12 @@ void FGPiston::doCHT(void)
|
|||
|
||||
double HeatCapacityCylinderHead = CpCylinderHead * MassCylinderHead;
|
||||
|
||||
CylinderHeadTemp_degK +=
|
||||
(dqdt_cylinder_head / HeatCapacityCylinderHead) * dt;
|
||||
if (in.TotalDeltaT > 0.0)
|
||||
CylinderHeadTemp_degK +=
|
||||
(dqdt_cylinder_head / HeatCapacityCylinderHead) * in.TotalDeltaT;
|
||||
else
|
||||
CylinderHeadTemp_degK +=
|
||||
(dqdt_cylinder_head / HeatCapacityCylinderHead) / 120.0;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -847,7 +879,10 @@ void FGPiston::doOilTemperature(void)
|
|||
|
||||
double dOilTempdt = (target_oil_temp - OilTemp_degK) / time_constant;
|
||||
|
||||
OilTemp_degK += (dOilTempdt * dt);
|
||||
if (in.TotalDeltaT > 0.0)
|
||||
OilTemp_degK += (dOilTempdt * in.TotalDeltaT);
|
||||
else
|
||||
OilTemp_degK += (dOilTempdt / 120.0);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -875,6 +910,30 @@ void FGPiston::doOilPressure(void)
|
|||
OilPressure_psi += (Design_Oil_Temp - OilTemp_degK) * Oil_Viscosity_Index * OilPressure_psi / Oil_Press_Relief_Valve;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
//
|
||||
// This is a local copy of the same function in FGStandardAtmosphere.
|
||||
|
||||
double FGPiston::GetStdPressure100K(double altitude) const
|
||||
{
|
||||
// Limit this equation to input altitudes of 100000 ft.
|
||||
if (altitude > 100000.0) altitude = 100000.0;
|
||||
|
||||
double alt[5];
|
||||
const double coef[5] = { 2116.217,
|
||||
-7.648932746E-2,
|
||||
1.0925498604E-6,
|
||||
-7.1135726027E-12,
|
||||
1.7470331356E-17 };
|
||||
|
||||
alt[0] = 1;
|
||||
for (int pwr=1; pwr<=4; pwr++) alt[pwr] = alt[pwr-1]*altitude;
|
||||
|
||||
double press = 0.0;
|
||||
for (int ctr=0; ctr<=4; ctr++) press += coef[ctr]*alt[ctr];
|
||||
return press;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
string FGPiston::GetEngineLabels(const string& delimiter)
|
||||
|
|
|
@ -46,7 +46,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_PISTON "$Id: FGPiston.h,v 1.29 2011/06/16 16:32:10 jentron Exp $";
|
||||
#define ID_PISTON "$Id: FGPiston.h,v 1.31 2011/08/04 13:45:42 jberndt Exp $";
|
||||
#define FG_MAX_BOOST_SPEEDS 3
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -198,7 +198,7 @@ boostspeed they refer to:
|
|||
@author David Megginson (initial porting and additional code)
|
||||
@author Ron Jensen (additional engine code)
|
||||
@see Taylor, Charles Fayette, "The Internal Combustion Engine in Theory and Practice"
|
||||
@version $Id: FGPiston.h,v 1.29 2011/06/16 16:32:10 jentron Exp $
|
||||
@version $Id: FGPiston.h,v 1.31 2011/08/04 13:45:42 jberndt Exp $
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -209,7 +209,7 @@ class FGPiston : public FGEngine
|
|||
{
|
||||
public:
|
||||
/// Constructor
|
||||
FGPiston(FGFDMExec* exec, Element* el, int engine_number);
|
||||
FGPiston(FGFDMExec* exec, Element* el, int engine_number, struct Inputs& input);
|
||||
/// Destructor
|
||||
~FGPiston();
|
||||
|
||||
|
@ -244,9 +244,6 @@ private:
|
|||
double FMEPDynamic;
|
||||
double FMEPStatic;
|
||||
|
||||
// timestep
|
||||
double dt;
|
||||
|
||||
void doEngineStartup(void);
|
||||
void doBoostControl(void);
|
||||
void doMAP(void);
|
||||
|
@ -257,6 +254,7 @@ private:
|
|||
void doCHT(void);
|
||||
void doOilPressure(void);
|
||||
void doOilTemperature(void);
|
||||
double GetStdPressure100K(double altitude) const;
|
||||
|
||||
int InitRunning(void);
|
||||
|
||||
|
|
|
@ -39,16 +39,13 @@ INCLUDES
|
|||
#include <sstream>
|
||||
|
||||
#include "FGPropeller.h"
|
||||
#include "models/FGPropagate.h"
|
||||
#include "models/FGAtmosphere.h"
|
||||
#include "models/FGAuxiliary.h"
|
||||
#include "input_output/FGXMLElement.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGPropeller.cpp,v 1.34 2011/06/16 14:54:06 jentron Exp $";
|
||||
static const char *IdSrc = "$Id: FGPropeller.cpp,v 1.36 2011/08/03 03:21:06 jberndt Exp $";
|
||||
static const char *IdHdr = ID_PROPELLER;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -195,19 +192,18 @@ FGPropeller::~FGPropeller()
|
|||
|
||||
double FGPropeller::Calculate(double EnginePower)
|
||||
{
|
||||
double omega, alpha, beta, PowerAvailable;
|
||||
double omega, PowerAvailable;
|
||||
|
||||
double Vel = fdmex->GetAuxiliary()->GetAeroUVW(eU);
|
||||
double rho = fdmex->GetAtmosphere()->GetDensity();
|
||||
double Vel = in.AeroUVW(eU);
|
||||
double rho = in.Density;
|
||||
double RPS = RPM/60.0;
|
||||
|
||||
PowerAvailable = EnginePower - GetPowerRequired();
|
||||
|
||||
// Calculate helical tip Mach
|
||||
double Area = 0.25*Diameter*Diameter*M_PI;
|
||||
double Vtip = RPS * Diameter * M_PI;
|
||||
HelicalTipMach = sqrt(Vtip*Vtip + Vel*Vel) /
|
||||
fdmex->GetAtmosphere()->GetSoundSpeed();
|
||||
HelicalTipMach = sqrt(Vtip*Vtip + Vel*Vel) / in.Soundspeed;
|
||||
|
||||
PowerAvailable = EnginePower - GetPowerRequired();
|
||||
|
||||
if (RPS > 0.0) J = Vel / (Diameter * RPS); // Calculate J normally
|
||||
else J = Vel / Diameter;
|
||||
|
@ -225,10 +221,8 @@ double FGPropeller::Calculate(double EnginePower)
|
|||
if (CtMach) ThrustCoeff *= CtMach->GetValue(HelicalTipMach);
|
||||
|
||||
if (P_Factor > 0.0001) {
|
||||
alpha = fdmex->GetAuxiliary()->Getalpha();
|
||||
beta = fdmex->GetAuxiliary()->Getbeta();
|
||||
SetActingLocationY( GetLocationY() + P_Factor*alpha*Sense);
|
||||
SetActingLocationZ( GetLocationZ() + P_Factor*beta*Sense);
|
||||
SetActingLocationY( GetLocationY() + P_Factor*in.Alpha*Sense);
|
||||
SetActingLocationZ( GetLocationZ() + P_Factor*in.Beta*Sense);
|
||||
}
|
||||
|
||||
Thrust = ThrustCoeff*RPS*RPS*D4*rho;
|
||||
|
@ -258,7 +252,7 @@ double FGPropeller::Calculate(double EnginePower)
|
|||
|
||||
// Transform Torque and momentum first, as PQR is used in this
|
||||
// equation and cannot be transformed itself.
|
||||
vMn = fdmex->GetPropagate()->GetPQR()*(Transform()*vH) + Transform()*vTorque;
|
||||
vMn = in.PQR*(Transform()*vH) + Transform()*vTorque;
|
||||
|
||||
return Thrust; // return thrust in pounds
|
||||
}
|
||||
|
@ -268,8 +262,8 @@ double FGPropeller::Calculate(double EnginePower)
|
|||
double FGPropeller::GetPowerRequired(void)
|
||||
{
|
||||
double cPReq, J;
|
||||
double rho = fdmex->GetAtmosphere()->GetDensity();
|
||||
double Vel = fdmex->GetAuxiliary()->GetAeroUVW(eU);
|
||||
double rho = in.Density;
|
||||
double Vel = in.AeroUVW(eU);
|
||||
double RPS = RPM / 60.0;
|
||||
|
||||
if (RPS != 0.0) J = Vel / (Diameter * RPS);
|
||||
|
|
|
@ -41,23 +41,21 @@ INCLUDES
|
|||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include "FGRocket.h"
|
||||
#include "models/FGPropulsion.h"
|
||||
#include "FGThruster.h"
|
||||
#include "FGTank.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGRocket.cpp,v 1.23 2011/01/24 13:01:56 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGRocket.cpp,v 1.26 2011/08/04 13:45:42 jberndt Exp $";
|
||||
static const char *IdHdr = ID_ROCKET;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS IMPLEMENTATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
FGRocket::FGRocket(FGFDMExec* exec, Element *el, int engine_number)
|
||||
: FGEngine(exec, el, engine_number)
|
||||
FGRocket::FGRocket(FGFDMExec* exec, Element *el, int engine_number, struct Inputs& input)
|
||||
: FGEngine(exec, el, engine_number, input)
|
||||
{
|
||||
Type = etRocket;
|
||||
Element* thrust_table_element = 0;
|
||||
|
@ -66,6 +64,7 @@ FGRocket::FGRocket(FGFDMExec* exec, Element *el, int engine_number)
|
|||
previousFuelNeedPerTank = 0.0;
|
||||
previousOxiNeedPerTank = 0.0;
|
||||
PropellantFlowRate = 0.0;
|
||||
TotalPropellantExpended = 0.0;
|
||||
FuelFlowRate = FuelExpended = 0.0;
|
||||
OxidizerFlowRate = OxidizerExpended = 0.0;
|
||||
SLOxiFlowMax = SLFuelFlowMax = 0.0;
|
||||
|
@ -126,14 +125,10 @@ void FGRocket::Calculate(void)
|
|||
{
|
||||
if (FDMExec->IntegrationSuspended()) return;
|
||||
|
||||
double dT = FDMExec->GetDeltaT()*Propulsion->GetRate();
|
||||
|
||||
RunPreFunctions();
|
||||
|
||||
if (!Flameout && !Starved) ConsumeFuel();
|
||||
|
||||
PropellantFlowRate = (FuelExpended + OxidizerExpended)/dT;
|
||||
Throttle = FCS->GetThrottlePos(EngineNumber);
|
||||
PropellantFlowRate = (FuelExpended + OxidizerExpended)/in.TotalDeltaT;
|
||||
TotalPropellantExpended += FuelExpended + OxidizerExpended;
|
||||
|
||||
// If there is a thrust table, it is a function of propellant burned. The
|
||||
// engine is started when the throttle is advanced to 1.0. After that, it
|
||||
|
@ -141,30 +136,23 @@ void FGRocket::Calculate(void)
|
|||
|
||||
if (ThrustTable != 0L) { // Thrust table given -> Solid fuel used
|
||||
|
||||
if ((Throttle == 1 || BurnTime > 0.0 ) && !Starved) {
|
||||
double TotalEngineFuelBurned=0.0;
|
||||
for (int i=0; i<(int)SourceTanks.size(); i++) {
|
||||
FGTank* tank = Propulsion->GetTank(i);
|
||||
if (SourceTanks[i] == 1) {
|
||||
TotalEngineFuelBurned += tank->GetCapacity() - tank->GetContents();
|
||||
}
|
||||
}
|
||||
if ((in.ThrottlePos[EngineNumber] == 1 || BurnTime > 0.0 ) && !Starved) {
|
||||
|
||||
VacThrust = ThrustTable->GetValue(TotalEngineFuelBurned)
|
||||
VacThrust = ThrustTable->GetValue(TotalPropellantExpended)
|
||||
* (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
|
||||
}
|
||||
BurnTime += FDMExec->GetDeltaT(); // Increment burn time
|
||||
BurnTime += in.TotalDeltaT; // Increment burn time
|
||||
} else {
|
||||
VacThrust = 0.0;
|
||||
}
|
||||
|
||||
} else { // liquid fueled rocket assumed
|
||||
|
||||
if (Throttle < MinThrottle || Starved) { // Combustion not supported
|
||||
if (in.ThrottlePos[EngineNumber] < MinThrottle || Starved) { // Combustion not supported
|
||||
|
||||
PctPower = 0.0; // desired thrust
|
||||
Flameout = true;
|
||||
|
@ -172,12 +160,9 @@ void FGRocket::Calculate(void)
|
|||
|
||||
} else { // Calculate thrust
|
||||
|
||||
// This is nonsensical. Max throttle should be assumed to be 1.0. One might
|
||||
// conceivably have a throttle setting > 1.0 for some rocket engines. But, 1.0
|
||||
// should always be the default.
|
||||
// PctPower = Throttle / MaxThrottle; // Min and MaxThrottle range from 0.0 to 1.0, normally.
|
||||
|
||||
PctPower = Throttle;
|
||||
PctPower = in.ThrottlePos[EngineNumber];
|
||||
Flameout = false;
|
||||
VacThrust = Isp * PropellantFlowRate;
|
||||
|
||||
|
@ -185,79 +170,12 @@ void FGRocket::Calculate(void)
|
|||
|
||||
} // End thrust calculations
|
||||
|
||||
It += Thruster->Calculate(VacThrust) * dT;
|
||||
LoadThrusterInputs();
|
||||
It += Thruster->Calculate(VacThrust) * in.TotalDeltaT;
|
||||
|
||||
RunPostFunctions();
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// This overrides the base class ConsumeFuel() function, for special rocket
|
||||
// engine processing.
|
||||
|
||||
void FGRocket::ConsumeFuel(void)
|
||||
{
|
||||
unsigned int i;
|
||||
FGTank* Tank;
|
||||
bool haveOxTanks = false;
|
||||
double Fshortage=0, Oshortage=0, TanksWithFuel=0, TanksWithOxidizer=0;
|
||||
|
||||
if (FuelFreeze) return;
|
||||
if (FDMExec->GetTrimStatus()) return;
|
||||
|
||||
// Count how many assigned tanks have fuel for this engine at this time.
|
||||
// If there is/are fuel tanks but no oxidizer tanks, this indicates
|
||||
// a solid rocket is being modeled.
|
||||
|
||||
for (i=0; i<SourceTanks.size(); i++) {
|
||||
Tank = Propulsion->GetTank(i);
|
||||
switch(Tank->GetType()) {
|
||||
case FGTank::ttFUEL:
|
||||
if (Tank->GetContents() > 0.0 && Tank->GetSelected() && SourceTanks[i] > 0) ++TanksWithFuel;
|
||||
break;
|
||||
case FGTank::ttOXIDIZER:
|
||||
if (Tank->GetSelected() && SourceTanks[i] > 0) {
|
||||
haveOxTanks = true;
|
||||
if (Tank->GetContents() > 0.0) ++TanksWithOxidizer;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If this engine has burned out, it is starved.
|
||||
|
||||
if (TanksWithFuel==0 || (haveOxTanks && TanksWithOxidizer==0)) {
|
||||
Starved = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Expend fuel from the engine's tanks if the tank is selected as a source
|
||||
// for this engine.
|
||||
|
||||
double fuelNeedPerTank = 0;
|
||||
double oxiNeedPerTank = 0;
|
||||
|
||||
if (TanksWithFuel > 0) fuelNeedPerTank = CalcFuelNeed()/TanksWithFuel;
|
||||
if (TanksWithOxidizer > 0) oxiNeedPerTank = CalcOxidizerNeed()/TanksWithOxidizer;
|
||||
|
||||
for (i=0; i<SourceTanks.size(); i++) {
|
||||
Tank = Propulsion->GetTank(i);
|
||||
if ( ! Tank->GetSelected() || SourceTanks[i] == 0) continue; // If this tank is not selected as a source, skip it.
|
||||
switch(Tank->GetType()) {
|
||||
case FGTank::ttFUEL:
|
||||
Fshortage += Tank->Drain(2.0*fuelNeedPerTank - previousFuelNeedPerTank);
|
||||
previousFuelNeedPerTank = fuelNeedPerTank;
|
||||
break;
|
||||
case FGTank::ttOXIDIZER:
|
||||
Oshortage += Tank->Drain(2.0*oxiNeedPerTank - previousOxiNeedPerTank);
|
||||
previousOxiNeedPerTank = oxiNeedPerTank;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Fshortage < 0.00 || (haveOxTanks && Oshortage < 0.00)) Starved = true;
|
||||
else Starved = false;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
//
|
||||
// The FuelFlowRate can be affected by the TotalIspVariation value (settable
|
||||
|
@ -267,8 +185,6 @@ void FGRocket::ConsumeFuel(void)
|
|||
|
||||
double FGRocket::CalcFuelNeed(void)
|
||||
{
|
||||
double dT = FDMExec->GetDeltaT()*Propulsion->GetRate();
|
||||
|
||||
if (ThrustTable != 0L) { // Thrust table given - infers solid fuel
|
||||
FuelFlowRate = VacThrust/Isp; // This calculates wdot (weight flow rate in lbs/sec)
|
||||
FuelFlowRate /= (1 + TotalIspVariation);
|
||||
|
@ -276,7 +192,7 @@ double FGRocket::CalcFuelNeed(void)
|
|||
FuelFlowRate = SLFuelFlowMax*PctPower;
|
||||
}
|
||||
|
||||
FuelExpended = FuelFlowRate*dT; // For this time step ...
|
||||
FuelExpended = FuelFlowRate * in.TotalDeltaT; // For this time step ...
|
||||
return FuelExpended;
|
||||
}
|
||||
|
||||
|
@ -284,9 +200,8 @@ double FGRocket::CalcFuelNeed(void)
|
|||
|
||||
double FGRocket::CalcOxidizerNeed(void)
|
||||
{
|
||||
double dT = FDMExec->GetDeltaT()*Propulsion->GetRate();
|
||||
OxidizerFlowRate = SLOxiFlowMax*PctPower;
|
||||
OxidizerExpended = OxidizerFlowRate*dT;
|
||||
OxidizerFlowRate = SLOxiFlowMax * PctPower;
|
||||
OxidizerExpended = OxidizerFlowRate * in.TotalDeltaT;
|
||||
return OxidizerExpended;
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_ROCKET "$Id: FGRocket.h,v 1.14 2010/08/21 18:08:25 jberndt Exp $"
|
||||
#define ID_ROCKET "$Id: FGRocket.h,v 1.17 2011/08/04 13:45:42 jberndt Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -118,13 +118,11 @@ for the rocket engine to be throttle up to 1. At that time, the solid rocket
|
|||
fuel begins burning and thrust is provided.
|
||||
|
||||
@author Jon S. Berndt
|
||||
$Id: FGRocket.h,v 1.14 2010/08/21 18:08:25 jberndt Exp $
|
||||
$Id: FGRocket.h,v 1.17 2011/08/04 13:45:42 jberndt Exp $
|
||||
@see FGNozzle,
|
||||
FGThruster,
|
||||
FGForce,
|
||||
FGEngine,
|
||||
FGPropulsion,
|
||||
FGTank
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -138,7 +136,7 @@ public:
|
|||
@param exec pointer to JSBSim parent object, the FDM Executive.
|
||||
@param el a pointer to the XML Element instance representing the engine.
|
||||
@param engine_number engine number */
|
||||
FGRocket(FGFDMExec* exec, Element *el, int engine_number);
|
||||
FGRocket(FGFDMExec* exec, Element *el, int engine_number, struct FGEngine::Inputs& input);
|
||||
|
||||
/** Destructor */
|
||||
~FGRocket(void);
|
||||
|
@ -146,6 +144,18 @@ public:
|
|||
/** Determines the thrust.*/
|
||||
void Calculate(void);
|
||||
|
||||
/** The fuel need is calculated based on power levels and flow rate for that
|
||||
power level. It is also turned from a rate into an actual amount (pounds)
|
||||
by multiplying it by the delta T and the rate.
|
||||
@return Total fuel requirement for this engine in pounds. */
|
||||
double CalcFuelNeed(void);
|
||||
|
||||
/** The oxidizer need is calculated based on power levels and flow rate for that
|
||||
power level. It is also turned from a rate into an actual amount (pounds)
|
||||
by multiplying it by the delta T and the rate.
|
||||
@return Total oxidizer requirement for this engine in pounds. */
|
||||
double CalcOxidizerNeed(void);
|
||||
|
||||
/** Gets the total impulse of the rocket.
|
||||
@return The cumulative total impulse of the rocket up to this time.*/
|
||||
double GetTotalImpulse(void) const {return It;}
|
||||
|
@ -188,25 +198,6 @@ public:
|
|||
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
|
||||
derived class' Calculate() function before any other calculations are
|
||||
done. This base class method removes fuel from the fuel tanks as
|
||||
appropriate, and sets the starved flag if necessary. */
|
||||
void ConsumeFuel(void);
|
||||
|
||||
/** The fuel need is calculated based on power levels and flow rate for that
|
||||
power level. It is also turned from a rate into an actual amount (pounds)
|
||||
by multiplying it by the delta T and the rate.
|
||||
@return Total fuel requirement for this engine in pounds. */
|
||||
double CalcFuelNeed(void);
|
||||
|
||||
/** The oxidizer need is calculated based on power levels and flow rate for that
|
||||
power level. It is also turned from a rate into an actual amount (pounds)
|
||||
by multiplying it by the delta T and the rate.
|
||||
@return Total oxidizer requirement for this engine in pounds. */
|
||||
double CalcOxidizerNeed(void);
|
||||
|
||||
/** Returns the vacuum thrust.
|
||||
@return The vacuum thrust in lbs. */
|
||||
double GetVacThrust(void) const {return VacThrust;}
|
||||
|
@ -223,6 +214,7 @@ private:
|
|||
double previousFuelNeedPerTank;
|
||||
double previousOxiNeedPerTank;
|
||||
double OxidizerExpended;
|
||||
double TotalPropellantExpended;
|
||||
double SLOxiFlowMax;
|
||||
double OxidizerFlowRate;
|
||||
double PropellantFlowRate;
|
||||
|
|
|
@ -45,20 +45,17 @@ INCLUDES
|
|||
#include <sstream>
|
||||
|
||||
#include "FGRotor.h"
|
||||
|
||||
#include "models/FGPropagate.h"
|
||||
#include "models/FGAtmosphere.h"
|
||||
#include "models/FGAuxiliary.h"
|
||||
#include "input_output/FGXMLElement.h"
|
||||
#include "models/FGMassBalance.h"
|
||||
|
||||
#include "input_output/FGXMLElement.h"
|
||||
|
||||
|
||||
using namespace std;
|
||||
using std::cerr;
|
||||
using std::endl;
|
||||
using std::ostringstream;
|
||||
using std::cout;
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGRotor.cpp,v 1.12 2011/03/10 01:35:25 dpculp Exp $";
|
||||
static const char *IdSrc = "$Id: FGRotor.cpp,v 1.13 2011/08/03 03:21:06 jberndt Exp $";
|
||||
static const char *IdHdr = ID_ROTOR;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -77,46 +74,28 @@ CLASS IMPLEMENTATION
|
|||
// Constructor
|
||||
|
||||
FGRotor::FGRotor(FGFDMExec *exec, Element* rotor_element, int num)
|
||||
: FGThruster(exec, rotor_element, num),
|
||||
|
||||
|
||||
// environment
|
||||
dt(0.0), rho(0.002356),
|
||||
|
||||
// configuration parameters
|
||||
Radius(0.0), BladeNum(0),
|
||||
|
||||
Sense(1.0), NominalRPM(0.0), ExternalRPM(0), RPMdefinition(0), ExtRPMsource(NULL),
|
||||
|
||||
BladeChord(0.0), LiftCurveSlope(0.0), BladeTwist(0.0), HingeOffset(0.0),
|
||||
BladeFlappingMoment(0.0), BladeMassMoment(0.0), PolarMoment(0.0),
|
||||
InflowLag(0.0),
|
||||
TipLossB(0.0),
|
||||
|
||||
GroundEffectExp(0.0), GroundEffectShift(0.0),
|
||||
|
||||
// derived parameters
|
||||
LockNumberByRho(0.0), Solidity(0.0),
|
||||
|
||||
// dynamic values
|
||||
RPM(0.0), Omega(0.0),
|
||||
|
||||
beta_orient(0.0),
|
||||
a0(0.0), a_1(0.0), b_1(0.0), a_dw(0.0), a1s(0.0), b1s(0.0),
|
||||
|
||||
H_drag(0.0), J_side(0.0), Torque(0.0), C_T(0.0),
|
||||
|
||||
lambda(-0.001), mu(0.0), nu(0.001), v_induced(0.0),
|
||||
theta_downwash(0.0), phi_downwash(0.0),
|
||||
|
||||
// control
|
||||
ControlMap(eMainCtrl),
|
||||
CollectiveCtrl(0.0), LateralCtrl(0.0), LongitudinalCtrl(0.0),
|
||||
BrakeCtrlNorm(0.0), MaxBrakePower(0.0),
|
||||
|
||||
// free-wheeling-unit (FWU)
|
||||
FreeWheelPresent(0), FreeWheelThresh(0.0), FreeWheelTransmission(0.0)
|
||||
|
||||
: FGThruster(exec, rotor_element, num),
|
||||
rho(0.002356), // environment
|
||||
Radius(0.0), BladeNum(0), // configuration parameters
|
||||
Sense(1.0), NominalRPM(0.0), ExternalRPM(0),
|
||||
RPMdefinition(0), ExtRPMsource(NULL),
|
||||
BladeChord(0.0), LiftCurveSlope(0.0), BladeTwist(0.0), HingeOffset(0.0),
|
||||
BladeFlappingMoment(0.0), BladeMassMoment(0.0), PolarMoment(0.0),
|
||||
InflowLag(0.0), TipLossB(0.0),
|
||||
GroundEffectExp(0.0), GroundEffectShift(0.0),
|
||||
LockNumberByRho(0.0), Solidity(0.0), // derived parameters
|
||||
RPM(0.0), Omega(0.0), // dynamic values
|
||||
beta_orient(0.0),
|
||||
a0(0.0), a_1(0.0), b_1(0.0), a_dw(0.0),
|
||||
a1s(0.0), b1s(0.0),
|
||||
H_drag(0.0), J_side(0.0), Torque(0.0), C_T(0.0),
|
||||
lambda(-0.001), mu(0.0), nu(0.001), v_induced(0.0),
|
||||
theta_downwash(0.0), phi_downwash(0.0),
|
||||
ControlMap(eMainCtrl), // control
|
||||
CollectiveCtrl(0.0), LateralCtrl(0.0), LongitudinalCtrl(0.0),
|
||||
BrakeCtrlNorm(0.0), MaxBrakePower(0.0),
|
||||
FreeWheelPresent(0), FreeWheelThresh(0.0), // free-wheeling-unit (FWU)
|
||||
FreeWheelTransmission(0.0)
|
||||
{
|
||||
FGColumnVector3 location(0.0, 0.0, 0.0), orientation(0.0, 0.0, 0.0);
|
||||
Element *thruster_element;
|
||||
|
@ -194,7 +173,7 @@ FGRotor::FGRotor(FGFDMExec *exec, Element* rotor_element, int num)
|
|||
|
||||
// smooth out jumps in hagl reported, otherwise the ground effect
|
||||
// calculation would cause jumps too. 1Hz seems sufficient.
|
||||
damp_hagl = Filter(1.0,dt);
|
||||
damp_hagl = Filter(1.0, dt);
|
||||
|
||||
// avoid too abrupt changes in power transmission
|
||||
FreeWheelLag = Filter(200.0,dt);
|
||||
|
@ -583,21 +562,14 @@ void FGRotor::CalcStatePart1(void)
|
|||
double B_IC; // longitudinal (pitch) control in radians
|
||||
double theta_col; // rotor collective pitch in radians
|
||||
|
||||
double Vt ;
|
||||
|
||||
FGColumnVector3 UVW_h, PQR_h;
|
||||
FGColumnVector3 vHub_ca, avFus_ca;
|
||||
|
||||
double h_agl_ft, filtered_hagl = 0.0;
|
||||
double filtered_hagl = 0.0;
|
||||
double ge_factor = 1.0;
|
||||
|
||||
// fetch needed values from environment
|
||||
Vt = fdmex->GetAuxiliary()->GetVt(); // total vehicle velocity including wind
|
||||
dt = fdmex->GetDeltaT();
|
||||
rho = fdmex->GetAtmosphere()->GetDensity(); // slugs/ft^3.
|
||||
UVW_h = fdmex->GetAuxiliary()->GetAeroUVW();
|
||||
PQR_h = fdmex->GetAuxiliary()->GetAeroPQR();
|
||||
h_agl_ft = fdmex->GetPropagate()->GetDistanceAGL();
|
||||
rho = in.Density; // slugs/ft^3.
|
||||
double h_agl_ft = in.H_agl;
|
||||
// update InvTransform, the rotor orientation could have been altered
|
||||
InvTransform = Transform().Transposed();
|
||||
|
||||
|
@ -628,9 +600,9 @@ void FGRotor::CalcStatePart1(void)
|
|||
|
||||
// all set, start calculations
|
||||
|
||||
vHub_ca = hub_vel_body2ca(UVW_h, PQR_h, A_IC, B_IC);
|
||||
vHub_ca = hub_vel_body2ca(in.AeroUVW, in.AeroPQR, A_IC, B_IC);
|
||||
|
||||
avFus_ca = fus_angvel_body2ca(PQR_h);
|
||||
avFus_ca = fus_angvel_body2ca(in.AeroPQR);
|
||||
|
||||
calc_flow_and_thrust(theta_col, vHub_ca(eU), vHub_ca(eW), ge_factor);
|
||||
|
||||
|
@ -643,8 +615,8 @@ void FGRotor::CalcStatePart1(void)
|
|||
calc_torque(theta_col);
|
||||
|
||||
// Fixme: only valid for a 'decent' rotor
|
||||
theta_downwash = atan2( - UVW_h(eU), v_induced - UVW_h(eW));
|
||||
phi_downwash = atan2( UVW_h(eV), v_induced - UVW_h(eW));
|
||||
theta_downwash = atan2( -in.AeroUVW(eU), v_induced - in.AeroUVW(eW));
|
||||
phi_downwash = atan2( in.AeroUVW(eV), v_induced - in.AeroUVW(eW));
|
||||
|
||||
vFn = body_forces(A_IC, B_IC);
|
||||
vMn = Transform() * body_moments(A_IC, B_IC);
|
||||
|
@ -658,7 +630,7 @@ void FGRotor::CalcStatePart2(double PowerAvailable)
|
|||
if (! ExternalRPM) {
|
||||
// calculate new RPM
|
||||
double ExcessTorque = PowerAvailable / Omega;
|
||||
double deltaOmega = ExcessTorque / PolarMoment * dt;
|
||||
double deltaOmega = ExcessTorque / PolarMoment * in.TotalDeltaT;
|
||||
RPM += deltaOmega/(2.0*M_PI) * 60.0;
|
||||
if (RPM < 0.0) RPM = 0.0; // Engine won't turn backwards
|
||||
}
|
||||
|
|
|
@ -38,7 +38,6 @@ INCLUDES
|
|||
|
||||
#include "FGTank.h"
|
||||
#include "FGFDMExec.h"
|
||||
#include "models/FGAuxiliary.h"
|
||||
#include "input_output/FGXMLElement.h"
|
||||
#include "input_output/FGPropertyManager.h"
|
||||
#include <iostream>
|
||||
|
@ -48,7 +47,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGTank.cpp,v 1.30 2011/06/21 04:41:54 jberndt Exp $";
|
||||
static const char *IdSrc = "$Id: FGTank.cpp,v 1.31 2011/08/03 03:21:06 jberndt Exp $";
|
||||
static const char *IdHdr = ID_TANK;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -66,6 +65,7 @@ FGTank::FGTank(FGFDMExec* exec, Element* el, int tank_number)
|
|||
InitialTemperature = Temperature = -9999.0;
|
||||
Ixx = Iyy = Izz = 0.0;
|
||||
Radius = Contents = Standpipe = Length = InnerRadius = 0.0;
|
||||
PreviousUsed = 0.0;
|
||||
ExternalFlow = 0.0;
|
||||
InitialStandpipe = 0.0;
|
||||
Capacity = 0.00001;
|
||||
|
@ -192,6 +192,7 @@ void FGTank::ResetToIC(void)
|
|||
SetContents ( InitialContents );
|
||||
PctFull = 100.0*Contents/Capacity;
|
||||
SetPriority( InitialPriority );
|
||||
PreviousUsed = 0.0;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -212,6 +213,7 @@ const double FGTank::GetXYZ(int idx)
|
|||
|
||||
double FGTank::Drain(double used)
|
||||
{
|
||||
// double AmountToDrain = 2.0*used - PreviousUsed;
|
||||
double remaining = Contents - used;
|
||||
|
||||
if (remaining >= 0) { // Reduce contents by amount used.
|
||||
|
@ -224,7 +226,7 @@ double FGTank::Drain(double used)
|
|||
Contents = 0.0;
|
||||
PctFull = 0.0;
|
||||
}
|
||||
|
||||
// PreviousUsed = AmountToDrain;
|
||||
if (grainType != gtUNKNOWN) CalculateInertias();
|
||||
|
||||
return remaining;
|
||||
|
@ -271,7 +273,7 @@ void FGTank::SetContentsGallons(double gallons)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGTank::Calculate(double dt)
|
||||
double FGTank::Calculate(double dt, double TAT_C)
|
||||
{
|
||||
if(ExternalFlow < 0.) Drain( -ExternalFlow *dt);
|
||||
else Fill(ExternalFlow * dt);
|
||||
|
@ -279,8 +281,7 @@ double FGTank::Calculate(double dt)
|
|||
if (Temperature == -9999.0) return 0.0;
|
||||
double HeatCapacity = 900.0; // Joules/lbm/C
|
||||
double TempFlowFactor = 1.115; // Watts/sqft/C
|
||||
double TAT = Exec->GetAuxiliary()->GetTAT_C();
|
||||
double Tdiff = TAT - Temperature;
|
||||
double Tdiff = TAT_C - Temperature;
|
||||
double dTemp = 0.0; // Temp change due to one surface
|
||||
if (fabs(Tdiff) > 0.1) {
|
||||
dTemp = (TempFlowFactor * Area * Tdiff * dt) / (Contents * HeatCapacity);
|
||||
|
|
|
@ -52,7 +52,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_TANK "$Id: FGTank.h,v 1.23 2011/06/13 15:23:09 jentron Exp $"
|
||||
#define ID_TANK "$Id: FGTank.h,v 1.24 2011/08/03 03:21:06 jberndt Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -218,9 +218,10 @@ public:
|
|||
/** Performs local, tanks-specific calculations, such as fuel temperature.
|
||||
This function calculates the temperature of the fuel in the tank.
|
||||
@param dt the time step for this model.
|
||||
@param TempC the Total Air Temperature in degrees Celsius.
|
||||
@return the current temperature in degrees Celsius.
|
||||
*/
|
||||
double Calculate(double dt);
|
||||
double Calculate(double dt, double TempC);
|
||||
|
||||
/** Retrieves the type of tank: Fuel or Oxidizer.
|
||||
@return the tank type, 0 for undefined, 1 for fuel, and 2 for oxidizer.
|
||||
|
@ -318,6 +319,7 @@ private:
|
|||
double Izz;
|
||||
double PctFull;
|
||||
double Contents, InitialContents;
|
||||
double PreviousUsed;
|
||||
double Area;
|
||||
double Temperature, InitialTemperature;
|
||||
double Standpipe, InitialStandpipe;
|
||||
|
@ -326,6 +328,7 @@ private:
|
|||
int Priority, InitialPriority;
|
||||
FGFDMExec* Exec;
|
||||
FGPropertyManager* PropertyManager;
|
||||
|
||||
void CalculateInertias(void);
|
||||
void Debug(int from);
|
||||
};
|
||||
|
|
|
@ -46,7 +46,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_THRUSTER "$Id: FGThruster.h,v 1.16 2011/03/10 01:35:25 dpculp Exp $"
|
||||
#define ID_THRUSTER "$Id: FGThruster.h,v 1.17 2011/08/03 03:21:06 jberndt Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -74,7 +74,7 @@ CLASS DOCUMENTATION
|
|||
1.57 (pi/2) results in no thrust at all.
|
||||
|
||||
@author Jon Berndt
|
||||
@version $Id: FGThruster.h,v 1.16 2011/03/10 01:35:25 dpculp Exp $
|
||||
@version $Id: FGThruster.h,v 1.17 2011/08/03 03:21:06 jberndt Exp $
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -112,6 +112,20 @@ public:
|
|||
virtual string GetThrusterLabels(int id, string delimeter);
|
||||
virtual string GetThrusterValues(int id, string delimeter);
|
||||
|
||||
struct Inputs {
|
||||
double TotalDeltaT;
|
||||
double H_agl;
|
||||
FGColumnVector3 PQR;
|
||||
FGColumnVector3 AeroPQR;
|
||||
FGColumnVector3 AeroUVW;
|
||||
double Density;
|
||||
double Pressure;
|
||||
double Soundspeed;
|
||||
double Alpha;
|
||||
double Beta;
|
||||
double Vt;
|
||||
} in;
|
||||
|
||||
protected:
|
||||
eType Type;
|
||||
string Name;
|
||||
|
|
|
@ -41,17 +41,15 @@ INCLUDES
|
|||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "FGTurbine.h"
|
||||
#include "FGThruster.h"
|
||||
#include "models/FGPropulsion.h"
|
||||
#include "models/FGAuxiliary.h"
|
||||
#include "models/FGAtmosphere.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGTurbine.cpp,v 1.32 2011/06/07 00:28:03 jentron Exp $";
|
||||
static const char *IdSrc = "$Id: FGTurbine.cpp,v 1.35 2011/08/04 13:45:42 jberndt Exp $";
|
||||
static const char *IdHdr = ID_TURBINE;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -59,8 +57,8 @@ CLASS IMPLEMENTATION
|
|||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
|
||||
FGTurbine::FGTurbine(FGFDMExec* exec, Element *el, int engine_number)
|
||||
: FGEngine(exec, el, engine_number)
|
||||
FGTurbine::FGTurbine(FGFDMExec* exec, Element *el, int engine_number, struct Inputs& input)
|
||||
: FGEngine(exec, el, engine_number, input)
|
||||
{
|
||||
Type = etTurbine;
|
||||
|
||||
|
@ -103,12 +101,12 @@ void FGTurbine::ResetToIC(void)
|
|||
N1 = N2 = 0.0;
|
||||
N2norm = 0.0;
|
||||
correctedTSFC = TSFC;
|
||||
ThrottlePos = AugmentCmd = 0.0;
|
||||
AugmentCmd = 0.0;
|
||||
InletPosition = NozzlePosition = 1.0;
|
||||
Stalled = Seized = Overtemp = Fire = Augmentation = Injection = Reversed = false;
|
||||
Cutoff = true;
|
||||
phase = tpOff;
|
||||
TAT = (Auxiliary->GetTotalTemperature() - 491.69) * 0.5555556;
|
||||
TAT = (in.TotalTempearture - 491.69) * 0.5555556;
|
||||
EGT_degC = TAT;
|
||||
OilTemp_degK = TAT + 273.0;
|
||||
}
|
||||
|
@ -123,10 +121,9 @@ void FGTurbine::Calculate(void)
|
|||
|
||||
RunPreFunctions();
|
||||
|
||||
TAT = (Auxiliary->GetTotalTemperature() - 491.69) * 0.5555556;
|
||||
double qbar = Auxiliary->Getqbar();
|
||||
dt = FDMExec->GetDeltaT() * Propulsion->GetRate();
|
||||
ThrottlePos = FCS->GetThrottlePos(EngineNumber);
|
||||
ThrottlePos = in.ThrottlePos[EngineNumber];
|
||||
|
||||
TAT = (in.TotalTempearture - 491.69) * 0.5555556;
|
||||
if (ThrottlePos > 1.0) {
|
||||
AugmentCmd = ThrottlePos - 1.0;
|
||||
ThrottlePos -= AugmentCmd;
|
||||
|
@ -135,7 +132,7 @@ void FGTurbine::Calculate(void)
|
|||
}
|
||||
|
||||
// When trimming is finished check if user wants engine OFF or RUNNING
|
||||
if ((phase == tpTrim) && (dt > 0)) {
|
||||
if ((phase == tpTrim) && (in.TotalDeltaT > 0)) {
|
||||
if (Running && !Starved) {
|
||||
phase = tpRun;
|
||||
N2 = IdleN2 + ThrottlePos * N2_factor;
|
||||
|
@ -155,12 +152,12 @@ void FGTurbine::Calculate(void)
|
|||
}
|
||||
|
||||
// start
|
||||
if ((Starter == true) || (qbar > 30.0)) {
|
||||
if ((Starter == true) || (in.qbar > 30.0)) {
|
||||
if (!Running && !Cutoff && (N2 > 15.0)) phase = tpStart;
|
||||
}
|
||||
|
||||
if (Cutoff && (phase != tpSpinUp)) phase = tpOff;
|
||||
if (dt == 0) phase = tpTrim;
|
||||
if (in.TotalDeltaT == 0) phase = tpTrim;
|
||||
if (Starved) phase = tpOff;
|
||||
if (Stalled) phase = tpStall;
|
||||
if (Seized) phase = tpSeize;
|
||||
|
@ -185,18 +182,16 @@ void FGTurbine::Calculate(void)
|
|||
|
||||
double FGTurbine::Off(void)
|
||||
{
|
||||
double qbar = Auxiliary->Getqbar();
|
||||
Running = false;
|
||||
FuelFlow_pph = Seek(&FuelFlow_pph, 0, 1000.0, 10000.0);
|
||||
N1 = Seek(&N1, qbar/10.0, N1/2.0, N1/2.0);
|
||||
N2 = Seek(&N2, qbar/15.0, N2/2.0, N2/2.0);
|
||||
N1 = Seek(&N1, in.qbar/10.0, N1/2.0, N1/2.0);
|
||||
N2 = Seek(&N2, in.qbar/15.0, N2/2.0, N2/2.0);
|
||||
EGT_degC = Seek(&EGT_degC, TAT, 11.7, 7.3);
|
||||
OilTemp_degK = Seek(&OilTemp_degK, TAT + 273.0, 0.2, 0.2);
|
||||
OilPressure_psi = N2 * 0.62;
|
||||
NozzlePosition = Seek(&NozzlePosition, 1.0, 0.8, 0.8);
|
||||
EPR = Seek(&EPR, 1.0, 0.2, 0.2);
|
||||
Augmentation = false;
|
||||
ConsumeFuel();
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
|
@ -206,8 +201,8 @@ double FGTurbine::Run()
|
|||
{
|
||||
double idlethrust, milthrust, thrust;
|
||||
double spoolup; // acceleration in pct/sec
|
||||
double sigma = Atmosphere->GetDensityRatio();
|
||||
double T = Atmosphere->GetTemperature();
|
||||
double sigma = in.DensityRatio;
|
||||
double T = in.Temperature;
|
||||
|
||||
idlethrust = MilThrust * IdleThrustLookup->GetValue();
|
||||
milthrust = (MilThrust - idlethrust) * MilThrustLookup->GetValue();
|
||||
|
@ -261,7 +256,7 @@ double FGTurbine::Run()
|
|||
}
|
||||
|
||||
if ((Injected == 1) && Injection) {
|
||||
InjectionTimer += dt;
|
||||
InjectionTimer += in.TotalDeltaT;
|
||||
if (InjectionTimer < InjectionTime) {
|
||||
thrust = thrust * InjectionLookup->GetValue();
|
||||
} else {
|
||||
|
@ -269,7 +264,6 @@ double FGTurbine::Run()
|
|||
}
|
||||
}
|
||||
|
||||
ConsumeFuel();
|
||||
if (Cutoff) phase = tpOff;
|
||||
if (Starved) phase = tpOff;
|
||||
|
||||
|
@ -297,7 +291,6 @@ double FGTurbine::SpinUp(void)
|
|||
|
||||
double FGTurbine::Start(void)
|
||||
{
|
||||
double qbar = Auxiliary->Getqbar();
|
||||
if ((N2 > 15.0) && !Starved) { // minimum 15% N2 needed for start
|
||||
Cranking = true; // provided for sound effects signal
|
||||
if (N2 < IdleN2) {
|
||||
|
@ -306,8 +299,7 @@ double FGTurbine::Start(void)
|
|||
EGT_degC = Seek(&EGT_degC, TAT + 363.1, 21.3, 7.3);
|
||||
FuelFlow_pph = IdleFF * N2 / IdleN2;
|
||||
OilPressure_psi = N2 * 0.62;
|
||||
ConsumeFuel();
|
||||
if ((Starter == false) && (qbar < 30.0)) phase = tpOff; // aborted start
|
||||
if ((Starter == false) && (in.qbar < 30.0)) phase = tpOff; // aborted start
|
||||
}
|
||||
else {
|
||||
phase = tpRun;
|
||||
|
@ -328,12 +320,10 @@ double FGTurbine::Start(void)
|
|||
|
||||
double FGTurbine::Stall(void)
|
||||
{
|
||||
double qbar = Auxiliary->Getqbar();
|
||||
EGT_degC = TAT + 903.14;
|
||||
FuelFlow_pph = IdleFF;
|
||||
N1 = Seek(&N1, qbar/10.0, 0, N1/10.0);
|
||||
N2 = Seek(&N2, qbar/15.0, 0, N2/10.0);
|
||||
ConsumeFuel();
|
||||
N1 = Seek(&N1, in.qbar/10.0, 0, N1/10.0);
|
||||
N2 = Seek(&N2, in.qbar/15.0, 0, N2/10.0);
|
||||
if (ThrottlePos < 0.01) {
|
||||
phase = tpRun; // clear the stall with throttle to idle
|
||||
Stalled = false;
|
||||
|
@ -345,11 +335,9 @@ double FGTurbine::Stall(void)
|
|||
|
||||
double FGTurbine::Seize(void)
|
||||
{
|
||||
double qbar = Auxiliary->Getqbar();
|
||||
N2 = 0.0;
|
||||
N1 = Seek(&N1, qbar/20.0, 0, N1/15.0);
|
||||
N1 = Seek(&N1, in.qbar/20.0, 0, N1/15.0);
|
||||
FuelFlow_pph = Cutoff ? 0.0 : IdleFF;
|
||||
ConsumeFuel();
|
||||
OilPressure_psi = 0.0;
|
||||
OilTemp_degK = Seek(&OilTemp_degK, TAT + 273.0, 0, 0.2);
|
||||
Running = false;
|
||||
|
@ -395,9 +383,8 @@ double FGTurbine::Trim()
|
|||
|
||||
double FGTurbine::CalcFuelNeed(void)
|
||||
{
|
||||
double dT = FDMExec->GetDeltaT() * Propulsion->GetRate();
|
||||
FuelFlowRate = FuelFlow_pph / 3600.0; // Calculates flow in lbs/sec from lbs/hr
|
||||
FuelExpended = FuelFlowRate * dT; // Calculates fuel expended in this time step
|
||||
FuelExpended = FuelFlowRate * in.TotalDeltaT; // Calculates fuel expended in this time step
|
||||
return FuelExpended;
|
||||
}
|
||||
|
||||
|
@ -415,10 +402,10 @@ double FGTurbine::GetPowerAvailable(void) {
|
|||
double FGTurbine::Seek(double *var, double target, double accel, double decel) {
|
||||
double v = *var;
|
||||
if (v > target) {
|
||||
v -= dt * decel;
|
||||
v -= in.TotalDeltaT * decel;
|
||||
if (v < target) v = target;
|
||||
} else if (v < target) {
|
||||
v += dt * accel;
|
||||
v += in.TotalDeltaT * accel;
|
||||
if (v > target) v = target;
|
||||
}
|
||||
return v;
|
||||
|
@ -488,7 +475,7 @@ bool FGTurbine::Load(FGFDMExec* exec, Element *el)
|
|||
delay = 90.0 / (BypassRatio + 3.0);
|
||||
N1_factor = MaxN1 - IdleN1;
|
||||
N2_factor = MaxN2 - IdleN2;
|
||||
OilTemp_degK = (Auxiliary->GetTotalTemperature() - 491.69) * 0.5555556 + 273.0;
|
||||
OilTemp_degK = (in.TotalTempearture - 491.69) * 0.5555556 + 273.0;
|
||||
IdleFF = pow(MilThrust, 0.2) * 107.0; // just an estimate
|
||||
|
||||
bindmodel();
|
||||
|
@ -544,7 +531,8 @@ void FGTurbine::bindmodel()
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
int FGTurbine::InitRunning(void) {
|
||||
int FGTurbine::InitRunning(void)
|
||||
{
|
||||
FDMExec->SuspendIntegration();
|
||||
Cutoff=false;
|
||||
Running=true;
|
||||
|
|
|
@ -42,7 +42,7 @@ INCLUDES
|
|||
|
||||
#include "FGEngine.h"
|
||||
|
||||
#define ID_TURBINE "$Id: FGTurbine.h,v 1.20 2011/06/07 00:28:03 jentron Exp $"
|
||||
#define ID_TURBINE "$Id: FGTurbine.h,v 1.22 2011/08/04 13:45:42 jberndt Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -150,7 +150,7 @@ CLASS DOCUMENTATION
|
|||
/engine/direct.xml
|
||||
</pre>
|
||||
@author David P. Culp
|
||||
@version "$Id: FGTurbine.h,v 1.20 2011/06/07 00:28:03 jentron Exp $"
|
||||
@version "$Id: FGTurbine.h,v 1.22 2011/08/04 13:45:42 jberndt Exp $"
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -164,7 +164,7 @@ public:
|
|||
@param Executive pointer to executive structure
|
||||
@param el pointer to the XML element representing the turbine engine
|
||||
@param engine_number engine number */
|
||||
FGTurbine(FGFDMExec* Executive, Element *el, int engine_number);
|
||||
FGTurbine(FGFDMExec* Executive, Element *el, int engine_number, struct Inputs& input);
|
||||
/// Destructor
|
||||
~FGTurbine();
|
||||
|
||||
|
@ -233,10 +233,9 @@ private:
|
|||
double MaxN2; ///< N2 at 100% throttle
|
||||
double IdleFF; ///< Idle Fuel Flow (lbm/hr)
|
||||
double delay; ///< Inverse spool-up time from idle to 100% (seconds)
|
||||
double dt; ///< Simulator time slice
|
||||
double N1_factor; ///< factor to tie N1 and throttle
|
||||
double N2_factor; ///< factor to tie N2 and throttle
|
||||
double ThrottlePos; ///< FCS-supplied throttle position
|
||||
double ThrottlePos; ///< FCS-supplied throttle position - modified for local use!
|
||||
double AugmentCmd; ///< modulated afterburner command (0.0 to 1.0)
|
||||
double TAT; ///< total air temperature (deg C)
|
||||
double N1_spinup; ///< N1 spin up rate from starter (per second)
|
||||
|
|
74
src/FDM/JSBSim/models/propulsion/FGTurboProp.cpp
Normal file → Executable file
74
src/FDM/JSBSim/models/propulsion/FGTurboProp.cpp
Normal file → Executable file
|
@ -44,25 +44,24 @@ INCLUDES
|
|||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "FGTurboProp.h"
|
||||
#include "FGPropeller.h"
|
||||
#include "FGRotor.h"
|
||||
#include "models/FGPropulsion.h"
|
||||
#include "models/FGAuxiliary.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id: FGTurboProp.cpp,v 1.19 2011/03/10 01:35:25 dpculp Exp $";
|
||||
static const char *IdSrc = "$Id: FGTurboProp.cpp,v 1.22 2011/08/04 13:45:42 jberndt Exp $";
|
||||
static const char *IdHdr = ID_TURBOPROP;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS IMPLEMENTATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
FGTurboProp::FGTurboProp(FGFDMExec* exec, Element *el, int engine_number)
|
||||
: FGEngine(exec, el, engine_number),
|
||||
FGTurboProp::FGTurboProp(FGFDMExec* exec, Element *el, int engine_number, struct Inputs& input)
|
||||
: FGEngine(exec, el, engine_number, input),
|
||||
ITT_N1(NULL), EnginePowerRPM_N1(NULL), EnginePowerVC(NULL)
|
||||
{
|
||||
SetDefaults();
|
||||
|
@ -151,7 +150,7 @@ bool FGTurboProp::Load(FGFDMExec* exec, Element *el)
|
|||
delay=1;
|
||||
N1_factor = MaxN1 - IdleN1;
|
||||
N2_factor = MaxN2 - IdleN2;
|
||||
OilTemp_degK = Auxiliary->GetTAT_C() + 273.0;
|
||||
OilTemp_degK = in.TAT_c + 273.0;
|
||||
if (IdleFF==-1) IdleFF = pow(MilThrust, 0.2) * 107.0; // just an estimate
|
||||
|
||||
// cout << "ENG POWER:" << EnginePowerRPM_N1->GetValue(1200,90) << endl;
|
||||
|
@ -167,34 +166,33 @@ void FGTurboProp::Calculate(void)
|
|||
{
|
||||
RunPreFunctions();
|
||||
|
||||
TAT = Auxiliary->GetTAT_C();
|
||||
dt = FDMExec->GetDeltaT() * Propulsion->GetRate();
|
||||
TAT = in.TAT_c;
|
||||
|
||||
Throttle = FCS->GetThrottlePos(EngineNumber);
|
||||
ThrottlePos = in.ThrottlePos[EngineNumber];
|
||||
|
||||
RPM = Thruster->GetRPM() * Thruster->GetGearRatio();
|
||||
if (thrusterType == FGThruster::ttPropeller) {
|
||||
((FGPropeller*)Thruster)->SetAdvance(FCS->GetPropAdvance(EngineNumber));
|
||||
((FGPropeller*)Thruster)->SetFeather(FCS->GetPropFeather(EngineNumber));
|
||||
((FGPropeller*)Thruster)->SetAdvance(in.PropAdvance[EngineNumber]);
|
||||
((FGPropeller*)Thruster)->SetFeather(in.PropFeather[EngineNumber]);
|
||||
((FGPropeller*)Thruster)->SetReverse(Reversed);
|
||||
if (Reversed) {
|
||||
((FGPropeller*)Thruster)->SetReverseCoef(Throttle);
|
||||
((FGPropeller*)Thruster)->SetReverseCoef(ThrottlePos);
|
||||
} else {
|
||||
((FGPropeller*)Thruster)->SetReverseCoef(0.0);
|
||||
}
|
||||
|
||||
if (Reversed) {
|
||||
if (Throttle < BetaRangeThrottleEnd) {
|
||||
Throttle = 0.0; // idle when in Beta-range
|
||||
if (ThrottlePos < BetaRangeThrottleEnd) {
|
||||
ThrottlePos = 0.0; // idle when in Beta-range
|
||||
} else {
|
||||
// when reversed:
|
||||
Throttle = (Throttle-BetaRangeThrottleEnd)/(1-BetaRangeThrottleEnd) * ReverseMaxPower;
|
||||
ThrottlePos = (ThrottlePos-BetaRangeThrottleEnd)/(1-BetaRangeThrottleEnd) * ReverseMaxPower;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// When trimming is finished check if user wants engine OFF or RUNNING
|
||||
if ((phase == tpTrim) && (dt > 0)) {
|
||||
if ((phase == tpTrim) && (in.TotalDeltaT > 0)) {
|
||||
if (Running && !Starved) {
|
||||
phase = tpRun;
|
||||
N2 = IdleN2;
|
||||
|
@ -221,7 +219,7 @@ void FGTurboProp::Calculate(void)
|
|||
StartTime = -1;
|
||||
}
|
||||
if (Cutoff && (phase != tpSpinUp)) phase = tpOff;
|
||||
if (dt == 0) phase = tpTrim;
|
||||
if (in.TotalDeltaT == 0) phase = tpTrim;
|
||||
if (Starved) phase = tpOff;
|
||||
if (Condition >= 10) {
|
||||
phase = tpOff;
|
||||
|
@ -239,11 +237,11 @@ void FGTurboProp::Calculate(void)
|
|||
}
|
||||
|
||||
if (Condition < 1) {
|
||||
if ( abs(torque) > Ielu_max_torque && Throttle >= OldThrottle ) {
|
||||
Throttle = OldThrottle - 0.1 * dt; //IELU down
|
||||
if ( abs(torque) > Ielu_max_torque && ThrottlePos >= OldThrottle ) {
|
||||
ThrottlePos = OldThrottle - 0.1 * in.TotalDeltaT; //IELU down
|
||||
Ielu_intervent = true;
|
||||
} else if ( Ielu_intervent && Throttle >= OldThrottle) {
|
||||
Throttle = OldThrottle + 0.05 * dt; //IELU up
|
||||
} else if ( Ielu_intervent && ThrottlePos >= OldThrottle) {
|
||||
ThrottlePos = OldThrottle + 0.05 * in.TotalDeltaT; //IELU up
|
||||
Ielu_intervent = true;
|
||||
} else {
|
||||
Ielu_intervent = false;
|
||||
|
@ -251,7 +249,7 @@ void FGTurboProp::Calculate(void)
|
|||
} else {
|
||||
Ielu_intervent = false;
|
||||
}
|
||||
OldThrottle = Throttle;
|
||||
OldThrottle = ThrottlePos;
|
||||
}
|
||||
|
||||
switch (phase) {
|
||||
|
@ -262,6 +260,7 @@ void FGTurboProp::Calculate(void)
|
|||
default: HP = 0;
|
||||
}
|
||||
|
||||
LoadThrusterInputs();
|
||||
Thruster->Calculate(HP * hptoftlbssec);
|
||||
|
||||
RunPostFunctions();
|
||||
|
@ -271,13 +270,12 @@ void FGTurboProp::Calculate(void)
|
|||
|
||||
double FGTurboProp::Off(void)
|
||||
{
|
||||
double qbar = Auxiliary->Getqbar();
|
||||
Running = false; EngStarting = false;
|
||||
|
||||
FuelFlow_pph = Seek(&FuelFlow_pph, 0, 800.0, 800.0);
|
||||
|
||||
//allow the air turn with generator
|
||||
N1 = ExpSeek(&N1, qbar/15.0, Idle_Max_Delay*2.5, Idle_Max_Delay * 5);
|
||||
N1 = ExpSeek(&N1, in.qbar/15.0, Idle_Max_Delay*2.5, Idle_Max_Delay * 5);
|
||||
|
||||
OilTemp_degK = ExpSeek(&OilTemp_degK,273.15 + TAT, 400 , 400);
|
||||
|
||||
|
@ -287,9 +285,6 @@ double FGTurboProp::Off(void)
|
|||
|
||||
OilPressure_psi = (N1/100.0*0.25+(0.1-(OilTemp_degK-273.15)*0.1/80.0)*N1/100.0) / 7692.0e-6; //from MPa to psi
|
||||
|
||||
ConsumeFuel(); // for possible setting Starved = false when fuel tank
|
||||
// is refilled (fuel crossfeed etc.)
|
||||
|
||||
if (RPM>5) return -0.012; // friction in engine when propeller spining (estimate)
|
||||
return 0.0;
|
||||
}
|
||||
|
@ -303,7 +298,7 @@ double FGTurboProp::Run(void)
|
|||
|
||||
//---
|
||||
double old_N1 = N1;
|
||||
N1 = ExpSeek(&N1, IdleN1 + Throttle * N1_factor, Idle_Max_Delay, Idle_Max_Delay * 2.4);
|
||||
N1 = ExpSeek(&N1, IdleN1 + ThrottlePos * N1_factor, Idle_Max_Delay, Idle_Max_Delay * 2.4);
|
||||
|
||||
EngPower_HP = EnginePowerRPM_N1->GetValue(RPM,N1);
|
||||
EngPower_HP *= EnginePowerVC->GetValue();
|
||||
|
@ -322,8 +317,6 @@ double FGTurboProp::Run(void)
|
|||
|
||||
OilTemp_degK = Seek(&OilTemp_degK, 353.15, 0.4-N1*0.001, 0.04);
|
||||
|
||||
ConsumeFuel();
|
||||
|
||||
if (Cutoff) phase = tpOff;
|
||||
if (Starved) phase = tpOff;
|
||||
|
||||
|
@ -360,15 +353,12 @@ double FGTurboProp::SpinUp(void)
|
|||
EngPower_HP *= EnginePowerVC->GetValue();
|
||||
if (EngPower_HP > MaxPower) EngPower_HP = MaxPower;
|
||||
|
||||
if (StartTime>=0) StartTime+=dt;
|
||||
if (StartTime>=0) StartTime+=in.TotalDeltaT;
|
||||
if (StartTime > MaxStartingTime && MaxStartingTime > 0) { //start failed due timeout
|
||||
phase = tpOff;
|
||||
StartTime = -1;
|
||||
}
|
||||
|
||||
ConsumeFuel(); // for possible setting Starved = false when fuel tank
|
||||
// is refilled (fuel crossfeed etc.)
|
||||
|
||||
return EngPower_HP;
|
||||
}
|
||||
|
||||
|
@ -409,8 +399,6 @@ double FGTurboProp::Start(void)
|
|||
Starter = false;
|
||||
}
|
||||
|
||||
ConsumeFuel();
|
||||
|
||||
return EngPower_HP;
|
||||
}
|
||||
|
||||
|
@ -419,9 +407,8 @@ double FGTurboProp::Start(void)
|
|||
|
||||
double FGTurboProp::CalcFuelNeed(void)
|
||||
{
|
||||
double dT = FDMExec->GetDeltaT() * Propulsion->GetRate();
|
||||
FuelFlowRate = FuelFlow_pph / 3600.0;
|
||||
FuelExpended = FuelFlowRate * dT;
|
||||
FuelExpended = FuelFlowRate * in.TotalDeltaT;
|
||||
return FuelExpended;
|
||||
}
|
||||
|
||||
|
@ -431,10 +418,10 @@ double FGTurboProp::Seek(double *var, double target, double accel, double decel)
|
|||
{
|
||||
double v = *var;
|
||||
if (v > target) {
|
||||
v -= dt * decel;
|
||||
v -= in.TotalDeltaT * decel;
|
||||
if (v < target) v = target;
|
||||
} else if (v < target) {
|
||||
v += dt * accel;
|
||||
v += in.TotalDeltaT * accel;
|
||||
if (v > target) v = target;
|
||||
}
|
||||
return v;
|
||||
|
@ -447,9 +434,9 @@ double FGTurboProp::ExpSeek(double *var, double target, double accel_tau, double
|
|||
// exponential delay instead of the linear delay used in Seek
|
||||
double v = *var;
|
||||
if (v > target) {
|
||||
v = (v - target) * exp ( -dt / decel_tau) + target;
|
||||
v = (v - target) * exp ( -in.TotalDeltaT / decel_tau) + target;
|
||||
} else if (v < target) {
|
||||
v = (target - v) * (1 - exp ( -dt / accel_tau)) + v;
|
||||
v = (target - v) * (1 - exp ( -in.TotalDeltaT / accel_tau)) + v;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
@ -467,7 +454,6 @@ void FGTurboProp::SetDefaults(void)
|
|||
IdleN2 = 60.0;
|
||||
MaxN1 = 100.0;
|
||||
MaxN2 = 100.0;
|
||||
Throttle = 0.0;
|
||||
InletPosition = 1.0;
|
||||
NozzlePosition = 1.0;
|
||||
Reversed = false;
|
||||
|
@ -485,7 +471,7 @@ void FGTurboProp::SetDefaults(void)
|
|||
|
||||
Idle_Max_Delay = 1.0;
|
||||
|
||||
Throttle = OldThrottle = 0.0;
|
||||
ThrottlePos = OldThrottle = 0.0;
|
||||
ITT_Delay = 0.05;
|
||||
ReverseMaxPower = 0.0;
|
||||
BetaRangeThrottleEnd = 0.0;
|
||||
|
|
9
src/FDM/JSBSim/models/propulsion/FGTurboProp.h
Normal file → Executable file
9
src/FDM/JSBSim/models/propulsion/FGTurboProp.h
Normal file → Executable file
|
@ -47,7 +47,7 @@ INCLUDES
|
|||
#include "input_output/FGXMLElement.h"
|
||||
#include "math/FGTable.h"
|
||||
|
||||
#define ID_TURBOPROP "$Id: FGTurboProp.h,v 1.14 2011/03/10 01:35:25 dpculp Exp $"
|
||||
#define ID_TURBOPROP "$Id: FGTurboProp.h,v 1.16 2011/08/04 13:45:42 jberndt Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -99,7 +99,7 @@ public:
|
|||
@param Executive pointer to executive structure
|
||||
@param el pointer to the XML element representing the turbine engine
|
||||
@param engine_number engine number*/
|
||||
FGTurboProp(FGFDMExec* Executive, Element *el, int engine_number);
|
||||
FGTurboProp(FGFDMExec* Executive, Element *el, int engine_number, struct Inputs& input);
|
||||
/// Destructor
|
||||
~FGTurboProp();
|
||||
|
||||
|
@ -110,7 +110,7 @@ public:
|
|||
|
||||
double GetPowerAvailable(void) const { return (HP * hptoftlbssec); }
|
||||
double GetRPM(void) const { return (RPM); }
|
||||
double GetIeluThrottle(void) const { return (Throttle); }
|
||||
double GetIeluThrottle(void) const { return (ThrottlePos); }
|
||||
bool GetIeluIntervent(void) const { return Ielu_intervent; }
|
||||
|
||||
double Seek(double* var, double target, double accel, double decel);
|
||||
|
@ -162,10 +162,9 @@ private:
|
|||
double MaxN2; ///< N2 at 100% throttle
|
||||
double IdleFF; ///< Idle Fuel Flow (lbm/hr)
|
||||
double delay; ///< Inverse spool-up time from idle to 100% (seconds)
|
||||
double dt; ///< Simulator time slice
|
||||
double N1_factor; ///< factor to tie N1 and throttle
|
||||
double N2_factor; ///< factor to tie N2 and throttle
|
||||
double Throttle; ///< FCS-supplied throttle position
|
||||
double ThrottlePos; ///< FCS-supplied throttle position, modified locally
|
||||
double TAT; ///< total air temperature (deg C)
|
||||
bool Stalled; ///< true if engine is compressor-stalled
|
||||
bool Seized; ///< true if inner spool is seized
|
||||
|
|
|
@ -35,9 +35,9 @@ GFX_CODE = fg_os_osgviewer.cxx fg_os_common.cxx fg_os.hxx
|
|||
JSBSIM_LIBS = \
|
||||
$(top_builddir)/src/FDM/JSBSim/libJSBSim.a \
|
||||
$(top_builddir)/src/FDM/JSBSim/initialization/libInit.a \
|
||||
$(top_builddir)/src/FDM/JSBSim/models/atmosphere/libAtmosphere.a \
|
||||
$(top_builddir)/src/FDM/JSBSim/models/libModels.a \
|
||||
$(top_builddir)/src/FDM/JSBSim/models/flight_control/libFlightControl.a\
|
||||
$(top_builddir)/src/FDM/JSBSim/models/atmosphere/libAtmosphere.a \
|
||||
$(top_builddir)/src/FDM/JSBSim/models/propulsion/libPropulsion.a \
|
||||
$(top_builddir)/src/FDM/JSBSim/input_output/libInputOutput.a \
|
||||
$(top_builddir)/src/FDM/JSBSim/math/libMath.a
|
||||
|
|
Loading…
Add table
Reference in a new issue