public void AddSizeVariables(InstantConditionSim ics, double pitch, int flapSetting, bool spoilers)
        {
            Vector3d com; double mass, area, mac, b;

            ics.GetCoMAndSize(out com, out mass, out area, out mac, out b);

            AddVariableToList("CoM", "Center of Mass", new double[3] {
                com.x, com.y, com.z
            });
            AddVariableToList("mass", "Craft mass (kg)", new double[1] {
                mass
            });
            AddVariableToList("area", "Reference area for Cl and Cd (m^2)", new double[1] {
                area
            });
            AddVariableToList("mac", "Weighted wing chord (m)", new double[1] {
                mac
            });
            AddVariableToList("b", "Weighted wing span (m)", new double[1] {
                b
            });
            AddVariableToList("pitch", "Elevator setting, [-1; 1]", new double[1] {
                pitch
            });
            AddVariableToList("flapSetting", "Flap setting (0= up, 1-2= take off, 3= landing)", new double[1] {
                flapSetting
            });
            AddVariableToList("spoilers", "Spoiler setting (0= retracted, 1= deployed)", new double[1] {
                spoilers? 1: 0
            });
        }
 public EditorSimManager(InstantConditionSim _instantSim)
 {
     _instantCondition   = _instantSim;
     StabDerivCalculator = new StabilityDerivCalculator(_instantCondition);
     SweepSim            = new SweepSim(_instantCondition);
     _aeroCenter         = new EditorAeroCenter();
     vehicleData         = new StabilityDerivOutput();
 }
 public EditorSimManager(InstantConditionSim _instantSim)
 {
     _instantCondition = _instantSim;
     _stabDerivCalculator = new StabilityDerivCalculator(_instantCondition);
     _stabDerivLinearSim = new StabilityDerivLinearSim(_instantCondition);
     _sweepSim = new SweepSim(_instantCondition);
     _aeroCenter = new EditorAeroCenter();
     vehicleData = new StabilityDerivOutput();
 }
        public InstantConditionSimVars(InstantConditionSim parent, CelestialBody body, double altitude, double machNumber, double neededCl, double beta, double phi, int flap, bool spoilers)
        {
            this.parent   = parent;
            this.neededCl = neededCl;
            this.CoM      = parent.GetCoM();
            FlightEnv fltenv = FlightEnv.NewSim(body, altitude, machNumber);

            iterationInput  = new InstantConditionSimInput(0, beta, phi, 0, 0, 0, fltenv, 0, flap, spoilers);
            iterationOutput = new InstantConditionSimOutput();
        }
        void Start()
        {
            if (CompatibilityChecker.IsAllCompatible() && instance == null)
                instance = this;
            else
            {
                GameObject.Destroy(this);
                return;
            }

            _vehicleAero = new VehicleAerodynamics();

            guiRect = new Rect(Screen.width / 4, Screen.height / 6, 10, 10);

            _instantSim = new InstantConditionSim();
            GUIDropDown<int> flapSettingDropDown = new GUIDropDown<int>(new string[] { "0 (up)", "1 (init climb)", "2 (takeoff)", "3 (landing)" }, new int[] { 0, 1, 2, 3 }, 0);
            GUIDropDown<CelestialBody> celestialBodyDropdown = CreateBodyDropdown();

            _simManager = new EditorSimManager(_instantSim);

            _editorGraph = new StaticAnalysisGraphGUI(_simManager, flapSettingDropDown, celestialBodyDropdown);
            _stabDeriv = new StabilityDerivGUI(_simManager, flapSettingDropDown, celestialBodyDropdown);
            _stabDerivLinSim = new StabilityDerivSimulationGUI(_simManager);

            Color crossSection = GUIColors.GetColor(3);
            crossSection.a = 0.8f;

            Color crossSectionDeriv = GUIColors.GetColor(2);
            crossSectionDeriv.a = 0.8f;

            _areaRulingOverlay = new EditorAreaRulingOverlay(new Color(0.05f, 0.05f, 0.05f, 0.7f), crossSection, crossSectionDeriv, 10, 5);
            guiRect.height = 500;
            guiRect.width = 650;

            GameEvents.onEditorPartEvent.Add(UpdateGeometryEvent);
            GameEvents.onEditorUndo.Add(ResetEditorEvent);
            GameEvents.onEditorRedo.Add(ResetEditorEvent);
            GameEvents.onEditorShipModified.Add(ResetEditorEvent);
            GameEvents.onEditorLoad.Add(ResetEditorEvent);

            GameEvents.onGUIEngineersReportReady.Add(AddDesignConcerns);
            GameEvents.onGUIEngineersReportDestroy.Add(RemoveDesignConcerns);

            RequestUpdateVoxel();
        }
        void OnDestroy()
        {
            GameEvents.onEditorPartEvent.Remove(UpdateGeometryEvent);
            GameEvents.onEditorUndo.Remove(ResetEditorEvent);
            GameEvents.onEditorRedo.Remove(ResetEditorEvent);
            GameEvents.onEditorShipModified.Remove(ResetEditorEvent);
            GameEvents.onEditorLoad.Remove(ResetEditorEvent);

            GameEvents.onGUIEngineersReportReady.Remove(AddDesignConcerns);
            GameEvents.onGUIEngineersReportDestroy.Remove(AddDesignConcerns);

            EditorLogic.fetch.Unlock("FAREdLock");

            if (blizzyEditorGUIButton != null)
                blizzyEditorGUIButton.Destroy();

            _stabDerivLinSim = null;
            _instantSim = null;
            _areaRulingOverlay = null;
            _editorGraph = null;
            _stabDeriv = null;

            if(_vehicleAero != null)
                _vehicleAero.ForceCleanup();
            _vehicleAero = null;
        }
