// Merge two force sets
 public void AddAll(FARCenterQuery q2)
 {
     force += q2.force;
     torque += q2.torque;
     pos += q2.pos;
     amount += q2.amount;
 }
        public void SimulateAeroProperties(out Vector3 aeroForce, out Vector3 aeroTorque, Vector3 velocityWorldVector, double altitude)
        {
            FARCenterQuery center = new FARCenterQuery();

            float pressure;
            float density;
            float temperature;
            float speedOfSound;

            CelestialBody body = _vessel.mainBody;      //Calculate main gas properties
            pressure = (float)body.GetPressure(altitude);
            temperature = (float)body.GetTemperature(altitude);
            density = (float)body.GetDensity(pressure, temperature);
            speedOfSound = (float)body.GetSpeedOfSound(pressure, density);

            float velocityMag = velocityWorldVector.magnitude;
            float machNumber = velocityMag / speedOfSound;
            float reynoldsNumber = (float)FARAeroUtil.CalculateReynoldsNumber(density, Length, velocityMag, machNumber, temperature, body.atmosphereAdiabaticIndex);

            float reynoldsPerLength = reynoldsNumber / (float)Length;
            float skinFriction = (float)FARAeroUtil.SkinFrictionDrag(reynoldsNumber, machNumber);

            for(int i = 0; i < _currentAeroSections.Count; i++)
                _currentAeroSections[i].PredictionCalculateAeroForces(density, machNumber, reynoldsPerLength, skinFriction, velocityWorldVector, center);

            for (int i = 0; i < _legacyWingModels.Count; i++)
                _legacyWingModels[i].PrecomputeCenterOfLift(velocityWorldVector, machNumber, density, center);

            aeroForce = center.force;
            aeroTorque = center.TorqueAt(_vessel.CoM);
        }
        public static void PrecomputeGlobalCenterOfLift(FARCenterQuery lift, FARCenterQuery dummy, Vector3 vel, double density)
        {
            /* Center of lift is the location where the derivative of
               the total torque provided by aerodynamic forces relative to
               AoA is zero (or at least minimal). This approximates the
               derivative by a simple subtraction, like before. */

            var parts = GetAllEditorModules();

            for(int i = 0; i < parts.Count; i++)
            {
                FARBaseAerodynamics ba = parts[i];
                ba.velocityEditor = vel;
                ba.ResetCenterOfLift();
            }

            // run computations twice to let things like flap interactions settle
            for (int i = 0; i < parts.Count; i++)
            {
                FARBaseAerodynamics ba = parts[i];
                ba.PrecomputeCenterOfLift(vel, 0, density, dummy);
            }
            for (int i = 0; i < parts.Count; i++)
            {
                FARBaseAerodynamics ba = parts[i];
                ba.PrecomputeCenterOfLift(vel, 0, density, lift);
            }
        }
 public virtual Vector3d PrecomputeCenterOfLift(Vector3d velocity, double MachNumber, double density, FARCenterQuery center)
 {
     return Vector3d.zero;
 }
        public void GetClCdCmSteady(InstantConditionSimInput input, out InstantConditionSimOutput output, bool clear, bool reset_stall = false)
        {
            output = new InstantConditionSimOutput();

            double area = 0;
            double MAC = 0;
            double b_2 = 0;

            Vector3d forward = Vector3.forward;
            Vector3d up = Vector3.up;
            Vector3d right = Vector3.right;

            Vector3d CoM = Vector3d.zero;
            double mass = 0;
            List<Part> partsList = EditorLogic.SortedShipList;
            for (int i = 0; i < partsList.Count; i++)
            {
                Part p = partsList[i];

                if (FARAeroUtil.IsNonphysical(p))
                    continue;

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

                //partMass += p.GetModuleMass(p.mass);
                // 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;
            }
            CoM /= mass;

            if (EditorDriver.editorFacility == EditorFacility.VAB)
            {
                forward = Vector3.up;
                up = -Vector3.forward;
            }

            double sinAlpha = Math.Sin(input.alpha * Math.PI / 180);
            double cosAlpha = Math.Sqrt(Math.Max(1 - sinAlpha * sinAlpha, 0));

            double sinBeta = Math.Sin(input.beta * Math.PI / 180);
            double cosBeta = Math.Sqrt(Math.Max(1 - sinBeta * sinBeta, 0));

            double sinPhi = Math.Sin(input.phi * Math.PI / 180);
            double cosPhi = Math.Sqrt(Math.Max(1 - sinPhi * sinPhi, 0));

            double alphaDot = input.alphaDot * Math.PI / 180;
            double betaDot = input.betaDot * Math.PI / 180;
            double phiDot = input.phiDot * Math.PI / 180;

            Vector3d AngVel = (phiDot - sinAlpha * betaDot) * forward;
            AngVel += (cosPhi * alphaDot + cosAlpha * sinPhi * betaDot) * right;
            AngVel += (sinPhi * alphaDot - cosAlpha * cosPhi * betaDot) * up;

            Vector3d velocity = forward * cosAlpha * cosBeta;
            velocity += right * (sinPhi * cosAlpha * cosBeta + cosPhi * sinBeta);
            velocity += -up * cosPhi * (sinAlpha * cosBeta + sinBeta);

            velocity.Normalize();

            //this is negative wrt the ground
            Vector3d liftVector = -forward * sinAlpha + right * sinPhi * cosAlpha - up * cosPhi * cosAlpha;

            Vector3d sideways = Vector3.Cross(velocity, liftVector).normalized;


            for (int i = 0; i < _wingAerodynamicModel.Count; i++)
            {
                FARWingAerodynamicModel w = _wingAerodynamicModel[i];
                if (!(w && w.part))
                    continue;

                w.ComputeForceEditor(velocity.normalized, input.machNumber, 2);

                if (clear)
                    w.EditorClClear(reset_stall);

                Vector3d relPos = w.GetAerodynamicCenter() - CoM;

                Vector3d vel = velocity + Vector3d.Cross(AngVel, relPos);

                if (w is FARControllableSurface)
                    (w as FARControllableSurface).SetControlStateEditor(CoM, vel, (float)input.pitchValue, 0, 0, input.flaps, input.spoilers);
                else if (w.isShielded)
                    continue;


                //w.ComputeForceEditor(velocity, input.machNumber);     //do this just to get the AC right

                Vector3d force = w.ComputeForceEditor(vel.normalized, input.machNumber, 2) * 1000;

                output.Cl += -Vector3d.Dot(force, liftVector);
                output.Cy += Vector3d.Dot(force, sideways);
                output.Cd += -Vector3d.Dot(force, velocity);

                Vector3d moment = -Vector3d.Cross(relPos, force);

                output.Cm += Vector3d.Dot(moment, sideways);
                output.Cn += Vector3d.Dot(moment, liftVector);
                output.C_roll += Vector3d.Dot(moment, velocity);

                //w.ComputeClCdEditor(vel.normalized, input.machNumber);

                /*double tmpCl = w.GetCl() * w.S;
                output.Cl += tmpCl * -Vector3d.Dot(w.GetLiftDirection(), liftVector);
                output.Cy += tmpCl * -Vector3d.Dot(w.GetLiftDirection(), sideways);
                double tmpCd = w.GetCd() * w.S;
                output.Cd += tmpCd;
                output.Cm += tmpCl * Vector3d.Dot((relPos), velocity) * -Vector3d.Dot(w.GetLiftDirection(), liftVector) + tmpCd * -Vector3d.Dot((relPos), liftVector);
                output.Cn += tmpCd * Vector3d.Dot((relPos), sideways) + tmpCl * Vector3d.Dot((relPos), velocity) * -Vector3d.Dot(w.GetLiftDirection(), sideways);
                output.C_roll += tmpCl * Vector3d.Dot((relPos), sideways) * -Vector3d.Dot(w.GetLiftDirection(), liftVector);*/
                area += w.S;
                MAC += w.GetMAC() * w.S;
                b_2 += w.Getb_2() * w.S;
            }
            FARCenterQuery center = new FARCenterQuery();
            for (int i = 0; i < _currentAeroSections.Count; i++)
            {
                _currentAeroSections[i].PredictionCalculateAeroForces(2, (float)input.machNumber, 10000, 0.005f, velocity.normalized, center);
            }

            Vector3d centerForce = center.force * 1000;

            output.Cl += -Vector3d.Dot(centerForce, liftVector);
            output.Cy += Vector3d.Dot(centerForce, sideways);
            output.Cd += -Vector3d.Dot(centerForce, velocity);

            Vector3d centerMoment = -center.TorqueAt(CoM) * 1000;

            output.Cm += Vector3d.Dot(centerMoment, sideways);
            output.Cn += Vector3d.Dot(centerMoment, liftVector);
            output.C_roll += Vector3d.Dot(centerMoment, velocity);
            

            /*for (int i = 0; i < FARAeroUtil.CurEditorParts.Count; i++)
            {
                Part p = FARAeroUtil.CurEditorParts[i];
                if (FARAeroUtil.IsNonphysical(p))
                    continue;

                Vector3 part_pos = p.transform.TransformPoint(p.CoMOffset) - CoM;
                double partMass = p.mass;
                if (p.Resources.Count > 0)
                    partMass += p.GetResourceMass();

                double stock_drag = partMass * p.maximum_drag * FlightGlobals.DragMultiplier * 1000;
                output.Cd += stock_drag;
                output.Cm += stock_drag * -Vector3d.Dot(part_pos, liftVector);
                output.Cn += stock_drag * Vector3d.Dot(part_pos, sideways);
            }*/

            if (area == 0)
            {
                area = _maxCrossSectionFromBody;
                b_2 = 1;
                MAC = _bodyLength;
            }

            double recipArea = 1 / area;

            MAC *= recipArea;
            b_2 *= recipArea;
            output.Cl *= recipArea;
            output.Cd *= recipArea;
            output.Cm *= recipArea / MAC;
            output.Cy *= recipArea;
            output.Cn *= recipArea / b_2;
            output.C_roll *= recipArea / b_2;
        }
