From 7375166c2b426f672cbada959cd2925525730777 Mon Sep 17 00:00:00 2001 From: Erik Hofman <erik@ehofman.com> Date: Sun, 11 Sep 2011 11:42:21 +0200 Subject: [PATCH] New version of JSBSim, a big rewrite. --- src/FDM/JSBSim/CMakeLists.txt | 87 ++- src/FDM/JSBSim/FGFDMExec.cpp | 501 ++++++++---- src/FDM/JSBSim/FGFDMExec.h | 112 +-- src/FDM/JSBSim/FGJSBBase.cpp | 5 +- src/FDM/JSBSim/FGJSBBase.h | 21 +- src/FDM/JSBSim/JSBSim.cxx | 91 ++- src/FDM/JSBSim/JSBSim.hxx | 23 +- .../initialization/FGInitialCondition.cpp | 39 +- .../initialization/FGInitialCondition.h | 10 +- src/FDM/JSBSim/initialization/FGTrimAxis.cpp | 26 +- src/FDM/JSBSim/input_output/FGScript.cpp | 18 +- src/FDM/JSBSim/input_output/FGScript.h | 9 +- src/FDM/JSBSim/input_output/FGXMLElement.cpp | 6 +- src/FDM/JSBSim/math/FGFunction.cpp | 412 +++++++++- src/FDM/JSBSim/math/FGFunction.h | 103 ++- src/FDM/JSBSim/math/FGLocation.h | 13 +- src/FDM/JSBSim/math/FGModelFunctions.h | 4 +- src/FDM/JSBSim/math/LagrangeMultiplier.h | 67 ++ src/FDM/JSBSim/math/Makefile.am | 2 +- src/FDM/JSBSim/models/FGAccelerations.cpp | 397 ++++++++++ src/FDM/JSBSim/models/FGAccelerations.h | 230 ++++++ src/FDM/JSBSim/models/FGAerodynamics.cpp | 125 +-- src/FDM/JSBSim/models/FGAerodynamics.h | 30 +- src/FDM/JSBSim/models/FGAircraft.cpp | 59 +- src/FDM/JSBSim/models/FGAircraft.h | 31 +- src/FDM/JSBSim/models/FGAtmosphere.cpp | 730 +++--------------- src/FDM/JSBSim/models/FGAtmosphere.h | 392 ++++------ src/FDM/JSBSim/models/FGAuxiliary.cpp | 313 ++++---- src/FDM/JSBSim/models/FGAuxiliary.h | 100 ++- src/FDM/JSBSim/models/FGBuoyantForces.cpp | 4 +- src/FDM/JSBSim/models/FGBuoyantForces.h | 10 +- src/FDM/JSBSim/models/FGExternalReactions.cpp | 27 +- src/FDM/JSBSim/models/FGExternalReactions.h | 9 +- src/FDM/JSBSim/models/FGFCS.cpp | 28 +- src/FDM/JSBSim/models/FGFCS.h | 39 +- src/FDM/JSBSim/models/FGGasCell.cpp | 35 +- src/FDM/JSBSim/models/FGGasCell.h | 27 +- src/FDM/JSBSim/models/FGGroundReactions.cpp | 77 +- src/FDM/JSBSim/models/FGGroundReactions.h | 22 +- src/FDM/JSBSim/models/FGInertial.cpp | 18 +- src/FDM/JSBSim/models/FGInertial.h | 11 +- src/FDM/JSBSim/models/FGLGear.cpp | 238 +++--- src/FDM/JSBSim/models/FGLGear.h | 67 +- src/FDM/JSBSim/models/FGMassBalance.cpp | 46 +- src/FDM/JSBSim/models/FGMassBalance.h | 17 +- src/FDM/JSBSim/models/FGModel.h | 4 +- src/FDM/JSBSim/models/FGOutput.cpp | 39 +- src/FDM/JSBSim/models/FGPropagate.cpp | 364 +-------- src/FDM/JSBSim/models/FGPropagate.h | 126 +-- src/FDM/JSBSim/models/FGPropulsion.cpp | 192 ++++- src/FDM/JSBSim/models/FGPropulsion.h | 13 +- src/FDM/JSBSim/models/Makefile.am | 4 +- src/FDM/JSBSim/models/atmosphere/FGMSIS.cpp | 44 +- src/FDM/JSBSim/models/atmosphere/FGMars.cpp | 19 +- .../atmosphere/FGStandardAtmosphere.cpp | 179 +---- .../models/atmosphere/FGStandardAtmosphere.h | 136 +--- src/FDM/JSBSim/models/atmosphere/FGWinds.cpp | 553 +++++++++++++ src/FDM/JSBSim/models/atmosphere/FGWinds.h | 349 +++++++++ src/FDM/JSBSim/models/atmosphere/Makefile.am | 4 +- .../models/flight_control/FGAccelerometer.cpp | 12 +- .../models/flight_control/FGAccelerometer.h | 12 +- .../models/flight_control/FGActuator.cpp | 13 +- .../JSBSim/models/flight_control/FGActuator.h | 13 +- .../JSBSim/models/flight_control/FGGyro.cpp | 8 +- src/FDM/JSBSim/models/flight_control/FGGyro.h | 10 +- .../JSBSim/models/flight_control/FGSensor.cpp | 4 +- .../JSBSim/models/flight_control/FGSensor.h | 34 +- .../JSBSim/models/flight_control/Makefile.am | 4 +- .../JSBSim/models/propulsion/FGElectric.cpp | 25 +- src/FDM/JSBSim/models/propulsion/FGElectric.h | 9 +- src/FDM/JSBSim/models/propulsion/FGEngine.cpp | 150 ++-- src/FDM/JSBSim/models/propulsion/FGEngine.h | 85 +- src/FDM/JSBSim/models/propulsion/FGForce.cpp | 16 +- src/FDM/JSBSim/models/propulsion/FGNozzle.cpp | 15 +- src/FDM/JSBSim/models/propulsion/FGNozzle.h | 5 +- src/FDM/JSBSim/models/propulsion/FGPiston.cpp | 223 ++++-- src/FDM/JSBSim/models/propulsion/FGPiston.h | 10 +- .../JSBSim/models/propulsion/FGPropeller.cpp | 30 +- src/FDM/JSBSim/models/propulsion/FGRocket.cpp | 117 +-- src/FDM/JSBSim/models/propulsion/FGRocket.h | 40 +- src/FDM/JSBSim/models/propulsion/FGRotor.cpp | 102 +-- src/FDM/JSBSim/models/propulsion/FGTank.cpp | 13 +- src/FDM/JSBSim/models/propulsion/FGTank.h | 7 +- src/FDM/JSBSim/models/propulsion/FGThruster.h | 18 +- .../JSBSim/models/propulsion/FGTurbine.cpp | 66 +- src/FDM/JSBSim/models/propulsion/FGTurbine.h | 9 +- .../JSBSim/models/propulsion/FGTurboProp.cpp | 74 +- .../JSBSim/models/propulsion/FGTurboProp.h | 9 +- src/Main/Makefile.am | 2 +- 89 files changed, 4428 insertions(+), 3364 deletions(-) mode change 100644 => 100755 src/FDM/JSBSim/math/FGFunction.h mode change 100644 => 100755 src/FDM/JSBSim/math/FGModelFunctions.h create mode 100755 src/FDM/JSBSim/math/LagrangeMultiplier.h create mode 100644 src/FDM/JSBSim/models/FGAccelerations.cpp create mode 100644 src/FDM/JSBSim/models/FGAccelerations.h mode change 100644 => 100755 src/FDM/JSBSim/models/atmosphere/FGMars.cpp create mode 100644 src/FDM/JSBSim/models/atmosphere/FGWinds.cpp create mode 100644 src/FDM/JSBSim/models/atmosphere/FGWinds.h mode change 100644 => 100755 src/FDM/JSBSim/models/flight_control/FGAccelerometer.cpp mode change 100644 => 100755 src/FDM/JSBSim/models/flight_control/FGAccelerometer.h mode change 100644 => 100755 src/FDM/JSBSim/models/flight_control/FGGyro.cpp mode change 100644 => 100755 src/FDM/JSBSim/models/flight_control/FGGyro.h mode change 100644 => 100755 src/FDM/JSBSim/models/flight_control/FGSensor.cpp mode change 100644 => 100755 src/FDM/JSBSim/models/flight_control/FGSensor.h mode change 100644 => 100755 src/FDM/JSBSim/models/propulsion/FGTurboProp.cpp mode change 100644 => 100755 src/FDM/JSBSim/models/propulsion/FGTurboProp.h diff --git a/src/FDM/JSBSim/CMakeLists.txt b/src/FDM/JSBSim/CMakeLists.txt index afc377ddd..c0082591a 100644 --- a/src/FDM/JSBSim/CMakeLists.txt +++ b/src/FDM/JSBSim/CMakeLists.txt @@ -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}") diff --git a/src/FDM/JSBSim/FGFDMExec.cpp b/src/FDM/JSBSim/FGFDMExec.cpp index bcfe557f1..624f10354 100644 --- a/src/FDM/JSBSim/FGFDMExec.cpp +++ b/src/FDM/JSBSim/FGFDMExec.cpp @@ -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"; } diff --git a/src/FDM/JSBSim/FGFDMExec.h b/src/FDM/JSBSim/FGFDMExec.h index e745b2224..4295348d0 100644 --- a/src/FDM/JSBSim/FGFDMExec.h +++ b/src/FDM/JSBSim/FGFDMExec.h @@ -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); diff --git a/src/FDM/JSBSim/FGJSBBase.cpp b/src/FDM/JSBSim/FGJSBBase.cpp index d34075e70..ccf098b59 100644 --- a/src/FDM/JSBSim/FGJSBBase.cpp +++ b/src/FDM/JSBSim/FGJSBBase.cpp @@ -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'; diff --git a/src/FDM/JSBSim/FGJSBBase.h b/src/FDM/JSBSim/FGJSBBase.h index 69d9f9c09..50735c3f7 100644 --- a/src/FDM/JSBSim/FGJSBBase.h +++ b/src/FDM/JSBSim/FGJSBBase.h @@ -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. diff --git a/src/FDM/JSBSim/JSBSim.cxx b/src/FDM/JSBSim/JSBSim.cxx index 94ca5a1dc..eed3c6873 100644 --- a/src/FDM/JSBSim/JSBSim.cxx +++ b/src/FDM/JSBSim/JSBSim.cxx @@ -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()); diff --git a/src/FDM/JSBSim/JSBSim.hxx b/src/FDM/JSBSim/JSBSim.hxx index 4e8cf1880..a0294d5b5 100644 --- a/src/FDM/JSBSim/JSBSim.hxx +++ b/src/FDM/JSBSim/JSBSim.hxx @@ -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; diff --git a/src/FDM/JSBSim/initialization/FGInitialCondition.cpp b/src/FDM/JSBSim/initialization/FGInitialCondition.cpp index d1b65f1bc..fabae4c5c 100644 --- a/src/FDM/JSBSim/initialization/FGInitialCondition.cpp +++ b/src/FDM/JSBSim/initialization/FGInitialCondition.cpp @@ -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, diff --git a/src/FDM/JSBSim/initialization/FGInitialCondition.h b/src/FDM/JSBSim/initialization/FGInitialCondition.h index e110ebbb3..3b349e424 100644 --- a/src/FDM/JSBSim/initialization/FGInitialCondition.h +++ b/src/FDM/JSBSim/initialization/FGInitialCondition.h @@ -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; } diff --git a/src/FDM/JSBSim/initialization/FGTrimAxis.cpp b/src/FDM/JSBSim/initialization/FGTrimAxis.cpp index e0378793f..d2baa66df 100644 --- a/src/FDM/JSBSim/initialization/FGTrimAxis.cpp +++ b/src/FDM/JSBSim/initialization/FGTrimAxis.cpp @@ -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(); } diff --git a/src/FDM/JSBSim/input_output/FGScript.cpp b/src/FDM/JSBSim/input_output/FGScript.cpp index 60d39ed9b..7a88d54ab 100755 --- a/src/FDM/JSBSim/input_output/FGScript.cpp +++ b/src/FDM/JSBSim/input_output/FGScript.cpp @@ -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: diff --git a/src/FDM/JSBSim/input_output/FGScript.h b/src/FDM/JSBSim/input_output/FGScript.h index 1ef0cfaa3..c0f8acb74 100644 --- a/src/FDM/JSBSim/input_output/FGScript.h +++ b/src/FDM/JSBSim/input_output/FGScript.h @@ -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 $" */ /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/src/FDM/JSBSim/input_output/FGXMLElement.cpp b/src/FDM/JSBSim/input_output/FGXMLElement.cpp index 383603d32..96a03d74b 100755 --- a/src/FDM/JSBSim/input_output/FGXMLElement.cpp +++ b/src/FDM/JSBSim/input_output/FGXMLElement.cpp @@ -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; diff --git a/src/FDM/JSBSim/math/FGFunction.cpp b/src/FDM/JSBSim/math/FGFunction.cpp index c0d2e6afd..c3042221e 100755 --- a/src/FDM/JSBSim/math/FGFunction.cpp +++ b/src/FDM/JSBSim/math/FGFunction.cpp @@ -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; diff --git a/src/FDM/JSBSim/math/FGFunction.h b/src/FDM/JSBSim/math/FGFunction.h old mode 100644 new mode 100755 index 91a811f9a..f3277eb6c --- a/src/FDM/JSBSim/math/FGFunction.h +++ b/src/FDM/JSBSim/math/FGFunction.h @@ -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); }; diff --git a/src/FDM/JSBSim/math/FGLocation.h b/src/FDM/JSBSim/math/FGLocation.h index c60e8ea2e..743d6ea09 100644 --- a/src/FDM/JSBSim/math/FGLocation.h +++ b/src/FDM/JSBSim/math/FGLocation.h @@ -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 diff --git a/src/FDM/JSBSim/math/FGModelFunctions.h b/src/FDM/JSBSim/math/FGModelFunctions.h old mode 100644 new mode 100755 index 2b3f94e17..b47604b6c --- a/src/FDM/JSBSim/math/FGModelFunctions.h +++ b/src/FDM/JSBSim/math/FGModelFunctions.h @@ -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=""); diff --git a/src/FDM/JSBSim/math/LagrangeMultiplier.h b/src/FDM/JSBSim/math/LagrangeMultiplier.h new file mode 100755 index 000000000..b754c5b38 --- /dev/null +++ b/src/FDM/JSBSim/math/LagrangeMultiplier.h @@ -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 diff --git a/src/FDM/JSBSim/math/Makefile.am b/src/FDM/JSBSim/math/Makefile.am index b97253ac3..5e1282ef0 100644 --- a/src/FDM/JSBSim/math/Makefile.am +++ b/src/FDM/JSBSim/math/Makefile.am @@ -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 diff --git a/src/FDM/JSBSim/models/FGAccelerations.cpp b/src/FDM/JSBSim/models/FGAccelerations.cpp new file mode 100644 index 000000000..3df618a4f --- /dev/null +++ b/src/FDM/JSBSim/models/FGAccelerations.cpp @@ -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; + } + } +} +} diff --git a/src/FDM/JSBSim/models/FGAccelerations.h b/src/FDM/JSBSim/models/FGAccelerations.h new file mode 100644 index 000000000..5cc609103 --- /dev/null +++ b/src/FDM/JSBSim/models/FGAccelerations.h @@ -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 diff --git a/src/FDM/JSBSim/models/FGAerodynamics.cpp b/src/FDM/JSBSim/models/FGAerodynamics.cpp index 4208ef626..13a9b9f17 100644 --- a/src/FDM/JSBSim/models/FGAerodynamics.cpp +++ b/src/FDM/JSBSim/models/FGAerodynamics.cpp @@ -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; } diff --git a/src/FDM/JSBSim/models/FGAerodynamics.h b/src/FDM/JSBSim/models/FGAerodynamics.h index 87744e86e..f4194e97d 100644 --- a/src/FDM/JSBSim/models/FGAerodynamics.h +++ b/src/FDM/JSBSim/models/FGAerodynamics.h @@ -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; diff --git a/src/FDM/JSBSim/models/FGAircraft.cpp b/src/FDM/JSBSim/models/FGAircraft.cpp index 7b0f3705a..a433a56fa 100644 --- a/src/FDM/JSBSim/models/FGAircraft.cpp +++ b/src/FDM/JSBSim/models/FGAircraft.cpp @@ -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); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/src/FDM/JSBSim/models/FGAircraft.h b/src/FDM/JSBSim/models/FGAircraft.h index 684f1dd2e..a7a2ba69b 100644 --- a/src/FDM/JSBSim/models/FGAircraft.h +++ b/src/FDM/JSBSim/models/FGAircraft.h @@ -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; diff --git a/src/FDM/JSBSim/models/FGAtmosphere.cpp b/src/FDM/JSBSim/models/FGAtmosphere.cpp index 990adb882..1387f013f 100644 --- a/src/FDM/JSBSim/models/FGAtmosphere.cpp +++ b/src/FDM/JSBSim/models/FGAtmosphere.cpp @@ -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; } } } diff --git a/src/FDM/JSBSim/models/FGAtmosphere.h b/src/FDM/JSBSim/models/FGAtmosphere.h index d2c8b5dbe..157cdd9d5 100644 --- a/src/FDM/JSBSim/models/FGAtmosphere.h +++ b/src/FDM/JSBSim/models/FGAtmosphere.h @@ -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); }; diff --git a/src/FDM/JSBSim/models/FGAuxiliary.cpp b/src/FDM/JSBSim/models/FGAuxiliary.cpp index 0993bc757..8e29a7e39 100755 --- a/src/FDM/JSBSim/models/FGAuxiliary.cpp +++ b/src/FDM/JSBSim/models/FGAuxiliary.cpp @@ -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; diff --git a/src/FDM/JSBSim/models/FGAuxiliary.h b/src/FDM/JSBSim/models/FGAuxiliary.h index 3061a8cd6..45a7382f5 100644 --- a/src/FDM/JSBSim/models/FGAuxiliary.h +++ b/src/FDM/JSBSim/models/FGAuxiliary.h @@ -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; diff --git a/src/FDM/JSBSim/models/FGBuoyantForces.cpp b/src/FDM/JSBSim/models/FGBuoyantForces.cpp index a1824e7a0..d98d543dd 100644 --- a/src/FDM/JSBSim/models/FGBuoyantForces.cpp +++ b/src/FDM/JSBSim/models/FGBuoyantForces.cpp @@ -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"); } diff --git a/src/FDM/JSBSim/models/FGBuoyantForces.h b/src/FDM/JSBSim/models/FGBuoyantForces.h index ac712e242..a844b9c3b 100644 --- a/src/FDM/JSBSim/models/FGBuoyantForces.h +++ b/src/FDM/JSBSim/models/FGBuoyantForces.h @@ -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. diff --git a/src/FDM/JSBSim/models/FGExternalReactions.cpp b/src/FDM/JSBSim/models/FGExternalReactions.cpp index 54a219bc4..f9e98f9f5 100755 --- a/src/FDM/JSBSim/models/FGExternalReactions.cpp +++ b/src/FDM/JSBSim/models/FGExternalReactions.cpp @@ -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 diff --git a/src/FDM/JSBSim/models/FGExternalReactions.h b/src/FDM/JSBSim/models/FGExternalReactions.h index 36666697f..9f9164ed4 100755 --- a/src/FDM/JSBSim/models/FGExternalReactions.h +++ b/src/FDM/JSBSim/models/FGExternalReactions.h @@ -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); }; } diff --git a/src/FDM/JSBSim/models/FGFCS.cpp b/src/FDM/JSBSim/models/FGFCS.cpp index 67c02d698..d781f54f1 100644 --- a/src/FDM/JSBSim/models/FGFCS.cpp +++ b/src/FDM/JSBSim/models/FGFCS.cpp @@ -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); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/src/FDM/JSBSim/models/FGFCS.h b/src/FDM/JSBSim/models/FGFCS.h index 9e6736eed..c48cc4cc1 100644 --- a/src/FDM/JSBSim/models/FGFCS.h +++ b/src/FDM/JSBSim/models/FGFCS.h @@ -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; diff --git a/src/FDM/JSBSim/models/FGGasCell.cpp b/src/FDM/JSBSim/models/FGGasCell.cpp index 742288cd6..de92cc1fa 100644 --- a/src/FDM/JSBSim/models/FGGasCell.cpp +++ b/src/FDM/JSBSim/models/FGGasCell.cpp @@ -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; diff --git a/src/FDM/JSBSim/models/FGGasCell.h b/src/FDM/JSBSim/models/FGGasCell.h index abe73ac5b..ff3613c17 100644 --- a/src/FDM/JSBSim/models/FGGasCell.h +++ b/src/FDM/JSBSim/models/FGGasCell.h @@ -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); diff --git a/src/FDM/JSBSim/models/FGGroundReactions.cpp b/src/FDM/JSBSim/models/FGGroundReactions.cpp index 7f92cec41..e38878102 100644 --- a/src/FDM/JSBSim/models/FGGroundReactions.cpp +++ b/src/FDM/JSBSim/models/FGGroundReactions.cpp @@ -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); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/src/FDM/JSBSim/models/FGGroundReactions.h b/src/FDM/JSBSim/models/FGGroundReactions.h index 64bfafa1b..5774918ad 100644 --- a/src/FDM/JSBSim/models/FGGroundReactions.h +++ b/src/FDM/JSBSim/models/FGGroundReactions.h @@ -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); diff --git a/src/FDM/JSBSim/models/FGInertial.cpp b/src/FDM/JSBSim/models/FGInertial.cpp index 93874c120..b241f78ed 100644 --- a/src/FDM/JSBSim/models/FGInertial.cpp +++ b/src/FDM/JSBSim/models/FGInertial.cpp @@ -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); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/src/FDM/JSBSim/models/FGInertial.h b/src/FDM/JSBSim/models/FGInertial.h index 5394d81b8..0e08abe29 100644 --- a/src/FDM/JSBSim/models/FGInertial.h +++ b/src/FDM/JSBSim/models/FGInertial.h @@ -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; diff --git a/src/FDM/JSBSim/models/FGLGear.cpp b/src/FDM/JSBSim/models/FGLGear.cpp index 4a4c9946f..f3fd05df7 100644 --- a/src/FDM/JSBSim/models/FGLGear.cpp +++ b/src/FDM/JSBSim/models/FGLGear.cpp @@ -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: diff --git a/src/FDM/JSBSim/models/FGLGear.h b/src/FDM/JSBSim/models/FGLGear.h index f1828f8cf..ba44029fe 100644 --- a/src/FDM/JSBSim/models/FGLGear.h +++ b/src/FDM/JSBSim/models/FGLGear.h @@ -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); diff --git a/src/FDM/JSBSim/models/FGMassBalance.cpp b/src/FDM/JSBSim/models/FGMassBalance.cpp index aee3cc3bb..9cb32f885 100644 --- a/src/FDM/JSBSim/models/FGMassBalance.cpp +++ b/src/FDM/JSBSim/models/FGMassBalance.cpp @@ -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 diff --git a/src/FDM/JSBSim/models/FGMassBalance.h b/src/FDM/JSBSim/models/FGMassBalance.h index 53279d39c..981eef6de 100644 --- a/src/FDM/JSBSim/models/FGMassBalance.h +++ b/src/FDM/JSBSim/models/FGMassBalance.h @@ -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; diff --git a/src/FDM/JSBSim/models/FGModel.h b/src/FDM/JSBSim/models/FGModel.h index eae604668..7483dface 100644 --- a/src/FDM/JSBSim/models/FGModel.h +++ b/src/FDM/JSBSim/models/FGModel.h @@ -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; diff --git a/src/FDM/JSBSim/models/FGOutput.cpp b/src/FDM/JSBSim/models/FGOutput.cpp index 3131cd6c0..36dc45ed3 100644 --- a/src/FDM/JSBSim/models/FGOutput.cpp +++ b/src/FDM/JSBSim/models/FGOutput.cpp @@ -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)); diff --git a/src/FDM/JSBSim/models/FGPropagate.cpp b/src/FDM/JSBSim/models/FGPropagate.cpp index 51bc472d2..96545104d 100644 --- a/src/FDM/JSBSim/models/FGPropagate.cpp +++ b/src/FDM/JSBSim/models/FGPropagate.cpp @@ -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; diff --git a/src/FDM/JSBSim/models/FGPropagate.h b/src/FDM/JSBSim/models/FGPropagate.h index 1afe7f641..f262d1fb1 100644 --- a/src/FDM/JSBSim/models/FGPropagate.h +++ b/src/FDM/JSBSim/models/FGPropagate.h @@ -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); diff --git a/src/FDM/JSBSim/models/FGPropulsion.cpp b/src/FDM/JSBSim/models/FGPropulsion.cpp index bb260f09b..6c5942e8d 100644 --- a/src/FDM/JSBSim/models/FGPropulsion.cpp +++ b/src/FDM/JSBSim/models/FGPropulsion.cpp @@ -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); } diff --git a/src/FDM/JSBSim/models/FGPropulsion.h b/src/FDM/JSBSim/models/FGPropulsion.h index 3dacfc4fd..b16b17382 100644 --- a/src/FDM/JSBSim/models/FGPropulsion.h +++ b/src/FDM/JSBSim/models/FGPropulsion.h @@ -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; diff --git a/src/FDM/JSBSim/models/Makefile.am b/src/FDM/JSBSim/models/Makefile.am index 6a7a7e932..ade54931b 100644 --- a/src/FDM/JSBSim/models/Makefile.am +++ b/src/FDM/JSBSim/models/Makefile.am @@ -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 diff --git a/src/FDM/JSBSim/models/atmosphere/FGMSIS.cpp b/src/FDM/JSBSim/models/atmosphere/FGMSIS.cpp index 23f185f12..429a5cbb3 100755 --- a/src/FDM/JSBSim/models/atmosphere/FGMSIS.cpp +++ b/src/FDM/JSBSim/models/atmosphere/FGMSIS.cpp @@ -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 diff --git a/src/FDM/JSBSim/models/atmosphere/FGMars.cpp b/src/FDM/JSBSim/models/atmosphere/FGMars.cpp old mode 100644 new mode 100755 index 93c388f5f..28673d3c8 --- a/src/FDM/JSBSim/models/atmosphere/FGMars.cpp +++ b/src/FDM/JSBSim/models/atmosphere/FGMars.cpp @@ -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 diff --git a/src/FDM/JSBSim/models/atmosphere/FGStandardAtmosphere.cpp b/src/FDM/JSBSim/models/atmosphere/FGStandardAtmosphere.cpp index ab0011c7f..5c8d93c87 100644 --- a/src/FDM/JSBSim/models/atmosphere/FGStandardAtmosphere.cpp +++ b/src/FDM/JSBSim/models/atmosphere/FGStandardAtmosphere.cpp @@ -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); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/src/FDM/JSBSim/models/atmosphere/FGStandardAtmosphere.h b/src/FDM/JSBSim/models/atmosphere/FGStandardAtmosphere.h index 07978941e..380550ade 100644 --- a/src/FDM/JSBSim/models/atmosphere/FGStandardAtmosphere.h +++ b/src/FDM/JSBSim/models/atmosphere/FGStandardAtmosphere.h @@ -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); }; diff --git a/src/FDM/JSBSim/models/atmosphere/FGWinds.cpp b/src/FDM/JSBSim/models/atmosphere/FGWinds.cpp new file mode 100644 index 000000000..d6c55afde --- /dev/null +++ b/src/FDM/JSBSim/models/atmosphere/FGWinds.cpp @@ -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 diff --git a/src/FDM/JSBSim/models/atmosphere/FGWinds.h b/src/FDM/JSBSim/models/atmosphere/FGWinds.h new file mode 100644 index 000000000..6ea065af6 --- /dev/null +++ b/src/FDM/JSBSim/models/atmosphere/FGWinds.h @@ -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 + diff --git a/src/FDM/JSBSim/models/atmosphere/Makefile.am b/src/FDM/JSBSim/models/atmosphere/Makefile.am index c4fc9d844..1cbe13238 100644 --- a/src/FDM/JSBSim/models/atmosphere/Makefile.am +++ b/src/FDM/JSBSim/models/atmosphere/Makefile.am @@ -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 diff --git a/src/FDM/JSBSim/models/flight_control/FGAccelerometer.cpp b/src/FDM/JSBSim/models/flight_control/FGAccelerometer.cpp old mode 100644 new mode 100755 index 30c2f2244..028509deb --- a/src/FDM/JSBSim/models/flight_control/FGAccelerometer.cpp +++ b/src/FDM/JSBSim/models/flight_control/FGAccelerometer.cpp @@ -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 diff --git a/src/FDM/JSBSim/models/flight_control/FGAccelerometer.h b/src/FDM/JSBSim/models/flight_control/FGAccelerometer.h old mode 100644 new mode 100755 index 5616ed55b..5f966b8a3 --- a/src/FDM/JSBSim/models/flight_control/FGAccelerometer.h +++ b/src/FDM/JSBSim/models/flight_control/FGAccelerometer.h @@ -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; diff --git a/src/FDM/JSBSim/models/flight_control/FGActuator.cpp b/src/FDM/JSBSim/models/flight_control/FGActuator.cpp index 9571d33f7..3baa82a9a 100644 --- a/src/FDM/JSBSim/models/flight_control/FGActuator.cpp +++ b/src/FDM/JSBSim/models/flight_control/FGActuator.cpp @@ -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; diff --git a/src/FDM/JSBSim/models/flight_control/FGActuator.h b/src/FDM/JSBSim/models/flight_control/FGActuator.h index 7a7866e6d..9259430d0 100644 --- a/src/FDM/JSBSim/models/flight_control/FGActuator.h +++ b/src/FDM/JSBSim/models/flight_control/FGActuator.h @@ -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); diff --git a/src/FDM/JSBSim/models/flight_control/FGGyro.cpp b/src/FDM/JSBSim/models/flight_control/FGGyro.cpp old mode 100644 new mode 100755 index dffb3c9da..7ee6abe44 --- a/src/FDM/JSBSim/models/flight_control/FGGyro.cpp +++ b/src/FDM/JSBSim/models/flight_control/FGGyro.cpp @@ -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); diff --git a/src/FDM/JSBSim/models/flight_control/FGGyro.h b/src/FDM/JSBSim/models/flight_control/FGGyro.h old mode 100644 new mode 100755 index 2dcc9fb21..39db505bb --- a/src/FDM/JSBSim/models/flight_control/FGGyro.h +++ b/src/FDM/JSBSim/models/flight_control/FGGyro.h @@ -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); diff --git a/src/FDM/JSBSim/models/flight_control/FGSensor.cpp b/src/FDM/JSBSim/models/flight_control/FGSensor.cpp old mode 100644 new mode 100755 index 60b5f955a..bccf5187e --- a/src/FDM/JSBSim/models/flight_control/FGSensor.cpp +++ b/src/FDM/JSBSim/models/flight_control/FGSensor.cpp @@ -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(); } diff --git a/src/FDM/JSBSim/models/flight_control/FGSensor.h b/src/FDM/JSBSim/models/flight_control/FGSensor.h old mode 100644 new mode 100755 index bcc18dbe5..4a34ac7cb --- a/src/FDM/JSBSim/models/flight_control/FGSensor.h +++ b/src/FDM/JSBSim/models/flight_control/FGSensor.h @@ -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 $ */ /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/src/FDM/JSBSim/models/flight_control/Makefile.am b/src/FDM/JSBSim/models/flight_control/Makefile.am index 2d7a1aa67..63487bcb8 100644 --- a/src/FDM/JSBSim/models/flight_control/Makefile.am +++ b/src/FDM/JSBSim/models/flight_control/Makefile.am @@ -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 diff --git a/src/FDM/JSBSim/models/propulsion/FGElectric.cpp b/src/FDM/JSBSim/models/propulsion/FGElectric.cpp index 341c02a39..c591ceb63 100644 --- a/src/FDM/JSBSim/models/propulsion/FGElectric.cpp +++ b/src/FDM/JSBSim/models/propulsion/FGElectric.cpp @@ -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(); diff --git a/src/FDM/JSBSim/models/propulsion/FGElectric.h b/src/FDM/JSBSim/models/propulsion/FGElectric.h index 28c703dee..f35be2186 100644 --- a/src/FDM/JSBSim/models/propulsion/FGElectric.h +++ b/src/FDM/JSBSim/models/propulsion/FGElectric.h @@ -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; diff --git a/src/FDM/JSBSim/models/propulsion/FGEngine.cpp b/src/FDM/JSBSim/models/propulsion/FGEngine.cpp index 707d425e4..4d8c2dc41 100644 --- a/src/FDM/JSBSim/models/propulsion/FGEngine.cpp +++ b/src/FDM/JSBSim/models/propulsion/FGEngine.cpp @@ -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; diff --git a/src/FDM/JSBSim/models/propulsion/FGEngine.h b/src/FDM/JSBSim/models/propulsion/FGEngine.h index 03b774d94..33db9998e 100644 --- a/src/FDM/JSBSim/models/propulsion/FGEngine.h +++ b/src/FDM/JSBSim/models/propulsion/FGEngine.h @@ -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; diff --git a/src/FDM/JSBSim/models/propulsion/FGForce.cpp b/src/FDM/JSBSim/models/propulsion/FGForce.cpp index 0bebb1772..bd5872b95 100644 --- a/src/FDM/JSBSim/models/propulsion/FGForce.cpp +++ b/src/FDM/JSBSim/models/propulsion/FGForce.cpp @@ -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: diff --git a/src/FDM/JSBSim/models/propulsion/FGNozzle.cpp b/src/FDM/JSBSim/models/propulsion/FGNozzle.cpp index f1d0fb12e..65cbf9ec1 100644 --- a/src/FDM/JSBSim/models/propulsion/FGNozzle.cpp +++ b/src/FDM/JSBSim/models/propulsion/FGNozzle.cpp @@ -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); diff --git a/src/FDM/JSBSim/models/propulsion/FGNozzle.h b/src/FDM/JSBSim/models/propulsion/FGNozzle.h index d2945ba7b..d210b2f50 100644 --- a/src/FDM/JSBSim/models/propulsion/FGNozzle.h +++ b/src/FDM/JSBSim/models/propulsion/FGNozzle.h @@ -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); diff --git a/src/FDM/JSBSim/models/propulsion/FGPiston.cpp b/src/FDM/JSBSim/models/propulsion/FGPiston.cpp index c687b31e8..2220cacd1 100644 --- a/src/FDM/JSBSim/models/propulsion/FGPiston.cpp +++ b/src/FDM/JSBSim/models/propulsion/FGPiston.cpp @@ -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) diff --git a/src/FDM/JSBSim/models/propulsion/FGPiston.h b/src/FDM/JSBSim/models/propulsion/FGPiston.h index 4a536b5d0..2174b806a 100644 --- a/src/FDM/JSBSim/models/propulsion/FGPiston.h +++ b/src/FDM/JSBSim/models/propulsion/FGPiston.h @@ -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); diff --git a/src/FDM/JSBSim/models/propulsion/FGPropeller.cpp b/src/FDM/JSBSim/models/propulsion/FGPropeller.cpp index 64ae65574..6d86d134d 100644 --- a/src/FDM/JSBSim/models/propulsion/FGPropeller.cpp +++ b/src/FDM/JSBSim/models/propulsion/FGPropeller.cpp @@ -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); diff --git a/src/FDM/JSBSim/models/propulsion/FGRocket.cpp b/src/FDM/JSBSim/models/propulsion/FGRocket.cpp index f8fb091cb..143c71402 100644 --- a/src/FDM/JSBSim/models/propulsion/FGRocket.cpp +++ b/src/FDM/JSBSim/models/propulsion/FGRocket.cpp @@ -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; } diff --git a/src/FDM/JSBSim/models/propulsion/FGRocket.h b/src/FDM/JSBSim/models/propulsion/FGRocket.h index 38e367510..b375c47d6 100644 --- a/src/FDM/JSBSim/models/propulsion/FGRocket.h +++ b/src/FDM/JSBSim/models/propulsion/FGRocket.h @@ -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; diff --git a/src/FDM/JSBSim/models/propulsion/FGRotor.cpp b/src/FDM/JSBSim/models/propulsion/FGRotor.cpp index 1ac58405a..401d6a0b9 100644 --- a/src/FDM/JSBSim/models/propulsion/FGRotor.cpp +++ b/src/FDM/JSBSim/models/propulsion/FGRotor.cpp @@ -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 } diff --git a/src/FDM/JSBSim/models/propulsion/FGTank.cpp b/src/FDM/JSBSim/models/propulsion/FGTank.cpp index a39fbcec3..a0417d540 100644 --- a/src/FDM/JSBSim/models/propulsion/FGTank.cpp +++ b/src/FDM/JSBSim/models/propulsion/FGTank.cpp @@ -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); diff --git a/src/FDM/JSBSim/models/propulsion/FGTank.h b/src/FDM/JSBSim/models/propulsion/FGTank.h index 4bf420a38..dc929beb5 100644 --- a/src/FDM/JSBSim/models/propulsion/FGTank.h +++ b/src/FDM/JSBSim/models/propulsion/FGTank.h @@ -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); }; diff --git a/src/FDM/JSBSim/models/propulsion/FGThruster.h b/src/FDM/JSBSim/models/propulsion/FGThruster.h index 4ef760e98..04313d797 100644 --- a/src/FDM/JSBSim/models/propulsion/FGThruster.h +++ b/src/FDM/JSBSim/models/propulsion/FGThruster.h @@ -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; diff --git a/src/FDM/JSBSim/models/propulsion/FGTurbine.cpp b/src/FDM/JSBSim/models/propulsion/FGTurbine.cpp index c4cfc3033..5b676ed8f 100644 --- a/src/FDM/JSBSim/models/propulsion/FGTurbine.cpp +++ b/src/FDM/JSBSim/models/propulsion/FGTurbine.cpp @@ -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; diff --git a/src/FDM/JSBSim/models/propulsion/FGTurbine.h b/src/FDM/JSBSim/models/propulsion/FGTurbine.h index 907d08dd2..67816c191 100644 --- a/src/FDM/JSBSim/models/propulsion/FGTurbine.h +++ b/src/FDM/JSBSim/models/propulsion/FGTurbine.h @@ -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) diff --git a/src/FDM/JSBSim/models/propulsion/FGTurboProp.cpp b/src/FDM/JSBSim/models/propulsion/FGTurboProp.cpp old mode 100644 new mode 100755 index acc35cca2..58188112a --- a/src/FDM/JSBSim/models/propulsion/FGTurboProp.cpp +++ b/src/FDM/JSBSim/models/propulsion/FGTurboProp.cpp @@ -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; diff --git a/src/FDM/JSBSim/models/propulsion/FGTurboProp.h b/src/FDM/JSBSim/models/propulsion/FGTurboProp.h old mode 100644 new mode 100755 index 1c5f48ae9..330a7267a --- a/src/FDM/JSBSim/models/propulsion/FGTurboProp.h +++ b/src/FDM/JSBSim/models/propulsion/FGTurboProp.h @@ -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 diff --git a/src/Main/Makefile.am b/src/Main/Makefile.am index f6dab96a7..fc617ad0f 100644 --- a/src/Main/Makefile.am +++ b/src/Main/Makefile.am @@ -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