示例#1
0
        /// <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");
        }
示例#2
0
        /// <summary>
        /// This set of calculations results in the body and inertial frame accelerations
        /// being computed.
        /// Compute body and inertial frames accelerations based on the current body
        /// forces including centripetal and Coriolis accelerations for the former.
        /// in.vOmegaPlanet is the Earth angular rate - expressed in the inertial frame -
        /// so it has to be transformed to the body frame. More completely,
        /// in.vOmegaPlanet is the rate of the ECEF frame relative to the Inertial
        /// frame (ECI), expressed in the Inertial frame.
        /// in.Force is the total force on the vehicle in the body frame.
        /// in.vPQR is the vehicle body rate relative to the ECEF frame, expressed
        /// in the body frame.
        /// in.vUVW is the vehicle velocity relative to the ECEF frame, expressed
        /// in the body frame.
        /// Reference: See Stevens and Lewis, "Aircraft Control and Simulation",
        ///            Second edition (2004), eqns 1.5-13 (pg 48) and 1.5-16d (page 50)
        /// </summary>
        private void CalculateUVWdot()
        {
            if (FDMExec.GetHoldDown() && !FDMExec.GetTrimStatus())
            {
                vBodyAccel = Vector3D.Zero;
            }
            else
            {
                vBodyAccel = inputs.Force / inputs.Mass;
            }

            vUVWdot = vBodyAccel - (inputs.vPQR + 2.0 * (inputs.Ti2b * inputs.vOmegaPlanet)) * inputs.vUVW;

            // Include Centripetal acceleration.
            vUVWdot -= inputs.Ti2b * (inputs.vOmegaPlanet * (inputs.vOmegaPlanet * inputs.vInertialPosition));

            if (FDMExec.GetHoldDown())
            {
                // The acceleration in ECI is calculated so that the acceleration is zero
                // in the body frame.
                vUVWidot = inputs.vOmegaPlanet * (inputs.vOmegaPlanet * inputs.vInertialPosition);
                vUVWdot  = Vector3D.Zero;
            }
            else
            {
                vUVWdot += inputs.Tec2b * inputs.vGravAccel;
                vUVWidot = inputs.Tb2i * vBodyAccel + inputs.Tec2i * inputs.vGravAccel;
            }
        }
示例#3
0
        /// <summary>
        // Compute body frame rotational accelerations based on the current body moments
        ///
        /// vPQRdot is the derivative of the absolute angular velocity of the vehicle
        /// (body rate with respect to the ECEF frame), expressed in the body frame,
        /// where the derivative is taken in the body frame.
        /// J is the inertia matrix
        /// Jinv is the inverse inertia matrix
        /// vMoments is the moment vector in the body frame
        /// in.vPQRi is the total inertial angular velocity of the vehicle
        /// expressed in the body frame.
        /// Reference: See Stevens and Lewis, "Aircraft Control and Simulation",
        ///            Second edition (2004), eqn 1.5-16e (page 50)
        /// </summary>
        private void CalculatePQRdot()
        {
            if (gravTorque)
            {
                // Compute the gravitational torque
                // Reference: See Harris and Lyle "Spacecraft Gravitational Torques",
                //            NASA SP-8024 (1969) eqn (2) (page 7)
                Vector3D R         = inputs.Ti2b * inputs.vInertialPosition;
                double   invRadius = 1.0 / R.Magnitude();
                R             *= invRadius;
                inputs.Moment += (3.0 * inputs.vGravAccel.Magnitude() * invRadius) * (R * (inputs.J * R));
            }

            // Compute body frame rotational accelerations based on the current body
            // moments and the total inertial angular velocity expressed in the body
            // frame.
            //  if (HoldDown && !FDMExec->GetTrimStatus()) {
            if (FDMExec.GetHoldDown())
            {
                // The rotational acceleration in ECI is calculated so that the rotational
                // acceleration is zero in the body frame.
                vPQRdot  = Vector3D.Zero;
                vPQRidot = inputs.vPQRi * (inputs.Ti2b * inputs.vOmegaPlanet);
            }
            else
            {
                vPQRidot = inputs.Jinv * (inputs.Moment - inputs.vPQRi * (inputs.J * inputs.vPQRi));
                vPQRdot  = vPQRidot - inputs.vPQRi * (inputs.Ti2b * inputs.vOmegaPlanet);
            }
        }
