public void UpdateTransformMatrixList(Matrix4x4 worldToVesselMatrix) { if (meshDataList != null) { _ready = false; //if the previous transform order hasn't been completed yet, wait here to let it while (_meshesToUpdate > 0) { if (this == null) { return; } } _ready = false; _meshesToUpdate = meshDataList.Count; for (int i = 0; i < meshDataList.Count; ++i) { GeometryMesh mesh = meshDataList[i]; if (mesh.TrySetThisToVesselMatrixForTransform()) { mesh.TransformBasis(worldToVesselMatrix); } else { FARLogger.Info("A mesh on " + part.partInfo.title + " did not exist and was removed"); meshDataList.RemoveAt(i); --i; lock (this) { --_meshesToUpdate; } } } } if (crossSectionAdjusters == null) { return; } foreach (ICrossSectionAdjuster adjuster in crossSectionAdjusters) { adjuster.SetThisToVesselMatrixForTransform(); adjuster.TransformBasis(worldToVesselMatrix); adjuster.UpdateArea(); } }
private void OnDisplayList(int id) { GUI.BringWindowToFront(id); scrollPos = GUILayout.BeginScrollView(scrollPos, listStyle); for (int i = 0; i < stringOptions.Length; i++) { // Highlight the selected item GUIStyle tmpStyle = (selectedOption == i) ? selectedItemStyle : dropdownItemStyle; if (GUILayout.Button(stringOptions[i], tmpStyle)) { FARLogger.Info("Selected " + stringOptions[i]); selectedOption = i; HideList(); } } GUILayout.EndScrollView(); }
private void UpdateInfo() { if (_infoMessages.Count <= 0) { return; } var sB = new StringBuilder(); foreach (string message in _infoMessages) { sB.AppendLine(message); } _infoMessages.Clear(); FARLogger.Info("" + sB); }
public void UpdateTransformMatrixList(Matrix4x4 worldToVesselMatrix) { if (meshDataList != null) { _ready = false; while (_meshesToUpdate > 0) //if the previous transform order hasn't been completed yet, wait here to let it { if (this == null) { return; } } _ready = false; _meshesToUpdate = meshDataList.Count; for (int i = 0; i < meshDataList.Count; ++i) { GeometryMesh mesh = meshDataList[i]; if (mesh.TrySetThisToVesselMatrixForTransform()) { //ThreadPool.QueueUserWorkItem(mesh.MultithreadTransformBasis, worldToVesselMatrix); mesh.TransformBasis(worldToVesselMatrix); } else { FARLogger.Info("A mesh on " + part.partInfo.title + " did not exist and was removed"); meshDataList.RemoveAt(i); --i; lock (this) --_meshesToUpdate; } } } if (crossSectionAdjusters != null) { for (int i = 0; i < crossSectionAdjusters.Count; ++i) { ICrossSectionAdjuster adjuster = crossSectionAdjusters[i]; adjuster.SetThisToVesselMatrixForTransform(); adjuster.TransformBasis(worldToVesselMatrix); adjuster.UpdateArea(); } } //overallMeshBounds = part.GetPartOverallMeshBoundsInBasis(worldToVesselMatrix); }
private void DataInput(InitialConditions inits, StabilityDerivOutput vehicleData, bool longitudinal) { GUILayout.BeginHorizontal(); for (int i = 0; i < inits.inits.Length; i++) { GUILayout.Label(Localizer.Format("FAREditorSimInit") + inits.names[i] + ": "); inits.inits[i] = GUILayout.TextField(inits.inits[i], GUILayout.ExpandWidth(true)); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label(Localizer.Format("FAREditorSimEndTime")); inits.maxTime = GUILayout.TextField(inits.maxTime, GUILayout.ExpandWidth(true)); GUILayout.Label(Localizer.Format("FAREditorSimTimestep")); inits.dt = GUILayout.TextField(inits.dt, GUILayout.ExpandWidth(true)); if (GUILayout.Button(Localizer.Format("FAREditorSimRunButton"), GUILayout.Width(150.0F), GUILayout.Height(25.0F))) { for (int i = 0; i < inits.inits.Length; i++) { inits.inits[i] = Regex.Replace(inits.inits[i], @"[^-?[0-9]*(\.[0-9]*)?]", ""); } inits.maxTime = Regex.Replace(inits.maxTime, @"[^-?[0-9]*(\.[0-9]*)?]", ""); inits.dt = Regex.Replace(inits.dt, @"[^-?[0-9]*(\.[0-9]*)?]", ""); double[] initCond = new double[inits.inits.Length]; for (int i = 0; i < initCond.Length; i++) { initCond[i] = Convert.ToDouble(inits.inits[i]) * inits.scaling[i]; FARLogger.Info("initCond[" + i + "]= " + initCond[i] + ", after scaling with " + inits.scaling[i] + "."); } GraphData data; if (longitudinal) { data = simManager.StabDerivLinearSim.RunTransientSimLongitudinal(vehicleData, Convert.ToDouble(inits.maxTime), Convert.ToDouble(inits.dt), initCond); } else { data = simManager.StabDerivLinearSim.RunTransientSimLateral(vehicleData, Convert.ToDouble(inits.maxTime), Convert.ToDouble(inits.dt), initCond); } UpdateGraph(data, Localizer.Format("FAREditorSimGraphTime"), Localizer.Format("FAREditorSimGraphParams"), 0, Convert.ToDouble(inits.maxTime), 50); } GUILayout.EndHorizontal(); }
protected override void OnStart() { FARLogger.Info("FARVesselAero on " + vessel.name + " reporting startup"); base.OnStart(); if (!HighLogic.LoadedSceneIsFlight) { enabled = false; return; } _currentGeoModules = new List <GeometryPartModule>(); foreach (Part p in vessel.parts) { p.maximum_drag = 0; p.minimum_drag = 0; p.angularDrag = 0; GeometryPartModule g = p.GetComponent <GeometryPartModule>(); if (!(g is null)) { _currentGeoModules.Add(g); if (g.Ready) { geoModulesReady++; } } if (!p.Modules.Contains <KerbalEVA>() && !p.Modules.Contains <FlagSite>()) { continue; } 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); enabled = true; }
public static void LoadConfiguration() { string[] namesTmp = Enum.GetNames(typeof(KSPActionGroup)); string[] names = new string[namesTmp.Length - 1]; for (int i = 0; i < namesTmp.Length - 1; ++i) { names[i] = namesTmp[i]; } KSPActionGroup[] agTypes = new KSPActionGroup[names.Length]; actionGroupDropDown = new GUIDropDown <KSPActionGroup> [3]; for (int i = 0; i < agTypes.Length; i++) { agTypes[i] = (KSPActionGroup)Enum.Parse(typeof(KSPActionGroup), names[i]); } // straight forward, reading the (action name, action group) tuples KSP.IO.PluginConfiguration config = FARDebugAndSettings.config; for (int i = 0; i < ACTION_COUNT; ++i) { try { id2actionGroup[i] = (KSPActionGroup)Enum.Parse(typeof(KSPActionGroup), config.GetValue(configKeys[i], id2actionGroup[i].ToString()));; currentGuiStrings[i] = id2actionGroup[i].ToString(); // don't forget to initialize the gui FARLogger.Info(String.Format("Loaded AG {0} as {1}", configKeys[i], id2actionGroup[i])); } catch (Exception e) { FARLogger.Warning("Error reading config key '" + configKeys[i] + "' with value '" + config.GetValue(configKeys[i], "n/a") + "' gave " + e.ToString()); } int initIndex = 0; for (int j = 0; j < agTypes.Length; j++) { if (id2actionGroup[i] == agTypes[j]) { initIndex = j; break; } } GUIDropDown <KSPActionGroup> dropDown = new GUIDropDown <KSPActionGroup>(names, agTypes, initIndex); actionGroupDropDown[i] = dropDown; } }
private Bounds SetBoundsFromMeshes() { if (meshDataList.Count == 0) { // If the mesh is empty, try rebuilding it. This can happen when a part was added to the editor but not // the ship before adding it to the ship RebuildAllMeshData(); } Vector3 upper = Vector3.one * float.NegativeInfinity, lower = Vector3.one * float.PositiveInfinity; foreach (GeometryMesh geoMesh in meshDataList) { if (!geoMesh.valid) { continue; } upper = Vector3.Max(upper, geoMesh.bounds.max); lower = Vector3.Min(lower, geoMesh.bounds.min); } var overallBounds = new Bounds((upper + lower) * 0.5f, upper - lower); float tmpTestBounds = overallBounds.center.x + overallBounds.center.y + overallBounds.center.z + overallBounds.extents.x + overallBounds.extents.y + overallBounds.extents.z; if (float.IsNaN(tmpTestBounds) || float.IsInfinity(tmpTestBounds)) { FARLogger.Info("Overall bounds error in " + part.partInfo.title + " " + meshDataList.Count + " meshes"); Valid = false; } else { Valid = true; } return(overallBounds); }
public StockProcFairingGeoUpdater(ModuleProceduralFairing fairing, GeometryPartModule geoModule) { this.fairing = fairing; this.geoModule = geoModule; if (validParts == null) { FARLogger.Info("Fairing event setup"); validParts = new Dictionary <Part, GeometryPartModule>(); GameEvents.onFairingsDeployed.Add(FairingDeployGeometryUpdate); } validParts.Add(geoModule.part, geoModule); if (HighLogic.LoadedSceneIsEditor) { prevPanelBounds = new List <Bounds>(); } }
private void FixedUpdate() { if (EditorLogic.RootPart != null) { if (_vehicleAero.CalculationCompleted) { _vehicleAero.UpdateSonicDragArea(); LEGACY_UpdateWingAeroModels(EditorLogic.SortedShipList.Count != prevPartCount || partMovement); prevPartCount = EditorLogic.SortedShipList.Count; voxelWatch.Stop(); FARLogger.Info("Voxelization Time (ms): " + voxelWatch.ElapsedMilliseconds); voxelWatch.Reset(); _simManager.UpdateAeroData(_vehicleAero, _wingAerodynamicModel); UpdateCrossSections(); foreach (IDesignConcern designConcern in _customDesignConcerns) { designConcern.Test(); } editorReportUpdate.Invoke(EngineersReport.Instance, null); } if (_updateRateLimiter < FARSettingsScenarioModule.VoxelSettings.minPhysTicksPerUpdate) { _updateRateLimiter++; } else if (VoxelizationUpdateQueued) { string shipname = EditorLogic.fetch.ship.shipName ?? "unknown ship"; FARLogger.Info("Updating " + shipname); RecalculateVoxel(); } } else { VoxelizationUpdateQueued = true; _updateRateLimiter = FARSettingsScenarioModule.VoxelSettings.minPhysTicksPerUpdate - 2; } }
public void Rebuild() { FARLogger.Info("Rebuilding visual voxel mesh..."); Clear(false); int submeshes = m_debugVoxels.Count / MAX_VOXELS_PER_SUBMESH + 1; FARLogger.Info("Voxel mesh contains " + m_debugVoxels.Count + " voxels in " + submeshes + " submeshes"); SetupSubmeshes(submeshes); int indexOffset = 0; for (int i = 0; i < submeshes; i++) { for (int j = i * MAX_VOXELS_PER_SUBMESH; j < Math.Min((i + 1) * MAX_VOXELS_PER_SUBMESH, m_debugVoxels.Count); j++) { m_debugVoxels[j].AddToMesh(m_submeshes[i].Vertices, m_submeshes[i].Uvs, m_submeshes[i].Triangles, indexOffset); } m_submeshes[i].Rebuild(); } FARLogger.Info("Finished rebuilding visual voxel mesh."); }
private void OnDisplayList(int id) { GUI.BringWindowToFront(id); scrollPos = GUILayout.BeginScrollView(scrollPos, GUIDropDownStyles.List); for (int i = 0; i < stringOptions.Length; i++) { // Highlight the selected item GUIStyle tmpStyle = selectedOption == i ? GUIDropDownStyles.SelectedItem : GUIDropDownStyles.DropDownItem; if (!GUILayout.Button(stringOptions[i], tmpStyle)) { continue; } FARLogger.Info("Selected " + stringOptions[i]); selectedOption = i; HideList(); } GUILayout.EndScrollView(); }
public void Rebuild() { FARLogger.Info("Rebuilding visual voxel mesh..."); Clear(); int meshes = DebugVoxels.Count / MaxVoxelsPerSubmesh + 1; FARLogger.Info("Voxel mesh contains " + DebugVoxels.Count + " voxels in " + meshes + " submeshes"); SetupSubmeshes(meshes); for (int i = 0; i < meshes; i++) { for (int j = i * MaxVoxelsPerSubmesh; j < Math.Min((i + 1) * MaxVoxelsPerSubmesh, DebugVoxels.Count); j++) { DebugVoxels[j].AddToMesh(submeshes[i].Vertices, submeshes[i].Uvs, submeshes[i].Triangles); } submeshes[i].Rebuild(); } FARLogger.Info("Finished rebuilding visual voxel mesh."); }
public void PrintToConsole() { StringBuilder MatrixDump = new StringBuilder(); for (int j = 0; j < n; j++) { MatrixDump.Append("["); for (int i = 0; i < m; i++) { MatrixDump.Append(matrix[i, j]); if (i < m - 1) { MatrixDump.Append(","); } else { MatrixDump.Append("]\n\r"); } } } FARLogger.Info(MatrixDump.ToString()); }
private void Start() { FARLogger.Info("Initiating RealChuteLite Chute Property Calculation"); foreach (AvailablePart part in PartLoader.Instance.loadedParts) { Part prefab = part.partPrefab; if (prefab != null && prefab.Modules.Contains <RealChuteFAR>()) { //Updates the part's GetInfo. RealChuteFAR module = prefab.Modules.GetModule <RealChuteFAR>(); DragCubeSystem.Instance.LoadDragCubes(prefab); DragCube semi = prefab.DragCubes.Cubes.Find(c => c.Name == "SEMIDEPLOYED"), deployed = prefab.DragCubes.Cubes.Find(c => c.Name == "DEPLOYED"); if (semi == null || deployed == null) { FARLogger.Info("" + part.title + " cannot find drag cube for RealChuteLite"); } module.preDeployedDiameter = GetApparentDiameter(semi); module.deployedDiameter = GetApparentDiameter(deployed); part.moduleInfos.Find(m => m.moduleName == "RealChute").info = module.GetInfo(); } } }
private Bounds SetBoundsFromMeshes() { Vector3 upper = Vector3.one * float.NegativeInfinity, lower = Vector3.one * float.PositiveInfinity; foreach (GeometryMesh geoMesh in meshDataList) { if (!geoMesh.valid) { continue; } upper = Vector3.Max(upper, geoMesh.bounds.max); lower = Vector3.Min(lower, geoMesh.bounds.min); } var overallBounds = new Bounds((upper + lower) * 0.5f, upper - lower); float tmpTestBounds = overallBounds.center.x + overallBounds.center.y + overallBounds.center.z + overallBounds.extents.x + overallBounds.extents.y + overallBounds.extents.z; if (float.IsNaN(tmpTestBounds) || float.IsInfinity(tmpTestBounds)) { FARLogger.Info("Overall bounds error in " + part.partInfo.title + " " + meshDataList.Count + " meshes"); Valid = false; } else { Valid = true; } return(overallBounds); }
public GraphData RunTransientSimLateral(StabilityDerivOutput vehicleData, double endTime, double initDt, double[] InitCond) { SimMatrix A = new SimMatrix(4, 4); A.PrintToConsole(); int i = 0; int j = 0; int num = 0; double[] 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; for (int k = 0; k < Derivs.Length; k++) { double f = Derivs[k]; if (num < 15) { num++; //Avoid Ix, Iy, Iz and long derivs continue; } else { num++; } FARLogger.Info("" + i + "," + j); if (i <= 2) { A.Add(f, i, j); } if (j < 2) { j++; } else { j = 0; i++; } } A.Add(_instantCondition.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 ] * * */ 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); }
public void LoadAssets() { FARLogger.Info("Loading shader bundle"); MainThread.StartCoroutine(Load); }
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 StabilityDerivOutput CalculateStabilityDerivs( CelestialBody body, double alt, double machNumber, int flapSetting, bool spoilers, double alpha, double beta, double phi ) { GasProperties properties = FARAtmosphere.GetGasProperties(body, new Vector3d(0, 0, alt), Planetarium.GetUniversalTime()); double pressure = properties.Pressure; double temperature = properties.Temperature; double density = properties.Density; double sspeed = properties.SpeedOfSound; 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; FARWingAerodynamicModel 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); }
private List <MeshData> CreateMeshListFromTransforms(ref List <Transform> meshTransforms) { 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); } Bounds rendererBounds = this.part.GetPartOverallMeshBoundsInBasis(part.partTransform.worldToLocalMatrix); Bounds colliderBounds = this.part.GetPartColliderBoundsInBasis(part.partTransform.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; } meshList.Add(md); validTransformList.Add(t); cantUseColliders = false; } } if (part.Modules.Contains <ModuleJettison>()) { List <ModuleJettison> jettisons = part.Modules.GetModules <ModuleJettison>(); HashSet <Transform> jettisonTransforms = new HashSet <Transform>(); for (int i = 0; i < jettisons.Count; i++) { ModuleJettison j = jettisons[i]; if (j.jettisonTransform == null) { continue; } jettisonTransforms.Add(j.jettisonTransform); if (j.isJettisoned) { continue; } Transform t = j.jettisonTransform; if (t.gameObject.activeInHierarchy == false) { continue; } MeshData md = GetVisibleMeshData(t, false); if (md == null) { continue; } 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)) { continue; } MeshData md = GetVisibleMeshData(t, false); if (md == null) { continue; } 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, false); if (md == null) { continue; } meshList.Add(md); validTransformList.Add(t); } } } meshTransforms = validTransformList; return(meshList); }
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(); } if (_updateRateLimiter < FARSettingsScenarioModule.VoxelSettings.minPhysTicksPerUpdate) //this has been updated recently in the past; queue an update and return { _updateQueued = true; return; } else //last update was far enough in the past to run; reset rate limit counter and clear the queued flag { _updateRateLimiter = 0; _updateQueued = false; } if (vessel.rootPart.Modules.Contains <LaunchClamp>())// || _vessel.rootPart.Modules.Contains("KerbalEVA")) { DisableModule(); return; } if (recalcGeoModules) { _currentGeoModules.Clear(); geoModulesReady = 0; for (int i = 0; i < vessel.Parts.Count; i++) { Part p = vessel.Parts[i]; GeometryPartModule g = p.Modules.GetModule <GeometryPartModule>(); if ((object)g != null) { _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 (FARThreading.VoxelizationThreadpool.RunInMainThread) { for (int i = _currentGeoModules.Count - 1; i >= 0; --i) { if (!_currentGeoModules[i].Ready) { _updateRateLimiter = FARSettingsScenarioModule.VoxelSettings.minPhysTicksPerUpdate - 2; _updateQueued = true; return; } } } _voxelCount = VoxelCountFromType(); if (!_vehicleAero.TryVoxelUpdate(vessel.vesselTransform.worldToLocalMatrix, vessel.vesselTransform.localToWorldMatrix, _voxelCount, vessel.Parts, _currentGeoModules, !setup)) { _updateRateLimiter = FARSettingsScenarioModule.VoxelSettings.minPhysTicksPerUpdate - 2; _updateQueued = true; } if (!_updateQueued) { setup = true; } FARLogger.Info("Updating vessel voxel for " + vessel.vesselName); }
public StabilityDerivExportOutput 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; StabilityDerivOutput stabDerivOutput = new StabilityDerivOutput(); StabilityDerivExportVariables stabDerivExport = new StabilityDerivExportVariables(); 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.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; 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.SelectedSearchMethod(machNumber, _instantCondition.FunctionIterateForAlpha); 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 // 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, 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); // 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, 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; // 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, 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 // Assign values to export variables stabDerivExport.craftmass = mass; stabDerivExport.envpressure = pressure; stabDerivExport.envtemperature = temperature; stabDerivExport.envdensity = density; stabDerivExport.envsoundspeed = sspeed; stabDerivExport.envg = _instantCondition.CalculateAccelerationDueToGravity(body, alt); stabDerivExport.sitmach = machNumber; stabDerivExport.sitdynpres = q; stabDerivExport.siteffg = effectiveG; return(new StabilityDerivExportOutput(stabDerivOutput, stabDerivExport)); }
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"); }
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 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); }
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); }
private List <MeshData> CreateMeshListFromTransforms(ref List <Transform> meshTransforms) { DebugClear(); var meshList = new List <MeshData>(); var 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); } Matrix4x4 worldToLocalMatrix = part.partTransform.worldToLocalMatrix; Bounds rendererBounds = part.GetPartOverallMeshBoundsInBasis(worldToLocalMatrix); Bounds 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>(); var jettisonTransforms = new HashSet <string>(); foreach (ModuleJettison j in jettisons) { if (j.jettisonTransform == null) { continue; } if (variants) { // with part variants, jettison name is a comma separated list of transform names foreach (string transformName in j.jettisonName.Split(',')) { jettisonTransforms.Add(transformName); } } 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) { 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) { 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 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); }