Пример #1
0
        protected static float computeTorqueRatio(Vector3 lever, Vector3 thrustDir, Vector3 specTorque, float mass, Vector3 MoI, float ratio_factor, out float specificThrustToCom)
        {
            specificThrustToCom = Vector3.Dot(lever.normalized, thrustDir);
            var specificLinearAccel  = Mathf.Abs(specificThrustToCom / mass);
            var specificAngularAccel = TorqueProps.AngularAcceleration(specTorque, MoI).magnitude;
            var ratio = specificLinearAccel > 0
                ? Mathf.Clamp01(1 - 1 / (1 + specificAngularAccel * ratio_factor / specificLinearAccel))
                : 0;

            return(ratio);
        }
Пример #2
0
        public bool OptimizeForZeroTorque(Vector3 MoI)
        {
            var   torque = Vector3.zero;
            float torque_error, angle_error, max_limit;

            if (Balanced.Count > 0)
            {
                torque = TorqueProps.CalculateImbalance(true, Manual, UnBalanced);
                EngineOptimizer.OptimizeLimitsForTorque(Balanced, Vector3.zero, torque, MoI, true,
                                                        out max_limit, out torque_error, out angle_error);
            }
            if (Steering.Count > 0)
            {
                torque = TorqueProps.CalculateImbalance(true, Manual, UnBalanced, Balanced);
                return(EngineOptimizer.OptimizeLimitsForTorque(Steering, Vector3.zero, torque, MoI, true,
                                                               out max_limit, out torque_error, out angle_error));
            }
            return(true);
        }
Пример #3
0
        void UpdateShipStats()
        {
            MinLimit = 0;
            var thrust         = Vector3.zero;
            var selected_parts = GetSelectedParts();

            CalculateMassAndCoM(selected_parts);
            if (CFG != null && CFG.Enabled && Engines.Count > 0)
            {
                ActiveEngines.Clear();
                for (int i = 0, EnginesCount = Engines.Count; i < EnginesCount; i++)
                {
                    var e    = Engines[i];
                    var ecfg = CFG.ActiveProfile.GetConfig(e);
                    if (ecfg == null || ecfg.On)
                    {
                        ActiveEngines.Add(e);
                    }
                }
                if (selected_parts.Count > 0)
                {
                    var selected_engines = new List <EngineWrapper>();
                    selected_parts.ForEach(p => find_engines_recursively(p, selected_engines));
                    ActiveEngines.AddRange(selected_engines);
                }
                if (ActiveEngines.Count > 0)
                {
                    ActiveEngines.ForEach(process_active_engine);
                    compute_inertia_tensor();
                    selected_parts.ForEach(update_inertia_tensor);
                    ActiveEngines.SortByRole();
                    float max_limit, torque_error, angle_error;
                    var   imbalance = TorqueProps.CalculateImbalance(true, ActiveEngines.Manual, ActiveEngines.UnBalanced);
                    if (ActiveEngines.Balanced.Count > 0)
                    {
                        EngineOptimizer.OptimizeLimitsForTorque(ActiveEngines.Balanced, Vector3.zero, imbalance, MoI, true,
                                                                out max_limit, out torque_error, out angle_error);
                        imbalance = TorqueProps.CalculateImbalance(true, ActiveEngines.Manual, ActiveEngines.UnBalanced, ActiveEngines.Balanced);
                    }
                    if (ActiveEngines.Steering.Count > 0)
                    {
                        if (!EngineOptimizer.OptimizeLimitsForTorque(ActiveEngines.Steering, Vector3.zero, imbalance, MoI, true,
                                                                     out max_limit, out torque_error, out angle_error))
                        {
                            ActiveEngines.Steering.ForEach(e => e.limit = 0);
                            ActiveEngines.Balanced.ForEach(e => e.limit = 0);
                        }
                    }
                    MinLimit = 1;
                    for (int i = 0, ActiveEnginesCount = ActiveEngines.Count; i < ActiveEnginesCount; i++)
                    {
                        var e = ActiveEngines[i];
                        thrust += e.wThrustDir * e.nominalCurrentThrust(e.limit);
                        if (e.Role != TCARole.MANUAL &&
                            e.Role != TCARole.MANEUVER &&
                            MinLimit > e.limit)
                        {
                            MinLimit = e.limit;
                        }
                        e.forceThrustPercentage(e.limit * 100);
                    }
                    var T = thrust.magnitude / Utils.G0;
                    MinTWR = T / Mass;
                    MaxTWR = T / DryMass;
                }
            }
        }