Example #6
0
        protected override Vector3d PrecomputeCenterOfLift(Vector3d velocity, double MachNumber, FARCenterQuery center)
        {
            Vector3d force = RunDragCalculation(velocity, MachNumber, 1);
            Vector3d pos   = GetCoD();

            center.AddForce(pos, force);
            return(force);
        }
Example #7
0
 public virtual Vector3d PrecomputeCenterOfLift(Vector3d velocity, FlightEnv fltenv, FARCenterQuery center)
 {
     return(Vector3d.zero);
 }
 public void UpdateSimulationContext(Vector4 worldVel, FARCenterQuery center, float atmDensity)
 {
     this.worldVel   = worldVel;
     this.center     = center;
     this.atmDensity = atmDensity;
 }
        protected override Vector3d PrecomputeCenterOfLift(Vector3d velocity, double MachNumber, FARCenterQuery center)
        {
            double AoA = CalculateAoA(velocity);

            Vector3d force = CalculateForces(velocity, MachNumber, AoA);
            center.AddForce(AerodynamicCenter, force);

            return force;
        }
 public virtual Vector3d PrecomputeCenterOfLift(Vector3d velocity, double MachNumber, double density, FARCenterQuery center)
 {
     return(Vector3d.zero);
 }
 protected override Vector3d PrecomputeCenterOfLift(Vector3d velocity, double MachNumber, FARCenterQuery center)
 {
     Vector3d force = RunDragCalculation(velocity, MachNumber, 1);
     Vector3d pos = GetCoD();
     center.AddForce(pos, force);
     return force;
 }
        private static void PrecomputeGlobalCenterOfLift()
        {
            /* Center of lift is the location where the derivative of
             * the total torque provided by aerodynamic forces relative to
             * AoA is zero (or at least minimal). This approximates the
             * derivative by a simple subtraction, like before. */

            Vector3 vel_base, vel_fuzz;

            if (EditorLogic.fetch.editorType == EditorLogic.EditorMode.SPH)
            {
                vel_base = Vector3.forward;
                vel_fuzz = 0.02f * Vector3.up;
            }
            else
            {
                vel_base = Vector3.up;
                vel_fuzz = -0.02f * Vector3.forward;
            }

            FARCenterQuery lift  = new FARCenterQuery();
            FARCenterQuery dummy = new FARCenterQuery();

            var parts = GetAllEditorModules();

            // Pass 1
            Vector3 vel = (vel_base - vel_fuzz).normalized;

            foreach (var ba in parts)
            {
                ba.velocityEditor = vel;
                ba.ResetCenterOfLift();
            }

            // run computations twice to let things like flap interactions settle
            foreach (var ba in parts)
            {
                ba.PrecomputeCenterOfLift(vel, 0, dummy);
            }
            foreach (var ba in parts)
            {
                ba.CoLForce = ba.PrecomputeCenterOfLift(vel, 0, lift);
            }

            // flip sign of data in the accumulator to indirectly subtract passes
            lift.force  = -lift.force;
            lift.torque = -lift.torque;

            // Pass 2
            vel = (vel_base + vel_fuzz).normalized;
            foreach (var ba in parts)
            {
                ba.velocityEditor = vel;
                ba.ResetCenterOfLift();
            }

            foreach (var ba in parts)
            {
                ba.PrecomputeCenterOfLift(vel, 0, dummy);
            }
            foreach (var ba in parts)
            {
                ba.CoLForce -= ba.PrecomputeCenterOfLift(vel, 0, lift);
            }

            // Choose the center location
            GlobalCoL      = lift.GetMinTorquePos();
            GlobalCoLReady = true;
        }
 public void PredictionCalculateAeroForces(float atmDensity, float machNumber, float reynoldsPerUnitLength, float pseudoKnudsenNumber, float skinFrictionDrag, Vector3 vel, ferram4.FARCenterQuery center)
 {
     simContext.UpdateSimulationContext(vel, center, atmDensity);
     CalculateAeroForces(atmDensity, machNumber, reynoldsPerUnitLength, pseudoKnudsenNumber, skinFrictionDrag, simContext);
 }
