#include "FGFDMExec.h"
#include "FGState.h"
-#include <models/FGAtmosphere.h>
-#include <models/atmosphere/FGMSIS.h>
-#include <models/atmosphere/FGMars.h>
-#include <models/FGFCS.h>
-#include <models/FGPropulsion.h>
-#include <models/FGMassBalance.h>
-#include <models/FGGroundReactions.h>
-#include <models/FGExternalReactions.h>
-#include <models/FGBuoyantForces.h>
-#include <models/FGAerodynamics.h>
-#include <models/FGInertial.h>
-#include <models/FGAircraft.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 "models/FGAtmosphere.h"
+#include "models/atmosphere/FGMSIS.h"
+#include "models/atmosphere/FGMars.h"
+#include "models/FGFCS.h"
+#include "models/FGPropulsion.h"
+#include "models/FGMassBalance.h"
+#include "models/FGGroundReactions.h"
+#include "models/FGExternalReactions.h"
+#include "models/FGBuoyantForces.h"
+#include "models/FGAerodynamics.h"
+#include "models/FGInertial.h"
+#include "models/FGAircraft.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>
int node_idx = 0;
char int_buf[10];
- for (unsigned int i=0; i<pcs->node->nChildren(); i++) {
+ for (int i=0; i<pcs->node->nChildren(); i++) {
pcsNew->base_string = pcs->base_string + "/" + pcs->node->getChild(i)->getName();
node_idx = pcs->node->getChild(i)->getIndex();
sprintf(int_buf, "[%d]", node_idx);
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-#include <models/FGModel.h>
-#include <models/FGOutput.h>
-#include <models/FGInput.h>
-#include <initialization/FGTrim.h>
-#include <initialization/FGInitialCondition.h>
-#include <FGJSBBase.h>
-#include <input_output/FGPropertyManager.h>
-#include <input_output/FGGroundCallback.h>
-#include <input_output/FGXMLFileRead.h>
-#include <models/FGPropagate.h>
-#include <math/FGColumnVector3.h>
+#include "models/FGModel.h"
+#include "models/FGOutput.h"
+#include "models/FGInput.h"
+#include "initialization/FGTrim.h"
+#include "initialization/FGInitialCondition.h"
+#include "FGJSBBase.h"
+#include "input_output/FGPropertyManager.h"
+#include "input_output/FGGroundCallback.h"
+#include "input_output/FGXMLFileRead.h"
+#include "models/FGPropagate.h"
+#include "math/FGColumnVector3.h"
#include <vector>
#include <string>
#include <string>
#include <map>
#include "FGJSBBase.h"
-#include <initialization/FGInitialCondition.h>
-#include <math/FGColumnVector3.h>
-#include <math/FGQuaternion.h>
+#include "initialization/FGInitialCondition.h"
+#include "math/FGColumnVector3.h"
+#include "math/FGQuaternion.h"
#include "FGFDMExec.h"
-#include <models/FGAtmosphere.h>
-#include <models/FGFCS.h>
-#include <models/FGPropagate.h>
-#include <models/FGAuxiliary.h>
-#include <models/FGAerodynamics.h>
-#include <models/FGAircraft.h>
-#include <models/FGGroundReactions.h>
-#include <models/FGPropulsion.h>
+#include "models/FGAtmosphere.h"
+#include "models/FGFCS.h"
+#include "models/FGPropagate.h"
+#include "models/FGAuxiliary.h"
+#include "models/FGAerodynamics.h"
+#include "models/FGAircraft.h"
+#include "models/FGGroundReactions.h"
+#include "models/FGPropulsion.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
*******************************************************************************/
#include "FGInitialCondition.h"
-#include <FGFDMExec.h>
-#include <models/FGInertial.h>
-#include <models/FGAtmosphere.h>
-#include <models/FGAerodynamics.h>
-#include <models/FGPropagate.h>
-#include <input_output/FGPropertyManager.h>
-#include <models/FGPropulsion.h>
-#include <input_output/FGXMLParse.h>
-#include <math/FGQuaternion.h>
+#include "FGFDMExec.h"
+#include "models/FGInertial.h"
+#include "models/FGAtmosphere.h"
+#include "models/FGAerodynamics.h"
+#include "models/FGPropagate.h"
+#include "input_output/FGPropertyManager.h"
+#include "models/FGPropulsion.h"
+#include "input_output/FGXMLParse.h"
+#include "math/FGQuaternion.h"
#include <fstream>
namespace JSBSim {
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-#include <FGFDMExec.h>
-#include <FGJSBBase.h>
-#include <math/FGColumnVector3.h>
-#include <input_output/FGXMLFileRead.h>
+#include "FGFDMExec.h"
+#include "FGJSBBase.h"
+#include "math/FGColumnVector3.h"
+#include "input_output/FGXMLFileRead.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
#include <cstdlib>
#include <iomanip>
#include "FGTrim.h"
-#include <models/FGAtmosphere.h>
+#include "models/FGAtmosphere.h"
#include "FGInitialCondition.h"
-#include <models/FGAircraft.h>
-#include <models/FGMassBalance.h>
-#include <models/FGGroundReactions.h>
-#include <models/FGInertial.h>
-#include <models/FGAerodynamics.h>
-#include <math/FGColumnVector3.h>
+#include "models/FGAircraft.h"
+#include "models/FGMassBalance.h"
+#include "models/FGGroundReactions.h"
+#include "models/FGInertial.h"
+#include "models/FGAerodynamics.h"
+#include "math/FGColumnVector3.h"
#if _MSC_VER
#pragma warning (disable : 4786 4788)
#include <string>
#include <cstdlib>
-#include <FGFDMExec.h>
-#include <models/FGAtmosphere.h>
+#include "FGFDMExec.h"
+#include "models/FGAtmosphere.h"
#include "FGInitialCondition.h"
#include "FGTrimAxis.h"
-#include <models/FGAircraft.h>
-#include <models/FGPropulsion.h>
-#include <models/FGAerodynamics.h>
+#include "models/FGAircraft.h"
+#include "models/FGPropulsion.h"
+#include "models/FGAerodynamics.h"
namespace JSBSim {
SENTRY
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-#include <math/FGColumnVector3.h>
-#include <math/FGLocation.h>
+#include "math/FGColumnVector3.h"
+#include "math/FGLocation.h"
#include "FGGroundCallback.h"
namespace JSBSim {
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-#include <math/FGColumnVector3.h>
-#include <math/FGLocation.h>
+#include "math/FGColumnVector3.h"
+#include "math/FGLocation.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
#include <string>
#include <iostream>
-#include <simgear/props/props.hxx>
+#include "simgear/props/props.hxx"
#if !PROPS_STANDALONE
-# include <simgear/math/SGMath.hxx>
+# include "simgear/math/SGMath.hxx"
#endif
#include "FGJSBBase.h"
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGScript.h"
-#include <input_output/FGXMLParse.h>
-#include <initialization/FGTrim.h>
+#include "input_output/FGXMLParse.h"
+#include "initialization/FGTrim.h"
#include <iostream>
#include "FGJSBBase.h"
#include "FGState.h"
#include "FGFDMExec.h"
-#include <math/FGFunction.h>
-#include <math/FGCondition.h>
+#include "math/FGFunction.h"
+#include "math/FGCondition.h"
#include <vector>
-#include <input_output/FGXMLFileRead.h>
+#include "input_output/FGXMLFileRead.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
static const char *IdSrc = "$Id$";
static const char *IdHdr = ID_XMLELEMENT;
+bool Element::converterIsInitialized = false;
+map <string, map <string, double> > Element::convert;
+
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS IMPLEMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
parent = 0L;
element_index = 0;
- // convert ["from"]["to"] = factor, so: from * factor = to
- // Length
- convert["M"]["FT"] = 3.2808399;
- convert["FT"]["M"] = 1.0/convert["M"]["FT"];
- convert["FT"]["IN"] = 12.0;
- convert["IN"]["FT"] = 1.0/convert["FT"]["IN"];
- convert["IN"]["M"] = convert["IN"]["FT"] * convert["FT"]["M"];
- convert["M"]["IN"] = convert["M"]["FT"] * convert["FT"]["IN"];
- // Area
- convert["M2"]["FT2"] = convert["M"]["FT"]*convert["M"]["FT"];
- convert["FT2"]["M2"] = 1.0/convert["M2"]["FT2"];
- convert["M2"]["IN2"] = convert["M"]["IN"]*convert["M"]["IN"];
- convert["IN2"]["M2"] = 1.0/convert["M2"]["IN2"];
- convert["FT2"]["IN2"] = 144.0;
- convert["IN2"]["FT2"] = 1.0/convert["FT2"]["IN2"];
- // Volume
- convert["IN3"]["CC"] = 16.387064;
- convert["CC"]["IN3"] = 1.0/convert["IN3"]["CC"];
- convert["FT3"]["IN3"] = 1728.0;
- convert["IN3"]["FT3"] = 1.0/convert["FT3"]["IN3"];
- convert["M3"]["FT3"] = 35.3146667;
- convert["FT3"]["M3"] = 1.0/convert["M3"]["FT3"];
- convert["LTR"]["IN3"] = 61.0237441;
- convert["IN3"]["LTR"] = 1.0/convert["LTR"]["IN3"];
- // Mass & Weight
- convert["LBS"]["KG"] = 0.45359237;
- convert["KG"]["LBS"] = 1.0/convert["LBS"]["KG"];
- convert["SLUG"]["KG"] = 14.59390;
- convert["KG"]["SLUG"] = 1.0/convert["SLUG"]["KG"];
- // Moments of Inertia
- convert["SLUG*FT2"]["KG*M2"] = 1.35594;
- convert["KG*M2"]["SLUG*FT2"] = 1.0/convert["SLUG*FT2"]["KG*M2"];
- // Angles
- convert["RAD"]["DEG"] = 360.0/(2.0*3.1415926);
- convert["DEG"]["RAD"] = 1.0/convert["RAD"]["DEG"];
- // Spring force
- convert["LBS/FT"]["N/M"] = 14.5939;
- convert["N/M"]["LBS/FT"] = 1.0/convert["LBS/FT"]["N/M"];
- // Damping force
- convert["LBS/FT/SEC"]["N/M/SEC"] = 14.5939;
- convert["N/M/SEC"]["LBS/FT/SEC"] = 1.0/convert["LBS/FT/SEC"]["N/M/SEC"];
- // Damping force (Square Law)
- convert["LBS/FT2/SEC2"]["N/M2/SEC2"] = 47.880259;
- convert["N/M2/SEC2"]["LBS/FT2/SEC2"] = 1.0/convert["LBS/FT2/SEC2"]["N/M2/SEC2"];
- // Power
- convert["WATTS"]["HP"] = 0.001341022;
- convert["HP"]["WATTS"] = 1.0/convert["WATTS"]["HP"];
- // Force
- convert["N"]["LBS"] = 0.22482;
- convert["LBS"]["N"] = 1.0/convert["N"]["LBS"];
- // Velocity
- convert["KTS"]["FT/SEC"] = 1.68781;
- convert["FT/SEC"]["KTS"] = 1.0/convert["KTS"]["FT/SEC"];
- convert["M/S"]["FT/S"] = 3.2808399;
- convert["FT/S"]["M/S"] = 1.0/convert["M/S"]["FT/S"];
- // Torque
- convert["FT*LBS"]["N*M"] = 1.35581795;
- convert["N*M"]["FT*LBS"] = 1/convert["FT*LBS"]["N*M"];
- // Valve
- convert["M4*SEC/KG"]["FT4*SEC/SLUG"] = convert["M"]["FT"]*convert["M"]["FT"]*
- convert["M"]["FT"]*convert["M"]["FT"]/convert["KG"]["SLUG"];
- convert["FT4*SEC/SLUG"]["M4*SEC/KG"] =
- 1.0/convert["M4*SEC/KG"]["FT4*SEC/SLUG"];
- // Pressure
- convert["INHG"]["PSF"] = 70.7180803;
- convert["PSF"]["INHG"] = 1.0/convert["INHG"]["PSF"];
- convert["ATM"]["INHG"] = 29.9246899;
- convert["INHG"]["ATM"] = 1.0/convert["ATM"]["INHG"];
- convert["PSI"]["INHG"] = 2.03625437;
- convert["INHG"]["PSI"] = 1.0/convert["PSI"]["INHG"];
- convert["INHG"]["PA"] = 3386.0; // inches Mercury to pascals
- convert["PA"]["INHG"] = 1.0/convert["INHG"]["PA"];
- convert["LBS/FT2"]["N/M2"] = 14.5939/convert["FT"]["M"];
- convert["N/M2"]["LBS/FT2"] = 1.0/convert["LBS/FT2"]["N/M2"];
- convert["LBS/FT2"]["PA"] = convert["LBS/FT2"]["N/M2"];
- convert["PA"]["LBS/FT2"] = 1.0/convert["LBS/FT2"]["PA"];
- // Mass flow
- convert["KG/MIN"]["LBS/MIN"] = convert["KG"]["LBS"];
- // Fuel Consumption
- convert["LBS/HP*HR"]["KG/KW*HR"] = 0.6083;
- convert["KG/KW*HR"]["LBS/HP*HR"] = 1.0/convert["LBS/HP*HR"]["KG/KW*HR"];
-
- // Length
- convert["M"]["M"] = 1.00;
- convert["FT"]["FT"] = 1.00;
- convert["IN"]["IN"] = 1.00;
- // Area
- convert["M2"]["M2"] = 1.00;
- convert["FT2"]["FT2"] = 1.00;
- // Volume
- convert["IN3"]["IN3"] = 1.00;
- convert["CC"]["CC"] = 1.0;
- convert["M3"]["M3"] = 1.0;
- convert["FT3"]["FT3"] = 1.0;
- convert["LTR"]["LTR"] = 1.0;
- // Mass & Weight
- convert["KG"]["KG"] = 1.00;
- convert["LBS"]["LBS"] = 1.00;
- // Moments of Inertia
- convert["KG*M2"]["KG*M2"] = 1.00;
- convert["SLUG*FT2"]["SLUG*FT2"] = 1.00;
- // Angles
- convert["DEG"]["DEG"] = 1.00;
- convert["RAD"]["RAD"] = 1.00;
- // Spring force
- convert["LBS/FT"]["LBS/FT"] = 1.00;
- convert["N/M"]["N/M"] = 1.00;
- // Damping force
- convert["LBS/FT/SEC"]["LBS/FT/SEC"] = 1.00;
- convert["N/M/SEC"]["N/M/SEC"] = 1.00;
- // Damping force (Square law)
- convert["LBS/FT2/SEC2"]["LBS/FT2/SEC2"] = 1.00;
- convert["N/M2/SEC2"]["N/M2/SEC2"] = 1.00;
- // Power
- convert["HP"]["HP"] = 1.00;
- convert["WATTS"]["WATTS"] = 1.00;
- // Force
- convert["N"]["N"] = 1.00;
- // Velocity
- convert["FT/SEC"]["FT/SEC"] = 1.00;
- convert["KTS"]["KTS"] = 1.00;
- convert["M/S"]["M/S"] = 1.0;
- // Torque
- convert["FT*LBS"]["FT*LBS"] = 1.00;
- convert["N*M"]["N*M"] = 1.00;
- // Valve
- convert["M4*SEC/KG"]["M4*SEC/KG"] = 1.0;
- convert["FT4*SEC/SLUG"]["FT4*SEC/SLUG"] = 1.0;
- // Pressure
- convert["PSI"]["PSI"] = 1.00;
- convert["PSF"]["PSF"] = 1.00;
- convert["INHG"]["INHG"] = 1.00;
- convert["ATM"]["ATM"] = 1.0;
- convert["PA"]["PA"] = 1.0;
- convert["N/M2"]["N/M2"] = 1.00;
- convert["LBS/FT2"]["LBS/FT2"] = 1.00;
- // Mass flow
- convert["LBS/SEC"]["LBS/SEC"] = 1.00;
- convert["KG/MIN"]["KG/MIN"] = 1.0;
- convert["LBS/MIN"]["LBS/MIN"] = 1.0;
- // Fuel Consumption
- convert["LBS/HP*HR"]["LBS/HP*HR"] = 1.0;
- convert["KG/KW*HR"]["KG/KW*HR"] = 1.0;
+ if (!converterIsInitialized) {
+ converterIsInitialized = true;
+ // convert ["from"]["to"] = factor, so: from * factor = to
+ // Length
+ convert["M"]["FT"] = 3.2808399;
+ convert["FT"]["M"] = 1.0/convert["M"]["FT"];
+ convert["FT"]["IN"] = 12.0;
+ convert["IN"]["FT"] = 1.0/convert["FT"]["IN"];
+ convert["IN"]["M"] = convert["IN"]["FT"] * convert["FT"]["M"];
+ convert["M"]["IN"] = convert["M"]["FT"] * convert["FT"]["IN"];
+ // Area
+ convert["M2"]["FT2"] = convert["M"]["FT"]*convert["M"]["FT"];
+ convert["FT2"]["M2"] = 1.0/convert["M2"]["FT2"];
+ convert["M2"]["IN2"] = convert["M"]["IN"]*convert["M"]["IN"];
+ convert["IN2"]["M2"] = 1.0/convert["M2"]["IN2"];
+ convert["FT2"]["IN2"] = 144.0;
+ convert["IN2"]["FT2"] = 1.0/convert["FT2"]["IN2"];
+ // Volume
+ convert["IN3"]["CC"] = 16.387064;
+ convert["CC"]["IN3"] = 1.0/convert["IN3"]["CC"];
+ convert["FT3"]["IN3"] = 1728.0;
+ convert["IN3"]["FT3"] = 1.0/convert["FT3"]["IN3"];
+ convert["M3"]["FT3"] = 35.3146667;
+ convert["FT3"]["M3"] = 1.0/convert["M3"]["FT3"];
+ convert["LTR"]["IN3"] = 61.0237441;
+ convert["IN3"]["LTR"] = 1.0/convert["LTR"]["IN3"];
+ // Mass & Weight
+ convert["LBS"]["KG"] = 0.45359237;
+ convert["KG"]["LBS"] = 1.0/convert["LBS"]["KG"];
+ convert["SLUG"]["KG"] = 14.59390;
+ convert["KG"]["SLUG"] = 1.0/convert["SLUG"]["KG"];
+ // Moments of Inertia
+ convert["SLUG*FT2"]["KG*M2"] = 1.35594;
+ convert["KG*M2"]["SLUG*FT2"] = 1.0/convert["SLUG*FT2"]["KG*M2"];
+ // Angles
+ convert["RAD"]["DEG"] = 360.0/(2.0*3.1415926);
+ convert["DEG"]["RAD"] = 1.0/convert["RAD"]["DEG"];
+ // Spring force
+ convert["LBS/FT"]["N/M"] = 14.5939;
+ convert["N/M"]["LBS/FT"] = 1.0/convert["LBS/FT"]["N/M"];
+ // Damping force
+ convert["LBS/FT/SEC"]["N/M/SEC"] = 14.5939;
+ convert["N/M/SEC"]["LBS/FT/SEC"] = 1.0/convert["LBS/FT/SEC"]["N/M/SEC"];
+ // Damping force (Square Law)
+ convert["LBS/FT2/SEC2"]["N/M2/SEC2"] = 47.880259;
+ convert["N/M2/SEC2"]["LBS/FT2/SEC2"] = 1.0/convert["LBS/FT2/SEC2"]["N/M2/SEC2"];
+ // Power
+ convert["WATTS"]["HP"] = 0.001341022;
+ convert["HP"]["WATTS"] = 1.0/convert["WATTS"]["HP"];
+ // Force
+ convert["N"]["LBS"] = 0.22482;
+ convert["LBS"]["N"] = 1.0/convert["N"]["LBS"];
+ // Velocity
+ convert["KTS"]["FT/SEC"] = 1.68781;
+ convert["FT/SEC"]["KTS"] = 1.0/convert["KTS"]["FT/SEC"];
+ convert["M/S"]["FT/S"] = 3.2808399;
+ convert["FT/S"]["M/S"] = 1.0/convert["M/S"]["FT/S"];
+ // Torque
+ convert["FT*LBS"]["N*M"] = 1.35581795;
+ convert["N*M"]["FT*LBS"] = 1/convert["FT*LBS"]["N*M"];
+ // Valve
+ convert["M4*SEC/KG"]["FT4*SEC/SLUG"] = convert["M"]["FT"]*convert["M"]["FT"]*
+ convert["M"]["FT"]*convert["M"]["FT"]/convert["KG"]["SLUG"];
+ convert["FT4*SEC/SLUG"]["M4*SEC/KG"] =
+ 1.0/convert["M4*SEC/KG"]["FT4*SEC/SLUG"];
+ // Pressure
+ convert["INHG"]["PSF"] = 70.7180803;
+ convert["PSF"]["INHG"] = 1.0/convert["INHG"]["PSF"];
+ convert["ATM"]["INHG"] = 29.9246899;
+ convert["INHG"]["ATM"] = 1.0/convert["ATM"]["INHG"];
+ convert["PSI"]["INHG"] = 2.03625437;
+ convert["INHG"]["PSI"] = 1.0/convert["PSI"]["INHG"];
+ convert["INHG"]["PA"] = 3386.0; // inches Mercury to pascals
+ convert["PA"]["INHG"] = 1.0/convert["INHG"]["PA"];
+ convert["LBS/FT2"]["N/M2"] = 14.5939/convert["FT"]["M"];
+ convert["N/M2"]["LBS/FT2"] = 1.0/convert["LBS/FT2"]["N/M2"];
+ convert["LBS/FT2"]["PA"] = convert["LBS/FT2"]["N/M2"];
+ convert["PA"]["LBS/FT2"] = 1.0/convert["LBS/FT2"]["PA"];
+ // Mass flow
+ convert["KG/MIN"]["LBS/MIN"] = convert["KG"]["LBS"];
+ // Fuel Consumption
+ convert["LBS/HP*HR"]["KG/KW*HR"] = 0.6083;
+ convert["KG/KW*HR"]["LBS/HP*HR"] = 1.0/convert["LBS/HP*HR"]["KG/KW*HR"];
+
+ // Length
+ convert["M"]["M"] = 1.00;
+ convert["FT"]["FT"] = 1.00;
+ convert["IN"]["IN"] = 1.00;
+ // Area
+ convert["M2"]["M2"] = 1.00;
+ convert["FT2"]["FT2"] = 1.00;
+ // Volume
+ convert["IN3"]["IN3"] = 1.00;
+ convert["CC"]["CC"] = 1.0;
+ convert["M3"]["M3"] = 1.0;
+ convert["FT3"]["FT3"] = 1.0;
+ convert["LTR"]["LTR"] = 1.0;
+ // Mass & Weight
+ convert["KG"]["KG"] = 1.00;
+ convert["LBS"]["LBS"] = 1.00;
+ // Moments of Inertia
+ convert["KG*M2"]["KG*M2"] = 1.00;
+ convert["SLUG*FT2"]["SLUG*FT2"] = 1.00;
+ // Angles
+ convert["DEG"]["DEG"] = 1.00;
+ convert["RAD"]["RAD"] = 1.00;
+ // Spring force
+ convert["LBS/FT"]["LBS/FT"] = 1.00;
+ convert["N/M"]["N/M"] = 1.00;
+ // Damping force
+ convert["LBS/FT/SEC"]["LBS/FT/SEC"] = 1.00;
+ convert["N/M/SEC"]["N/M/SEC"] = 1.00;
+ // Damping force (Square law)
+ convert["LBS/FT2/SEC2"]["LBS/FT2/SEC2"] = 1.00;
+ convert["N/M2/SEC2"]["N/M2/SEC2"] = 1.00;
+ // Power
+ convert["HP"]["HP"] = 1.00;
+ convert["WATTS"]["WATTS"] = 1.00;
+ // Force
+ convert["N"]["N"] = 1.00;
+ // Velocity
+ convert["FT/SEC"]["FT/SEC"] = 1.00;
+ convert["KTS"]["KTS"] = 1.00;
+ convert["M/S"]["M/S"] = 1.0;
+ // Torque
+ convert["FT*LBS"]["FT*LBS"] = 1.00;
+ convert["N*M"]["N*M"] = 1.00;
+ // Valve
+ convert["M4*SEC/KG"]["M4*SEC/KG"] = 1.0;
+ convert["FT4*SEC/SLUG"]["FT4*SEC/SLUG"] = 1.0;
+ // Pressure
+ convert["PSI"]["PSI"] = 1.00;
+ convert["PSF"]["PSF"] = 1.00;
+ convert["INHG"]["INHG"] = 1.00;
+ convert["ATM"]["ATM"] = 1.0;
+ convert["PA"]["PA"] = 1.0;
+ convert["N/M2"]["N/M2"] = 1.00;
+ convert["LBS/FT2"]["LBS/FT2"] = 1.00;
+ // Mass flow
+ convert["LBS/SEC"]["LBS/SEC"] = 1.00;
+ convert["KG/MIN"]["KG/MIN"] = 1.0;
+ convert["LBS/MIN"]["LBS/MIN"] = 1.0;
+ // Fuel Consumption
+ convert["LBS/HP*HR"]["LBS/HP*HR"] = 1.0;
+ convert["KG/KW*HR"]["KG/KW*HR"] = 1.0;
+ }
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
using std::cout;
using std::endl;
-#include <math/FGColumnVector3.h>
+#include "math/FGColumnVector3.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
Element *parent;
unsigned int element_index;
typedef map <string, map <string, double> > tMapConvert;
- tMapConvert convert;
+ static tMapConvert convert;
+ static bool converterIsInitialized;
};
} // namespace JSBSim
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-#include <input_output/FGXMLParse.h>
+#include "input_output/FGXMLParse.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include <map>
-#include <FGJSBBase.h>
-#include <input_output/FGXMLElement.h>
-#include <input_output/FGPropertyManager.h>
+#include "FGJSBBase.h"
+#include "input_output/FGXMLElement.h"
+#include "input_output/FGPropertyManager.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
{
Element* element;
string operation, property_name;
- int size = el->GetNumElements();
cached = false;
cachedValue = -HUGE_VAL;
#include <vector>
#include <string>
#include "FGParameter.h"
-#include <input_output/FGXMLElement.h>
-#include <input_output/FGPropertyManager.h>
+#include "input_output/FGXMLElement.h"
+#include "input_output/FGPropertyManager.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
#include <cmath>
#include "FGLocation.h"
-#include <input_output/FGPropertyManager.h>
+#include "input_output/FGPropertyManager.h"
namespace JSBSim {
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-#include <FGJSBBase.h>
-#include <input_output/FGPropertyManager.h>
+#include "FGJSBBase.h"
+#include "input_output/FGPropertyManager.h"
#include "FGColumnVector3.h"
#include "FGMatrix33.h"
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGParameter.h"
-#include <input_output/FGPropertyManager.h>
+#include "input_output/FGPropertyManager.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-#include <FGJSBBase.h>
+#include "FGJSBBase.h"
#include "FGMatrix33.h"
#include "FGColumnVector3.h"
-#include <input_output/FGPropertyManager.h>
+#include "input_output/FGPropertyManager.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
FGTable& FGTable::operator<<(const double n)
{
Data[rowCounter][colCounter] = n;
- if (colCounter == nCols) {
+ if (colCounter == (int)nCols) {
colCounter = 0;
rowCounter++;
} else {
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-#include <input_output/FGXMLElement.h>
+#include "input_output/FGXMLElement.h"
#include "FGParameter.h"
-#include <input_output/FGPropertyManager.h>
+#include "input_output/FGPropertyManager.h"
#include <sstream>
#include <vector>
#include "FGAircraft.h"
#include "FGAuxiliary.h"
#include "FGMassBalance.h"
-#include <input_output/FGPropertyManager.h>
+#include "input_output/FGPropertyManager.h"
namespace JSBSim {
Debug(2);
- if (temp_element = document->FindElement("alphalimits")) {
+ if ((temp_element = document->FindElement("alphalimits"))) {
scratch_unit = temp_element->GetAttributeValue("unit");
if (scratch_unit.empty()) scratch_unit = "RAD";
alphaclmin = temp_element->FindElementValueAsNumberConvertFromTo("min", scratch_unit, "RAD");
alphaclmax = temp_element->FindElementValueAsNumberConvertFromTo("max", scratch_unit, "RAD");
}
- if (temp_element = document->FindElement("hysteresis_limits")) {
+ if ((temp_element = document->FindElement("hysteresis_limits"))) {
scratch_unit = temp_element->GetAttributeValue("unit");
if (scratch_unit.empty()) scratch_unit = "RAD";
alphahystmin = temp_element->FindElementValueAsNumberConvertFromTo("min", scratch_unit, "RAD");
alphahystmax = temp_element->FindElementValueAsNumberConvertFromTo("max", scratch_unit, "RAD");
}
- if (temp_element = document->FindElement("aero_ref_pt_shift_x")) {
+ if ((temp_element = document->FindElement("aero_ref_pt_shift_x"))) {
function_element = temp_element->FindElement("function");
AeroRPShift = new FGFunction(PropertyManager, function_element);
}
case (atBodyXYZ):
cout << endl << " Aerodynamics (X|Y|Z axes):" << endl << endl;
break;
+ case (atNone):
+ cout << endl << " Aerodynamics (undefined axes):" << endl << endl;
+ break;
}
}
}
#include <map>
#include "FGModel.h"
-#include <math/FGFunction.h>
-#include <math/FGColumnVector3.h>
-#include <math/FGMatrix33.h>
-#include <input_output/FGXMLFileRead.h>
+#include "math/FGFunction.h"
+#include "math/FGColumnVector3.h"
+#include "math/FGMatrix33.h"
+#include "input_output/FGXMLFileRead.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
#include "FGExternalReactions.h"
#include "FGBuoyantForces.h"
#include "FGAerodynamics.h"
-#include <FGFDMExec.h>
+#include "FGFDMExec.h"
#include "FGPropagate.h"
-#include <input_output/FGPropertyManager.h>
+#include "input_output/FGPropertyManager.h"
namespace JSBSim {
#include <vector>
#include "FGModel.h"
-#include <input_output/FGXMLElement.h>
-#include <math/FGColumnVector3.h>
+#include "input_output/FGXMLElement.h"
+#include "math/FGColumnVector3.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGAtmosphere.h"
-#include <FGState.h>
-#include <FGFDMExec.h>
+#include "FGState.h"
+#include "FGFDMExec.h"
#include "FGAircraft.h"
#include "FGPropagate.h"
#include "FGInertial.h"
-#include <input_output/FGPropertyManager.h>
+#include "input_output/FGPropertyManager.h"
namespace JSBSim {
vDirectiondAccelDt(eX) = GaussianRandomNumber();
vDirectiondAccelDt(eY) = GaussianRandomNumber();
vDirectiondAccelDt(eZ) = GaussianRandomNumber();
-
+/*
MagnitudedAccelDt = GaussianRandomNumber();
MagnitudeAccel += MagnitudedAccelDt * DeltaT;
Magnitude += MagnitudeAccel * DeltaT;
+*/
+ Magnitude += GaussianRandomNumber() * DeltaT;
vDirectiondAccelDt.Normalize();
vDirectionAccel += TurbRate * vDirectiondAccelDt * DeltaT;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGModel.h"
-#include <math/FGColumnVector3.h>
+#include "math/FGColumnVector3.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
#include "FGAerodynamics.h"
#include "FGPropagate.h"
#include "FGAtmosphere.h"
-#include <FGFDMExec.h>
+#include "FGFDMExec.h"
#include "FGAircraft.h"
#include "FGInertial.h"
#include "FGExternalReactions.h"
#include "FGBuoyantForces.h"
#include "FGGroundReactions.h"
#include "FGPropulsion.h"
-#include <input_output/FGPropertyManager.h>
+#include "input_output/FGPropertyManager.h"
namespace JSBSim {
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGModel.h"
-#include <FGFDMExec.h>
-#include <math/FGColumnVector3.h>
-#include <math/FGLocation.h>
+#include "FGFDMExec.h"
+#include "math/FGColumnVector3.h"
+#include "math/FGLocation.h"
#include "FGPropagate.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#include "FGBuoyantForces.h"
#include "FGMassBalance.h"
-#include <input_output/FGPropertyManager.h> // Need?
+#include "input_output/FGPropertyManager.h" // Need?
namespace JSBSim {
#include "FGModel.h"
#include "FGGasCell.h"
-#include <math/FGColumnVector3.h>
-#include <input_output/FGXMLFileRead.h>
+#include "math/FGColumnVector3.h"
+#include "input_output/FGXMLFileRead.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-#include <FGFDMExec.h>
-#include <FGJSBBase.h>
-#include <models/propulsion/FGForce.h>
+#include "FGFDMExec.h"
+#include "FGJSBBase.h"
+#include "models/propulsion/FGForce.h"
#include <string>
-#include <input_output/FGPropertyManager.h>
-#include <math/FGColumnVector3.h>
-#include <math/FGFunction.h>
+#include "input_output/FGPropertyManager.h"
+#include "math/FGColumnVector3.h"
+#include "math/FGFunction.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
#include "FGModel.h"
#include "FGExternalForce.h"
-#include <input_output/FGXMLElement.h>
+#include "input_output/FGXMLElement.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGFCS.h"
-#include <FGFDMExec.h>
-#include <input_output/FGPropertyManager.h>
+#include "FGFDMExec.h"
+#include "input_output/FGPropertyManager.h"
#include <fstream>
#include <sstream>
#include <iomanip>
-#include <models/flight_control/FGFilter.h>
-#include <models/flight_control/FGDeadBand.h>
-#include <models/flight_control/FGGain.h>
-#include <models/flight_control/FGPID.h>
-#include <models/flight_control/FGSwitch.h>
-#include <models/flight_control/FGSummer.h>
-#include <models/flight_control/FGKinemat.h>
-#include <models/flight_control/FGFCSFunction.h>
-#include <models/flight_control/FGSensor.h>
-#include <models/flight_control/FGActuator.h>
-#include <models/flight_control/FGAccelerometer.h>
-#include <models/flight_control/FGGyro.h>
+#include "models/flight_control/FGFilter.h"
+#include "models/flight_control/FGDeadBand.h"
+#include "models/flight_control/FGGain.h"
+#include "models/flight_control/FGPID.h"
+#include "models/flight_control/FGSwitch.h"
+#include "models/flight_control/FGSummer.h"
+#include "models/flight_control/FGKinemat.h"
+#include "models/flight_control/FGFCSFunction.h"
+#include "models/flight_control/FGSensor.h"
+#include "models/flight_control/FGActuator.h"
+#include "models/flight_control/FGAccelerometer.h"
+#include "models/flight_control/FGMagnetometer.h"
+#include "models/flight_control/FGGyro.h"
namespace JSBSim {
Components->push_back(new FGSensor(this, component_element));
} else if (component_element->GetName() == string("accelerometer")) {
Components->push_back(new FGAccelerometer(this, component_element));
+ } else if (component_element->GetName() == string("magnetometer")) {
+ Components->push_back(new FGMagnetometer(this, component_element));
} else if (component_element->GetName() == string("gyro")) {
Components->push_back(new FGGyro(this, component_element));
} else {
#include <vector>
#include <string>
-#include <models/flight_control/FGFCSComponent.h>
-#include <models/FGModel.h>
-#include <models/FGLGear.h>
-#include <input_output/FGXMLFileRead.h>
+#include "models/flight_control/FGFCSComponent.h"
+#include "models/FGModel.h"
+#include "models/FGLGear.h"
+#include "input_output/FGXMLFileRead.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-#include <FGFDMExec.h>
-#include <models/FGAuxiliary.h>
-#include <models/FGAtmosphere.h>
-#include <models/FGInertial.h>
-#include <models/FGMassBalance.h>
+#include "FGFDMExec.h"
+#include "models/FGAuxiliary.h"
+#include "models/FGAtmosphere.h"
+#include "models/FGInertial.h"
+#include "models/FGMassBalance.h"
#include "FGGasCell.h"
using std::cerr;
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-#include <FGJSBBase.h>
-#include <input_output/FGXMLElement.h>
-#include <math/FGColumnVector3.h>
-#include <models/propulsion/FGForce.h>
-#include <math/FGFunction.h>
+#include "FGJSBBase.h"
+#include "input_output/FGXMLElement.h"
+#include "math/FGColumnVector3.h"
+#include "models/propulsion/FGForce.h"
+#include "math/FGFunction.h"
#include <string>
using std::string;
#include <iomanip>
#include "FGGroundReactions.h"
-#include <input_output/FGPropertyManager.h>
+#include "input_output/FGPropertyManager.h"
namespace JSBSim {
// Perhaps there is some commonality for things which only need to be
// calculated once.
for (unsigned int i=0; i<lGear.size(); i++) {
- vForces += lGear[i]->Force();
- vMoments += lGear[i]->Moment();
+ vForces += lGear[i]->GetBodyForces();
+ vMoments += lGear[i]->GetMoments();
}
return false;
#include "FGModel.h"
#include "FGLGear.h"
-#include <math/FGColumnVector3.h>
-#include <input_output/FGXMLElement.h>
+#include "math/FGColumnVector3.h"
+#include "input_output/FGXMLElement.h"
#define ID_GROUNDREACTIONS "$Id$"
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGInertial.h"
-#include <FGFDMExec.h>
+#include "FGFDMExec.h"
#include "FGPropagate.h"
#include "FGState.h"
#include "FGMassBalance.h"
#include <vector>
#include "FGModel.h"
-#include <math/FGColumnVector3.h>
+#include "math/FGColumnVector3.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
bool FGInput::Run(void)
{
string line, token, info_string;
- int start=0, string_start=0, string_end=0;
- int token_start=0, token_end=0;
+ size_t start=0, string_start=0, string_end=0;
char buf[100];
double value=0;
FGPropertyManager* node=0;
} else if (command == "info") { // INFO
// get info about the sim run and/or aircraft, etc.
- sprintf(buf, "%8.3f\0", State->Getsim_time());
+ sprintf(buf, "%8.3f", State->Getsim_time());
info_string = "JSBSim version: " + JSBSim_version + "\n";
info_string += "Config File version: " + needed_cfg_version + "\n";
info_string += "Aircraft simulated: " + Aircraft->GetAircraftName() + "\n";
#include <iostream>
#include <fstream>
-#include <input_output/FGfdmSocket.h>
-#include <input_output/FGXMLElement.h>
+#include "input_output/FGfdmSocket.h"
+#include "input_output/FGXMLElement.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
static const char *IdSrc = "$Id$";
static const char *IdHdr = ID_LGEAR;
+// Body To Structural (body frame is rotated 180 deg about Y and lengths are given in
+// ft instead of inches)
+const FGMatrix33 FGLGear::Tb2s(-1./inchtoft, 0., 0., 0., 1./inchtoft, 0., 0., 0., -1./inchtoft);
+
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS IMPLEMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
FGLGear::FGLGear(Element* el, FGFDMExec* fdmex, int number) :
- GearNumber(number),
- Exec(fdmex)
+ FGForce(fdmex),
+ GearNumber(number)
{
Element *force_table=0;
Element *dampCoeff=0;
} else if (sContactType == "STRUCTURE") {
eContactType = ctSTRUCTURE;
} else {
- eContactType = ctUNKNOWN;
+ // Unknown contact point types will be treated as STRUCTURE.
+ eContactType = ctSTRUCTURE;
}
if (el->FindElement("spring_coeff"))
while (force_table) {
force_type = force_table->GetAttributeValue("type");
if (force_type == "CORNERING_COEFF") {
- ForceY_Table = new FGTable(Exec->GetPropertyManager(), force_table);
+ ForceY_Table = new FGTable(fdmex->GetPropertyManager(), force_table);
} else {
cerr << "Undefined force table for " << name << " contact point" << endl;
}
else sSteerType = "STEERABLE";
Element* element = el->FindElement("location");
- if (element) vXYZ = element->FindElementTripletConvertTo("IN");
+ if (element) vXYZn = element->FindElementTripletConvertTo("IN");
else {cerr << "No location given for contact " << name << endl; exit(-1);}
+ SetTransformType(FGForce::tCustom);
+
+ element = el->FindElement("orientation");
+ if (element && (eContactType == ctBOGEY)) {
+ vGearOrient = element->FindElementTripletConvertTo("RAD");
+
+ double cp,sp,cr,sr,cy,sy;
+
+ cp=cos(vGearOrient(ePitch)); sp=sin(vGearOrient(ePitch));
+ cr=cos(vGearOrient(eRoll)); sr=sin(vGearOrient(eRoll));
+ cy=cos(vGearOrient(eYaw)); sy=sin(vGearOrient(eYaw));
+
+ mTGear(1,1) = cp*cy;
+ mTGear(2,1) = cp*sy;
+ mTGear(3,1) = -sp;
+
+ mTGear(1,2) = sr*sp*cy - cr*sy;
+ mTGear(2,2) = sr*sp*sy + cr*cy;
+ mTGear(3,2) = sr*cp;
+
+ mTGear(1,3) = cr*sp*cy + sr*sy;
+ mTGear(2,3) = cr*sp*sy - sr*cy;
+ mTGear(3,3) = cr*cp;
+ }
+ else {
+ mTGear(1,1) = 1.;
+ mTGear(2,2) = 1.;
+ mTGear(3,3) = 1.;
+ }
if (sBrakeGroup == "LEFT" ) eBrakeGrp = bgLeft;
else if (sBrakeGroup == "RIGHT" ) eBrakeGrp = bgRight;
}
}
- State = Exec->GetState();
+ State = fdmex->GetState();
+ Aircraft = fdmex->GetAircraft();
+ Propagate = fdmex->GetPropagate();
+ Auxiliary = fdmex->GetAuxiliary();
+ FCS = fdmex->GetFCS();
+ MassBalance = fdmex->GetMassBalance();
+
LongForceLagFilterCoeff = 1/State->Getdt(); // default longitudinal force filter coefficient
LatForceLagFilterCoeff = 1/State->Getdt(); // default lateral force filter coefficient
// Add some AI here to determine if gear is located properly according to its
// brake group type ??
- State = Exec->GetState();
- Aircraft = Exec->GetAircraft();
- Propagate = Exec->GetPropagate();
- Auxiliary = Exec->GetAuxiliary();
- FCS = Exec->GetFCS();
- MassBalance = Exec->GetMassBalance();
-
WOW = lastWOW = false;
ReportEnable = true;
FirstContact = false;
MaximumStrutForce = MaximumStrutTravel = 0.0;
SinkRate = GroundSpeed = 0.0;
- vWhlBodyVec = MassBalance->StructuralToBody(vXYZ);
-
+ vWhlBodyVec = MassBalance->StructuralToBody(vXYZn);
vLocalGear = Propagate->GetTb2l() * vWhlBodyVec;
-
- vLocalWhlVel.InitMatrix();
+ vWhlVelVec.InitMatrix();
compressLength = 0.0;
compressSpeed = 0.0;
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FGColumnVector3& FGLGear::Force(void)
+FGColumnVector3& FGLGear::GetBodyForces(void)
{
- double t = Exec->GetState()->Getsim_time();
- dT = State->Getdt()*Exec->GetGroundReactions()->GetRate();
+ double t = fdmex->GetState()->Getsim_time();
+ dT = State->Getdt()*fdmex->GetGroundReactions()->GetRate();
- vForce.InitMatrix();
- vLocalForce.InitMatrix();
- vMoment.InitMatrix();
+ vFn.InitMatrix();
if (isRetractable) ComputeRetractionState();
if (GearDown) {
+ double verticalZProj = 0.;
- vWhlBodyVec = MassBalance->StructuralToBody(vXYZ); // Get wheel in body frame
+ vWhlBodyVec = MassBalance->StructuralToBody(vXYZn); // Get wheel in body frame
vLocalGear = Propagate->GetTb2l() * vWhlBodyVec; // Get local frame wheel location
gearLoc = Propagate->GetLocation().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 = Exec->GetGroundCallback()->GetAGLevel(t, gearLoc, contact, normal, cvel);
+ double height = fdmex->GetGroundCallback()->GetAGLevel(t, gearLoc, contact, normal, cvel);
vGroundNormal = -1. * Propagate->GetTec2b() * normal;
+ // The height returned above is the AGL and is expressed in the Z direction of the local
+ // 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)
switch (eContactType) {
case ctBOGEY:
- // Project the height in the local coordinate frame of the strut to compute the actual compression
- // length. The strut is assumed to be parallel to Z in the body frame.
- compressLength = vGroundNormal(eZ) < 0.0 ? height / vGroundNormal(eZ) : 0.0;
+ verticalZProj = (Propagate->GetTb2l()*mTGear*FGColumnVector3(0.,0.,1.))(eZ);
+ compressLength = verticalZProj > 0.0 ? -height / verticalZProj : 0.0;
break;
case ctSTRUCTURE:
- compressLength = -height;
+ verticalZProj = (Propagate->GetTec2l()*normal)(eZ);
+ compressLength = fabs(verticalZProj) > 0.0 ? -height / verticalZProj : 0.0;
break;
}
// [The next equation should really use the vector to the contact patch of
// the tire including the strut compression and not the original vWhlBodyVec.]
- FGColumnVector3 vWhlContactVec = vWhlBodyVec - FGColumnVector3(0., 0., compressLength);
- vWhlVelVec = Propagate->GetPQR() * vWhlContactVec;
- vWhlVelVec += Propagate->GetUVW() - Propagate->GetTec2b() * cvel;
+ FGColumnVector3 vWhlDisplVec = mTGear * FGColumnVector3(0., 0., compressLength);
+ FGColumnVector3 vWhlContactVec = vWhlBodyVec - vWhlDisplVec;
+ vActingXYZn = vXYZn - Tb2s * vWhlDisplVec;
+ FGColumnVector3 vBodyWhlVel = Propagate->GetPQR() * vWhlContactVec;
+ vBodyWhlVel += Propagate->GetUVW() - Propagate->GetTec2b() * cvel;
+
+ vWhlVelVec = mTGear.Transposed() * vBodyWhlVel;
InitializeReporting();
ComputeSteeringAngle();
ComputeGroundCoordSys();
- vLocalWhlVel = Tb2g * vWhlVelVec;
+ vLocalWhlVel = Transform().Transposed() * vBodyWhlVel;
- compressSpeed = -vLocalWhlVel(eZ);
- if (eContactType == ctBOGEY)
- // Project the compression speed in the local coordinate frame of the strut
- compressSpeed /= -vGroundNormal(eZ);
+ switch (eContactType) {
+ case ctBOGEY:
+ // Compression speed along the strut
+ compressSpeed = -vWhlVelVec(eZ);
+ case ctSTRUCTURE:
+ // Compression speed along the ground normal
+ compressSpeed = -vLocalWhlVel(eX);
+ }
ComputeVerticalStrutForce();
ComputeSlipAngle();
ComputeBrakeForceCoefficient();
ComputeSideForceCoefficient();
- double sign = vLocalWhlVel(eX)>0?1.0:(vLocalWhlVel(eX)<0?-1.0:0.0);
- vLocalForce(eX) = - ((1.0 - TirePressureNorm) * 30 + vLocalForce(eZ) * BrakeFCoeff) * sign;
- vLocalForce(eY) = vLocalForce(eZ) * FCoeff;
+ double sign = vLocalWhlVel(eY)>0?1.0:(vLocalWhlVel(eY)<0?-1.0:0.0);
+ vFn(eY) = - ((1.0 - TirePressureNorm) * 30 + vFn(eX) * BrakeFCoeff) * sign;
+ vFn(eZ) = vFn(eX) * FCoeff;
}
else if (eContactType == ctSTRUCTURE) {
FGColumnVector3 vSlipVec = vLocalWhlVel;
- vSlipVec(eZ) = 0.;
+ vSlipVec(eX) = 0.;
vSlipVec.Normalize();
- vLocalForce -= staticFCoeff * vLocalForce(eZ) * vSlipVec;
+ vFn -= staticFCoeff * vFn(eX) * vSlipVec;
}
// Lag and attenuate the XY-plane forces dependent on velocity. This code
// If a coefficient is set to something equal to or less than zero, the
// filter is bypassed.
- if (LongForceLagFilterCoeff > 0) vLocalForce(eX) = LongForceFilter.execute(vLocalForce(eX));
- if (LatForceLagFilterCoeff > 0) vLocalForce(eY) = LatForceFilter.execute(vLocalForce(eY));
+ if (LongForceLagFilterCoeff > 0) vFn(eY) = LongForceFilter.execute(vFn(eY));
+ if (LatForceLagFilterCoeff > 0) vFn(eZ) = LatForceFilter.execute(vFn(eZ));
- if ((fabs(vLocalWhlVel(eX)) <= RFRV) && RFRV > 0) vLocalForce(eX) *= fabs(vLocalWhlVel(eX))/RFRV;
- if ((fabs(vLocalWhlVel(eY)) <= SFRV) && SFRV > 0) vLocalForce(eY) *= fabs(vLocalWhlVel(eY))/SFRV;
+ if ((fabs(vLocalWhlVel(eY)) <= RFRV) && RFRV > 0) vFn(eY) *= fabs(vLocalWhlVel(eY))/RFRV;
+ if ((fabs(vLocalWhlVel(eZ)) <= SFRV) && SFRV > 0) vFn(eZ) *= fabs(vLocalWhlVel(eZ))/SFRV;
// End section for attenuating gear jitter
- // Transform the forces back to the body frame and compute the moment.
-
- vForce = Tg2b * vLocalForce;
- vMoment = vWhlContactVec * vForce;
-
} else { // Gear is NOT compressed
WOW = false;
compressSpeed = 0.0;
// Let wheel spin down slowly
- vLocalWhlVel(eX) -= 13.0*dT;
- if (vLocalWhlVel(eX) < 0.0) vLocalWhlVel(eX) = 0.0;
+ vWhlVelVec(eX) -= 13.0*dT;
+ if (vWhlVelVec(eX) < 0.0) vWhlVelVec(eX) = 0.0;
// Return to neutral position between 1.0 and 0.8 gear pos.
SteerAngle *= max(GetGearUnitPos()-0.8, 0.0)/0.2;
lastWOW = WOW;
- return vForce;
+ return FGForce::GetBodyForces();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Build a local "ground" coordinate system defined by
-// eX : projection of the rolling direction on the ground
-// eY : projection of the sliping direction on the ground
-// eZ : normal to the ground
+// eX : normal to the ground
+// eY : projection of the rolling direction on the ground
+// eZ : projection of the sliping direction on the ground
void FGLGear::ComputeGroundCoordSys(void)
{
- FGColumnVector3 vRollingGroundVec;
+ // Euler angles are built up to create a local frame to describe the forces
+ // applied to the gear by the ground. Here pitch, yaw and roll do not have
+ // any physical meaning. It is just a convenient notation.
+ // First, "pitch" and "yaw" are determined in order to align eX with the
+ // ground normal.
+ if (vGroundNormal(eZ) < -1.0)
+ vOrient(ePitch) = 0.5*M_PI;
+ else if (1.0 < vGroundNormal(eZ))
+ vOrient(ePitch) = -0.5*M_PI;
+ else
+ vOrient(ePitch) = asin(-vGroundNormal(eZ));
+
+ if (fabs(vOrient(ePitch)) == 0.5*M_PI)
+ vOrient(eYaw) = 0.;
+ else
+ vOrient(eYaw) = atan2(vGroundNormal(eY), vGroundNormal(eX));
+
+ vOrient(eRoll) = 0.;
+ UpdateCustomTransformMatrix();
if (eContactType == ctBOGEY) {
- // Compute the rolling direction projected on the ground
- // It consists in finding a vector 'r' such that 'r' lies in the plane (w,z) and r.n = 0 (scalar
- // product) where:
- // 'n' is the normal to the ground,
- // (x,y,z) are the directions defined in the body coord system
- // and 'w' is 'x' rotated by the steering angle (SteerAngle) in the plane (x,y).
- // r = u * w + v * z and r.n = 0 => v/u = -w.n/z.n = a
- // We also want u**2+v**2=1 and u > 0 (i.e. r orientated in the same 'direction' than w)
- // after some arithmetic, one finds that :
- double a = -(vGroundNormal(eX)*cos(SteerAngle)+vGroundNormal(eY)*sin(SteerAngle)) / vGroundNormal(eZ);
- double u = 1. / sqrt(1. + a*a);
- double v = a * u;
- vRollingGroundVec = FGColumnVector3(u * cos(SteerAngle), u * sin(SteerAngle), v);
- }
- else {
- // Here the only significant direction is the normal to the ground "vGroundNormal". Since there is
- // no wheel the 2 other vectors of the orthonormal basis are not meaningful and are only used to
- // create the transformation matrix Tg2b. So we are building vRollingGroundVec as an arbitrary
- // vector normal to vGroundNormal
- if (fabs(vGroundNormal(eX)) > 0.)
- vRollingGroundVec = FGColumnVector3(-vGroundNormal(eZ)/vGroundNormal(eX), 0., 1.);
- else if (fabs(vGroundNormal(eY)) > 0.)
- vRollingGroundVec = FGColumnVector3(0., -vGroundNormal(eZ)/vGroundNormal(eY), 1.);
- else
- vRollingGroundVec = FGColumnVector3(1., 0., -vGroundNormal(eX)/vGroundNormal(eZ));
+ // In the case of a bogey, the third angle "roll" is used to align the axis eY and eZ
+ // to the rolling and sliping direction respectively.
+ FGColumnVector3 updatedRollingAxis = Transform().Transposed() * mTGear
+ * FGColumnVector3(-sin(SteerAngle), cos(SteerAngle), 0.);
- vRollingGroundVec.Normalize();
+ vOrient(eRoll) = atan2(updatedRollingAxis(eY), -updatedRollingAxis(eZ));
+ UpdateCustomTransformMatrix();
}
-
- // The sliping direction is the cross product multiplication of the ground normal and rolling
- // directions
- FGColumnVector3 vSlipGroundVec = vGroundNormal * vRollingGroundVec;
-
- Tg2b(1,1) = vRollingGroundVec(eX);
- Tg2b(2,1) = vRollingGroundVec(eY);
- Tg2b(3,1) = vRollingGroundVec(eZ);
- Tg2b(1,2) = vSlipGroundVec(eX);
- Tg2b(2,2) = vSlipGroundVec(eY);
- Tg2b(3,2) = vSlipGroundVec(eZ);
- Tg2b(1,3) = vGroundNormal(eX);
- Tg2b(2,3) = vGroundNormal(eY);
- Tg2b(3,3) = vGroundNormal(eZ);
-
- Tb2g = Tg2b.Transposed();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
GearUp = true;
WOW = false;
GearDown = false;
- vLocalWhlVel.InitMatrix();
+ vWhlVelVec.InitMatrix();
} else if (gearPos > 0.99) {
GearDown = true;
GearUp = false;
void FGLGear::ComputeSlipAngle(void)
{
// Calculate tire slip angle.
- WheelSlip = -atan2(vLocalWhlVel(eY), fabs(vLocalWhlVel(eX)))*radtodeg;
+ WheelSlip = -atan2(vLocalWhlVel(eZ), fabs(vLocalWhlVel(eY)))*radtodeg;
// Filter the wheel slip angle
if (WheelSlipLagFilterCoeff > 0) WheelSlip = WheelSlipFilter.execute(WheelSlip);
SteerAngle = 0.0;
break;
case stCaster:
- SteerAngle = atan2(fabs(vWhlVelVec(eX)), vWhlVelVec(eY));
+ SteerAngle = atan2(vWhlVelVec(eY), fabs(vWhlVelVec(eX)));
break;
default:
cerr << "Improper steering type membership detected for this gear." << endl;
void FGLGear::ReportTakeoffOrLanding(void)
{
- double deltaT = State->Getdt()*Exec->GetGroundReactions()->GetRate();
+ double deltaT = State->Getdt()*fdmex->GetGroundReactions()->GetRate();
if (FirstContact)
LandingDistanceTraveled += Auxiliary->GetVground()*deltaT;
if ( ReportEnable
&& Auxiliary->GetVground() <= 0.05
&& !LandingReported
- && Exec->GetGroundReactions()->GetWOW())
+ && fdmex->GetGroundReactions()->GetWOW())
{
if (debug_lvl > 0) Report(erLand);
}
if ( ReportEnable
&& !TakeoffReported
&& (Propagate->GetDistanceAGL() - vLocalGear(eZ)) > 50.0
- && !Exec->GetGroundReactions()->GetWOW())
+ && !fdmex->GetGroundReactions()->GetWOW())
{
if (debug_lvl > 0) Report(erTakeoff);
}
void FGLGear::CrashDetect(void)
{
if ( (compressLength > 500.0 ||
- vForce.Magnitude() > 100000000.0 ||
- vMoment.Magnitude() > 5000000000.0 ||
+ vFn.Magnitude() > 100000000.0 ||
+ GetMoments().Magnitude() > 5000000000.0 ||
SinkRate > 1.4666*30 ) && !State->IntegrationSuspended())
{
PutMessage("Crash Detected: Simulation FREEZE.");
switch (eContactType) {
case ctBOGEY:
// Project back the strut force in the local coordinate frame of the ground
- vLocalForce(eZ) = StrutForce / vGroundNormal(eZ);
+ vFn(eX) = StrutForce / (mTGear.Transposed()*vGroundNormal)(eZ);
break;
case ctSTRUCTURE:
- vLocalForce(eZ) = -StrutForce;
+ vFn(eX) = -StrutForce;
break;
}
base_property_name = CreateIndexedPropertyName("gear/unit", GearNumber);
if (eContactType == ctBOGEY) {
property_name = base_property_name + "/slip-angle-deg";
- Exec->GetPropertyManager()->Tie( property_name.c_str(), &WheelSlip );
+ fdmex->GetPropertyManager()->Tie( property_name.c_str(), &WheelSlip );
property_name = base_property_name + "/WOW";
- Exec->GetPropertyManager()->Tie( property_name.c_str(), &WOW );
+ fdmex->GetPropertyManager()->Tie( property_name.c_str(), &WOW );
property_name = base_property_name + "/wheel-speed-fps";
- Exec->GetPropertyManager()->Tie( property_name.c_str(), (FGLGear*)this,
+ fdmex->GetPropertyManager()->Tie( property_name.c_str(), (FGLGear*)this,
&FGLGear::GetWheelRollVel);
property_name = base_property_name + "/z-position";
- Exec->GetPropertyManager()->Tie( property_name.c_str(), (FGLGear*)this,
- &FGLGear::GetZPosition, &FGLGear::SetZPosition);
+ fdmex->GetPropertyManager()->Tie( property_name.c_str(), (FGForce*)this,
+ &FGForce::GetLocationZ, &FGForce::SetLocationZ);
property_name = base_property_name + "/compression-ft";
- Exec->GetPropertyManager()->Tie( property_name.c_str(), &compressLength );
+ fdmex->GetPropertyManager()->Tie( property_name.c_str(), &compressLength );
property_name = base_property_name + "/side_friction_coeff";
- Exec->GetPropertyManager()->Tie( property_name.c_str(), &FCoeff );
+ fdmex->GetPropertyManager()->Tie( property_name.c_str(), &FCoeff );
property_name = base_property_name + "/static_friction_coeff";
- Exec->GetPropertyManager()->Tie( property_name.c_str(), &staticFCoeff );
+ fdmex->GetPropertyManager()->Tie( property_name.c_str(), &staticFCoeff );
+ if (eSteerType == stCaster) {
+ property_name = base_property_name + "/steering-angle-rad";
+ fdmex->GetPropertyManager()->Tie( property_name.c_str(), &SteerAngle );
+ }
}
if( isRetractable ) {
property_name = base_property_name + "/pos-norm";
- Exec->GetPropertyManager()->Tie( property_name.c_str(), &GearPos );
+ fdmex->GetPropertyManager()->Tie( property_name.c_str(), &GearPos );
}
-
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
switch(repType) {
case erLand:
cout << endl << "Touchdown report for " << name << " (WOW at time: "
- << Exec->GetState()->Getsim_time() << " seconds)" << endl;
+ << fdmex->GetState()->Getsim_time() << " seconds)" << endl;
cout << " Sink rate at contact: " << SinkRate << " fps, "
<< SinkRate*0.3048 << " mps" << endl;
cout << " Contact ground speed: " << GroundSpeed*.5925 << " knots, "
break;
case erTakeoff:
cout << endl << "Takeoff report for " << name << " (Liftoff at time: "
- << Exec->GetState()->Getsim_time() << " seconds)" << endl;
+ << fdmex->GetState()->Getsim_time() << " seconds)" << endl;
cout << " Distance traveled: " << TakeoffDistanceTraveled
<< " ft, " << TakeoffDistanceTraveled*0.3048 << " meters" << endl;
cout << " Distance traveled (over 50'): " << TakeoffDistanceTraveled50ft
<< " ft, " << TakeoffDistanceTraveled50ft*0.3048 << " meters" << endl;
- cout << " [Altitude (ASL): " << Exec->GetPropagate()->GetAltitudeASL() << " ft. / "
- << Exec->GetPropagate()->GetAltitudeASLmeters() << " m | Temperature: "
- << Exec->GetAtmosphere()->GetTemperature() - 459.67 << " F / "
- << RankineToCelsius(Exec->GetAtmosphere()->GetTemperature()) << " C]" << endl;
- cout << " [Velocity (KCAS): " << Exec->GetAuxiliary()->GetVcalibratedKTS() << "]" << endl;
+ cout << " [Altitude (ASL): " << fdmex->GetPropagate()->GetAltitudeASL() << " ft. / "
+ << fdmex->GetPropagate()->GetAltitudeASLmeters() << " m | Temperature: "
+ << fdmex->GetAtmosphere()->GetTemperature() - 459.67 << " F / "
+ << RankineToCelsius(fdmex->GetAtmosphere()->GetTemperature()) << " C]" << endl;
+ cout << " [Velocity (KCAS): " << fdmex->GetAuxiliary()->GetVcalibratedKTS() << "]" << endl;
TakeoffReported = true;
break;
+ case erNone:
+ break;
}
}
if (debug_lvl & 1) { // Standard console startup message output
if (from == 0) { // Constructor - loading and initialization
cout << " " << sContactType << " " << name << endl;
- cout << " Location: " << vXYZ << endl;
+ cout << " Location: " << vXYZn << endl;
cout << " Spring Constant: " << kSpring << endl;
if (eDampType == dtLinear)
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-#include <FGJSBBase.h>
-#include <FGFDMExec.h>
-#include <input_output/FGXMLElement.h>
-#include <math/FGColumnVector3.h>
-#include <math/FGTable.h>
+#include "FGFDMExec.h"
+#include "models/propulsion/FGForce.h"
+#include "input_output/FGXMLElement.h"
+#include "math/FGColumnVector3.h"
+#include "math/FGTable.h"
#include <string>
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS DECLARATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-class FGLGear : public FGJSBBase
+class FGLGear : public FGForce
{
public:
/// Brake grouping enumerators
/// Steering group membership enumerators
enum SteerType {stSteer, stFixed, stCaster};
/// Contact point type
- enum ContactType {ctBOGEY, ctSTRUCTURE, ctUNKNOWN};
+ enum ContactType {ctBOGEY, ctSTRUCTURE};
/// Report type enumerators
enum ReportType {erNone=0, erTakeoff, erLand};
/// Damping types
~FGLGear();
/// The Force vector for this gear
- FGColumnVector3& Force(void);
- /// The Moment vector for this gear
- FGColumnVector3& Moment(void) {return vMoment;}
+ FGColumnVector3& GetBodyForces(void);
/// Gets the location of the gear in Body axes
FGColumnVector3& GetBodyLocation(void) { return vWhlBodyVec; }
int GetBrakeGroup(void) const { return (int)eBrakeGrp; }
int GetSteerType(void) const { return (int)eSteerType; }
- double GetZPosition(void) const { return vXYZ(3); }
- void SetZPosition(double z) { vXYZ(3) = z; }
-
- bool GetSteerable(void) const { return eSteerType != stFixed; }
+ bool GetSteerable(void) const { return eSteerType != stFixed; }
bool GetRetractable(void) const { return isRetractable; }
bool GetGearUnitUp(void) const { return GearUp; }
bool GetGearUnitDown(void) const { return GearDown; }
- double GetWheelSideForce(void) const { return vLocalForce(eY); }
- double GetWheelRollForce(void) const { return vLocalForce(eX); }
- double GetWheelSideVel(void) const { return vWhlVelVec(eY); }
- double GetWheelRollVel(void) const { return vWhlVelVec(eX); }
- double GetBodyXForce(void) const { return vForce(eX); }
- double GetBodyYForce(void) const { return vForce(eY); }
+ double GetWheelRollForce(void) {
+ FGColumnVector3 vForce = mTGear.Transposed() * FGForce::GetBodyForces();
+ return vForce(eX)*cos(SteerAngle) + vForce(eY)*sin(SteerAngle); }
+ double GetWheelSideForce(void) {
+ FGColumnVector3 vForce = mTGear.Transposed() * FGForce::GetBodyForces();
+ return vForce(eY)*cos(SteerAngle) - vForce(eX)*sin(SteerAngle); }
+ double GetWheelRollVel(void) const { return vWhlVelVec(eX)*cos(SteerAngle)
+ + vWhlVelVec(eY)*sin(SteerAngle); }
+ double GetWheelSideVel(void) const { return vWhlVelVec(eY)*cos(SteerAngle)
+ - vWhlVelVec(eX)*sin(SteerAngle); }
double GetWheelSlipAngle(void) const { return WheelSlip; }
- double GetWheelVel(int axis) const { return vWhlVelVec(axis);}
- bool IsBogey(void) const { return (eContactType == ctBOGEY);}
+ double GetWheelVel(int axis) const { return vWhlVelVec(axis);}
+ bool IsBogey(void) const { return (eContactType == ctBOGEY);}
double GetGearUnitPos(void);
void bind(void);
private:
int GearNumber;
- FGMatrix33 Tg2b, Tb2g;
- FGColumnVector3 vXYZ;
- FGColumnVector3 vMoment;
+ static const FGMatrix33 Tb2s;
+ FGMatrix33 mTGear;
+ FGColumnVector3 vGearOrient;
FGColumnVector3 vWhlBodyVec;
FGColumnVector3 vLocalGear;
- FGColumnVector3 vForce;
- FGColumnVector3 vLocalForce;
FGColumnVector3 vWhlVelVec, vLocalWhlVel; // Velocity of this wheel
FGColumnVector3 normal, cvel, vGroundNormal;
FGLocation contact, gearLoc;
Filter LatForceFilter;
Filter WheelSlipFilter;
- FGFDMExec* Exec;
FGState* State;
FGAircraft* Aircraft;
FGPropagate* Propagate;
#include "FGMassBalance.h"
#include "FGPropulsion.h"
#include "FGBuoyantForces.h"
-#include <input_output/FGPropertyManager.h>
+#include "input_output/FGPropertyManager.h"
namespace JSBSim {
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGModel.h"
-#include <math/FGColumnVector3.h>
-#include <math/FGMatrix33.h>
-#include <input_output/FGXMLElement.h>
+#include "math/FGColumnVector3.h"
+#include "math/FGMatrix33.h"
+#include "input_output/FGXMLElement.h"
#include <vector>
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-#include <FGJSBBase.h>
-#include <input_output/FGPropertyManager.h>
-#include <input_output/FGXMLElement.h>
+#include "FGJSBBase.h"
+#include "input_output/FGPropertyManager.h"
+#include "input_output/FGXMLElement.h"
#include <iostream>
#include <string>
if (!FGModel::InitModel()) return false;
if (Filename.size() > 0 && StartNewFile) {
- int idx = BaseFilename.find_last_of(".");
- int len = BaseFilename.length();
+ size_t idx = BaseFilename.find_last_of(".");
+ size_t len = BaseFilename.length();
string extension = "";
if (idx != string::npos) {
extension = BaseFilename.substr(idx, len-idx);
cout << scratch << " in CSV format output at rate " << 1/(State->Getdt()*rate) << " Hz" << endl;
break;
case otNone:
+ default:
cout << " No log output" << endl;
break;
}
#include <iomanip>
#include "FGPropagate.h"
-#include <FGFDMExec.h>
-#include <FGState.h>
+#include "FGFDMExec.h"
+#include "FGState.h"
#include "FGAircraft.h"
#include "FGMassBalance.h"
#include "FGInertial.h"
-#include <input_output/FGPropertyManager.h>
+#include "input_output/FGPropertyManager.h"
namespace JSBSim {
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-#include <models/FGModel.h>
-#include <math/FGColumnVector3.h>
-#include <math/FGLocation.h>
-#include <math/FGQuaternion.h>
-#include <math/FGMatrix33.h>
+#include "models/FGModel.h"
+#include "math/FGColumnVector3.h"
+#include "math/FGLocation.h"
+#include "math/FGQuaternion.h"
+#include "math/FGMatrix33.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-#include <initialization/FGInitialCondition.h>
+#include "initialization/FGInitialCondition.h"
#endif
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGPropulsion.h"
-#include <models/propulsion/FGRocket.h>
-#include <models/propulsion/FGTurbine.h>
-#include <models/propulsion/FGPiston.h>
-#include <models/propulsion/FGElectric.h>
-#include <models/propulsion/FGTurboProp.h>
-#include <input_output/FGPropertyManager.h>
-#include <input_output/FGXMLParse.h>
-#include <math/FGColumnVector3.h>
+#include "models/propulsion/FGRocket.h"
+#include "models/propulsion/FGTurbine.h"
+#include "models/propulsion/FGPiston.h"
+#include "models/propulsion/FGElectric.h"
+#include "models/propulsion/FGTurboProp.h"
+#include "input_output/FGPropertyManager.h"
+#include "input_output/FGXMLParse.h"
+#include "math/FGColumnVector3.h"
#include <sstream>
namespace JSBSim {
FGModel::Load(el); // Perform base class Load.
+ // Process tank definitions first to establish the number of fuel tanks
+
+ Element* tank_element = el->FindElement("tank");
+ while (tank_element) {
+ Tanks.push_back(new FGTank(FDMExec, tank_element, numTanks));
+ if (Tanks.back()->GetType() == FGTank::ttFUEL) numFuelTanks++;
+ else if (Tanks.back()->GetType() == FGTank::ttOXIDIZER) numOxiTanks++;
+ else {cerr << "Unknown tank type specified." << endl; return false;}
+ numTanks++;
+ tank_element = el->FindNextElement("tank");
+ }
+ numSelectedFuelTanks = numFuelTanks;
+ numSelectedOxiTanks = numOxiTanks;
+
Element* engine_element = el->FindElement("engine");
while (engine_element) {
engine_filename = engine_element->GetAttributeValue("file");
ResetParser();
}
- // Process tank definitions
-
- Element* tank_element = el->FindElement("tank");
- while (tank_element) {
- Tanks.push_back(new FGTank(FDMExec, tank_element, numTanks));
- if (Tanks.back()->GetType() == FGTank::ttFUEL) numFuelTanks++;
- else if (Tanks.back()->GetType() == FGTank::ttOXIDIZER) numOxiTanks++;
- else {cerr << "Unknown tank type specified." << endl; return false;}
- numTanks++;
- tank_element = el->FindNextElement("tank");
- }
- numSelectedFuelTanks = numFuelTanks;
- numSelectedOxiTanks = numOxiTanks;
-
CalculateTankInertias();
if (!ThrottleAdded) FCS->AddThrottle(); // need to have at least one throttle
#include <fstream>
#include "FGModel.h"
-#include <models/propulsion/FGEngine.h>
-#include <models/propulsion/FGTank.h>
-#include <math/FGMatrix33.h>
-#include <input_output/FGXMLFileRead.h>
+#include "models/propulsion/FGEngine.h"
+#include "models/propulsion/FGTank.h"
+#include "math/FGMatrix33.h"
+#include "input_output/FGXMLFileRead.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-#include <models/FGAtmosphere.h>
+#include "models/FGAtmosphere.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-#include <models/FGAtmosphere.h>
+#include "models/FGAtmosphere.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
CLASS IMPLEMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-FGAccelerometer::FGAccelerometer(FGFCS* fcs, Element* element) : FGSensor(fcs, element)
+FGAccelerometer::FGAccelerometer(FGFCS* fcs, Element* element)
+ : FGSensor(fcs, element),
+ FGSensorOrientation(element)
{
Propagate = fcs->GetExec()->GetPropagate();
MassBalance = fcs->GetExec()->GetMassBalance();
vRadius = MassBalance->StructuralToBody(vLocation);
- Element* orient_element = element->FindElement("orientation");
- if (orient_element) vOrient = orient_element->FindElementTripletConvertTo("RAD");
- else {cerr << "No orientation given for accelerometer. " << endl;}
-
- Element* axis_element = element->FindElement("axis");
- if (axis_element) {
- string sAxis = element->FindElementValue("axis");
- if (sAxis == "X" || sAxis == "x") {
- axis = 1;
- } else if (sAxis == "Y" || sAxis == "y") {
- axis = 2;
- } else if (sAxis == "Z" || sAxis == "z") {
- axis = 3;
- } else {
- cerr << " Incorrect/no axis specified for accelerometer; assuming X axis" << endl;
- axis = 1;
- }
- }
-
- CalculateTransformMatrix();
-
Debug(0);
}
bool FGAccelerometer::Run(void )
{
// There is no input assumed. This is a dedicated acceleration sensor.
-
+
vRadius = MassBalance->StructuralToBody(vLocation);
//gravitational forces
Input = vAccel(axis);
- Output = Input; // perfect accelerometer
-
- // Degrade signal as specified
-
- if (fail_stuck) {
- Output = PreviousOutput;
- return true;
- }
-
- if (lag != 0.0) Lag(); // models accelerometer lag
- if (noise_variance != 0.0) Noise(); // models noise
- if (drift_rate != 0.0) Drift(); // models drift over time
- if (bias != 0.0) Bias(); // models a finite bias
- if (gain != 0.0) Gain(); // models a gain
-
- if (fail_low) Output = -HUGE_VAL;
- if (fail_high) Output = HUGE_VAL;
+ ProcessSensorSignal();
- if (bits != 0) Quantize(); // models quantization degradation
-// if (delay != 0.0) Delay(); // models system signal transport latencies
-
- Clip(); // Is it right to clip an accelerometer?
return true;
}
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGAccelerometer::CalculateTransformMatrix(void)
-{
- double cp,sp,cr,sr,cy,sy;
-
- cp=cos(vOrient(ePitch)); sp=sin(vOrient(ePitch));
- cr=cos(vOrient(eRoll)); sr=sin(vOrient(eRoll));
- cy=cos(vOrient(eYaw)); sy=sin(vOrient(eYaw));
-
- mT(1,1) = cp*cy;
- mT(1,2) = cp*sy;
- mT(1,3) = -sp;
-
- mT(2,1) = sr*sp*cy - cr*sy;
- mT(2,2) = sr*sp*sy + cr*cy;
- mT(2,3) = sr*cp;
-
- mT(3,1) = cr*sp*cy + sr*sy;
- mT(3,2) = cr*sp*sy - sr*cy;
- mT(3,3) = cr*cp;
-
- // This transform is different than for FGForce, where we want a native nozzle
- // force in body frame. Here we calculate the body frame accel and want it in
- // the transformed accelerometer frame. So, the next line is commented out.
- // mT = mT.Inverse();
-}
-
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// The bitmasked value choices are as follows:
// unset: In this case (the default) JSBSim would only print
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGSensor.h"
-#include <input_output/FGXMLElement.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"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
CLASS DECLARATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-class FGAccelerometer : public FGSensor
+class FGAccelerometer : public FGSensor, public FGSensorOrientation
{
public:
FGAccelerometer(FGFCS* fcs, Element* element);
FGMassBalance* MassBalance;
FGInertial* Inertial;
FGColumnVector3 vLocation;
- FGColumnVector3 vOrient;
FGColumnVector3 vRadius;
FGColumnVector3 vAccel;
- FGMatrix33 mT;
- void CalculateTransformMatrix(void);
- int axis;
void Debug(int from);
};
FGActuator::FGActuator(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, element)
{
double denom;
- dt = fcs->GetDt();
// inputs are read from the base class constructor
bool FGActuator::Run(void )
{
- dt = fcs->GetDt();
-
Input = InputNodes[0]->getDoubleValue() * InputSigns[0];
if (fail_zero) Input = 0;
else
cout << " INPUT: " << InputNodes[0]->getName() << endl;
- if (IsOutput) cout << " OUTPUT: " << OutputNode->getName() << endl;
+ if (IsOutput) {
+ for (unsigned int i=0; i<OutputNodes.size(); i++)
+ cout << " OUTPUT: " << OutputNodes[i]->getName() << endl;
+ }
if (bias != 0.0) cout << " Bias: " << bias << endl;
if (rate_limit != 0) cout << " Rate limit: " << rate_limit << endl;
if (lag != 0) cout << " Actuator lag: " << lag << endl;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGFCSComponent.h"
-#include <input_output/FGXMLElement.h>
+#include "input_output/FGXMLElement.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
inline bool GetFailStuck(void) const {return fail_stuck;}
private:
- double dt;
double span;
double bias;
double rate_limit;
cout << " DEADBAND WIDTH: " << width << endl;
}
cout << " GAIN: " << gain << endl;
- if (IsOutput) cout << " OUTPUT: " << OutputNode->getName() << endl;
+ if (IsOutput) {
+ for (unsigned int i=0; i<OutputNodes.size(); i++)
+ cout << " OUTPUT: " << OutputNodes[i]->getName() << endl;
+ }
}
}
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGFCSComponent.h"
-#include <input_output/FGXMLElement.h>
+#include "input_output/FGXMLElement.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
{
Element *input_element, *clip_el;
Input = Output = clipmin = clipmax = 0.0;
- OutputNode = treenode = 0;
+ treenode = 0;
+ delay = index = 0;
ClipMinPropertyNode = ClipMaxPropertyNode = 0;
clipMinSign = clipMaxSign = 1.0;
IsOutput = clip = false;
string input, clip_string;
+ dt = fcs->GetDt();
PropertyManager = fcs->GetPropertyManager();
if (element->GetName() == string("lag_filter")) {
Type = "SENSOR";
} else if (element->GetName() == string("accelerometer")) {
Type = "ACCELEROMETER";
+ } else if (element->GetName() == string("magnetometer")) {
+ Type = "MAGNETOMETER";
} else if (element->GetName() == string("gyro")) {
Type = "GYRO";
} else if (element->GetName() == string("actuator")) {
input_element = element->FindNextElement("input");
}
- if (element->FindElement("output")) {
+ Element *out_elem = element->FindElement("output");
+ while (out_elem) {
IsOutput = true;
- OutputNode = PropertyManager->GetNode( element->FindElementValue("output"), true );
+ string output_node_name = out_elem->GetDataLine();
+ FGPropertyManager* OutputNode = PropertyManager->GetNode( output_node_name, true );
+ OutputNodes.push_back(OutputNode);
if (!OutputNode) {
- cerr << endl << " Unable to process property: " << element->FindElementValue("output") << endl;
+ cerr << endl << " Unable to process property: " << output_node_name << endl;
throw(string("Invalid output property name in flight control definition"));
}
+ out_elem = element->FindNextElement("output");
+ }
+
+ Element* delay_elem = element->FindElement("delay");
+ if ( delay_elem ) {
+ delay = (unsigned int)delay_elem->GetDataAsNumber();
+ string delayType = delay_elem->GetAttributeValue("type");
+ if (delayType.length() > 0) {
+ if (delayType == "time") {
+ delay = (int)(delay / dt);
+ } else {
+ cerr << "Unallowed delay type" << endl;
+ }
+ } else {
+ delay = (int)(delay / dt);
+ }
+ output_array.resize(delay);
+ for (int i=0; i<delay; i++) output_array[i] = 0.0;
}
clip_el = element->FindElement("clipto");
void FGFCSComponent::SetOutput(void)
{
- OutputNode->setDoubleValue(Output);
+ for (unsigned int i=0; i<OutputNodes.size(); i++) OutputNodes[i]->setDoubleValue(Output);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+void FGFCSComponent::Delay(void)
+{
+ output_array[index] = Output;
+ if (index == delay-1) index = 0;
+ else index++;
+ Output = output_array[index];
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
void FGFCSComponent::Clip(void)
{
if (clip) {
cout << " Maximum limit: " << clipmax << endl;
}
}
+ if (delay > 0) cout <<" Frame delay: " << delay
+ << " frames (" << delay*dt << " sec)" << endl;
}
}
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-#include <FGJSBBase.h>
-#include <input_output/FGPropertyManager.h>
-#include <input_output/FGXMLElement.h>
+#include "FGJSBBase.h"
+#include "input_output/FGPropertyManager.h"
+#include "input_output/FGXMLElement.h"
#include <string>
#include <vector>
virtual bool Run(void);
virtual void SetOutput(void);
- inline double GetOutput (void) const {return Output;}
- inline FGPropertyManager* GetOutputNode(void) { return OutputNode; }
- inline string GetName(void) const {return Name;}
- inline string GetType(void) const { return Type; }
+ double GetOutput (void) const {return Output;}
+ string GetName(void) const {return Name;}
+ string GetType(void) const { return Type; }
virtual double GetOutputPct(void) const { return 0; }
protected:
FGFCS* fcs;
FGPropertyManager* PropertyManager;
FGPropertyManager* treenode;
- FGPropertyManager* OutputNode;
+ vector <FGPropertyManager*> OutputNodes;
FGPropertyManager* ClipMinPropertyNode;
FGPropertyManager* ClipMaxPropertyNode;
vector <FGPropertyManager*> InputNodes;
vector <float> InputSigns;
+ vector <double> output_array;
string Type;
string Name;
double Input;
double Output;
double clipmax, clipmin;
+ int delay;
+ int index;
float clipMinSign, clipMaxSign;
+ double dt;
bool IsOutput;
bool clip;
+ void Delay(void);
void Clip(void);
virtual void bind();
virtual void Debug(int from);
if (InputNodes.size()>0)
cout << " INPUT: " << InputNodes[0]->getName() << endl;
// cout << " Function: " << endl;
- if (IsOutput) cout << " OUTPUT: " << OutputNode->getName() << endl;
+ if (IsOutput) {
+ for (unsigned int i=0; i<OutputNodes.size(); i++)
+ cout << " OUTPUT: " << OutputNodes[i]->getName() << endl;
+ }
}
}
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGFCSComponent.h"
-#include <input_output/FGXMLElement.h>
-#include <math/FGFunction.h>
+#include "input_output/FGXMLElement.h"
+#include "math/FGFunction.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
FGFilter::FGFilter(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, element)
{
- dt = fcs->GetState()->Getdt();
Trigger = 0;
DynamicFilter = false;
if (PropertyNode[1] == 0L) cout << " C[1]: " << C[1] << endl;
else cout << " C[1] is the value of property: " << sgn << PropertyNode[1]->GetName() << endl;
break;
+ case eUnknown:
+ break;
}
- if (IsOutput) cout << " OUTPUT: " << OutputNode->getName() << endl;
+ if (IsOutput) {
+ for (unsigned int i=0; i<OutputNodes.size(); i++)
+ cout << " OUTPUT: " << OutputNodes[i]->getName() << endl;
+ }
}
}
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGFCSComponent.h"
-#include <input_output/FGXMLElement.h>
+#include "input_output/FGXMLElement.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
enum {eLag, eLeadLag, eOrder2, eWashout, eIntegrator, eUnknown} FilterType;
private:
- double dt;
double ca;
double cb;
double cc;
} else {
cout << " GAIN: " << Gain << endl;
}
- if (IsOutput) cout << " OUTPUT: " << OutputNode->getName() << endl;
+ if (IsOutput) {
+ for (unsigned int i=0; i<OutputNodes.size(); i++)
+ cout << " OUTPUT: " << OutputNodes[i]->getName() << endl;
+ }
if (Type == "AEROSURFACE_SCALE") {
cout << " In/Out Mapping:" << endl;
cout << " Input MIN: " << InMin << endl;
#include "FGFCSComponent.h"
#include <string>
-#include <input_output/FGXMLElement.h>
-#include <math/FGTable.h>
+#include "input_output/FGXMLElement.h"
+#include "math/FGTable.h"
using std::string;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGFCSComponent.h"
-#include <input_output/FGXMLElement.h>
+#include "input_output/FGXMLElement.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
CLASS IMPLEMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-FGGyro::FGGyro(FGFCS* fcs, Element* element) : FGSensor(fcs, element)
+FGGyro::FGGyro(FGFCS* fcs, Element* element) : FGSensor(fcs, element),
+ FGSensorOrientation(element)
{
Propagate = fcs->GetExec()->GetPropagate();
- Element* orient_element = element->FindElement("orientation");
- if (orient_element) vOrient = orient_element->FindElementTripletConvertTo("RAD");
- else {cerr << "No orientation given for gyro. " << endl;}
-
- Element* axis_element = element->FindElement("axis");
- if (axis_element) {
- string sAxis = element->FindElementValue("axis");
- if (sAxis == "ROLL" || sAxis == "roll") {
- axis = 1;
- } else if (sAxis == "PITCH" || sAxis == "pitch") {
- axis = 2;
- } else if (sAxis == "YAW" || sAxis == "yaw") {
- axis = 3;
- } else {
- cerr << " Incorrect/no axis specified for gyro; assuming Roll axis" << endl;
- axis = 1;
- }
- }
-
- CalculateTransformMatrix();
-
Debug(0);
}
Input = vAccel(axis);
- Output = Input; // perfect gyro
-
- // Degrade signal as specified
-
- if (fail_stuck) {
- Output = PreviousOutput;
- return true;
- }
-
- if (lag != 0.0) Lag(); // models gyro lag
- if (noise_variance != 0.0) Noise(); // models noise
- if (drift_rate != 0.0) Drift(); // models drift over time
- if (bias != 0.0) Bias(); // models a finite bias
- if (gain != 0.0) Gain(); // models a gain
-
- if (fail_low) Output = -HUGE_VAL;
- if (fail_high) Output = HUGE_VAL;
-
- if (bits != 0) Quantize(); // models quantization degradation
-// if (delay != 0.0) Delay(); // models system signal transport latencies
+ ProcessSensorSignal();
- Clip(); // Is it right to clip a gyro?
return true;
}
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGGyro::CalculateTransformMatrix(void)
-{
- double cp,sp,cr,sr,cy,sy;
-
- cp=cos(vOrient(ePitch)); sp=sin(vOrient(ePitch));
- cr=cos(vOrient(eRoll)); sr=sin(vOrient(eRoll));
- cy=cos(vOrient(eYaw)); sy=sin(vOrient(eYaw));
-
- mT(1,1) = cp*cy;
- mT(1,2) = cp*sy;
- mT(1,3) = -sp;
-
- mT(2,1) = sr*sp*cy - cr*sy;
- mT(2,2) = sr*sp*sy + cr*cy;
- mT(2,3) = sr*cp;
-
- mT(3,1) = cr*sp*cy + sr*sy;
- mT(3,2) = cr*sp*sy - sr*cy;
- mT(3,3) = cr*cp;
-
- // This transform is different than for FGForce, where we want a native nozzle
- // force in body frame. Here we calculate the body frame accel and want it in
- // the transformed gyro frame. So, the next line is commented out.
- // mT = mT.Inverse();
-}
-
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// The bitmasked value choices are as follows:
// unset: In this case (the default) JSBSim would only print
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGSensor.h"
-#include <input_output/FGXMLElement.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"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
CLASS DECLARATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-class FGGyro : public FGSensor
+class FGGyro : public FGSensor, public FGSensorOrientation
{
public:
FGGyro(FGFCS* fcs, Element* element);
private:
FGPropagate* Propagate;
- FGColumnVector3 vOrient;
FGColumnVector3 vAccel;
- FGMatrix33 mT;
void CalculateTransformMatrix(void);
- int axis;
void Debug(int from);
};
bool FGKinemat::Run(void )
{
- double dt = fcs->GetState()->Getdt();
+ double dt0 = dt;
Input = InputNodes[0]->getDoubleValue() * InputSigns[0];
if (DoScale) Input *= Detents[NumDetents-1];
- if (IsOutput) Output = OutputNode->getDoubleValue();
+ if (IsOutput) Output = OutputNodes[0]->getDoubleValue();
if (Input < Detents[0])
Input = Detents[0];
// Process all detent intervals the movement traverses until either the
// final value is reached or the time interval has finished.
- while ( 0.0 < dt && !EqualToRoundoff(Input, Output) ) {
+ while ( dt0 > 0.0 && !EqualToRoundoff(Input, Output) ) {
// Find the area where Output is in
int ind;
double ThisDt = fabs((ThisInput-Output)/Rate);
// and clip to the timestep size
- if (dt < ThisDt) {
- ThisDt = dt;
+ if (dt0 < ThisDt) {
+ ThisDt = dt0;
if (Output < Input)
Output += ThisDt*Rate;
else
// is met even in inexact arithmetics ...
Output = ThisInput;
- dt -= ThisDt;
+ dt0 -= ThisDt;
}
}
for (int i=0;i<NumDetents;i++) {
cout << " " << Detents[i] << " " << TransitionTimes[i] << endl;
}
- if (IsOutput) cout << " OUTPUT: " << OutputNode->getName() << endl;
+ if (IsOutput) {
+ for (unsigned int i=0; i<OutputNodes.size(); i++)
+ cout << " OUTPUT: " << OutputNodes[i]->getName() << endl;
+ }
if (!DoScale) cout << " NOSCALE" << endl;
}
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGFCSComponent.h"
-#include <input_output/FGXMLElement.h>
+#include "input_output/FGXMLElement.h"
#include <vector>
#include <string>
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-FGMagnetometer::FGMagnetometer(FGFCS* fcs, Element* element) : FGSensor(fcs, element),\
+FGMagnetometer::FGMagnetometer(FGFCS* fcs, Element* element) : FGSensor(fcs, element),
+ FGSensorOrientation(element),
counter(0),
INERTIAL_UPDATE_RATE(1000)
{
vRadius = MassBalance->StructuralToBody(vLocation);
- Element* orient_element = element->FindElement("orientation");
- if (orient_element) vOrient = orient_element->FindElementTripletConvertTo("RAD");
- else {cerr << "No orientation given for magnetometer. " << endl;}
-
- Element* axis_element = element->FindElement("axis");
- if (axis_element) {
- string sAxis = element->FindElementValue("axis");
- if (sAxis == "X" || sAxis == "x") {
- axis = 1;
- } else if (sAxis == "Y" || sAxis == "y") {
- axis = 2;
- } else if (sAxis == "Z" || sAxis == "z") {
- axis = 3;
- } else {
- cerr << " Incorrect/no axis specified for magnetometer; assuming X axis" << endl;
- axis = 1;
- }
- }
-
- CalculateTransformMatrix();
-
//assuming date wont significantly change over a flight to affect mag field
//would be better to get the date from the sim if its simulated...
time_t rawtime;
void FGMagnetometer::updateInertialMag(void)
{
counter++;
- if(counter > INERTIAL_UPDATE_RATE)//dont need to update every iteration
+ if (counter > INERTIAL_UPDATE_RATE)//dont need to update every iteration
{
counter = 0;
usedAlt = (Propagate->GetGeodeticAltitude()*fttom*0.001);//km
//this should be done whenever the position changes significantly (in nTesla)
- double magvar = calc_magvar( usedLat,
- usedLon,
- usedAlt,
- date,
- field );
+ calc_magvar( usedLat,
+ usedLon,
+ usedAlt,
+ date,
+ field );
}
}
bool FGMagnetometer::Run(void )
{
- // There is no input assumed. This is a dedicated acceleration sensor.
+ // There is no input assumed. This is a dedicated magnetic field sensor.
vRadius = MassBalance->StructuralToBody(vLocation);
-
updateInertialMag();
- //Inertial magnetic field rotated to the body frame
+
+ // Inertial magnetic field rotated to the body frame
vMag = Propagate->GetTl2b() * FGColumnVector3(field[3], field[4], field[5]);
- //allow for sensor orientation
+ // Allow for sensor orientation
vMag = mT * vMag;
Input = vMag(axis);
- Output = Input; // perfect magnetometer
-
- // Degrade signal as specified
-
- if (fail_stuck) {
- Output = PreviousOutput;
- return true;
- }
-
- if (lag != 0.0) Lag(); // models magnetometer lag
- if (noise_variance != 0.0) Noise(); // models noise
- if (drift_rate != 0.0) Drift(); // models drift over time
- if (bias != 0.0) Bias(); // models a finite bias
- if (gain != 0.0) Gain(); // models a gain
-
- if (fail_low) Output = -HUGE_VAL;
- if (fail_high) Output = HUGE_VAL;
-
- if (bits != 0) Quantize(); // models quantization degradation
-// if (delay != 0.0) Delay(); // models system signal transport latencies
+ ProcessSensorSignal();
- Clip(); // Is it right to clip an magnetometer?
return true;
}
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGMagnetometer::CalculateTransformMatrix(void)
-{
- double cp,sp,cr,sr,cy,sy;
-
- cp=cos(vOrient(ePitch)); sp=sin(vOrient(ePitch));
- cr=cos(vOrient(eRoll)); sr=sin(vOrient(eRoll));
- cy=cos(vOrient(eYaw)); sy=sin(vOrient(eYaw));
-
-
- mT(1,1) = cp*cy;
- mT(1,2) = cp*sy;
- mT(1,3) = -sp;
-
- mT(2,1) = sr*sp*cy - cr*sy;
- mT(2,2) = sr*sp*sy + cr*cy;
- mT(2,3) = sr*cp;
-
- mT(3,1) = cr*sp*cy + sr*sy;
- mT(3,2) = cr*sp*sy - sr*cy;
- mT(3,3) = cr*cp;
-
-
- // This transform is different than for FGForce, where we want a native nozzle
- // force in body frame. Here we calculate the body frame accel and want it in
- // the transformed magnetometer frame. So, the next line is commented out.
- // mT = mT.Inverse();
-}
-
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// The bitmasked value choices are as follows:
// unset: In this case (the default) JSBSim would only print
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGSensor.h"
-#include <input_output/FGXMLElement.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"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
CLASS DECLARATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-class FGMagnetometer : public FGSensor
+class FGMagnetometer : public FGSensor, public FGSensorOrientation
{
public:
FGMagnetometer(FGFCS* fcs, Element* element);
FGMassBalance* MassBalance;
FGInertial* Inertial;
FGColumnVector3 vLocation;
- FGColumnVector3 vOrient;
FGColumnVector3 vRadius;
FGColumnVector3 vMag;
- FGMatrix33 mT;
- void CalculateTransformMatrix(void);
void updateInertialMag(void);
- int axis;
double field[6];
double usedLat;
double usedLon;
FGPID::FGPID(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, element)
{
string kp_string, ki_string, kd_string;
- dt = fcs->GetState()->Getdt();
Kp = Ki = Kd = 0.0;
KpPropertyNode = 0;
else
cout << " INPUT: " << InputNodes[0]->getName() << endl;
- if (IsOutput) cout << " OUTPUT: " << OutputNode->getName() << endl;
+ if (IsOutput) {
+ for (unsigned int i=0; i<OutputNodes.size(); i++)
+ cout << " OUTPUT: " << OutputNodes[i]->getName() << endl;
+ }
}
}
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGFCSComponent.h"
-#include <input_output/FGXMLElement.h>
+#include "input_output/FGXMLElement.h"
#include <string>
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void ResetPastStates(void) {Input_prev = Input_prev2 = Output = I_out_total = 0.0;}
private:
- double dt;
FGPropertyManager *Trigger;
double Kp, Ki, Kd;
double I_out_total;
FGSensor::FGSensor(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, element)
{
double denom;
- dt = fcs->GetDt();
// inputs are read from the base class constructor
- bits = quantized = divisions = index = delay = 0;
+ bits = quantized = divisions = 0;
PreviousInput = PreviousOutput = 0.0;
min = max = bias = gain = noise_variance = lag = drift_rate = drift = span = 0.0;
granularity = 0.0;
cerr << " defaulting to UNIFORM." << endl;
}
}
- if ( element->FindElement("delay") ) {
- delay = (unsigned int)element->FindElementValueAsNumber("delay");
- output_array.resize(delay);
- for (unsigned int i=0; i<delay; i++) output_array[i] = 0.0;
- }
FGFCSComponent::bind();
bind();
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-bool FGSensor::Run(void )
+bool FGSensor::Run(void)
{
Input = InputNodes[0]->getDoubleValue() * InputSigns[0];
+ ProcessSensorSignal();
+
+ return true;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGSensor::ProcessSensorSignal(void)
+{
Output = Input; // perfect sensor
// Degrade signal as specified
if (fail_stuck) {
Output = PreviousOutput;
- return true;
- }
-
- if (lag != 0.0) Lag(); // models sensor lag and filter
- if (noise_variance != 0.0) Noise(); // models noise
- if (drift_rate != 0.0) Drift(); // models drift over time
- if (bias != 0.0) Bias(); // models a finite bias
- if (gain != 0.0) Gain(); // models a finite gain
+ } else {
+ if (lag != 0.0) Lag(); // models sensor lag and filter
+ if (noise_variance != 0.0) Noise(); // models noise
+ if (drift_rate != 0.0) Drift(); // models drift over time
+ if (gain != 0.0) Gain(); // models a finite gain
+ if (bias != 0.0) Bias(); // models a finite bias
- if (delay != 0.0) Delay(); // models system signal transport latencies
+ if (delay != 0) Delay(); // models system signal transport latencies
- if (fail_low) Output = -HUGE_VAL;
- if (fail_high) Output = HUGE_VAL;
+ if (fail_low) Output = -HUGE_VAL;
+ if (fail_high) Output = HUGE_VAL;
- if (bits != 0) Quantize(); // models quantization degradation
+ if (bits != 0) Quantize(); // models quantization degradation
- Clip(); // Is it right to clip a sensor?
- return true;
+ Clip();
+ }
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-void FGSensor::Delay(void)
-{
- output_array[index] = Output;
- if (index == delay-1) index = 0;
- else index++;
- Output = output_array[index];
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
void FGSensor::bind(void)
{
string tmp = Name;
else
cout << " INPUT: " << InputNodes[0]->getName() << endl;
}
- if (delay > 0) cout <<" Frame delay: " << delay
- << " frames (" << delay*dt << " sec)" << endl;
if (bits != 0) {
if (quant_property.empty())
cout << " Quantized output" << endl;
cout << " Random noise is gaussian distributed." << endl;
}
}
- if (IsOutput) cout << " OUTPUT: " << OutputNode->getName() << endl;
+ if (IsOutput) {
+ for (unsigned int i=0; i<OutputNodes.size(); i++)
+ cout << " OUTPUT: " << OutputNodes[i]->getName() << endl;
+ }
}
}
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGFCSComponent.h"
-#include <input_output/FGXMLElement.h>
+#include "input_output/FGXMLElement.h"
#include <vector>
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
protected:
enum eNoiseType {ePercent=0, eAbsolute} NoiseType;
enum eDistributionType {eUniform=0, eGaussian} DistributionType;
- double dt;
double min, max;
double span;
double bias;
int bits;
int quantized;
int divisions;
- int delay;
- int index;
bool fail_low;
bool fail_high;
bool fail_stuck;
string quant_property;
- vector <double> output_array;
+ void ProcessSensorSignal(void);
void Noise(void);
void Bias(void);
void Drift(void);
void Quantize(void);
void Lag(void);
- void Delay(void);
void Gain(void);
void bind(void);
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGSensorOrientation.h
+ Author: Jon Berndt
+ Date started: September 2009
+
+ ------------- Copyright (C) 2009 -------------
+
+ 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
+--------------------------------------------------------------------------------
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGSENSORORIENTATION_H
+#define FGSENSORORIENTATION_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGSensor.h"
+#include "input_output/FGXMLElement.h"
+#include "math/FGColumnVector3.h"
+#include "math/FGMatrix33.h"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_SensorOrientation "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Encapsulates a SensorOrientation capability for a sensor.
+
+Syntax:
+
+@author Jon S. Berndt
+@version $Revision$
+*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGSensorOrientation : public FGJSBBase
+{
+public:
+ FGSensorOrientation(Element* element)
+ {
+ Element* orient_element = element->FindElement("orientation");
+ if (orient_element) vOrient = orient_element->FindElementTripletConvertTo("RAD");
+ else {cerr << "No orientation given for this sensor. " << endl;}
+
+ Element* axis_element = element->FindElement("axis");
+ if (axis_element) {
+ string sAxis = element->FindElementValue("axis");
+ if (sAxis == "X" || sAxis == "x") {
+ axis = 1;
+ } else if (sAxis == "Y" || sAxis == "y") {
+ axis = 2;
+ } else if (sAxis == "Z" || sAxis == "z") {
+ axis = 3;
+ } else {
+ cerr << " Incorrect/no axis specified for this sensor; assuming X axis" << endl;
+ axis = 1;
+ }
+ }
+
+ CalculateTransformMatrix();
+ }
+
+// ~FGSensorOrientation();
+
+protected:
+ FGColumnVector3 vOrient;
+ FGMatrix33 mT;
+ int axis;
+ void CalculateTransformMatrix(void)
+ {
+ double cp,sp,cr,sr,cy,sy;
+
+ cp=cos(vOrient(ePitch)); sp=sin(vOrient(ePitch));
+ cr=cos(vOrient(eRoll)); sr=sin(vOrient(eRoll));
+ cy=cos(vOrient(eYaw)); sy=sin(vOrient(eYaw));
+
+ mT(1,1) = cp*cy;
+ mT(1,2) = cp*sy;
+ mT(1,3) = -sp;
+
+ mT(2,1) = sr*sp*cy - cr*sy;
+ mT(2,2) = sr*sp*sy + cr*cy;
+ mT(2,3) = sr*cp;
+
+ mT(3,1) = cr*sp*cy + sr*sy;
+ mT(3,2) = cr*sp*sy - sr*cy;
+ mT(3,3) = cr*cp;
+
+ // This transform is different than for FGForce, where we want a native nozzle
+ // force in body frame. Here we calculate the body frame accel and want it in
+ // the transformed accelerometer frame. So, the next line is commented out.
+ // mT = mT.Inverse();
+ }
+
+private:
+ void Debug(int from);
+};
+}
+#endif
cout << " " << InputNodes[i]->getName() << endl;
}
if (Bias != 0.0) cout << " Bias: " << Bias << endl;
- if (IsOutput) cout << " OUTPUT: " <<OutputNode->getName() << endl;
+ if (IsOutput) {
+ for (unsigned int i=0; i<OutputNodes.size(); i++)
+ cout << " OUTPUT: " << OutputNodes[i]->getName() << endl;
+ }
}
}
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGFCSComponent.h"
-#include <input_output/FGXMLElement.h>
+#include "input_output/FGXMLElement.h"
#include <vector>
#include <string>
}
cout << endl;
}
- if (IsOutput) cout << " OUTPUT: " << OutputNode->getName() << endl;
+ if (IsOutput) {
+ for (unsigned int i=0; i<OutputNodes.size(); i++)
+ cout << " OUTPUT: " << OutputNodes[i]->getName() << endl;
+ }
}
}
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGFCSComponent.h"
-#include <input_output/FGXMLElement.h>
-#include <math/FGCondition.h>
+#include "input_output/FGXMLElement.h"
+#include "math/FGCondition.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
noinst_HEADERS = \
FGPID.h FGDeadBand.h FGFCSComponent.h FGFilter.h \
FGGain.h FGGradient.h FGKinemat.h FGSummer.h FGSwitch.h FGFCSFunction.h\
- FGSensor.h FGActuator.h FGAccelerometer.h FGGyro.h FGMagnetometer.h
+ FGSensor.h FGActuator.h FGAccelerometer.h FGGyro.h FGMagnetometer.h \
+ FGSensorOrientation.h
INCLUDES = -I$(top_srcdir)/src/FDM/JSBSim
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGElectric.h"
-#include <models/FGPropulsion.h>
+#include "models/FGPropulsion.h"
namespace JSBSim {
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGEngine.h"
-#include <input_output/FGXMLElement.h>
+#include "input_output/FGXMLElement.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
#include "FGTank.h"
#include "FGPropeller.h"
#include "FGNozzle.h"
-#include <input_output/FGXMLParse.h>
-#include <math/FGColumnVector3.h>
+#include "input_output/FGXMLParse.h"
+#include "math/FGColumnVector3.h"
#include <fstream>
namespace JSBSim {
SLFuelFlowMax = 0.0;
MaxThrottle = 1.0;
MinThrottle = 0.0;
+ unsigned int i;
ResetToIC(); // initialize dynamic terms
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) {
- AddFeedTank((int)local_element->GetDataAsNumber());
+ int tankID = (int)local_element->GetDataAsNumber();
+ AddFeedTank( tankID , Propulsion->GetTank(tankID)->GetPriority());
local_element = engine_element->GetParent()->FindNextElement("feed");
}
} else {
if (TrimMode) return;
unsigned int i;
- double Fshortage, TanksWithFuel;
+ double Fshortage, TanksWithFuel, FuelNeeded;
FGTank* Tank;
- Fshortage = TanksWithFuel = 0.0;
+ Fshortage = TanksWithFuel = FuelNeeded = 0.0;
+ double FuelToBurn = CalcFuelNeed();
+ unsigned int CurrentPriority = 1;
+ vector <int> FeedList;
+ Starved = false;
+
+ while (FuelToBurn > 0.0) {
+
+ // 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.0) && (CurrentPriority <= Propulsion->GetNumTanks())) {
+ for (i=0; i<Propulsion->GetNumTanks(); i++) {
+ 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.0) CurrentPriority++;
+ }
- // count how many assigned tanks have fuel
- for (i=0; i<SourceTanks.size(); i++) {
- Tank = Propulsion->GetTank(SourceTanks[i]);
- if (Tank->GetType() == FGTank::ttFUEL){
- if (Tank->GetContents() > 0.0) ++TanksWithFuel;
- } else {
- cerr << "No oxidizer tanks should be used for this engine type." << endl;
+ // No fuel found at any priority!
+ if (TanksWithFuel == 0.0) {
+ Starved = true;
+ return;
}
- }
- if (TanksWithFuel==0) {
- Starved = true;
- return;
- }
- for (i=0; i<SourceTanks.size(); i++) {
- Tank = Propulsion->GetTank(SourceTanks[i]);
- if (Tank->GetType() == FGTank::ttFUEL) {
- Fshortage += Tank->Drain(CalcFuelNeed()/TanksWithFuel);
- } else {
- cerr << "No oxidizer tanks should be used for this engine type." << endl;
+ // 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);
+ FuelToBurn -= FuelNeeded;
}
- }
- if (Fshortage < 0.00) Starved = true;
- else Starved = false;
+ // check if we were not able to burn all the fuel we needed to at this priority level
+ if (FuelToBurn > 0.001) {
+ CurrentPriority++;
+ TanksWithFuel = 0.0;
+ FeedList.clear();
+ }
+
+ } // while
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-void FGEngine::AddFeedTank(int tkID)
+void FGEngine::AddFeedTank(int tkID, int priority)
{
- SourceTanks.push_back(tkID);
+ SourceTanks[tkID] = priority;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
{
string token, fullpath, localpath;
string thruster_filename, thruster_fullpathname, thrType;
- double P_Factor = 0, Sense = 0.0;
string enginePath = FDMExec->GetEnginePath();
string aircraftPath = FDMExec->GetFullAircraftPath();
ifstream thruster_file;
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-#include <FGJSBBase.h>
+#include "FGJSBBase.h"
#include "FGThruster.h"
-#include <input_output/FGPropertyManager.h>
-#include <input_output/FGXMLFileRead.h>
+#include "input_output/FGPropertyManager.h"
+#include "input_output/FGXMLFileRead.h"
#include <vector>
#include <string>
virtual void SetRunning(bool bb) { Running=bb; }
virtual void SetName(string name) { Name = name; }
- virtual void AddFeedTank(int tkID);
+ virtual void AddFeedTank(int tkID, int priority);
virtual void SetFuelFreeze(bool f) { FuelFreeze = f; }
virtual void SetStarter(bool s) { Starter = s; }
void Debug(int from);
};
}
-#include <FGState.h>
-#include <FGFDMExec.h>
-#include <models/FGAtmosphere.h>
-#include <models/FGFCS.h>
-#include <models/FGAircraft.h>
-#include <models/FGPropagate.h>
-#include <models/FGPropulsion.h>
-#include <models/FGAuxiliary.h>
-#include <models/propulsion/FGThruster.h>
-#include <input_output/FGXMLElement.h>
+#include "FGState.h"
+#include "FGFDMExec.h"
+#include "models/FGAtmosphere.h"
+#include "models/FGFCS.h"
+#include "models/FGAircraft.h"
+#include "models/FGPropagate.h"
+#include "models/FGPropulsion.h"
+#include "models/FGAuxiliary.h"
+#include "models/propulsion/FGThruster.h"
+#include "input_output/FGXMLElement.h"
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#endif
*/
#include "FGForce.h"
-#include <FGFDMExec.h>
-#include <models/FGAircraft.h>
-#include <models/FGPropagate.h>
-#include <models/FGMassBalance.h>
-#include <models/FGAerodynamics.h>
+#include "FGFDMExec.h"
+#include "models/FGAircraft.h"
+#include "models/FGPropagate.h"
+#include "models/FGMassBalance.h"
+#include "models/FGAerodynamics.h"
namespace JSBSim {
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGForce::FGForce(FGFDMExec *FDMExec) :
- ttype(tNone),
- fdmex(FDMExec)
+ fdmex(FDMExec),
+ ttype(tNone)
{
mT(1,1) = 1; //identity matrix
mT(2,2) = 1;
void FGForce::UpdateCustomTransformMatrix(void)
{
double cp,sp,cr,sr,cy,sy;
+ double srsp, crcy, crsy;
cp=cos(vOrient(ePitch)); sp=sin(vOrient(ePitch));
cr=cos(vOrient(eRoll)); sr=sin(vOrient(eRoll));
cy=cos(vOrient(eYaw)); sy=sin(vOrient(eYaw));
+ srsp = sr*sp;
+ crcy = cr*cy;
+ crsy = cr*sy;
+
mT(1,1) = cp*cy;
- mT(1,2) = cp*sy;
- mT(1,3) = -sp;
+ mT(2,1) = cp*sy;
+ mT(3,1) = -sp;
- mT(2,1) = sr*sp*cy - cr*sy;
- mT(2,2) = sr*sp*sy + cr*cy;
- mT(2,3) = sr*cp;
+ mT(1,2) = srsp*cy - crsy;
+ mT(2,2) = srsp*sy + crcy;
+ mT(3,2) = sr*cp;
- mT(3,1) = cr*sp*cy + sr*sy;
- mT(3,2) = cr*sp*sy - sr*cy;
+ mT(1,3) = crcy*sp + sr*sy;
+ mT(2,3) = crsy*sp - sr*cy;
mT(3,3) = cr*cp;
- mT = mT.Inverse();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-#include <FGFDMExec.h>
-#include <FGJSBBase.h>
-#include <math/FGMatrix33.h>
-#include <math/FGColumnVector3.h>
+#include "FGFDMExec.h"
+#include "FGJSBBase.h"
+#include "math/FGMatrix33.h"
+#include "math/FGColumnVector3.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
virtual FGColumnVector3& GetBodyForces(void);
+ inline double GetBodyXForce(void) const { return vFb(eX); }
+ inline double GetBodyYForce(void) const { return vFb(eY); }
+ inline double GetBodyZForce(void) const { return vFb(eZ); }
inline FGColumnVector3& GetMoments(void) { return vM; }
// Normal point of application, JSBsim structural coords
inline void SetLocation(FGColumnVector3 vv) { vXYZn = vv; SetActingLocation(vv);}
inline void SetActingLocation(FGColumnVector3 vv) { vActingXYZn = vv; }
- inline double GetLocationX( void ) { return vXYZn(eX);}
- inline double GetLocationY( void ) { return vXYZn(eY);}
- inline double GetLocationZ( void ) { return vXYZn(eZ);}
- inline double GetActingLocationX( void ) { return vActingXYZn(eX);}
- inline double GetActingLocationY( void ) { return vActingXYZn(eY);}
- inline double GetActingLocationZ( void ) { return vActingXYZn(eZ);}
+ inline double GetLocationX( void ) const { return vXYZn(eX);}
+ inline double GetLocationY( void ) const { return vXYZn(eY);}
+ inline double GetLocationZ( void ) const { return vXYZn(eZ);}
+ inline double GetActingLocationX( void ) const { return vActingXYZn(eX);}
+ inline double GetActingLocationY( void ) const { return vActingXYZn(eY);}
+ inline double GetActingLocationZ( void ) const { return vActingXYZn(eZ);}
FGColumnVector3& GetLocation(void) { return vXYZn; }
FGColumnVector3& GetActingLocation(void) { return vActingXYZn; }
double GetYaw(void) const {return vOrient(eYaw);}
inline FGColumnVector3& GetAnglesToBody(void) {return vOrient;}
- inline double GetAnglesToBody(int axis) {return vOrient(axis);}
+ inline double GetAnglesToBody(int axis) const {return vOrient(axis);}
inline void SetTransformType(TransformType ii) { ttype=ii; }
- inline TransformType GetTransformType(void) { return ttype; }
+ inline TransformType GetTransformType(void) const { return ttype; }
FGMatrix33 Transform(void);
#include <sstream>
#include "FGNozzle.h"
-#include <models/FGAtmosphere.h>
+#include "models/FGAtmosphere.h"
namespace JSBSim {
#include <sstream>
#include "FGPiston.h"
-#include <models/FGPropulsion.h>
+#include "models/FGPropulsion.h"
#include "FGPropeller.h"
namespace JSBSim {
rho_fuel(800), // estimate
calorific_value_fuel(47.3e6),
Cp_air(1005), // Specific heat (constant pressure) J/Kg/K
- Cp_fuel(1700)
+ Cp_fuel(1700),
+ standard_pressure(101320.73)
{
string token;
Stroke = 4.375;
Cylinders = 4;
CompressionRatio = 8.5;
+ Z_airbox = -999;
+ Ram_Air_Factor = 1;
+ PeakMeanPistonSpeed_fps = 100;
// These are internal program variables
BoostSpeed = 0;
Boosted = false;
BoostOverride = 0;
+ BoostManual = 0;
bBoostOverride = false;
bTakeoffBoost = false;
TakeoffBoost = 0.0; // Default to no extra takeoff-boost
Stroke = el->FindElementValueAsNumberConvertTo("stroke","IN");
if (el->FindElement("cylinders"))
Cylinders = el->FindElementValueAsNumber("cylinders");
+ if (el->FindElement("air-intake-impedance-factor"))
+ Z_airbox = el->FindElementValueAsNumber("air-intake-impedance-factor");
+ if (el->FindElement("ram-air-factor"))
+ Ram_Air_Factor = el->FindElementValueAsNumber("ram-air-factor");
+ if (el->FindElement("peak-piston-speed"))
+ PeakMeanPistonSpeed_fps = el->FindElementValueAsNumber("peak-piston-speed");
if (el->FindElement("numboostspeeds")) { // Turbo- and super-charging parameters
BoostSpeeds = (int)el->FindElementValueAsNumber("numboostspeeds");
if (el->FindElement("boostoverride"))
BoostOverride = (int)el->FindElementValueAsNumber("boostoverride");
+ if (el->FindElement("boostmanual"))
+ BoostManual = (int)el->FindElementValueAsNumber("boostmanual");
if (el->FindElement("takeoffboost"))
TakeoffBoost = el->FindElementValueAsNumberConvertTo("takeoffboost", "PSI");
if (el->FindElement("ratedboost1"))
minMAP = MinManifoldPressure_inHg * inhgtopa; // inHg to Pa
maxMAP = MaxManifoldPressure_inHg * inhgtopa;
+// For throttle
+ RatedMeanPistonSpeed_fps = ( MaxRPM * Stroke) / (360); // AKA 2 * (RPM/60) * ( Stroke / 12) or 2NS
+ if(Z_airbox < 998){
+ double Ze=RatedMeanPistonSpeed_fps/PeakMeanPistonSpeed_fps; // engine impedence
+ Z_airbox = (standard_pressure *Ze / maxMAP) - Ze; // impedence of airbox
+ }
+ Z_throttle=(((MaxRPM * Stroke) / 360)/((IdleRPM * Stroke) / 360))*(standard_pressure/minMAP - 1) - Z_airbox; // Constant for Throttle impedence
+
string property_name, base_property_name;
base_property_name = CreateIndexedPropertyName("propulsion/engine", EngineNumber);
property_name = base_property_name + "/power-hp";
PropertyManager->Tie(property_name, &MAP);
property_name = base_property_name + "/map-inhg";
PropertyManager->Tie(property_name, &ManifoldPressure_inHg);
+ property_name = base_property_name + "/air-intake-impedance-factor";
+ PropertyManager->Tie(property_name, &Z_airbox);
+ property_name = base_property_name + "/ram-air-factor";
+ PropertyManager->Tie(property_name, &Ram_Air_Factor);
+ property_name = base_property_name + "/boost-speed";
+ PropertyManager->Tie(property_name, &BoostSpeed);
// Set up and sanity-check the turbo/supercharging configuration based on the input values.
if (TakeoffBoost > RatedBoost[0]) bTakeoffBoost = true;
BoostSpeed = 0;
}
bBoostOverride = (BoostOverride == 1 ? true : false);
+ bBoostManual = (BoostManual == 1 ? true : false);
Debug(0); // Call Debug() routine from constructor if needed
}
//
p_amb = Atmosphere->GetPressure() * psftopa;
+ double p = Auxiliary->GetTotalPressure() * psftopa;
+ p_ram = (p - p_amb) * Ram_Air_Factor + p_amb;
T_amb = RankineToKelvin(Atmosphere->GetTemperature());
RPM = Thruster->GetRPM() * Thruster->GetGearRatio();
void FGPiston::doBoostControl(void)
{
- if(BoostSpeed < BoostSpeeds - 1) {
- // Check if we need to change to a higher boost speed
- if(p_amb < BoostSwitchPressure[BoostSpeed] - BoostSwitchHysteresis) {
- BoostSpeed++;
- }
- } else if(BoostSpeed > 0) {
- // Check if we need to change to a lower boost speed
- if(p_amb > BoostSwitchPressure[BoostSpeed - 1] + BoostSwitchHysteresis) {
- BoostSpeed--;
+ if(BoostManual) {
+ if(BoostSpeed > BoostSpeeds-1) BoostSpeed = BoostSpeeds-1;
+ if(BoostSpeed < 0) BoostSpeed = 0;
+ } else {
+ if(BoostSpeed < BoostSpeeds - 1) {
+ // Check if we need to change to a higher boost speed
+ if(p_amb < BoostSwitchPressure[BoostSpeed] - BoostSwitchHysteresis) {
+ BoostSpeed++;
+ }
+ } else if(BoostSpeed > 0) {
+ // Check if we need to change to a lower boost speed
+ if(p_amb > BoostSwitchPressure[BoostSpeed - 1] + BoostSwitchHysteresis) {
+ BoostSpeed--;
+ }
}
}
}
void FGPiston::doMAP(void)
{
- // estimate throttle plate area.
- double throttle_area = ThrottleAngle*ThrottleAngle;
- // Internal Combustion Engine in Theory and Practice, Volume 2. Charles Fayette Taylor. Revised Edition, 1985 fig 6-13
- double map_coefficient = 1-((MeanPistonSpeed_fps*MeanPistonSpeed_fps)/(24978*throttle_area));
+ double Zt =(1-Throttle)*(1-Throttle)*Z_throttle; // throttle impedence
+ double Ze= MeanPistonSpeed_fps > 0 ? PeakMeanPistonSpeed_fps/MeanPistonSpeed_fps : 999999; // engine impedence
- if ( map_coefficient < 0.1 ) map_coefficient = 0.1;
+ double map_coefficient = Ze/(Ze+Z_airbox+Zt);
// Add a one second lag to manifold pressure changes
- double dMAP = (TMAP - p_amb * map_coefficient) * dt;
+ double dMAP = (TMAP - p_ram * map_coefficient) * dt;
TMAP -=dMAP;
// Find the mean effective pressure required to achieve this manifold pressure
}
}
// Boost the manifold pressure.
- double boost_factor = BoostMul[BoostSpeed] * RPM/RatedRPM[BoostSpeed];
- if (boost_factor < 1.0) boost_factor = 1.0; // boost will never reduce the MAP
+ double boost_factor = (( BoostMul[BoostSpeed] - 1 ) / RatedRPM[BoostSpeed] ) * RPM + 1;
MAP = TMAP * boost_factor;
// Now clip the manifold pressure to BCV or Wastegate setting.
if (bTakeoffPos) {
void FGPiston::doAirFlow(void)
{
- double gamma = 1.4; // specific heat constants
+ double gamma = 1.1; // specific heat constants
// loss of volumentric efficiency due to difference between MAP and exhaust pressure
double ve =((gamma-1)/gamma)+( CompressionRatio -(p_amb/MAP))/(gamma*( CompressionRatio - 1));
cout << " MaxHP: " << MaxHP << endl;
cout << " Cycles: " << Cycles << endl;
cout << " IdleRPM: " << IdleRPM << endl;
+ cout << " MaxRPM: " << MaxRPM << endl;
cout << " MaxThrottle: " << MaxThrottle << endl;
cout << " MinThrottle: " << MinThrottle << endl;
cout << " ISFC: " << ISFC << endl;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGEngine.h"
-#include <math/FGTable.h>
-#include <input_output/FGXMLElement.h>
+#include "math/FGTable.h"
+#include "input_output/FGXMLElement.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
<maxthrottle> {number} </maxthrottle>
<minthrottle> {number} </minthrottle>
<bsfc unit="{LBS/HP*HR | "KG/KW*HR"}"> {number} </bsfc>
- <volumetric_efficiency> {number} </volumetric_efficiency>
+ <volumetric-efficiency> {number} </volumetric-efficiency>
<numboostspeeds> {number} </numboostspeeds>
<boostoverride> {0 | 1} </boostoverride>
+ <boostmanual> {0 | 1} </boostmanual>
<ratedboost1 unit="{INHG | PA | ATM}"> {number} </ratedboost1>
<ratedpower1 unit="{HP | WATTS}"> {number} </ratedpower1>
<ratedrpm1> {number} </ratedrpm1>
<ratedrpm3> {number} </ratedrpm3>
<ratedaltitude3 unit="{FT | M}"> {number} </ratedaltitude3>
<takeoffboost unit="{INHG | PA | ATM}"> {number} </takeoffboost>
+ <air-intake-impedance-factor> {number} </air-intake-impedance-factor>
+ <ram-air-factor> {number} </ram-air-factor>
</piston_engine>
@endcode
some way of getting the boost control cutout lever position (on or off)
from FlightGear first.
+ - BOOSTMANUAL - whether a multispeed supercharger will manually or
+ automatically shift boost speeds. On manual shifting the boost speeds
+ is accomplished by controling propulsion/engine/boostspeed
+
- The next items are all appended with either 1, 2 or 3 depending on which
boost speed they refer to, eg RATEDBOOST1. The rated values seems to have
been a common convention at the time to express the maximum continuously
const double calorific_value_fuel; // W/Kg (approximate)
const double Cp_air; // J/KgK
const double Cp_fuel; // J/KgK
+ const double standard_pressure; //Pa
+
FGTable *Lookup_Combustion_Efficiency;
FGTable *Mixture_Efficiency_Correlation;
double Bore; // inches
double Stroke; // inches
double Cylinders; // number
- double CompressionRatio; // number
+ double CompressionRatio; // number
+ double Z_airbox; // number representing intake impediance before the throttle
+ double Z_throttle; // number representing slope of throttle impediance
+ double PeakMeanPistonSpeed_fps; // ft/sec speed where intake valves begin to choke. Typically 33-50 fps
+ double RatedMeanPistonSpeed_fps; // ft/sec derived from MaxRPM and stroke.
+ double Ram_Air_Factor; // number
double StarterHP; // initial horsepower of starter motor
int BoostSpeeds; // Number of super/turbocharger boost speeds - zero implies no turbo/supercharging.
int BoostSpeed; // The current boost-speed (zero-based).
bool Boosted; // Set true for boosted engine.
+ int BoostManual; // The raw value read in from the config file - should be 1 or 0 - see description below.
+ bool bBoostManual; // Set true if pilot must manually control the boost speed.
int BoostOverride; // The raw value read in from the config file - should be 1 or 0 - see description below.
bool bBoostOverride; // Set true if pilot override of the boost regulator was fitted.
// (Typically called 'war emergency power').
// Inputs (in addition to those in FGEngine).
//
double p_amb; // Pascals
+ double p_ram; // Pascals
double T_amb; // degrees Kelvin
double RPM; // revolutions per minute
double IAS; // knots
#include <sstream>
#include "FGPropeller.h"
-#include <models/FGPropagate.h>
-#include <models/FGAtmosphere.h>
-#include <models/FGAuxiliary.h>
+#include "models/FGPropagate.h"
+#include "models/FGAtmosphere.h"
+#include "models/FGAuxiliary.h"
namespace JSBSim {
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGThruster.h"
-#include <math/FGTable.h>
+#include "math/FGTable.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
if ((Throttle == 1 || BurnTime > 0.0 ) && !Starved) {
BurnTime += State->Getdt();
double TotalEngineFuelAvailable=0.0;
- for (int i=0; i<(int)SourceTanks.size(); i++)
- TotalEngineFuelAvailable += Propulsion->GetTank(SourceTanks[i])->GetContents();
+ for (int i=0; i<(int)SourceTanks.size(); i++) {
+ FGTank* tank = Propulsion->GetTank(i);
+ if (SourceTanks[i] == 1) {
+ TotalEngineFuelAvailable += tank->GetContents();
+ }
+ }
VacThrust = ThrustTable->GetValue(TotalEngineFuelAvailable);
} else {
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGEngine.h"
-#include <math/FGTable.h>
-#include <input_output/FGXMLElement.h>
+#include "math/FGTable.h"
+#include "input_output/FGXMLElement.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGTank.h"
-#include <models/FGAuxiliary.h>
+#include "models/FGAuxiliary.h"
using std::cerr;
using std::endl;
Area = 1.0;
Temperature = -9999.0;
Ixx = Iyy = Izz = 0.0;
- Radius = Capacity = Contents = Standpipe = Length = InnerRadius = 0.0;
+ Radius = Contents = Standpipe = Length = InnerRadius = 0.0;
+ Capacity = 0.00001;
+ Priority = InitialPriority = 1;
PropertyManager = Exec->GetPropertyManager();
vXYZ.InitMatrix();
vXYZ_drain.InitMatrix();
InitialTemperature = Temperature = el->FindElementValueAsNumber("temperature");
if (el->FindElement("standpipe"))
InitialStandpipe = Standpipe = el->FindElementValueAsNumberConvertTo("standpipe", "LBS");
+ if (el->FindElement("priority"))
+ InitialPriority = Priority = el->FindElementValueAsNumber("priority");
- Selected = true;
+ SetPriority( InitialPriority ); // this will also set the Selected flag
- if (Capacity != 0) {
- PctFull = 100.0*Contents/Capacity; // percent full; 0 to 100.0
- } else {
- Contents = 0;
- PctFull = 0;
+ if (Capacity == 0) {
+ cerr << "Tank capacity must not be zero. Reset to 0.00001 lbs!" << endl;
+ Capacity = 0.00001;
+ Contents = 0.0;
}
+ PctFull = 100.0*Contents/Capacity; // percent full; 0 to 100.0
// Check whether this is a solid propellant "tank". Initialize it if true.
property_name = base_property_name + "/contents-lbs";
PropertyManager->Tie( property_name.c_str(), (FGTank*)this, &FGTank::GetContents,
&FGTank::SetContents );
+ property_name = base_property_name + "/priority";
+ PropertyManager->Tie( property_name.c_str(), (FGTank*)this, &FGTank::GetPriority,
+ &FGTank::SetPriority );
if (Temperature != -9999.0) InitialTemperature = Temperature = FahrenheitToCelsius(Temperature);
Area = 40.0 * pow(Capacity/1975, 0.666666667);
void FGTank::ResetToIC(void)
{
- Temperature = InitialTemperature;
- Standpipe = InitialStandpipe;
- Contents = InitialContents;
+ SetTemperature( InitialTemperature );
+ SetStandpipe ( InitialStandpipe );
+ SetContents ( InitialContents );
PctFull = 100.0*Contents/Capacity;
- Selected = true;
+ SetPriority( InitialPriority );
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Contents = 0.0;
PctFull = 0.0;
- Selected = false;
+ SetPriority(0);
}
if (grainType != gtUNKNOWN) CalculateInertias();
Ixx = 0.5*Mass*Rad2/144.0;
Iyy = Mass*(3.0*Rad2 + Length*Length)/(144.0*12.0);
break;
+ case gtUNKNOWN:
+ cerr << "Unknown grain type found." << endl;
+ exit(-1);
+ break;
}
Izz = Iyy;
cout << " Tank location (X, Y, Z): " << vXYZ(eX) << ", " << vXYZ(eY) << ", " << vXYZ(eZ) << endl;
cout << " Effective radius: " << Radius << " inches" << endl;
cout << " Initial temperature: " << Temperature << " Fahrenheit" << endl;
+ cout << " Priority: " << Priority << endl;
}
}
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGFDMExec.h"
-#include <FGJSBBase.h>
-#include <input_output/FGXMLElement.h>
-#include <math/FGColumnVector3.h>
+#include "FGJSBBase.h"
+#include "input_output/FGXMLElement.h"
+#include "math/FGColumnVector3.h"
#include <string>
using std::string;
<contents unit="{LBS | KG}"> {number} </contents>
<temperature> {number} </temperature> <!-- must be degrees fahrenheit -->
<standpipe unit="{LBS | KG"}> {number} </standpipe>
+ <priority> {integer} </priority>
</tank>
@endcode
- \b contents - Initial contents, defaults to pounds.
- \b temperature - Initial temperature, defaults to degrees Fahrenheit.
- \b standpipe - Minimum contents to which tank can dump, defaults to pounds.
+- \b priority - Establishes feed sequence of tank. "1" is the highest priority.
location:
- \b x - Location of tank on aircraft's x-axis, defaults to inches.
- \b y - 0.0 (both full and drained CG locations)
- \b z - 0.0 (both full and drained CG locations)
- \b radius - 0.0
-- \b capacity - 0.0
+- \b capacity - 0.00001 (tank capacity must not be zero)
- \b contents - 0.0
-- \b temperature - -9999.0
-- \b standpipe - 0.0
+- \b temperature - -9999.0 (flag which indicates no temperature is set)
+- \b standpipe - 0.0 (all contents may be dumped)
+- \b priority - 1 (highest feed sequence priority)
@author Jon Berndt, Dave Culp
@see Akbar, Raza et al. "A Simple Analysis of Fuel Addition to the CWT of
/** Resets the tank parameters to the initial conditions */
void ResetToIC(void);
- /** If the tank is supplying fuel, this function returns true.
- @return true if this tank is feeding an engine.*/
+ /** If the tank is set to supply fuel, this function returns true.
+ @return true if this tank is set to a non-zero priority.*/
bool GetSelected(void) {return Selected;}
/** Gets the tank fill level.
double GetStandpipe(void) {return Standpipe;}
+ int GetPriority(void) const {return Priority;}
+ void SetPriority(int p) { Priority = p; Selected = p>0 ? true:false; }
+
const FGColumnVector3 GetXYZ(void);
const double GetXYZ(int idx);
void SetContents(double amount);
void SetTemperature(double temp) { Temperature = temp; }
void SetStandpipe(double amount) { Standpipe = amount; }
+ void SetSelected(bool sel) { sel==true ? SetPriority(1):SetPriority(0); }
enum TankType {ttUNKNOWN, ttFUEL, ttOXIDIZER};
enum GrainType {gtUNKNOWN, gtCYLINDRICAL, gtENDBURNING};
double Temperature, InitialTemperature;
double Standpipe, InitialStandpipe;
bool Selected;
+ int Priority, InitialPriority;
FGFDMExec* Exec;
FGPropertyManager* PropertyManager;
void CalculateInertias(void);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGForce.h"
-#include <input_output/FGXMLElement.h>
-#include <input_output/FGPropertyManager.h>
-#include <math/FGColumnVector3.h>
+#include "input_output/FGXMLElement.h"
+#include "input_output/FGPropertyManager.h"
+#include "math/FGColumnVector3.h"
#include <string>
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Stalled = Seized = Overtemp = Fire = Augmentation = Injection = Reversed = false;
Cutoff = true;
phase = tpOff;
- EGT_degC = 0.0;
- OilTemp_degK = (Auxiliary->GetTotalTemperature() - 491.69) * 0.5555556 + 273.0;
+ TAT = (Auxiliary->GetTotalTemperature() - 491.69) * 0.5555556;
+ EGT_degC = TAT;
+ OilTemp_degK = TAT + 273.0;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
N1 = Seek(&N1, qbar/10.0, 0, N1/10.0);
N2 = Seek(&N2, qbar/15.0, 0, N2/10.0);
ConsumeFuel();
- if (ThrottlePos < 0.01) phase = tpRun; // clear the stall with throttle
-
+ if (ThrottlePos < 0.01) {
+ phase = tpRun; // clear the stall with throttle to idle
+ Stalled = false;
+ }
return 0.0;
}
double qbar = Auxiliary->Getqbar();
N2 = 0.0;
N1 = Seek(&N1, qbar/20.0, 0, N1/15.0);
- FuelFlow_pph = IdleFF;
+ FuelFlow_pph = Cutoff ? 0.0 : IdleFF;
ConsumeFuel();
OilPressure_psi = 0.0;
OilTemp_degK = Seek(&OilTemp_degK, TAT + 273.0, 0, 0.2);
property_name = base_property_name + "/injection_cmd";
PropertyManager->Tie( property_name.c_str(), (FGTurbine*)this,
&FGTurbine::GetInjection, &FGTurbine::SetInjection);
+ property_name = base_property_name + "/seized";
+ PropertyManager->Tie( property_name.c_str(), &Seized);
+ property_name = base_property_name + "/stalled";
+ PropertyManager->Tie( property_name.c_str(), &Stalled);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
State->SuspendIntegration();
Cutoff=false;
Running=true;
- N2=16.0;
+ N2=IdleN2;
Calculate();
State->ResumeIntegration();
return phase==tpRun;
#include <vector>
#include "FGEngine.h"
-#include <input_output/FGXMLElement.h>
-#include <math/FGFunction.h>
+#include "input_output/FGXMLElement.h"
+#include "math/FGFunction.h"
#define ID_TURBINE "$Id$"
#include <vector>
#include "FGEngine.h"
-#include <input_output/FGXMLElement.h>
-#include <math/FGTable.h>
+#include "input_output/FGXMLElement.h"
+#include "math/FGTable.h"
#define ID_TURBOPROP "$Id$"