Пример #4
0
        public static bool OptimizeLimitsForTorque(IList <EngineWrapper> engines, Vector3 needed_torque, Vector3 start_imbalance, Vector3 MoI, bool useDefTorque,
                                                   out float max_limit, out float torque_error, out float angle_error)
        {
            var     num_engines = engines.Count;
            var     zero_torque = needed_torque.IsZero();
            var     preset_limits = engines.Any(e => e.preset_limit >= 0);
            float   error, angle;
            var     last_error    = -1f;
            Vector3 cur_imbalance = start_imbalance;
            Vector3 target;

            torque_error = -1f;
            angle_error  = -1f;
            //            Utils.Log("=============================== Optimization ===============================\n" +
            //                      "needed torque {}\n" +
            //                      "start imbalance {}\n" +
            //                      "MoI {}\n" +
            //                      "engines:\n{}",
            //                      needed_torque, start_imbalance, MoI, engines);//debug
            for (int i = 0; i < C.MaxIterations; i++)
            {
                //calculate current errors and target
                cur_imbalance = start_imbalance;
                for (int j = 0; j < num_engines; j++)
                {
                    var e = engines[j]; cur_imbalance += e.Torque(e.throttle * e.limit, useDefTorque);
                }
                angle  = zero_torque ? 0f : Utils.Angle2(cur_imbalance, needed_torque);
                target = needed_torque - cur_imbalance;
                error  = TorqueProps.AngularAcceleration(target, MoI).magnitude;
                //                Utils.Log("current imbalance: {}\nerror: {} < {}", cur_imbalance, error, ENG.OptimizationTorqueCutoff*ENG.OptimizationPrecision);//debug
                //remember the best state
                if (angle <= 0 && error < torque_error || angle + error < angle_error + torque_error || angle_error < 0)
                {
                    for (int j = 0; j < num_engines; j++)
                    {
                        var e = engines[j]; e.best_limit = e.limit;
                    }
                    angle_error  = angle;
                    torque_error = error;
                }
                //check convergence conditions
                if (error < C.OptimizationTorqueCutoff * C.OptimizationPrecision ||
                    last_error > 0 && Mathf.Abs(error - last_error) < C.OptimizationPrecision * last_error)
                {
                    break;
                }
                last_error = error;
                //normalize limits of main and balanced engines before optimization
                if (!preset_limits)
                {
                    var limit_norm = 0f;
                    for (int j = 0; j < num_engines; j++)
                    {
                        var e = engines[j];
                        if (e.Role == TCARole.MANEUVER)
                        {
                            continue;
                        }
                        if (limit_norm < e.limit)
                        {
                            limit_norm = e.limit;
                        }
                    }
                    if (limit_norm > 0)
                    {
                        for (int j = 0; j < num_engines; j++)
                        {
                            var e = engines[j];
                            if (e.Role == TCARole.MANEUVER)
                            {
                                continue;
                            }
                            e.limit = Mathf.Clamp01(e.limit / limit_norm);
                        }
                    }
                }
                //optimize limits
                if (!optimization_for_torque_pass(engines, num_engines, target, target.magnitude, C.OptimizationPrecision, useDefTorque))
                {
                    break;
                }
            }
            var optimized = torque_error < C.OptimizationTorqueCutoff ||
                            (!zero_torque && angle_error < C.OptimizationAngleCutoff);

            //            Utils.Log("num engines {}, optimized {}, TorqueError {}, TorqueAngle {}\nneeded torque {}\ncurrent turque {}\nlimits:\n{}\n" +
            //                "-------------------------------------------------------------------------------------------------",
            //                num_engines, optimized, torque_error, angle_error, needed_torque, cur_imbalance,
            //                engines.Aggregate("", (s, e) => s+string.Format("{0}: VSF {1:P1}, throttle {2:P1}, best limit {3:P1}\n",
            //                                                                e.name, e.VSF, e.throttle, e.best_limit)));//debug
            //treat single-engine crafts specially
            if (num_engines == 1)
            {
                engines[0].limit = optimized ? engines[0].best_limit : 0f;
                max_limit        = engines[0].limit;
            }
            else //restore the best state
            {
                max_limit = 0;
                for (int j = 0; j < num_engines; j++)
                {
                    var e = engines[j];
                    e.limit = e.best_limit;
                    if (e.limit > max_limit)
                    {
                        max_limit = e.limit;
                    }
                }
            }
            return(optimized);
        }