示例#4
0
        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);
        }
示例#5
0
        /// <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);
        }
示例#6
0
        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);
        }
示例#7
0
        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);
        }
示例#8
0
        /// <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);
        }
示例#9
0
        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);
        }
示例#10
0
        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);
        }
示例#11
0
        /// <summary>
        ///  Runs the state propagation model; called by the Executive
        /// Can pass in a value indicating if the executive is directing the simulation to Hold.
        /// </summary>
        /// <param name="Holding">if true, the executive has been directed to hold the sim from
        /// advancing time.Some models may ignore this flag, such as the Input
        /// model, which may need to be active to listen on a socket for the
        /// "Resume" command to be given.</param>
        /// <returns>false if no error</returns>
        public override bool Run(bool Holding)
        {
            if (base.Run(Holding))
            {
                return(true);                    // Fast return if we have nothing to do ...
            }
            if (Holding)
            {
                return(false);
            }

            CalculatePQRdot();   // Angular rate derivative
            CalculateUVWdot();   // Translational rate derivative

            if (!FDMExec.GetHoldDown())
            {
                CalculateFrictionForces(inputs.DeltaT * rate);  // Update rate derivatives with friction forces
            }
            Debug(2);
            return(false);
        }
示例#12
0
        /// <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);
        }
示例#13
0
        public bool Load(XmlElement root)
        {
            if (log.IsDebugEnabled)
            {
                log.Debug("Reading and running from script file " + scriptName);
            }

            string name = root.GetAttribute("name");

            if (name.Length != 0)
            {
                this.scriptName = name;
            }

            XmlNodeList childNodes = root.GetElementsByTagName("use");

            if (childNodes.Count != 2 && log.IsErrorEnabled)
            {
                if (log.IsErrorEnabled)
                {
                    log.Error("Two <use> tags must be specified in script file.");
                }
                return(false);
            }
            string aircraft   = (childNodes[0] as XmlElement).GetAttribute("aircraft");
            string initialize = (childNodes[1] as XmlElement).GetAttribute("initialize");

            if (aircraft.Length != 0)
            {
                try
                {
                    FDMExec.LoadModel(aircraft);
                }
                catch (Exception e)
                {
                    if (log.IsErrorEnabled)
                    {
                        log.Error("Exception reading script file: " + e);
                    }
                    return(false);
                }
            }
            else
            {
                if (log.IsErrorEnabled)
                {
                    log.Error("Aircraft must be specified first in script file.");
                }
                return(false);
            }

            childNodes = root.GetElementsByTagName("run");
            if (childNodes.Count != 1)
            {
                if (log.IsErrorEnabled)
                {
                    log.Error("One \"<run>\" tag must be specified in script file");
                }
                return(false);
            }

            // Set sim timing
            XmlElement run_element = childNodes[0] as XmlElement;

            startTime             = double.Parse(run_element.GetAttribute("start"), FormatHelper.numberFormatInfo);
            FDMExec.State.SimTime = startTime;
            endTime = double.Parse(run_element.GetAttribute("end"), FormatHelper.numberFormatInfo);
            FDMExec.State.DeltaTime = double.Parse(run_element.GetAttribute("dt"), FormatHelper.numberFormatInfo);

            foreach (XmlNode currentNode in root.GetElementsByTagName("when"))
            {
                ReadWhenClause(currentNode as XmlElement);
            }

            try
            {
                FDMExec.GetIC().Load(initialize, true);
            }
            catch (Exception e)
            {
                if (log.IsErrorEnabled)
                {
                    log.Error("Initialization unsuccessful. Exception " + e);
                }
            }

            return(true);
        }
示例#14
0
        /// <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);
        }