Example #14
0
 protected override Vector3d PrecomputeCenterOfLift(Vector3d velocity, double MachNumber, FARCenterQuery center)
 {
     try
     {
         Vector3d force = RunDragCalculation(velocity, MachNumber, 1);
         Vector3d pos   = GetCoD();
         center.AddForce(pos, force);
         return(force);
     }
     catch       //FIX ME!!!
     {           //Yell at KSP devs so that I don't have to engage in bad code practice
         //Debug.Log("The expected exception from the symmetry counterpart part transform internals was caught and suppressed");
         return(Vector3.zero);
     }
 }
        private static void PrecomputeGlobalCenterOfLift()
        {
            /* Center of lift is the location where the derivative of
               the total torque provided by aerodynamic forces relative to
               AoA is zero (or at least minimal). This approximates the
               derivative by a simple subtraction, like before. */

            Vector3 vel_base, vel_fuzz;

            if (EditorLogic.fetch.editorType == EditorLogic.EditorMode.SPH)
            {
                vel_base = Vector3.forward;
                vel_fuzz = 0.02f * Vector3.up;
            }
            else
            {
                vel_base = Vector3.up;
                vel_fuzz = -0.02f * Vector3.forward;
            }

            FARCenterQuery lift = new FARCenterQuery();
            FARCenterQuery dummy = new FARCenterQuery();

            var parts = GetAllEditorModules();

            // Pass 1
            Vector3 vel = (vel_base - vel_fuzz).normalized;
            foreach (var ba in parts)
            {
                ba.velocityEditor = vel;
                ba.ResetCenterOfLift();
            }

            // run computations twice to let things like flap interactions settle
            foreach (var ba in parts)
                ba.PrecomputeCenterOfLift(vel, 0, dummy);
            foreach (var ba in parts)
                ba.CoLForce = ba.PrecomputeCenterOfLift(vel, 0, lift);

            // flip sign of data in the accumulator to indirectly subtract passes
            lift.force = -lift.force;
            lift.torque = - lift.torque;

            // Pass 2
            vel = (vel_base + vel_fuzz).normalized;
            foreach (var ba in parts)
            {
                ba.velocityEditor = vel;
                ba.ResetCenterOfLift();
            }

            foreach (var ba in parts)
                ba.PrecomputeCenterOfLift(vel, 0, dummy);
            foreach (var ba in parts)
                ba.CoLForce -= ba.PrecomputeCenterOfLift(vel, 0, lift);

            // Choose the center location
            GlobalCoL = lift.GetMinTorquePos();
            GlobalCoLReady = true;
        }
        void UpdateAerodynamicCenter()
        {
            FARCenterQuery aeroSection, dummy;
            aeroSection = new FARCenterQuery();
            dummy = new FARCenterQuery();

            if((object)EditorLogic.RootPart == null)
                return;

            Vector3 vel_base, vel_fuzz;

            Transform rootPartTrans = EditorLogic.RootPart.partTransform;
            if (EditorDriver.editorFacility == EditorFacility.SPH)
            {
                vel_base = Vector3.forward;
                vel_fuzz = 0.02f * Vector3.up;
            }
            else
            {
                vel_base = Vector3.up;
                vel_fuzz = -0.02f * Vector3.forward;
            }

            Vector3 vel = (vel_base - vel_fuzz).normalized;

            for(int i = 0; i < _currentAeroSections.Count; i++)
            {
                FARAeroSection section = _currentAeroSections[i];
                section.PredictionCalculateAeroForces(1, 0.5f, 100000, 0.005f, vel, aeroSection);
            }

            FARBaseAerodynamics.PrecomputeGlobalCenterOfLift(aeroSection, dummy, vel, 1);

            Vector3 pos = Vector3.zero;//rootPartTrans.position;
            float mass = 0;
            for(int i = 0; i < EditorLogic.SortedShipList.Count; i++)
            {
                Part p = EditorLogic.SortedShipList[i];
                float tmpMass = p.mass + p.GetResourceMass();
                mass += tmpMass;
                pos += p.partTransform.position * tmpMass;
            }
            pos /= mass;

            Vector3 avgForcePos = Vector3.zero;

            Vector3 force0, moment0;
            force0 = aeroSection.force;
            moment0 = aeroSection.TorqueAt(pos);
            avgForcePos += aeroSection.GetPos();

            //aeroSection.force = -aeroSection.force;
            //aeroSection.torque = -aeroSection.torque;

            aeroSection.ClearAll();

            vel = (vel_base + vel_fuzz).normalized;

            for (int i = 0; i < _currentAeroSections.Count; i++)
            {
                FARAeroSection section = _currentAeroSections[i];
                section.PredictionCalculateAeroForces(1, 0.5f, 100000, 0.005f, vel, aeroSection);
            }

            FARBaseAerodynamics.PrecomputeGlobalCenterOfLift(aeroSection, dummy, vel, 1);

            Vector3 force1, moment1;
            force1 = aeroSection.force;
            moment1 = aeroSection.TorqueAt(pos);
            avgForcePos += aeroSection.GetPos();

            aeroSection.ClearAll();

            avgForcePos *= 0.5f;

            Vector3 deltaForce = force1 - force0;
            Vector3 deltaMoment = moment1 - moment0;

            Vector3 deltaForcePerp = Vector3.ProjectOnPlane(deltaForce, vel_base);
            float deltaForcePerpMag = deltaForcePerp.magnitude;

            Vector3 deltaForcePerpNorm = deltaForcePerp / deltaForcePerpMag;

            Vector3 deltaMomentPerp = deltaMoment - Vector3.Dot(deltaMoment, deltaForcePerpNorm) * deltaForcePerpNorm - Vector3.Project(deltaMoment, vel_base);

            //float dist = deltaMomentPerp.magnitude / deltaForcePerpMag;
            //vesselRootLocalAeroCenter = vel_base * dist;

            vesselRootLocalAeroCenter = deltaMomentPerp.magnitude / deltaForcePerpMag * vel_base * Math.Sign(Vector3.Dot(Vector3.Cross(deltaForce, deltaMoment), vel_base));

            //Debug.Log(dist + " " + deltaMomentPerp.magnitude + " " + deltaForcePerpMag);
            //vesselRootLocalAeroCenter += avgForcePos;
            //avgForcePos = rootPartTrans.worldToLocalMatrix.MultiplyPoint3x4(avgForcePos);
            //vesselRootLocalAeroCenter += Vector3.ProjectOnPlane(avgForcePos, Vector3.up);
            //vesselRootLocalAeroCenter = aeroSection.GetPos();
            vesselRootLocalAeroCenter += pos;//Vector3.ProjectOnPlane(avgForcePos - pos, vesselRootLocalAeroCenter) + pos;
            vesselRootLocalAeroCenter = rootPartTrans.worldToLocalMatrix.MultiplyPoint3x4(vesselRootLocalAeroCenter);
        }
 public SimulatedForceContext(Vector3 worldVel, FARCenterQuery center, float atmDensity)
 {
     this.worldVel   = worldVel;
     this.center     = center;
     this.atmDensity = atmDensity;
 }