Пример #5
0
        public static bool OptimizeLimitsForTorque(
            IList <EngineWrapper> engines,
            Vector3 needed_torque,
            Vector3 start_imbalance,
            Vector3 MoI,
            bool useDefTorque,
            out float max_limit,
            out float torque_error,
            out float angle_error
            )
        {
            torque_error = -1f;
            angle_error  = -1f;
            max_limit    = 0;
            var num_engines = engines.Count;

            if (num_engines == 0)
            {
                return(true);
            }
            var zero_torque   = needed_torque.IsZero();
            var preset_limits = engines.Any(e => e.preset_limit >= 0);
            var torqueOnly    = !preset_limits && engines.All(e => e.Role == TCARole.MANEUVER);
            var last_error    = -1f;

            for (var i = 0; i < C.MaxIterations; i++)
            {
                // calculate current target
                var cur_imbalance = start_imbalance;
                for (var j = 0; j < num_engines; j++)
                {
                    var e = engines[j];
                    cur_imbalance += e.Torque(e.throttle * e.limit, useDefTorque);
                }
                var target = needed_torque - cur_imbalance;
                if (target.IsZero())
                {
                    break;
                }
                // calculate torque and angle errors
                var error = TorqueProps.AngularAcceleration(target, MoI).sqrMagnitude;
                var angle = zero_torque ? 0f : Utils.Angle2Rad(cur_imbalance, needed_torque) * C.AngleErrorWeight;
                //remember the best state
                if (zero_torque && error < torque_error ||
                    angle + error < angle_error + torque_error ||
                    angle_error < 0)
                {
                    for (var j = 0; j < num_engines; j++)
                    {
                        var e = engines[j];
                        e.best_limit = e.limit;
                    }
                    torque_error = error;
                    if (!zero_torque && !cur_imbalance.IsZero())
                    {
                        angle_error = angle;
                    }
                }
                // check convergence conditions
                if (error < C.TorqueCutoff ||
                    last_error > 0 && Mathf.Abs(error - last_error) < C.OptimizationPrecision * last_error)
                {
                    break;
                }
                last_error = error;
                // normalize limits of main and balanced engines before optimization
                if (!preset_limits)
                {
                    var limit_norm = 0f;
                    for (var j = 0; j < num_engines; j++)
                    {
                        var e = engines[j];
                        if (e.Role == TCARole.MANEUVER)
                        {
                            continue;
                        }
                        if (limit_norm < e.limit)
                        {
                            limit_norm = e.limit;
                        }
                    }
                    if (limit_norm > 0 && limit_norm < 1)
                    {
                        for (var j = 0; j < num_engines; j++)
                        {
                            var e = engines[j];
                            if (e.Role == TCARole.MANEUVER)
                            {
                                continue;
                            }
                            e.limit = Mathf.Clamp01(e.limit / limit_norm);
                        }
                    }
                }
                // optimize limits
                if (!optimization_for_torque_pass(engines,
                                                  num_engines,
                                                  target,
                                                  target.magnitude,
                                                  C.OptimizationPrecision,
                                                  useDefTorque,
                                                  torqueOnly))
                {
                    break;
                }
            }
            var optimized = torque_error < C.OptimizationTorqueCutoff ||
                            (angle_error >= 0 && angle_error < C.OptimizationAngleCutoff);

            // treat single-engine crafts specially
            if (num_engines == 1)
            {
                engines[0].limit = optimized ? engines[0].best_limit : 0f;
                max_limit        = engines[0].limit;
            }
            else //restore the best state
            {
                max_limit = 0;
                for (var j = 0; j < num_engines; j++)
                {
                    var e = engines[j];
                    e.limit = e.best_limit;
                    if (e.limit > max_limit)
                    {
                        max_limit = e.limit;
                    }
                }
            }
            return(optimized);
        }