示例#15
0
        private void Turbulence(double h)
        {
            switch (turbType)
            {
            case tType.ttCulp:
                vTurbPQR.P = wind_from_clockwise;
                if (TurbGain == 0.0)
                {
                    return;
                }

                // keep the inputs within allowable limts for this model
                if (TurbGain < 0.0)
                {
                    TurbGain = 0.0;
                }
                if (TurbGain > 1.0)
                {
                    TurbGain = 1.0;
                }
                if (TurbRate < 0.0)
                {
                    TurbRate = 0.0;
                }
                if (TurbRate > 30.0)
                {
                    TurbRate = 30.0;
                }
                if (Rhythmicity < 0.0)
                {
                    Rhythmicity = 0.0;
                }
                if (Rhythmicity > 1.0)
                {
                    Rhythmicity = 1.0;
                }

                // generate a sine wave corresponding to turbulence rate in hertz
                double time     = FDMExec.GetSimTime();
                double sinewave = Math.Sin(time * TurbRate * 6.283185307);

                double random = 0.0;
                if (target_time == 0.0)
                {
                    strength    = random = 1 - 2.0 * uniformNumber.Next();
                    target_time = time + 0.71 + (random * 0.5);
                }
                if (time > target_time)
                {
                    spike       = 1.0;
                    target_time = 0.0;
                }

                // max vertical wind speed in fps, corresponds to TurbGain = 1.0
                double max_vs = 40;

                vTurbulenceNED = Vector3D.Zero;
                double delta = strength * max_vs * TurbGain * (1 - Rhythmicity) * spike;

                // Vertical component of turbulence.
                vTurbulenceNED.Down  = sinewave * max_vs * TurbGain * Rhythmicity;
                vTurbulenceNED.Down += delta;
                if (inputs.DistanceAGL / inputs.wingspan < 3.0)
                {
                    vTurbulenceNED.Down *= inputs.DistanceAGL / inputs.wingspan * 0.3333;
                }

                // Yaw component of turbulence.
                vTurbulenceNED.North = Math.Sin(delta * 3.0);
                vTurbulenceNED.East  = Math.Cos(delta * 3.0);

                // Roll component of turbulence. Clockwise vortex causes left roll.
                vTurbPQR.P += delta * 0.04;

                spike = spike * 0.9;
                break;

            case tType.ttMilspec:
            case tType.ttTustin:
                // an index of zero means turbulence is disabled
                // airspeed occurs as divisor in the code below
                if (probability_of_exceedence_index == 0 || inputs.V == 0)
                {
                    vTurbulenceNED.North = vTurbulenceNED.East = vTurbulenceNED.Down = 0.0;
                    vTurbPQR.P           = vTurbPQR.Q = vTurbPQR.R = 0.0;
                    return;
                }

                // Turbulence model according to MIL-F-8785C (Flying Qualities of Piloted Aircraft)
                double b_w = inputs.wingspan, L_u, L_w, sig_u, sig_w;

                if (b_w == 0.0)
                {
                    b_w = 30.0;
                }

                // clip height functions at 10 ft
                if (h <= 10.0)
                {
                    h = 10;
                }

                // Scale lengths L and amplitudes sigma as function of height
                if (h <= 1000)
                {
                    L_u   = h / Math.Pow(0.177 + 0.000823 * h, 1.2);   // MIL-F-8785c, Fig. 10, p. 55
                    L_w   = h;
                    sig_w = 0.1 * windspeed_at_20ft;
                    sig_u = sig_w / Math.Pow(0.177 + 0.000823 * h, 0.4);     // MIL-F-8785c, Fig. 11, p. 56
                }
                else if (h <= 2000)
                {
                    // linear interpolation between low altitude and high altitude models
                    L_u   = L_w = 1000 + (h - 1000.0) / 1000.0 * 750.0;
                    sig_u = sig_w = 0.1 * windspeed_at_20ft
                                    + (h - 1000.0) / 1000.0 * (POE_Table.GetValue(probability_of_exceedence_index, h) - 0.1 * windspeed_at_20ft);
                }
                else
                {
                    L_u   = L_w = 1750.0;   //  MIL-F-8785c, Sec. 3.7.2.1, p. 48
                    sig_u = sig_w = POE_Table.GetValue(probability_of_exceedence_index, h);
                }

                // keep values from last timesteps
                // TODO maybe use deque?
                double
                    xi_u_km1 = 0, nu_u_km1 = 0,
                    xi_v_km1 = 0, xi_v_km2 = 0, nu_v_km1 = 0, nu_v_km2 = 0,
                    xi_w_km1 = 0, xi_w_km2 = 0, nu_w_km1 = 0, nu_w_km2 = 0,
                    xi_p_km1 = 0, nu_p_km1 = 0,
                    xi_q_km1 = 0, xi_r_km1 = 0;


                double T_V   = inputs.totalDeltaT,                 // for compatibility of nomenclature
                       sig_p = 1.9 / Math.Sqrt(L_w * b_w) * sig_w, // Yeager1998, eq. (8)
                                                                   //sig_q = Math.Sqrt(M_PI/2/L_w/b_w), // eq. (14)
                                                                   //sig_r = Math.Sqrt(2*M_PI/3/L_w/b_w), // eq. (17)
                       L_p = Math.Sqrt(L_w * b_w) / 2.6,           // eq. (10)
                       tau_u = L_u / inputs.V,                     // eq. (6)
                       tau_w = L_w / inputs.V,                     // eq. (3)
                       tau_p = L_p / inputs.V,                     // eq. (9)
                       tau_q = 4 * b_w / Math.PI / inputs.V,       // eq. (13)
                       tau_r = 3 * b_w / Math.PI / inputs.V,       // eq. (17)
                       nu_u = gaussianNumber.Next(),
                       nu_v = gaussianNumber.Next(),
                       nu_w = gaussianNumber.Next(),
                       nu_p = gaussianNumber.Next(),
                       xi_u = 0, xi_v = 0, xi_w = 0, xi_p = 0, xi_q = 0, xi_r = 0;

                // values of turbulence NED velocities

                if (turbType == tType.ttTustin)
                {
                    // the following is the Tustin formulation of Yeager's report
                    double omega_w = inputs.V / L_w,                        // hidden in nomenclature p. 3
                           omega_v = inputs.V / L_u,                        // this is defined nowhere
                           C_BL    = 1 / tau_u / Math.Tan(T_V / 2 / tau_u), // eq. (19)
                           C_BLp   = 1 / tau_p / Math.Tan(T_V / 2 / tau_p), // eq. (22)
                           C_BLq   = 1 / tau_q / Math.Tan(T_V / 2 / tau_q), // eq. (24)
                           C_BLr   = 1 / tau_r / Math.Tan(T_V / 2 / tau_r); // eq. (26)

                    // all values calculated so far are strictly positive, except for
                    // the random numbers nu_*. This means that in the code below, all
                    // divisors are strictly positive, too, and no floating point
                    // exception should occur.
                    xi_u = -(1 - C_BL * tau_u) / (1 + C_BL * tau_u) * xi_u_km1
                           + sig_u * Math.Sqrt(2 * tau_u / T_V) / (1 + C_BL * tau_u) * (nu_u + nu_u_km1);   // eq. (18)
                    xi_v = -2 * (sqr(omega_v) - sqr(C_BL)) / sqr(omega_v + C_BL) * xi_v_km1
                           - sqr(omega_v - C_BL) / sqr(omega_v + C_BL) * xi_v_km2
                           + sig_u * Math.Sqrt(3 * omega_v / T_V) / sqr(omega_v + C_BL) * (
                        (C_BL + omega_v / Math.Sqrt(3.0)) * nu_v
                        + 2 / Math.Sqrt(3.0) * omega_v * nu_v_km1
                        + (omega_v / Math.Sqrt(3.0) - C_BL) * nu_v_km2);          // eq. (20) for v
                    xi_w = -2 * (sqr(omega_w) - sqr(C_BL)) / sqr(omega_w + C_BL) * xi_w_km1
                           - sqr(omega_w - C_BL) / sqr(omega_w + C_BL) * xi_w_km2
                           + sig_w * Math.Sqrt(3 * omega_w / T_V) / sqr(omega_w + C_BL) * (
                        (C_BL + omega_w / Math.Sqrt(3.0)) * nu_w
                        + 2 / Math.Sqrt(3.0) * omega_w * nu_w_km1
                        + (omega_w / Math.Sqrt(3.0) - C_BL) * nu_w_km2);                                        // eq. (20) for w
                    xi_p = -(1 - C_BLp * tau_p) / (1 + C_BLp * tau_p) * xi_p_km1
                           + sig_p * Math.Sqrt(2 * tau_p / T_V) / (1 + C_BLp * tau_p) * (nu_p + nu_p_km1);      // eq. (21)
                    xi_q = -(1 - 4 * b_w * C_BLq / Math.PI / inputs.V) / (1 + 4 * b_w * C_BLq / Math.PI / inputs.V) * xi_q_km1
                           + C_BLq / inputs.V / (1 + 4 * b_w * C_BLq / Math.PI / inputs.V) * (xi_w - xi_w_km1); // eq. (23)
                    xi_r = -(1 - 3 * b_w * C_BLr / Math.PI / inputs.V) / (1 + 3 * b_w * C_BLr / Math.PI / inputs.V) * xi_r_km1
                           + C_BLr / inputs.V / (1 + 3 * b_w * C_BLr / Math.PI / inputs.V) * (xi_v - xi_v_km1); // eq. (25)
                }
                else if (turbType == tType.ttMilspec)
                {
                    // the following is the MIL-STD-1797A formulation
                    // as cited in Yeager's report
                    xi_u = (1 - T_V / tau_u) * xi_u_km1 + sig_u * Math.Sqrt(2 * T_V / tau_u) * nu_u;     // eq. (30)
                    xi_v = (1 - 2 * T_V / tau_u) * xi_v_km1 + sig_u * Math.Sqrt(4 * T_V / tau_u) * nu_v; // eq. (31)
                    xi_w = (1 - 2 * T_V / tau_w) * xi_w_km1 + sig_w * Math.Sqrt(4 * T_V / tau_w) * nu_w; // eq. (32)
                    xi_p = (1 - T_V / tau_p) * xi_p_km1 + sig_p * Math.Sqrt(2 * T_V / tau_p) * nu_p;     // eq. (33)
                    xi_q = (1 - T_V / tau_q) * xi_q_km1 + Math.PI / 4 / b_w * (xi_w - xi_w_km1);         // eq. (34)
                    xi_r = (1 - T_V / tau_r) * xi_r_km1 + Math.PI / 3 / b_w * (xi_v - xi_v_km1);         // eq. (35)
                }

                // rotate by wind azimuth and assign the velocities
                double cospsi = Math.Cos(psiw), sinpsi = Math.Sin(psiw);
                vTurbulenceNED.North = cospsi * xi_u + sinpsi * xi_v;
                vTurbulenceNED.East  = -sinpsi * xi_u + cospsi * xi_v;
                vTurbulenceNED.Down  = xi_w;

                vTurbPQR.P = cospsi * xi_p + sinpsi * xi_q;
                vTurbPQR.Q = -sinpsi * xi_p + cospsi * xi_q;
                vTurbPQR.R = xi_r;

                // vTurbPQR is in the body fixed frame, not NED
                vTurbPQR = inputs.Tl2b * vTurbPQR;

                // hand on the values for the next timestep
                xi_u_km1 = xi_u; nu_u_km1 = nu_u;
                xi_v_km2 = xi_v_km1; xi_v_km1 = xi_v; nu_v_km2 = nu_v_km1; nu_v_km1 = nu_v;
                xi_w_km2 = xi_w_km1; xi_w_km1 = xi_w; nu_w_km2 = nu_w_km1; nu_w_km1 = nu_w;
                xi_p_km1 = xi_p; nu_p_km1 = nu_p;
                xi_q_km1 = xi_q;
                xi_r_km1 = xi_r;
                break;

            default:
                break;
            }

            TurbDirection = Math.Atan2(vTurbulenceNED.East, vTurbulenceNED.North) * Constants.radtodeg;
        }
示例#16
0
        /// <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);
        }
示例#17
0
        /// <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");
        }
示例#18
0
 public virtual string FindFullPathName(string path)
 {
     return(ModelLoader.CheckPathName(FDMExec.GetFullAircraftPath(), path));
 }