public override bool Run(bool Holding) { if (InternalRun()) { return(true); } if (FDMExec.Holding()) { return(false); // if paused don't execute } vForces = Vector3D.Zero; vMoments = Vector3D.Zero; // Only execute gear force code below 300 feet if (FDMExec.Propagate.DistanceAGL < 300.0) { // Sum forces and moments for all gear, here. // Some optimizations may be made here - or rather in the gear code itself. // The gear ::Run() method is called several times - once for each gear. // Perhaps there is some commonality for things which only need to be // calculated once. foreach (LGear gear in lGear) { vForces += gear.Force(); vMoments += gear.Moment(); } } else { // Crash Routine } return(false); }
/// <summary> /// Runs the Aircraft model; called by the Executive /// </summary> /// <returns>false if no error</returns> public override bool Run() { if (InternalRun()) { return(true); } if (FDMExec.Holding()) { return(false); // if paused don't execute } // if false then execute this Run() vForces = Vector3D.Zero; vForces = FDMExec.Aerodynamics.Forces; vForces += FDMExec.Propulsion.GetForces(); vForces += FDMExec.GroundReactions.GetForces(); vMoments = Vector3D.Zero; vMoments = FDMExec.Aerodynamics.Moments; vMoments += FDMExec.Propulsion.GetMoments(); vMoments += FDMExec.GroundReactions.GetMoments(); vBodyAccel = vForces / FDMExec.MassBalance.Mass; vNcg = vBodyAccel / FDMExec.Inertial.Gravity; vNwcg = FDMExec.State.GetTb2s() * vNcg; vNwcg.Z = -1 * vNwcg.Z + 1; return(false); }
/// <summary> /// Runs the Aircraft model; called by the Executive /// </summary> /// <returns>false if no error</returns> public override bool Run(bool Holding) { #if TODO if (InternalRun()) { return(true); } if (FDMExec.Holding()) { return(false); // if paused don't execute } // if false then execute this Run() vForces = Vector3D.Zero; vForces = FDMExec.Aerodynamics.Forces; vForces += FDMExec.Propulsion.GetForces(); vForces += FDMExec.GroundReactions.GetForces(); vMoments = Vector3D.Zero; vMoments = FDMExec.Aerodynamics.Moments; vMoments += FDMExec.Propulsion.GetMoments(); vMoments += FDMExec.GroundReactions.GetMoments(); vBodyAccel = vForces / FDMExec.MassBalance.Mass; vNcg = vBodyAccel / FDMExec.Inertial.Gravity; vNwcg = FDMExec.State.GetTb2s() * vNcg; vNwcg.Z = -1 * vNwcg.Z + 1; return(false); #endif throw new NotImplementedException("Pending upgrade to lastest version of JSBSIM"); }
public override bool Run() { double denom, k1, k2, k3, k4, k5, k6; double Ixx, Iyy, Izz, Ixy, Ixz, Iyz; if (InternalRun()) { return(true); } if (FDMExec.Holding()) { return(false); // if paused don't execute } weight = emptyWeight + FDMExec.Propulsion.GetTanksWeight() + GetPointMassWeight(); mass = Constants.lbtoslug * weight; // Calculate new CG vXYZcg = (FDMExec.Propulsion.GetTanksMoment() + emptyWeight * vbaseXYZcg + GetPointMassMoment()) / weight; // Calculate new total moments of inertia // At first it is the base configuration inertia matrix ... mJ = baseJ; // ... with the additional term originating from the parallel axis theorem. mJ += GetPointmassInertia(Constants.lbtoslug * emptyWeight, vbaseXYZcg); // Then add the contributions from the additional pointmasses. mJ += CalculatePMInertias(); mJ += FDMExec.Propulsion.CalculateTankInertias(); Ixx = mJ.M11; Iyy = mJ.M22; Izz = mJ.M33; Ixy = -mJ.M12; Ixz = -mJ.M13; Iyz = -mJ.M23; // Calculate inertia matrix inverse (ref. Stevens and Lewis, "Flight Control & Simulation") k1 = (Iyy * Izz - Iyz * Iyz); k2 = (Iyz * Ixz + Ixy * Izz); k3 = (Ixy * Iyz + Iyy * Ixz); denom = 1.0 / (Ixx * k1 - Ixy * k2 - Ixz * k3); k1 = k1 * denom; k2 = k2 * denom; k3 = k3 * denom; k4 = (Izz * Ixx - Ixz * Ixz) * denom; k5 = (Ixy * Ixz + Iyz * Ixx) * denom; k6 = (Ixx * Iyy - Ixy * Ixy) * denom; mJinv = new Matrix3D(k1, k2, k3, k2, k4, k5, k3, k5, k6); return(false); }
public override bool Run() { // Fast return if we have nothing to do ... if (InternalRun()) { return(true); } if (FDMExec.Holding()) { return(false); // if paused don't execute } // Gravitation accel double r = FDMExec.Propagate.Radius; gAccel = GetGAccel(r); return(false); }
/// <summary> /// Runs the Atmosphere model; called by the Executive /// </summary> /// <returns>false if no error</returns> public override bool Run() { if (InternalRun()) { return(true); } if (FDMExec.Holding()) { return(false); } T_dev = 0.0; h = FDMExec.Propagate.Altitude; if (!useExternal) { Calculate(h); CalculateDerived(); } else { CalculateDerived(); } // if false then execute this Run() //do temp, pressure, and density first if (!useExternal) { h = FDMExec.Propagate.Altitude; Calculate(h); } if (turbType != TurbType.ttNone) { Turbulence(); vWindNED += vTurbulence; } return(false); }
public override bool Run() { if (InternalRun()) { return(true); } if (FDMExec.Holding()) { return(false); } T_dev = 0.0; // if false then execute this Run() //do temp, pressure, and density first if (!useExternal) { h = FDMExec.Propagate.Altitude; Calculate(h); } if (turbType != TurbType.ttNone) { Turbulence(); vWindNED += vTurbulence; } if (vWindNED[0] != 0.0) { psiw = Math.Atan2(vWindNED[1], vWindNED[0]); } if (psiw < 0) { psiw += 2 * Math.PI; } soundspeed = Math.Sqrt(Constants.SHRatio * Constants.Reng * (useInfo.Temperature)); return(false); }
public override bool Run(bool Holding) { //if (log.IsInfoEnabled) // log.Info("Entering Run() for model " + name + "rate =" + rate); if (InternalRun()) { return(true); } if (enabled && !FDMExec.State.IsIntegrationSuspended && !FDMExec.Holding()) { if (outputType == OutputType.Socket) { // Not done yet //if (log.IsWarnEnabled) // log.Warn("Socket output is Not Implemented"); } else if (outputType == OutputType.CSV || outputType == OutputType.Tab) { DelimitedOutput(filename); //TODO } else if (outputType == OutputType.Terminal) { // Not done yet throw new NotImplementedException("Terminal output"); } else if (outputType == OutputType.Log4Net) { Log4NetOutput(); } else if (outputType == OutputType.None) { // Do nothing } else { // Not a valid type of output } } return(false); }
/// <summary> /// Executes the propulsion model. /// The initial plan for the FGPropulsion class calls for Run() to be executed, /// calculating the power available from the engine. /// /// [Note: Should we be checking the Starved flag here?] /// </summary> /// <returns></returns> public override bool Run(bool Holding) { if (InternalRun()) { return(true); } if (FDMExec.Holding()) { return(false); // if paused don't execute } double dt = FDMExec.State.DeltaTime; vForces = Vector3D.Zero; vMoments = Vector3D.Zero; for (int i = 0; i < engines.Count; i++) { engines[i].Calculate(); vForces += engines[i].GetBodyForces(); // sum body frame forces vMoments += engines[i].GetMoments(); // sum body frame moments } totalFuelQuantity = 0.0; for (int i = 0; i < tanks.Count; i++) { tanks[i].Calculate(dt * rate); if (tanks[i].TankType == Tank.EnumTankType.Fuel) { totalFuelQuantity += tanks[i].Contents; } } if (refuel) { DoRefuel(dt * rate); } return(false); }
/// <summary> /// Runs the Aerodynamics model; called by the Executive /// </summary> /// <returns>false if no error</returns> public override bool Run() { double alpha, twovel; if (InternalRun()) { return(true); } if (FDMExec.Holding()) { return(false); // if paused don't execute } // calculate some oft-used quantities for speed twovel = 2 * FDMExec.Auxiliary.Vt; if (twovel != 0) { bi2vel = FDMExec.Aircraft.WingSpan / twovel; ci2vel = FDMExec.Aircraft.WingChord / twovel; } alphaw = FDMExec.Auxiliary.Getalpha() + FDMExec.Aircraft.WingIncidence; alpha = FDMExec.Auxiliary.Getalpha(); qbar_area = FDMExec.Aircraft.WingArea * FDMExec.Auxiliary.Qbar; if (alphaclmax != 0) { if (alpha > 0.85 * alphaclmax) { impending_stall = 10 * (alpha / alphaclmax - 0.85); } else { impending_stall = 0; } } if (alphahystmax != 0.0 && alphahystmin != 0.0) { if (alpha > alphahystmax) { stall_hyst = 1; } else if (alpha < alphahystmin) { stall_hyst = 0; } } vLastFs = vFs; vFs = Vector3D.Zero; // Tell the variable functions to cache their values, so while the aerodynamic // functions are being calculated for each axis, these functions do not get // calculated each time, but instead use the values that have already // been calculated for this frame. for (int i = 0; i < variables.Count; i++) { variables[i].CacheValue(true); } for (int axis_ctr = 0; axis_ctr < 3; axis_ctr++) { if (Coeff[axis_ctr] != null) { foreach (Function func in Coeff[axis_ctr]) { vFs[axis_ctr] += func.GetValue(); } } } // calculate lift coefficient squared if (FDMExec.Auxiliary.Qbar > 0) { clsq = vFs[(int)StabilityAxisForces.eLift] / (FDMExec.Aircraft.WingArea * FDMExec.Auxiliary.Qbar); clsq *= clsq; } if (vFs[(int)StabilityAxisForces.eDrag] > 0) { lod = vFs[(int)StabilityAxisForces.eLift] / vFs[(int)StabilityAxisForces.eDrag]; } //correct signs of drag and lift to wind axes convention //positive forward, right, down vFs[(int)StabilityAxisForces.eDrag] *= -1; vFs[(int)StabilityAxisForces.eLift] *= -1; vForces = FDMExec.State.GetTs2b() * vFs; vDXYZcg = FDMExec.MassBalance.StructuralToBody(FDMExec.Aircraft.AeroRefPointXYZ); vMoments = Vector3D.Cross(vDXYZcg, vForces); // M = r X F for (int axis_ctr = 0; axis_ctr < 3; axis_ctr++) { if (Coeff[axis_ctr + 3] != null) { foreach (Function func in Coeff[axis_ctr + 3]) { vMoments[axis_ctr] += func.GetValue(); } } } return(false); }
/// <summary> /// Runs the Auxiliary routines; called by the Executive /// </summary> /// <returns>false if no error</returns> public override bool Run(bool Holding) { #if TODO double A, B, D, hdot_Vt; Vector3D vPQR = FDMExec.Propagate.GetPQR(); Vector3D vUVW = FDMExec.Propagate.GetUVW(); Vector3D vUVWdot = FDMExec.Propagate.GetUVWdot(); Vector3D vVel = FDMExec.Propagate.GetVel(); if (InternalRun()) { return(true); } if (FDMExec.Holding()) { return(false); // if paused don't execute } p = FDMExec.Atmosphere.Pressure; rhosl = FDMExec.Atmosphere.DensitySeaLevel; psl = FDMExec.Atmosphere.PressureSeaLevel; sat = FDMExec.Atmosphere.Temperature; // Rotation double cTht = FDMExec.Propagate.GetCosEuler((int)EulerAngleType.eTht); double cPhi = FDMExec.Propagate.GetCosEuler((int)EulerAngleType.ePhi); double sPhi = FDMExec.Propagate.GetSinEuler((int)EulerAngleType.ePhi); vEulerRates.Theta = vPQR.eQ * cPhi - vPQR.eR * sPhi; if (cTht != 0.0) { vEulerRates.Psi = (vPQR.eQ * sPhi + vPQR.eR * cPhi) / cTht; vEulerRates.Phi = vPQR.eP + vEulerRates.Psi * sPhi; } //TODO vAeroPQR = vPQR + FDMExec.Atmosphere.TurbPQR; // Translation //vAeroUVW = vUVW + FDMExec.Propagate.GetTl2b() * FDMExec.Atmosphere.GetWindNED(); vt = vAeroUVW.GetMagnitude(); if (vt > 0.05) { if (vAeroUVW.W != 0.0) { alpha = vAeroUVW.U * vAeroUVW.U > 0.0 ? Math.Atan2(vAeroUVW.W, vAeroUVW.U) : 0.0; } if (vAeroUVW.V != 0.0) { beta = vAeroUVW.U * vAeroUVW.U + vAeroUVW.W * vAeroUVW.W > 0.0 ? Math.Atan2(vAeroUVW.V, Math.Sqrt(vAeroUVW.U * vAeroUVW.U + vAeroUVW.W * vAeroUVW.W)) : 0.0; } double mUW = (vAeroUVW.U * vAeroUVW.U + vAeroUVW.W * vAeroUVW.W); double signU = 1; if (vAeroUVW.U != 0.0) { signU = vAeroUVW.U / Math.Abs(vAeroUVW.U); } if ((mUW == 0.0) || (vt == 0.0)) { adot = 0.0; bdot = 0.0; } else { adot = (vAeroUVW.U * vUVWdot.W - vAeroUVW.W * vUVWdot.U) / mUW; bdot = (signU * mUW * vUVWdot.V - vAeroUVW.V * (vAeroUVW.U * vUVWdot.U + vAeroUVW.W * vUVWdot.W)) / (vt * vt * Math.Sqrt(mUW)); } } else { alpha = beta = adot = bdot = 0; } qbar = 0.5 * FDMExec.Atmosphere.Density * vt * vt; qbarUW = 0.5 * FDMExec.Atmosphere.Density * (vAeroUVW.U * vAeroUVW.U + vAeroUVW.W * vAeroUVW.W); qbarUV = 0.5 * FDMExec.Atmosphere.Density * (vAeroUVW.U * vAeroUVW.U + vAeroUVW.V * vAeroUVW.V); mach = vt / FDMExec.Atmosphere.SoundSpeed; machU = vMachUVW.U = vAeroUVW.U / FDMExec.Atmosphere.SoundSpeed; vMachUVW.V = vAeroUVW.V / FDMExec.Atmosphere.SoundSpeed; vMachUVW.W = vAeroUVW.W / FDMExec.Atmosphere.SoundSpeed; // Position Vground = Math.Sqrt(vVel.North * vVel.North + vVel.East * vVel.East); if (vVel.North == 0) { psigt = 0; } else { psigt = Math.Atan2(vVel.East, vVel.North); } if (psigt < 0.0) { psigt += 2 * Math.PI; } if (vt != 0) { hdot_Vt = -vVel.Down / vt; if (Math.Abs(hdot_Vt) <= 1) { gamma = Math.Asin(hdot_Vt); } } else { gamma = 0.0; } tat = sat * (1 + 0.2 * mach * mach); // Total Temperature, isentropic flow tatc = Conversion.RankineToCelsius(tat); if (machU < 1) { // Calculate total pressure assuming isentropic flow pt = p * Math.Pow((1 + 0.2 * machU * machU), 3.5); } else { // Use Rayleigh pitot tube formula for normal shock in front of pitot tube B = 5.76 * machU * machU / (5.6 * machU * machU - 0.8); D = (2.8 * machU * machU - 0.4) * 0.4167; pt = p * Math.Pow(B, 3.5) * D; } A = Math.Pow(((pt - p) / psl + 1), 0.28571); if (machU > 0.0) { vcas = Math.Sqrt(7 * psl / rhosl * (A - 1)); veas = Math.Sqrt(2 * qbar / rhosl); } else { vcas = veas = 0.0; } ///TODO vPilotAccel.InitMatrix(); if (vt > 1.0) { vPilotAccel = FDMExec.Aerodynamics.Forces + FDMExec.Propulsion.GetForces() + FDMExec.GroundReactions.GetForces(); vPilotAccel /= FDMExec.MassBalance.Mass; vToEyePt = FDMExec.MassBalance.StructuralToBody(FDMExec.Aircraft.EyepointXYZ); vPilotAccel += Vector3D.Cross(FDMExec.Propagate.GetPQRdot(), vToEyePt); vPilotAccel += Vector3D.Cross(vPQR, Vector3D.Cross(vPQR, vToEyePt)); } else { Vector3D aux = new Vector3D(0.0, 0.0, FDMExec.Inertial.Gravity); vPilotAccel = FDMExec.Propagate.GetTl2b() * aux; } vPilotAccelN = vPilotAccel / FDMExec.Inertial.Gravity; earthPosAngle += FDMExec.State.DeltaTime * FDMExec.Inertial.Omega; // VRP computation Location vLocation = FDMExec.Propagate.GetLocation(); Vector3D vrpStructural = FDMExec.Aircraft.VisualRefPointXYZ; Vector3D vrpBody = FDMExec.MassBalance.StructuralToBody(vrpStructural); Vector3D vrpLocal = FDMExec.Propagate.GetTb2l() * vrpBody; vLocationVRP = vLocation.LocalToLocation(vrpLocal); // Recompute some derived values now that we know the dependent parameters values ... hoverbcg = FDMExec.Propagate.DistanceAGL / FDMExec.Aircraft.WingSpan; Vector3D vMac = FDMExec.Propagate.GetTb2l() * FDMExec.MassBalance.StructuralToBody(FDMExec.Aircraft.AeroRefPointXYZ); hoverbmac = (FDMExec.Propagate.DistanceAGL + vMac.Z) / FDMExec.Aircraft.WingSpan; return(false); #endif throw new NotImplementedException("Pending upgrade to lastest version of JSBSIM"); }
/// <summary> /// Runs the Propagate model; called by the Executive /// </summary> /// <returns>false if no error</returns> public override bool Run() { if (InternalRun()) { return(true); } if (FDMExec.Holding()) { return(false); // if paused don't execute } RecomputeRunwayRadius(); double dt = FDMExec.State.DeltaTime * rate; // The 'stepsize' Vector3D omega = new Vector3D(0.0, 0.0, FDMExec.Inertial.Omega); // earth rotation Vector3D vForces = FDMExec.Aircraft.Forces; // current forces Vector3D vMoments = FDMExec.Aircraft.Moments; // current moments double mass = FDMExec.MassBalance.Mass; // mass Matrix3D J = FDMExec.MassBalance.GetJ(); // inertia matrix Matrix3D Jinv = FDMExec.MassBalance.GetJinv(); // inertia matrix inverse double r = this.Radius; // radius if (r == 0.0) { if (log.IsErrorEnabled) { log.Error("radius = 0 !"); } r = 1e-16; } // radius check double rInv = 1.0 / r; Vector3D gAccel = new Vector3D(0.0, 0.0, FDMExec.Inertial.GetGAccel(r)); // The rotation matrices: Matrix3D Tl2b = GetTl2b(); // local to body frame Matrix3D Tb2l = GetTb2l(); // body to local frame Matrix3D Tec2l = VState.vLocation.GetTec2l(); // earth centered to local frame Matrix3D Tl2ec = VState.vLocation.GetTl2ec(); // local to earth centered frame // Inertial angular velocity measured in the body frame. Vector3D pqri = VState.vPQR + Tl2b * (Tec2l * omega); // Compute vehicle velocity wrt EC frame, expressed in Local horizontal frame. vVel = Tb2l * VState.vUVW; // First compute the time derivatives of the vehicle state values: // Compute body frame rotational accelerations based on the current body moments vPQRdot = Jinv * (vMoments - Vector3D.Cross(pqri, (J * pqri))); // Compute body frame accelerations based on the current body forces vUVWdot = Vector3D.Cross(VState.vUVW, VState.vPQR) + vForces / mass; // Coriolis acceleration. Vector3D ecVel = Tl2ec * vVel; Vector3D ace = 2.0 * Vector3D.Cross(omega, ecVel); vUVWdot -= Tl2b * (Tec2l * ace); // Centrifugal acceleration. if (!FDMExec.GroundReactions.GetWOW()) { Vector3D aeec = Vector3D.Cross(omega, Vector3D.Cross(omega, (Vector3D)VState.vLocation)); vUVWdot -= Tl2b * (Tec2l * aeec); } // Gravitation accel vUVWdot += Tl2b * gAccel; // Compute vehicle velocity wrt EC frame, expressed in EC frame Vector3D vLocationDot = Tl2ec * vVel; Vector3D omegaLocal = new Vector3D(rInv * vVel.East, -rInv * vVel.North, -rInv * vVel.East * VState.vLocation.TanLatitude); // Compute quaternion orientation derivative on current body rates Quaternion vQtrndot = VState.vQtrn.GetQDot(VState.vPQR - Tl2b * omegaLocal); // Propagate velocities VState.vPQR += dt * vPQRdot; VState.vUVW += dt * vUVWdot; // Propagate positions VState.vQtrn += dt * vQtrndot; VState.vLocation += (Location)(dt * vLocationDot); return(false); }