protected override void OnStart() { FARLogger.Info("FARVesselAero on " + vessel.name + " reporting startup"); base.OnStart(); if (!CompatibilityChecker.IsAllCompatible()) { this.enabled = false; return; } if (!HighLogic.LoadedSceneIsFlight) { this.enabled = false; return; } _currentGeoModules = new List <GeometryPartModule>(); /*if (!vessel.rootPart) * { * this.enabled = false; * return; * }*/ for (int i = 0; i < vessel.parts.Count; i++) { Part p = vessel.parts[i]; p.maximum_drag = 0; p.minimum_drag = 0; p.angularDrag = 0; /*p.dragModel = Part.DragModel.NONE; * p.dragReferenceVector = Vector3.zero; * p.dragScalar = 0; * p.dragVector = Vector3.zero; * p.dragVectorDir = Vector3.zero; * p.dragVectorDirLocal = Vector3.zero; * p.dragVectorMag = 0; * p.dragVectorSqrMag = 0; * * p.bodyLiftMultiplier = 0; * p.bodyLiftScalar = 0;*/ GeometryPartModule g = p.GetComponent <GeometryPartModule>(); if ((object)g != null) { _currentGeoModules.Add(g); if (g.Ready) { geoModulesReady++; } } if (p.Modules.Contains <KerbalEVA>() || p.Modules.Contains <FlagSite>()) { FARLogger.Info("Handling Stuff for KerbalEVA / Flag"); g = (GeometryPartModule)p.AddModule("GeometryPartModule"); g.OnStart(StartState()); p.AddModule("FARAeroPartModule").OnStart(StartState()); _currentGeoModules.Add(g); } } RequestUpdateVoxel(false); this.enabled = true; //GameEvents.onVesselLoaded.Add(VesselUpdateEvent); //GameEvents.onVesselChange.Add(VesselUpdateEvent); //GameEvents.onVesselLoaded.Add(VesselUpdate); //GameEvents.onVesselCreate.Add(VesselUpdateEvent); //FARLogger.Info("Starting " + _vessel.vesselName + " aero properties"); }
private void LogError(string msg) { FARLogger.Error(msg); StopLogging(); }
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); int calls = optResult.FunctionCalls; // if stable AoA doesn't exist, calculate derivatives at 0 incidence if (!optResult.Converged) { FARLogger.Info("Stable angle of attack not found, calculating derivatives at 0 incidence instead"); alpha = 0; _instantCondition.FunctionIterateForAlpha(alpha); calls += 1; } else { 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 = alpha; stabDerivOutput.stableAoAState = ""; if (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: " + calls.ToString()); //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 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, GUIColors.GetColor(3), "β", true); yVal = transSolve.GetSolution(1); ScaleAndClampValues(yVal, 180 / Math.PI, 50); lines.AddData(yVal, GUIColors.GetColor(2), "p", true); yVal = transSolve.GetSolution(2); ScaleAndClampValues(yVal, 180 / Math.PI, 50); lines.AddData(yVal, GUIColors.GetColor(1), "r", true); yVal = transSolve.GetSolution(3); ScaleAndClampValues(yVal, 180 / Math.PI, 50); lines.AddData(yVal, GUIColors.GetColor(0), "φ", true); return(lines); }
private void ToggleGear() { List <Part> partsList = EditorLogic.SortedShipList; foreach (Part p in partsList) { if (p.Modules.Contains <ModuleWheelDeployment>()) { ModuleWheelDeployment l = p.Modules.GetModule <ModuleWheelDeployment>(); l.ActionToggle(new KSPActionParam(KSPActionGroup.Gear, gearToggle ? KSPActionType.Activate : KSPActionType.Deactivate)); } if (p.Modules.Contains("FSwheel")) { PartModule m = p.Modules["FSwheel"]; MethodInfo method = m.GetType().GetMethod("animate", BindingFlags.Instance | BindingFlags.NonPublic); if (method == null) { FARLogger.Error("FSwheel does not have method 'animate"); } else { method.Invoke(m, gearToggle ? new object[] { "Deploy" } : new object[] { "Retract" }); } } if (p.Modules.Contains("FSBDwheel")) { PartModule m = p.Modules["FSBDwheel"]; MethodInfo method = m.GetType().GetMethod("animate", BindingFlags.Instance | BindingFlags.NonPublic); if (method == null) { FARLogger.Error("FSBDwheel does not have method 'animate"); } else { method.Invoke(m, gearToggle ? new object[] { "Deploy" } : new object[] { "Retract" }); } } // ReSharper disable once InvertIf if (p.Modules.Contains("KSPWheelAdjustableGear")) { PartModule m = p.Modules["KSPWheelAdjustableGear"]; MethodInfo method = m.GetType().GetMethod("deploy", BindingFlags.Instance | BindingFlags.Public); try { if (method == null) { FARLogger.Error("KSPWheelAdjustableGear does not have method 'animate"); } else { method.Invoke(m, null); } } catch (Exception e) { //we just catch and print this ourselves to allow things to continue working, since there seems to be a bug in KSPWheels as of this writing FARLogger.Exception(e); } } } gearToggle = !gearToggle; }
public void VesselUpdate(bool recalcGeoModules) { if (vessel == null) { vessel = gameObject.GetComponent <Vessel>(); if (vessel == null || vessel.vesselTransform == null) { return; } } if (_vehicleAero == null) { _vehicleAero = new VehicleAerodynamics(); _vesselIntakeRamDrag = new VesselIntakeRamDrag(); } //this has been updated recently in the past; queue an update and return if (_updateRateLimiter < FARSettingsScenarioModule.VoxelSettings.minPhysTicksPerUpdate) { _updateQueued = true; return; } _updateRateLimiter = 0; _updateQueued = false; if (vessel.rootPart.Modules.Contains <LaunchClamp>()) { DisableModule(); return; } if (recalcGeoModules) { _currentGeoModules.Clear(); geoModulesReady = 0; foreach (Part p in vessel.Parts) { GeometryPartModule g = p.Modules.GetModule <GeometryPartModule>(); if (g is null) { continue; } _currentGeoModules.Add(g); if (g.Ready) { geoModulesReady++; } } } if (_currentGeoModules.Count > geoModulesReady) { _updateRateLimiter = FARSettingsScenarioModule.VoxelSettings.minPhysTicksPerUpdate - 2; _updateQueued = true; return; } if (_currentGeoModules.Count == 0) { DisableModule(); FARLogger.Info("Disabling FARVesselAero on " + vessel.name + " due to no FARGeometryModules on board"); } TriggerIGeometryUpdaters(); if (VoxelizationThreadpool.RunInMainThread) { for (int i = _currentGeoModules.Count - 1; i >= 0; --i) { if (_currentGeoModules[i].Ready) { continue; } _updateRateLimiter = FARSettingsScenarioModule.VoxelSettings.minPhysTicksPerUpdate - 2; _updateQueued = true; return; } } _voxelCount = VoxelCountFromType(); if (!_vehicleAero.TryVoxelUpdate(vessel.vesselTransform.worldToLocalMatrix, vessel.vesselTransform.localToWorldMatrix, _voxelCount, vessel.Parts, _currentGeoModules, !setup, vessel)) { _updateRateLimiter = FARSettingsScenarioModule.VoxelSettings.minPhysTicksPerUpdate - 2; _updateQueued = true; } if (!_updateQueued) { setup = true; } FARLogger.Info("Updating vessel voxel for " + vessel.vesselName); }
public GraphData RunTransientSimLongitudinal(StabilityDerivOutput vehicleData, double endTime, double initDt, double[] InitCond) { SimMatrix A = new SimMatrix(4, 4); int i = 0; int j = 0; double[] Derivs = new double[27]; vehicleData.stabDerivs.CopyTo(Derivs, 0); double MAC2u = vehicleData.MAC / (2 * vehicleData.nominalVelocity); double effg = _instantCondition.CalculateEffectiveGravity(vehicleData.body, vehicleData.altitude, vehicleData.nominalVelocity); FARLogger.Info("MAC/(2u)= " + MAC2u + " IGNORED!"); FARLogger.Info("effg= " + effg); // Rodhern: For possible backward compability the rotation (moment) derivatives can be // scaled by "mac/(2u)" (pitch) and "b/(2u)" (roll and yaw). //for (int h = 9; h <= 11; h++) // Derivs[h] = Derivs[h] * MAC2u; Derivs[9] = Derivs[9] + vehicleData.nominalVelocity; for (int k = 3; k < 15 && k < Derivs.Length; k++) { double f = Derivs[k]; if (i <= 2) { FARLogger.Info("A[" + i + "," + j + "]= f_" + k + " = " + f); A.Add(f, i, j); } else { FARLogger.Debug("Ignore B[0," + j + "]= " + f); } if (j < 2) { j++; } else { j = 0; i++; } } A.Add(-effg, 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: (Unused) /* * [ Z e ] * [ X e ] * [ M e ] * [ 0 ] * */ RungeKutta4 transSolve = new RungeKutta4(endTime, initDt, A, InitCond); transSolve.Solve(); GraphData lines = new GraphData(); lines.xValues = transSolve.time; double[] yVal = transSolve.GetSolution(0); ScaleAndClampValues(yVal, 1, 50); lines.AddData(yVal, GUIColors.GetColor(3), "w", true); yVal = transSolve.GetSolution(1); ScaleAndClampValues(yVal, 1, 50); lines.AddData(yVal, GUIColors.GetColor(2), "u", true); yVal = transSolve.GetSolution(2); ScaleAndClampValues(yVal, 180 / Math.PI, 50); lines.AddData(yVal, GUIColors.GetColor(1), "q", true); yVal = transSolve.GetSolution(3); ScaleAndClampValues(yVal, 180 / Math.PI, 50); lines.AddData(yVal, GUIColors.GetColor(0), "θ", true); /*graph.SetBoundaries(0, endTime, -10, 10); * graph.SetGridScaleUsingValues(1, 5); * graph.horizontalLabel = "time"; * graph.verticalLabel = "value"; * graph.Update();*/ return(lines); }
/// <inheritdoc /> public void OnLoad(T resource) { FARLogger.DebugFormat("Loaded {0} from {1}", resource, Url); Asset = resource; AssetLoaded(); }
public void LoadAssets() { FARLogger.Info("Loading shader bundle"); MainThread.StartCoroutine(Load); }
public void LoadAssets() { FARLogger.InfoFormat("Loading {0} bundle", BundleType); MainThread.StartCoroutine(Load); }
/// <inheritdoc /> public void OnError() { FARLogger.ErrorFormat("Failed to load asset from {0}", Url); AssetError(); }
public StabilityDerivOutput CalculateStabilityDerivs(double u0, double q, double machNumber, double alpha, double beta, double phi, int flapSetting, bool spoilers, CelestialBody body, double alt) { StabilityDerivOutput stabDerivOutput = new StabilityDerivOutput(); stabDerivOutput.nominalVelocity = u0; stabDerivOutput.altitude = alt; stabDerivOutput.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; InstantConditionSimInput input = new InstantConditionSimInput(alpha, beta, phi, 0, 0, 0, machNumber, 0, flapSetting, spoilers); InstantConditionSimOutput nominalOutput; InstantConditionSimOutput pertOutput = new InstantConditionSimOutput(); _instantCondition.GetClCdCmSteady(input, out nominalOutput, true); 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; FARWingAerodynamicModel w = p.GetComponent <FARWingAerodynamicModel>(); if (w != null) { if (w.isShielded) { continue; } area += w.S; MAC += w.GetMAC() * w.S; b += w.Getb_2() * w.S; if (w is FARControllableSurface) { (w as FARControllableSurface).SetControlStateEditor(CoM, p.transform.up, 0, 0, 0, input.flaps, input.spoilers); } } } if (area == 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; for (int i = 0; i < partsList.Count; i++) { Part p = partsList[i]; if (p == null || FARAeroUtil.IsNonphysical(p)) { continue; } //This section handles the parallel axis theorem Vector3 relPos = p.transform.TransformPoint(p.CoMOffset) - CoM; double x2, y2, z2, x, y, z; x2 = relPos.z * relPos.z; y2 = relPos.x * relPos.x; z2 = relPos.y * relPos.y; x = relPos.z; y = relPos.x; z = relPos.y; 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 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 Vector3 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)); Vector3 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)); Vector3 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; double effectiveG = _instantCondition.CalculateAccelerationDueToGravity(body, alt); //This is the effect of gravity effectiveG -= u0 * u0 / (alt + body.Radius); //This is the effective reduction of gravity due to high velocity 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); alpha = FARMathUtil.BrentsMethod(_instantCondition.FunctionIterateForAlpha, -30d, 30d, 0.001, 500); input.alpha = alpha; nominalOutput = _instantCondition.iterationOutput; //alpha_str = (alpha * Mathf.PI / 180).ToString(); input.alpha = (alpha + 2); _instantCondition.GetClCdCmSteady(input, out pertOutput, true, true); stabDerivOutput.stableCl = neededCl; stabDerivOutput.stableCd = nominalOutput.Cd; stabDerivOutput.stableAoA = alpha; stabDerivOutput.stableAoAState = ""; if (Math.Abs((nominalOutput.Cl - neededCl) / neededCl) > 0.1) { stabDerivOutput.stableAoAState = ((nominalOutput.Cl > neededCl) ? "<" : ">"); } FARLogger.Info("Cl needed: " + neededCl + ", AoA: " + alpha + ", Cl: " + nominalOutput.Cl + ", Cd: " + nominalOutput.Cd); pertOutput.Cl = (pertOutput.Cl - nominalOutput.Cl) / (2 * FARMathUtil.deg2rad); //vert vel derivs 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 input.alpha = alpha; input.machNumber = machNumber + 0.05; _instantCondition.GetClCdCmSteady(input, out pertOutput, true, false); pertOutput.Cl = (pertOutput.Cl - nominalOutput.Cl) / 0.05 * machNumber; //fwd vel derivs 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, false); pertOutput.Cl = (pertOutput.Cl - nominalOutput.Cl) / 0.05; //pitch rate derivs pertOutput.Cd = (pertOutput.Cd - nominalOutput.Cd) / 0.05; pertOutput.Cm = (pertOutput.Cm - nominalOutput.Cm) / 0.05; pertOutput.Cl *= q * area * MAC / (2 * u0 * mass); pertOutput.Cd *= q * area * MAC / (2 * u0 * mass); 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, false); pertOutput.Cl = (pertOutput.Cl - nominalOutput.Cl) / 0.1; //elevator derivs pertOutput.Cd = (pertOutput.Cd - nominalOutput.Cd) / 0.1; pertOutput.Cm = (pertOutput.Cm - nominalOutput.Cm) / 0.1; pertOutput.Cl *= q * area / mass; pertOutput.Cd *= q * area / mass; 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, false); pertOutput.Cy = (pertOutput.Cy - nominalOutput.Cy) / (2 * FARMathUtil.deg2rad); //sideslip angle derivs 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, false); pertOutput.Cy = (pertOutput.Cy - nominalOutput.Cy) / 0.05; //roll rate derivs 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; _instantCondition.GetClCdCmSteady(input, out pertOutput, true, false); pertOutput.Cy = (pertOutput.Cy - nominalOutput.Cy) / 0.05f; //yaw rate derivs 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 GraphData RunTransientSimLongitudinal(StabilityDerivOutput vehicleData, double endTime, double initDt, double[] InitCond) { SimMatrix A = new SimMatrix(4, 4); SimMatrix B = new SimMatrix(1, 4); A.PrintToConsole(); int i = 0; int j = 0; int num = 0; double[] Derivs = new double[27]; for (int k = 0; k < vehicleData.stabDerivs.Length; k++) { double f = vehicleData.stabDerivs[k]; if (num < 3 || num >= 15) { num++; //Avoid Ix, Iy, Iz continue; } else { 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(-_instantCondition.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 ] * * */ RungeKutta4 transSolve = new RungeKutta4(endTime, initDt, A, InitCond); transSolve.Solve(); GraphData lines = new GraphData(); lines.xValues = transSolve.time; double[] yVal = transSolve.GetSolution(0); ScaleAndClampValues(yVal, 1, 50); lines.AddData(yVal, GUIColors.GetColor(3), "w", true); yVal = transSolve.GetSolution(1); ScaleAndClampValues(yVal, 1, 50); lines.AddData(yVal, GUIColors.GetColor(2), "u", true); yVal = transSolve.GetSolution(2); ScaleAndClampValues(yVal, 180 / Math.PI, 50); lines.AddData(yVal, GUIColors.GetColor(1), "q", true); yVal = transSolve.GetSolution(3); ScaleAndClampValues(yVal, 180 / Math.PI, 50); lines.AddData(yVal, GUIColors.GetColor(0), "θ", true); /*graph.SetBoundaries(0, endTime, -10, 10); * graph.SetGridScaleUsingValues(1, 5); * graph.horizontalLabel = "time"; * graph.verticalLabel = "value"; * graph.Update();*/ return(lines); }
public GraphData RunTransientSimLateral(StabilityDerivOutput vehicleData, double endTime, double initDt, double[] InitCond) { SimMatrix A = new SimMatrix(4, 4); int i = 0; int j = 0; double[] Derivs = new double[27]; vehicleData.stabDerivs.CopyTo(Derivs, 0); double u0 = vehicleData.nominalVelocity; double b2u = vehicleData.b / (2 * u0); double effg = _instantCondition.CalculateEffectiveGravity(vehicleData.body, vehicleData.altitude, u0) * Math.Cos(vehicleData.stableCondition.stableAoA * Math.PI / 180); double factor_xz_x = Derivs[26] / Derivs[0]; double factor_xz_z = Derivs[26] / Derivs[2]; double factor_invxz = 1 / (1 - factor_xz_x * factor_xz_z); FARLogger.Info("u0= " + u0); FARLogger.Info("b/(2u)= " + b2u + " IGNORED!"); FARLogger.Info("effg= " + effg + ", after multiplication with cos(AoA)."); FARLogger.Info("Ixz/Ix= " + factor_xz_x + ", used to add yaw to roll-deriv."); FARLogger.Info("Ixz/Iz= " + factor_xz_z + ", used to add roll to yaw-deriv."); FARLogger.Info("(1 - Ixz^2/(IxIz))^-1= " + factor_invxz); // Rodhern: For possible backward compability the rotation (moment) derivatives can be // scaled by "b/(2u)" (for pitch rate "mac/(2u)"). //for (int h = 18; h <= 23; h++) // Derivs[h] = Derivs[h] * b2u; Derivs[15] = Derivs[15] / u0; Derivs[18] = Derivs[18] / u0; Derivs[21] = Derivs[21] / u0 - 1; double Lb = Derivs[16] * factor_invxz; double Nb = Derivs[17] * factor_invxz; double Lp = Derivs[19] * factor_invxz; double Np = Derivs[20] * factor_invxz; double Lr = Derivs[22] * factor_invxz; double Nr = Derivs[23] * factor_invxz; Derivs[16] = Lb + factor_xz_x * Nb; Derivs[17] = Nb + factor_xz_z * Lb; Derivs[19] = Lp + factor_xz_x * Np; Derivs[20] = Np + factor_xz_z * Lp; Derivs[22] = Lr + factor_xz_x * Nr; Derivs[23] = Nr + factor_xz_z * Lr; for (int k = 15; k < Derivs.Length; k++) { double f = Derivs[k]; if (i <= 2) { FARLogger.Info("A[" + i + "," + j + "]= f_" + k + " = " + f + ", after manipulation."); A.Add(f, i, j); } if (j < 2) { j++; } else { j = 0; i++; } } A.Add(effg / u0, 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 */ RungeKutta4 transSolve = new RungeKutta4(endTime, initDt, A, InitCond); transSolve.Solve(); GraphData lines = new GraphData(); lines.xValues = transSolve.time; double[] yVal = transSolve.GetSolution(0); ScaleAndClampValues(yVal, 180 / Math.PI, 50); lines.AddData(yVal, GUIColors.GetColor(3), "β", true); yVal = transSolve.GetSolution(1); ScaleAndClampValues(yVal, 180 / Math.PI, 50); lines.AddData(yVal, GUIColors.GetColor(2), "p", true); yVal = transSolve.GetSolution(2); ScaleAndClampValues(yVal, 180 / Math.PI, 50); lines.AddData(yVal, GUIColors.GetColor(1), "r", true); yVal = transSolve.GetSolution(3); ScaleAndClampValues(yVal, 180 / Math.PI, 50); lines.AddData(yVal, GUIColors.GetColor(0), "φ", true); /*graph.SetBoundaries(0, endTime, -10, 10); * graph.SetGridScaleUsingValues(1, 5); * graph.horizontalLabel = "time"; * graph.verticalLabel = "value"; * graph.Update();*/ return(lines); }
private List <MeshData> CreateMeshListFromTransforms(ref List <Transform> meshTransforms) { DebugClear(); List <MeshData> meshList = new List <MeshData>(); List <Transform> validTransformList = new List <Transform>(); if (part.Modules.Contains <KerbalEVA>() || part.Modules.Contains <FlagSite>()) { FARLogger.Info("Adding vox box to Kerbal / Flag"); meshList.Add(CreateBoxMeshForKerbalEVA()); validTransformList.Add(part.partTransform); meshTransforms = validTransformList; return(meshList); } var worldToLocalMatrix = part.partTransform.worldToLocalMatrix; var rendererBounds = part.GetPartOverallMeshBoundsInBasis(worldToLocalMatrix); var colliderBounds = part.GetPartColliderBoundsInBasis(worldToLocalMatrix); bool cantUseColliders = true; bool isFairing = part.Modules.Contains <ModuleProceduralFairing>() || part.Modules.Contains("ProceduralFairingSide"); bool isDrill = part.Modules.Contains <ModuleAsteroidDrill>() || part.Modules.Contains <ModuleResourceHarvester>(); //Voxelize colliders if ((forceUseColliders || isFairing || isDrill || (rendererBounds.size.x * rendererBounds.size.z < colliderBounds.size.x * colliderBounds.size.z * 1.6f && rendererBounds.size.y < colliderBounds.size.y * 1.2f && (rendererBounds.center - colliderBounds.center).magnitude < 0.3f)) && !forceUseMeshes) { foreach (Transform t in meshTransforms) { MeshData md = GetColliderMeshData(t); if (md == null) { continue; } DebugAddCollider(t); meshList.Add(md); validTransformList.Add(t); cantUseColliders = false; } } if (part.Modules.Contains <ModuleJettison>()) { bool variants = part.Modules.Contains <ModulePartVariants>(); List <ModuleJettison> jettisons = part.Modules.GetModules <ModuleJettison>(); HashSet <string> jettisonTransforms = new HashSet <string>(); for (int i = 0; i < jettisons.Count; i++) { ModuleJettison j = jettisons[i]; if (j.jettisonTransform == null) { continue; } if (variants) { // with part variants, jettison name is a comma separated list of transform names foreach (string name in j.jettisonName.Split(',')) { jettisonTransforms.Add(name); } } else { jettisonTransforms.Add(j.jettisonTransform.name); } if (j.isJettisoned) { continue; } Transform t = j.jettisonTransform; if (t.gameObject.activeInHierarchy == false) { continue; } MeshData md = GetVisibleMeshData(t, ignoreIfNoRenderer, false); if (md == null) { continue; } DebugAddMesh(t); meshList.Add(md); validTransformList.Add(t); } //Voxelize Everything if ((cantUseColliders || forceUseMeshes || isFairing) && !isDrill) //in this case, voxelize _everything_ { foreach (Transform t in meshTransforms) { if (jettisonTransforms.Contains(t.name)) { continue; } MeshData md = GetVisibleMeshData(t, ignoreIfNoRenderer, false); if (md == null) { continue; } DebugAddMesh(t); meshList.Add(md); validTransformList.Add(t); } } } else { //Voxelize Everything if ((cantUseColliders || forceUseMeshes || isFairing) && !isDrill) //in this case, voxelize _everything_ { foreach (Transform t in meshTransforms) { MeshData md = GetVisibleMeshData(t, ignoreIfNoRenderer, false); if (md == null) { continue; } DebugAddMesh(t); meshList.Add(md); validTransformList.Add(t); } } } DebugPrint(); meshTransforms = validTransformList; return(meshList); }
public IEnumerator Load() { // wait for the other loading to be done if (State == Progress.InProgress) { yield return(new WaitWhile(() => State == Progress.InProgress)); yield break; } State = Progress.InProgress; // wait for config to be loaded fully while (FARConfig.IsLoading) { yield return(null); } NeedsReload = false; string path = Url; FARLogger.DebugFormat("Loading asset bundle from {0}", path); AssetBundleCreateRequest createRequest = AssetBundle.LoadFromFileAsync(path); yield return(createRequest); AssetBundle assetBundle = createRequest.assetBundle; if (assetBundle == null) { FARLogger.Error($"Could not load asset bundle from {path}"); State = Progress.Error; yield break; } AssetBundleRequest loadRequest = assetBundle.LoadAllAssetsAsync <T>(); yield return(loadRequest); LoadedAssets.Clear(); foreach (Object asset in loadRequest.allAssets) { if (!LoadedAssets.ContainsKey(asset.name)) { if (asset is T t) { LoadedAssets.Add(asset.name, t); } else { FARLogger .Warning($"Invalid asset type {asset.GetType().ToString()}, expected {typeof(T).ToString()}"); } } else { FARLogger.DebugFormat("Asset {0} is duplicated", asset); } } FARLogger.DebugFormat("Completed loading assets from {0}", path); State = Progress.Completed; }
public void PredictionCalculateAeroForces(float atmDensity, float machNumber, float reynoldsPerUnitLength, float pseudoKnudsenNumber, float skinFrictionDrag, Vector3 vel, ferram4.FARCenterQuery center) { if (partData.Count == 0) { return; } PartData data = partData[0]; FARAeroPartModule aeroModule = null; for (int i = 0; i < partData.Count; i++) { data = partData[i]; aeroModule = data.aeroModule; if (aeroModule.part == null || aeroModule.part.partTransform == null) { continue; } break; } if (aeroModule.part == null || aeroModule.part.transform == null) { return; } double skinFrictionForce = skinFrictionDrag * xForceSkinFriction.Evaluate(machNumber); //this will be the same for each part, so why recalc it multiple times? double xForceAoA0 = xForcePressureAoA0.Evaluate(machNumber); double xForceAoA180 = xForcePressureAoA180.Evaluate(machNumber); Vector3 xRefVector = data.xRefVectorPartSpace; Vector3 nRefVector = data.nRefVectorPartSpace; Vector3 velLocal = aeroModule.part.partTransform.worldToLocalMatrix.MultiplyVector(vel); Vector3 angVelLocal = aeroModule.partLocalAngVel; //Vector3 angVelLocal = aeroModule.partLocalAngVel; //velLocal += Vector3.Cross(angVelLocal, data.centroidPartSpace); //some transform issue here, needs investigation Vector3 velLocalNorm = velLocal.normalized; Vector3 localNormalForceVec = Vector3.ProjectOnPlane(-velLocalNorm, xRefVector).normalized; double cosAoA = Vector3.Dot(xRefVector, velLocalNorm); double cosSqrAoA = cosAoA * cosAoA; double sinSqrAoA = Math.Max(1 - cosSqrAoA, 0); double sinAoA = Math.Sqrt(sinSqrAoA); double sin2AoA = 2 * sinAoA * Math.Abs(cosAoA); double cosHalfAoA = Math.Sqrt(0.5 + 0.5 * Math.Abs(cosAoA)); double nForce = 0; nForce = potentialFlowNormalForce * Math.Sign(cosAoA) * cosHalfAoA * sin2AoA; //potential flow normal force if (nForce < 0) //potential flow is not significant over the rear face of things { nForce = 0; } //if (machNumber > 3) // nForce *= 2d - machNumber * 0.3333333333333333d; float normalForceFactor = Math.Abs(Vector3.Dot(localNormalForceVec, nRefVector)); normalForceFactor *= normalForceFactor; normalForceFactor = invFlatnessRatio * (1 - normalForceFactor) + flatnessRatio * normalForceFactor; //accounts for changes in relative flatness of shape float crossFlowMach, crossFlowReynolds; crossFlowMach = machNumber * (float)sinAoA; crossFlowReynolds = reynoldsPerUnitLength * diameter * (float)sinAoA / normalForceFactor; nForce += viscCrossflowDrag * sinSqrAoA * CalculateCrossFlowDrag(crossFlowMach, crossFlowReynolds); //viscous crossflow normal force nForce *= normalForceFactor; double xForce = -skinFrictionForce *Math.Sign(cosAoA) * cosSqrAoA; double localVelForce = xForce * pseudoKnudsenNumber; xForce -= localVelForce; localVelForce = Math.Abs(localVelForce); float moment = (float)(cosAoA * sinAoA); float dampingMoment = 4f * moment; if (cosAoA > 0) { xForce += cosSqrAoA * xForceAoA0; float momentFactor; if (machNumber > 6) { momentFactor = hypersonicMomentForward; } else if (machNumber < 0.6) { momentFactor = 0.6f * hypersonicMomentBackward; } else { float tmp = (-0.185185185f * machNumber + 1.11111111111f); momentFactor = tmp * hypersonicMomentBackward * 0.6f + (1 - tmp) * hypersonicMomentForward; } //if (machNumber < 1.5) // momentFactor += hypersonicMomentBackward * (0.5f - machNumber * 0.33333333333333333333333333333333f) * 0.2f; moment *= momentFactor; dampingMoment *= momentFactor; } else { xForce += cosSqrAoA * xForceAoA180; float momentFactor; //negative to deal with the ref vector facing the opposite direction, causing the moment vector to point in the opposite direction if (machNumber > 6) { momentFactor = hypersonicMomentBackward; } else if (machNumber < 0.6) { momentFactor = 0.6f * hypersonicMomentForward; } else { float tmp = (-0.185185185f * machNumber + 1.11111111111f); momentFactor = tmp * hypersonicMomentForward * 0.6f + (1 - tmp) * hypersonicMomentBackward; } //if (machNumber < 1.5) // momentFactor += hypersonicMomentForward * (0.5f - machNumber * 0.33333333333333333333333333333333f) * 0.2f; moment *= momentFactor; dampingMoment *= momentFactor; } moment /= normalForceFactor; dampingMoment = Math.Abs(dampingMoment) * 0.1f; //dampingMoment += (float)Math.Abs(skinFrictionForce) * 0.1f; float rollDampingMoment = (float)(skinFrictionForce * 0.5 * diameter); //skin friction force times avg moment arm for vehicle rollDampingMoment *= (0.75f + flatnessRatio * 0.25f); //this is just an approximation for now Vector3 forceVector = (float)xForce * xRefVector + (float)nForce * localNormalForceVec; forceVector -= (float)localVelForce * velLocalNorm; Vector3 torqueVector = Vector3.Cross(xRefVector, localNormalForceVec) * moment; Vector3 axialAngLocalVel = Vector3.Dot(xRefVector, angVelLocal) * xRefVector; Vector3 nonAxialAngLocalVel = angVelLocal - axialAngLocalVel; if (velLocal.sqrMagnitude > 0.001f) { torqueVector -= (dampingMoment * nonAxialAngLocalVel) + (rollDampingMoment * axialAngLocalVel * axialAngLocalVel.magnitude) / velLocal.sqrMagnitude; } else { torqueVector -= (dampingMoment * nonAxialAngLocalVel) + (rollDampingMoment * axialAngLocalVel * axialAngLocalVel.magnitude) / 0.001f; } Matrix4x4 localToWorld = aeroModule.part.partTransform.localToWorldMatrix; float dynPresAndScaling = 0.0005f * atmDensity * velLocal.sqrMagnitude; //dyn pres and N -> kN conversion forceVector *= dynPresAndScaling; torqueVector *= dynPresAndScaling; forceVector = localToWorld.MultiplyVector(forceVector); torqueVector = localToWorld.MultiplyVector(torqueVector); Vector3 centroid = Vector3.zero; if (!float.IsNaN(forceVector.x) && !float.IsNaN(torqueVector.x)) { for (int i = 0; i < partData.Count; i++) { PartData data2 = partData[i]; FARAeroPartModule module = data2.aeroModule; if ((object)module == null) { continue; } if (module.part == null || module.part.partTransform == null) { continue; } centroid = module.part.partTransform.localToWorldMatrix.MultiplyPoint3x4(data2.centroidPartSpace); center.AddForce(centroid, forceVector * data2.dragFactor); } center.AddTorque(torqueVector); } else { FARLogger.Error("NaN Prediction Section Error: Inputs: AtmDen: " + atmDensity + " Mach: " + machNumber + " Re: " + reynoldsPerUnitLength + " Kn: " + pseudoKnudsenNumber + " skin: " + skinFrictionDrag + " vel: " + vel); } }
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, GUIColors.GetColor(3), "w", true); yVal = transSolve.GetSolution(1); ScaleAndClampValues(yVal, 1, 50); lines.AddData(yVal, GUIColors.GetColor(2), "u", true); yVal = transSolve.GetSolution(2); ScaleAndClampValues(yVal, 180 / Math.PI, 50); lines.AddData(yVal, GUIColors.GetColor(1), "q", true); yVal = transSolve.GetSolution(3); ScaleAndClampValues(yVal, 180 / Math.PI, 50); lines.AddData(yVal, GUIColors.GetColor(0), "θ", true); return(lines); }
private void SetupMainThread() { _mainThread = Thread.CurrentThread; FARLogger.Debug("Main thread: " + _mainThread.Name); }
private int Apply(ref object owner, NodeVisitor visitor) { int count = 0; FARLogger.TraceFormat("Applying visitor to config node {0}[{1}]", Id, Name ?? "{null}"); foreach (ValueReflection value in Values) { FARLogger.TraceFormat("Visiting value {0}[{1}].{2}", Id, Name, value.Name); try { visitor.VisitValue(owner, value); } catch (Exception e) { FARLogger.ExceptionFormat(e, "Exception loading value {0} in {1}", value.Name, value.DeclaringType); count++; } } foreach (ListValueReflection reflection in ListValues) { if (reflection.IsNodeValue) { NodeReflection nodeReflection = GetReflection(reflection.ValueType); FARLogger.TraceFormat("Visiting list nodes {0}[{1}].{2}[{3}]", Id, Name ?? "{null}", reflection.NodeId, reflection.Name ?? "{null}"); try { visitor.VisitNodeList(owner, reflection, nodeReflection); } catch (Exception e) { FARLogger.ExceptionFormat(e, "Exception loading node ({2}) list {0} in {1}", reflection.Name, reflection.DeclaringType, reflection.NodeId); count++; } } else { FARLogger.TraceFormat("Visiting list values {0}[{1}].{2}", Id, Name ?? "{null}", reflection.Name); try { visitor.VisitValueList(owner, reflection); } catch (Exception e) { FARLogger.ExceptionFormat(e, "Exception loading value list {0} in {1}", reflection.Name, reflection.DeclaringType); count++; } } } foreach (NodeReflection node in Nodes) { FARLogger.TraceFormat("Visiting subnode {0}[{1}].{2}[{3}]", Id, Name ?? "{null}", node.Id, node.Name ?? "{null}"); try { visitor.VisitNode(owner, node); } catch (Exception e) { FARLogger.ExceptionFormat(e, "Exception loading node {2}[{0}] in {1}", node.Name, node.DeclaringType, node.Id); count++; } } return(count); }