Beispiel #7
0
 public StabilityDerivLinearSim(InstantConditionSim instantConditionSim)
 {
     _instantCondition = instantConditionSim;
 }
Beispiel #8
0
 public SweepSim(InstantConditionSim instantConditionSim)
 {
     _instantCondition = instantConditionSim;
 }
 public SweepSim(InstantConditionSim instantConditionSim)
 {
     _instantCondition = instantConditionSim;
 }
Beispiel #10
0
 public StabilityDerivCalculator(InstantConditionSim instantConditionSim)
 {
     _instantCondition = instantConditionSim;
 }
        public static GraphData RunTransientSimLateral(
            StabilityDerivOutput vehicleData,
            double endTime,
            double initDt,
            double[] InitCond
            )
        {
            var A = new SimMatrix(4, 4);

            A.PrintToConsole();

            int i      = 0;
            int j      = 0;
            int num    = 0;
            var Derivs = new double[27];

            vehicleData.stabDerivs.CopyTo(Derivs, 0);

            Derivs[15] = Derivs[15] / vehicleData.nominalVelocity;
            Derivs[18] = Derivs[18] / vehicleData.nominalVelocity;
            Derivs[21] = Derivs[21] / vehicleData.nominalVelocity - 1;

            double Lb = Derivs[16] / (1 - Derivs[26] * Derivs[26] / (Derivs[0] * Derivs[2]));
            double Nb = Derivs[17] / (1 - Derivs[26] * Derivs[26] / (Derivs[0] * Derivs[2]));

            double Lp = Derivs[19] / (1 - Derivs[26] * Derivs[26] / (Derivs[0] * Derivs[2]));
            double Np = Derivs[20] / (1 - Derivs[26] * Derivs[26] / (Derivs[0] * Derivs[2]));

            double Lr = Derivs[22] / (1 - Derivs[26] * Derivs[26] / (Derivs[0] * Derivs[2]));
            double Nr = Derivs[23] / (1 - Derivs[26] * Derivs[26] / (Derivs[0] * Derivs[2]));

            Derivs[16] = Lb + Derivs[26] / Derivs[0] * Nb;
            Derivs[17] = Nb + Derivs[26] / Derivs[2] * Lb;

            Derivs[19] = Lp + Derivs[26] / Derivs[0] * Np;
            Derivs[20] = Np + Derivs[26] / Derivs[2] * Lp;

            Derivs[22] = Lr + Derivs[26] / Derivs[0] * Nr;
            Derivs[23] = Nr + Derivs[26] / Derivs[2] * Lr;

            foreach (double f in Derivs)
            {
                if (num < 15)
                {
                    num++; //Avoid Ix, Iy, Iz and long derivs
                    continue;
                }

                num++;
                FARLogger.Info("" + i + "," + j);
                if (i <= 2)
                {
                    A.Add(f, i, j);
                }

                if (j < 2)
                {
                    j++;
                }
                else
                {
                    j = 0;
                    i++;
                }
            }

            A.Add(InstantConditionSim.CalculateAccelerationDueToGravity(vehicleData.body, vehicleData.altitude) *
                  Math.Cos(vehicleData.stableAoA * Math.PI / 180) /
                  vehicleData.nominalVelocity,
                  3,
                  0);
            A.Add(1, 1, 3);


            A.PrintToConsole(); //We should have an array that looks like this:

            /*             i --------------->
             *       j  [ Yb / u0 , Yp / u0 , -(1 - Yr/ u0) ,  g Cos(θ0) / u0 ]
             *       |  [   Lb    ,    Lp   ,      Lr       ,          0          ]
             *       |  [   Nb    ,    Np   ,      Nr       ,          0          ]
             *      \ / [    0    ,    1    ,      0        ,          0          ]
             *       V                              //And one that looks like this:
             *
             *          [ Z e ]
             *          [ X e ]
             *          [ M e ]
             *          [  0  ]
             *
             *
             */
            var transSolve = new RungeKutta4(endTime, initDt, A, InitCond);

            transSolve.Solve();

            var lines = new GraphData {
                xValues = transSolve.time
            };

            double[] yVal = transSolve.GetSolution(0);
            ScaleAndClampValues(yVal, 180 / Math.PI, 50);
            lines.AddData(yVal, FARConfig.GUIColors.LdColor, "β", true);

            yVal = transSolve.GetSolution(1);
            ScaleAndClampValues(yVal, 180 / Math.PI, 50);
            lines.AddData(yVal, FARConfig.GUIColors.CmColor, "p", true);

            yVal = transSolve.GetSolution(2);
            ScaleAndClampValues(yVal, 180 / Math.PI, 50);
            lines.AddData(yVal, FARConfig.GUIColors.CdColor, "r", true);

            yVal = transSolve.GetSolution(3);
            ScaleAndClampValues(yVal, 180 / Math.PI, 50);
            lines.AddData(yVal, FARConfig.GUIColors.ClColor, "φ", true);

            return(lines);
        }
        public static GraphData RunTransientSimLongitudinal(
            StabilityDerivOutput vehicleData,
            double endTime,
            double initDt,
            double[] InitCond
            )
        {
            var A = new SimMatrix(4, 4);
            var B = new SimMatrix(1, 4);

            A.PrintToConsole();

            int i   = 0;
            int j   = 0;
            int num = 0;

            foreach (double f in vehicleData.stabDerivs)
            {
                if (num < 3 || num >= 15)
                {
                    num++; //Avoid Ix, Iy, Iz
                    continue;
                }

                num++;
                FARLogger.Info(i + "," + j);
                if (i <= 2)
                {
                    if (num == 10)
                    {
                        A.Add(f + vehicleData.nominalVelocity, i, j);
                    }
                    else
                    {
                        A.Add(f, i, j);
                    }
                }
                else
                {
                    B.Add(f, 0, j);
                }
                if (j < 2)
                {
                    j++;
                }
                else
                {
                    j = 0;
                    i++;
                }
            }

            A.Add(-InstantConditionSim.CalculateAccelerationDueToGravity(vehicleData.body, vehicleData.altitude), 3, 1);
            A.Add(1, 2, 3);


            A.PrintToConsole(); //We should have an array that looks like this:

            /*             i --------------->
             *       j  [ Z w , Z u , Z q  + u,  0 ]
             *       |  [ X w , X u , X q     , -g ]
             *       |  [ M w , M u , M q     ,  0 ]
             *      \ / [  0  ,  0  ,  1      ,  0 ]
             *       V                              //And one that looks like this:
             *
             *          [ Z e ]
             *          [ X e ]
             *          [ M e ]
             *          [  0  ]
             *
             *
             */

            var transSolve = new RungeKutta4(endTime, initDt, A, InitCond);

            transSolve.Solve();

            var lines = new GraphData {
                xValues = transSolve.time
            };

            double[] yVal = transSolve.GetSolution(0);
            ScaleAndClampValues(yVal, 1, 50);
            lines.AddData(yVal, FARConfig.GUIColors.LdColor, "w", true);

            yVal = transSolve.GetSolution(1);
            ScaleAndClampValues(yVal, 1, 50);
            lines.AddData(yVal, FARConfig.GUIColors.CmColor, "u", true);

            yVal = transSolve.GetSolution(2);
            ScaleAndClampValues(yVal, 180 / Math.PI, 50);
            lines.AddData(yVal, FARConfig.GUIColors.CdColor, "q", true);

            yVal = transSolve.GetSolution(3);
            ScaleAndClampValues(yVal, 180 / Math.PI, 50);
            lines.AddData(yVal, FARConfig.GUIColors.ClColor, "θ", true);

            return(lines);
        }
 public StabilityDerivLinearSim(InstantConditionSim instantConditionSim)
 {
     _instantCondition = instantConditionSim;
 }
 public StabilityDerivCalculator(InstantConditionSim instantConditionSim)
 {
     _instantCondition = instantConditionSim;
 }
        public StabilityDerivOutput CalculateStabilityDerivs(
            CelestialBody body,
            double alt,
            double machNumber,
            int flapSetting,
            bool spoilers,
            double alpha,
            double beta,
            double phi
            )
        {
            double pressure    = body.GetPressure(alt);
            double temperature = body.GetTemperature(alt);
            double density     = body.GetDensity(pressure, temperature);
            double sspeed      = body.GetSpeedOfSound(pressure, density);
            double u0          = sspeed * machNumber;
            double q           = u0 * u0 * density * 0.5f;

            var stabDerivOutput = new StabilityDerivOutput
            {
                nominalVelocity = u0,
                altitude        = alt,
                body            = body
            };

            Vector3d CoM  = Vector3d.zero;
            double   mass = 0;

            double MAC  = 0;
            double b    = 0;
            double area = 0;

            double Ix  = 0;
            double Iy  = 0;
            double Iz  = 0;
            double Ixy = 0;
            double Iyz = 0;
            double Ixz = 0;

            var input      = new InstantConditionSimInput(alpha, beta, phi, 0, 0, 0, machNumber, 0, flapSetting, spoilers);
            var pertOutput = new InstantConditionSimOutput();

            _instantCondition.GetClCdCmSteady(input, out InstantConditionSimOutput nominalOutput, true);

            List <Part> partsList = EditorLogic.SortedShipList;

            foreach (Part p in partsList)
            {
                if (FARAeroUtil.IsNonphysical(p))
                {
                    continue;
                }
                double partMass = p.mass;
                if (p.Resources.Count > 0)
                {
                    partMass += p.GetResourceMass();
                }

                // If you want to use GetModuleMass, you need to start from p.partInfo.mass, not p.mass
                CoM  += partMass * (Vector3d)p.transform.TransformPoint(p.CoMOffset);
                mass += partMass;
                var w = p.GetComponent <FARWingAerodynamicModel>();
                if (w == null)
                {
                    continue;
                }
                if (w.isShielded)
                {
                    continue;
                }

                area += w.S;
                MAC  += w.GetMAC() * w.S;
                b    += w.Getb_2() * w.S;
                if (w is FARControllableSurface controllableSurface)
                {
                    controllableSurface.SetControlStateEditor(CoM,
                                                              p.transform.up,
                                                              0,
                                                              0,
                                                              0,
                                                              input.flaps,
                                                              input.spoilers);
                }
            }

            if (area.NearlyEqual(0))
            {
                area = _instantCondition._maxCrossSectionFromBody;
                MAC  = _instantCondition._bodyLength;
                b    = 1;
            }

            MAC  /= area;
            b    /= area;
            CoM  /= mass;
            mass *= 1000;

            stabDerivOutput.b    = b;
            stabDerivOutput.MAC  = MAC;
            stabDerivOutput.area = area;

            foreach (Part p in partsList)
            {
                if (p == null || FARAeroUtil.IsNonphysical(p))
                {
                    continue;
                }
                //This section handles the parallel axis theorem
                Vector3 relPos = p.transform.TransformPoint(p.CoMOffset) - CoM;
                double  x2     = relPos.z * relPos.z;
                double  y2     = relPos.x * relPos.x;
                double  z2     = relPos.y * relPos.y;
                double  x      = relPos.z;
                double  y      = relPos.x;
                double  z      = relPos.y;

                double partMass = p.mass;
                if (p.Resources.Count > 0)
                {
                    partMass += p.GetResourceMass();
                }

                // If you want to use GetModuleMass, you need to start from p.partInfo.mass, not p.mass

                Ix += (y2 + z2) * partMass;
                Iy += (x2 + z2) * partMass;
                Iz += (x2 + y2) * partMass;

                Ixy += -x * y * partMass;
                Iyz += -z * y * partMass;
                Ixz += -x * z * partMass;

                //And this handles the part's own moment of inertia
                Vector3    principalInertia = p.Rigidbody.inertiaTensor;
                Quaternion prncInertRot     = p.Rigidbody.inertiaTensorRotation;

                //The rows of the direction cosine matrix for a quaternion
                var Row1 =
                    new Vector3(prncInertRot.x * prncInertRot.x -
                                prncInertRot.y * prncInertRot.y -
                                prncInertRot.z * prncInertRot.z +
                                prncInertRot.w * prncInertRot.w,
                                2 * (prncInertRot.x * prncInertRot.y + prncInertRot.z * prncInertRot.w),
                                2 * (prncInertRot.x * prncInertRot.z - prncInertRot.y * prncInertRot.w));

                var Row2 = new Vector3(2 * (prncInertRot.x * prncInertRot.y - prncInertRot.z * prncInertRot.w),
                                       -prncInertRot.x * prncInertRot.x +
                                       prncInertRot.y * prncInertRot.y -
                                       prncInertRot.z * prncInertRot.z +
                                       prncInertRot.w * prncInertRot.w,
                                       2 * (prncInertRot.y * prncInertRot.z + prncInertRot.x * prncInertRot.w));

                var Row3 = new Vector3(2 * (prncInertRot.x * prncInertRot.z + prncInertRot.y * prncInertRot.w),
                                       2 * (prncInertRot.y * prncInertRot.z - prncInertRot.x * prncInertRot.w),
                                       -prncInertRot.x * prncInertRot.x -
                                       prncInertRot.y * prncInertRot.y +
                                       prncInertRot.z * prncInertRot.z +
                                       prncInertRot.w * prncInertRot.w);


                //And converting the principal moments of inertia into the coordinate system used by the system
                Ix += principalInertia.x * Row1.x * Row1.x +
                      principalInertia.y * Row1.y * Row1.y +
                      principalInertia.z * Row1.z * Row1.z;
                Iy += principalInertia.x * Row2.x * Row2.x +
                      principalInertia.y * Row2.y * Row2.y +
                      principalInertia.z * Row2.z * Row2.z;
                Iz += principalInertia.x * Row3.x * Row3.x +
                      principalInertia.y * Row3.y * Row3.y +
                      principalInertia.z * Row3.z * Row3.z;

                Ixy += principalInertia.x * Row1.x * Row2.x +
                       principalInertia.y * Row1.y * Row2.y +
                       principalInertia.z * Row1.z * Row2.z;
                Ixz += principalInertia.x * Row1.x * Row3.x +
                       principalInertia.y * Row1.y * Row3.y +
                       principalInertia.z * Row1.z * Row3.z;
                Iyz += principalInertia.x * Row2.x * Row3.x +
                       principalInertia.y * Row2.y * Row3.y +
                       principalInertia.z * Row2.z * Row3.z;
            }

            Ix *= 1000;
            Iy *= 1000;
            Iz *= 1000;

            stabDerivOutput.stabDerivs[0] = Ix;
            stabDerivOutput.stabDerivs[1] = Iy;
            stabDerivOutput.stabDerivs[2] = Iz;

            stabDerivOutput.stabDerivs[24] = Ixy;
            stabDerivOutput.stabDerivs[25] = Iyz;
            stabDerivOutput.stabDerivs[26] = Ixz;

            //This is the effect of gravity
            double effectiveG = InstantConditionSim.CalculateAccelerationDueToGravity(body, alt);

            //This is the effective reduction of gravity due to high velocity
            effectiveG -= u0 * u0 / (alt + body.Radius);
            double neededCl = mass * effectiveG / (q * area);


            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, true);
            //Longitudinal Mess
            _instantCondition.SetState(machNumber, neededCl, CoM, 0, input.flaps, input.spoilers);
            FARMathUtil.OptimizationResult optResult =
                FARMathUtil.Secant(_instantCondition.FunctionIterateForAlpha,
                                   0,
                                   10,
                                   1e-4,
                                   1e-4,
                                   minLimit: -90,
                                   maxLimit: 90);
            alpha = optResult.Result;

            input.alpha   = alpha;
            nominalOutput = _instantCondition.iterationOutput;

            input.alpha = alpha + 2;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, true);

            stabDerivOutput.stableCl       = neededCl;
            stabDerivOutput.stableCd       = nominalOutput.Cd;
            stabDerivOutput.stableAoA      = optResult.Converged ? alpha : double.NaN;
            stabDerivOutput.stableAoAState = "";
            if (optResult.Converged && Math.Abs((nominalOutput.Cl - neededCl) / neededCl) > 0.1)
            {
                stabDerivOutput.stableAoAState = nominalOutput.Cl > neededCl ? "<" : ">";
            }

            FARLogger.Info("Cl needed: " +
                           neededCl.ToString(CultureInfo.InvariantCulture) +
                           ", AoA: " +
                           stabDerivOutput.stableAoA.ToString(CultureInfo.InvariantCulture) +
                           ", Cl: " +
                           nominalOutput.Cl.ToString(CultureInfo.InvariantCulture) +
                           ", Cd: " +
                           nominalOutput.Cd.ToString(CultureInfo.InvariantCulture) +
                           ", function calls: " +
                           optResult.FunctionCalls.ToString());

            if (!optResult.Converged)
            {
                // couldn't find stable AoA, no reason to compute invalid stability derivatives
                for (int i = 3; i < 24; i++)
                {
                    stabDerivOutput.stabDerivs[i] = double.NaN;
                }
                return(stabDerivOutput);
            }

            //vert vel derivs
            pertOutput.Cl = (pertOutput.Cl - nominalOutput.Cl) / (2 * FARMathUtil.deg2rad);
            pertOutput.Cd = (pertOutput.Cd - nominalOutput.Cd) / (2 * FARMathUtil.deg2rad);
            pertOutput.Cm = (pertOutput.Cm - nominalOutput.Cm) / (2 * FARMathUtil.deg2rad);

            pertOutput.Cl += nominalOutput.Cd;
            pertOutput.Cd -= nominalOutput.Cl;

            pertOutput.Cl *= -q * area / (mass * u0);
            pertOutput.Cd *= -q * area / (mass * u0);
            pertOutput.Cm *= q * area * MAC / (Iy * u0);

            stabDerivOutput.stabDerivs[3] = pertOutput.Cl; //Zw
            stabDerivOutput.stabDerivs[4] = pertOutput.Cd; //Xw
            stabDerivOutput.stabDerivs[5] = pertOutput.Cm; //Mw

            // Rodhern: The motivation for the revised stability derivatives sign interpretations of Zq, Xq, Ze and Xe
            //  is to align the sign conventions used for Zu, Zq, Ze, Xu, Xq and Xe. Further explanation can be found
            //  here: https://forum.kerbalspaceprogram.com/index.php?/topic/109098-official-far-craft-repository/&do=findComment&comment=2425057

            input.alpha      = alpha;
            input.machNumber = machNumber + 0.05;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true);

            //fwd vel derivs
            pertOutput.Cl = (pertOutput.Cl - nominalOutput.Cl) / 0.05 * machNumber;
            pertOutput.Cd = (pertOutput.Cd - nominalOutput.Cd) / 0.05 * machNumber;
            pertOutput.Cm = (pertOutput.Cm - nominalOutput.Cm) / 0.05 * machNumber;

            pertOutput.Cl += 2 * nominalOutput.Cl;
            pertOutput.Cd += 2 * nominalOutput.Cd;

            pertOutput.Cl *= -q * area / (mass * u0);
            pertOutput.Cd *= -q * area / (mass * u0);
            pertOutput.Cm *= q * area * MAC / (u0 * Iy);

            stabDerivOutput.stabDerivs[6] = pertOutput.Cl; //Zu
            stabDerivOutput.stabDerivs[7] = pertOutput.Cd; //Xu
            stabDerivOutput.stabDerivs[8] = pertOutput.Cm; //Mu

            input.machNumber = machNumber;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, true);

            input.alphaDot = -0.05;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true);

            //pitch rate derivs
            pertOutput.Cl = (pertOutput.Cl - nominalOutput.Cl) / 0.05;
            pertOutput.Cd = (pertOutput.Cd - nominalOutput.Cd) / 0.05;
            pertOutput.Cm = (pertOutput.Cm - nominalOutput.Cm) / 0.05;

            pertOutput.Cl *= -q * area * MAC / (2 * u0 * mass); // Rodhern: Replaced 'q' by '-q', so that formulas
            pertOutput.Cd *= -q * area * MAC / (2 * u0 * mass); //  for Zq and Xq match those for Zu and Xu.
            pertOutput.Cm *= q * area * MAC * MAC / (2 * u0 * Iy);

            stabDerivOutput.stabDerivs[9]  = pertOutput.Cl; //Zq
            stabDerivOutput.stabDerivs[10] = pertOutput.Cd; //Xq
            stabDerivOutput.stabDerivs[11] = pertOutput.Cm; //Mq

            input.alphaDot   = 0;
            input.pitchValue = 0.1;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true);

            //elevator derivs
            pertOutput.Cl = (pertOutput.Cl - nominalOutput.Cl) / 0.1;
            pertOutput.Cd = (pertOutput.Cd - nominalOutput.Cd) / 0.1;
            pertOutput.Cm = (pertOutput.Cm - nominalOutput.Cm) / 0.1;

            pertOutput.Cl *= -q * area / mass; // Rodhern: Replaced 'q' by '-q', so that formulas
            pertOutput.Cd *= -q * area / mass; //  for Ze and Xe match those for Zu and Xu.
            pertOutput.Cm *= q * area * MAC / Iy;

            stabDerivOutput.stabDerivs[12] = pertOutput.Cl; //Ze
            stabDerivOutput.stabDerivs[13] = pertOutput.Cd; //Xe
            stabDerivOutput.stabDerivs[14] = pertOutput.Cm; //Me

            //Lateral Mess

            input.pitchValue = 0;
            input.beta       = beta + 2;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true);
            //sideslip angle derivs
            pertOutput.Cy     = (pertOutput.Cy - nominalOutput.Cy) / (2 * FARMathUtil.deg2rad);
            pertOutput.Cn     = (pertOutput.Cn - nominalOutput.Cn) / (2 * FARMathUtil.deg2rad);
            pertOutput.C_roll = (pertOutput.C_roll - nominalOutput.C_roll) / (2 * FARMathUtil.deg2rad);

            pertOutput.Cy     *= q * area / mass;
            pertOutput.Cn     *= q * area * b / Iz;
            pertOutput.C_roll *= q * area * b / Ix;

            stabDerivOutput.stabDerivs[15] = pertOutput.Cy;     //Yb
            stabDerivOutput.stabDerivs[17] = pertOutput.Cn;     //Nb
            stabDerivOutput.stabDerivs[16] = pertOutput.C_roll; //Lb

            input.beta = beta;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, true);

            input.phiDot = -0.05;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true);

            //roll rate derivs
            pertOutput.Cy     = (pertOutput.Cy - nominalOutput.Cy) / 0.05;
            pertOutput.Cn     = (pertOutput.Cn - nominalOutput.Cn) / 0.05;
            pertOutput.C_roll = (pertOutput.C_roll - nominalOutput.C_roll) / 0.05;

            pertOutput.Cy     *= q * area * b / (2 * mass * u0);
            pertOutput.Cn     *= q * area * b * b / (2 * Iz * u0);
            pertOutput.C_roll *= q * area * b * b / (2 * Ix * u0);

            stabDerivOutput.stabDerivs[18] = pertOutput.Cy;     //Yp
            stabDerivOutput.stabDerivs[20] = pertOutput.Cn;     //Np
            stabDerivOutput.stabDerivs[19] = pertOutput.C_roll; //Lp


            input.phiDot = 0;

            _instantCondition.GetClCdCmSteady(input, out pertOutput, true, true);

            input.betaDot = -0.05;

            //yaw rate derivs
            _instantCondition.GetClCdCmSteady(input, out pertOutput, true);
            pertOutput.Cy     = (pertOutput.Cy - nominalOutput.Cy) / 0.05f;
            pertOutput.Cn     = (pertOutput.Cn - nominalOutput.Cn) / 0.05f;
            pertOutput.C_roll = (pertOutput.C_roll - nominalOutput.C_roll) / 0.05f;

            pertOutput.Cy     *= q * area * b / (2 * mass * u0);
            pertOutput.Cn     *= q * area * b * b / (2 * Iz * u0);
            pertOutput.C_roll *= q * area * b * b / (2 * Ix * u0);

            stabDerivOutput.stabDerivs[21] = pertOutput.Cy;     //Yr
            stabDerivOutput.stabDerivs[23] = pertOutput.Cn;     //Nr
            stabDerivOutput.stabDerivs[22] = pertOutput.C_roll; //Lr

            return(stabDerivOutput);
        }
 public AeroStabilityConcern(InstantConditionSim instantSim, EditorFacilities editorFacility)
 {
     _instantSim = instantSim;
     _editorFacility = editorFacility;
     _simInput = new InstantConditionSimInput();
 }