Skip to content

Commit

Permalink
Fix PVG with upper stage solids (Castor 30XL)
Browse files Browse the repository at this point in the history
- Adds a new MaxThrust field to the stage stats display

This is computed as the MaxThrust of all the engines burning
at the end of the stage.  This is deliberately to avoid counting
ullage solids that burnout after a few seconds.  It may, however,
be viewed as being slightly misleading.  But the purpose of this
field is really for PVG to have a single number for the thrust of the
stage which is more realistic than the current behavior where it
gets the initial thrust of the engine including the thrust curve.

- Converts PVG to use MaxThrust + ISP + MassDelta to get total
burntime instead of the other way around.  PVGs computed burntime
for a Castor 30 XL is now 2mins instead of 8 mins.

- The displayed burntime, TWRs and SLTs are still wildly off, those
need to be fixed more deeply in the code which analyzes the
engine and produces the mass flow rate at conditions.

Signed-off-by: Lamont Granquist <[email protected]>
  • Loading branch information
lamont-granquist committed Apr 15, 2022
1 parent d849f6b commit 45dd09a
Show file tree
Hide file tree
Showing 10 changed files with 134 additions and 113 deletions.
1 change: 1 addition & 0 deletions Localization/en-us.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -1021,6 +1021,7 @@ Localization
#MechJeb_InfoItems_StatsColumn10 = Atmo ΔV
#MechJeb_InfoItems_StatsColumn11 = Vac ΔV
#MechJeb_InfoItems_StatsColumn12 = Time
#MechJeb_InfoItems_StatsColumn13 = Max Thrust


//Ascent Path Editor
Expand Down
26 changes: 13 additions & 13 deletions MechJeb2/CachedLocalizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,11 @@ public class CachedLocalizer : MonoBehaviour
public string MechJeb_InfoItems_StatsColumn0;
public string MechJeb_InfoItems_StatsColumn1, MechJeb_InfoItems_StatsColumn2, MechJeb_InfoItems_StatsColumn3, MechJeb_InfoItems_StatsColumn4, MechJeb_InfoItems_StatsColumn5;
public string MechJeb_InfoItems_StatsColumn6, MechJeb_InfoItems_StatsColumn7, MechJeb_InfoItems_StatsColumn8, MechJeb_InfoItems_StatsColumn9, MechJeb_InfoItems_StatsColumn10;
public string MechJeb_InfoItems_StatsColumn11, MechJeb_InfoItems_StatsColumn12;
public string MechJeb_InfoItems_StatsColumn11, MechJeb_InfoItems_StatsColumn12, MechJeb_InfoItems_StatsColumn13;

public string MechJeb_Ascent_title, MechJeb_WindowEd_title;
public string MechJeb_WindowEd_CustomInfoWindow_Label1;

private static WaitForSeconds _WaitForSeconds;
public static void Bootstrap()
{
if (Instance != null) return;
Expand Down Expand Up @@ -148,7 +147,7 @@ private void UpdateCachedStrings()
MechJeb_Ascent_status9 = Localizer.Format("#MechJeb_Ascent_status9");
MechJeb_Ascent_status10 = Localizer.Format("#MechJeb_Ascent_status10");
MechJeb_Ascent_status11 = Localizer.Format("#MechJeb_Ascent_status11");


MechJeb_Ascent_attachAlt = Localizer.Format("#MechJeb_Ascent_attachAlt");
MechJeb_Ascent_warnAttachAltHigh = Localizer.Format("#MechJeb_Ascent_warnAttachAltHigh");
Expand All @@ -170,19 +169,20 @@ private void UpdateCachedStrings()
MechJeb_InfoItems_button5 = Localizer.Format("#MechJeb_InfoItems_button5");
MechJeb_InfoItems_button6 = Localizer.Format("#MechJeb_InfoItems_button6");

MechJeb_InfoItems_StatsColumn0 = Localizer.Format("#MechJeb_InfoItems_StatsColumn0");
MechJeb_InfoItems_StatsColumn1 = Localizer.Format("#MechJeb_InfoItems_StatsColumn1");
MechJeb_InfoItems_StatsColumn2 = Localizer.Format("#MechJeb_InfoItems_StatsColumn2");
MechJeb_InfoItems_StatsColumn3 = Localizer.Format("#MechJeb_InfoItems_StatsColumn3");
MechJeb_InfoItems_StatsColumn4 = Localizer.Format("#MechJeb_InfoItems_StatsColumn4");
MechJeb_InfoItems_StatsColumn5 = Localizer.Format("#MechJeb_InfoItems_StatsColumn5");
MechJeb_InfoItems_StatsColumn6 = Localizer.Format("#MechJeb_InfoItems_StatsColumn6");
MechJeb_InfoItems_StatsColumn7 = Localizer.Format("#MechJeb_InfoItems_StatsColumn7");
MechJeb_InfoItems_StatsColumn8 = Localizer.Format("#MechJeb_InfoItems_StatsColumn8");
MechJeb_InfoItems_StatsColumn9 = Localizer.Format("#MechJeb_InfoItems_StatsColumn9");
MechJeb_InfoItems_StatsColumn0 = Localizer.Format("#MechJeb_InfoItems_StatsColumn0");
MechJeb_InfoItems_StatsColumn1 = Localizer.Format("#MechJeb_InfoItems_StatsColumn1");
MechJeb_InfoItems_StatsColumn2 = Localizer.Format("#MechJeb_InfoItems_StatsColumn2");
MechJeb_InfoItems_StatsColumn3 = Localizer.Format("#MechJeb_InfoItems_StatsColumn3");
MechJeb_InfoItems_StatsColumn4 = Localizer.Format("#MechJeb_InfoItems_StatsColumn4");
MechJeb_InfoItems_StatsColumn5 = Localizer.Format("#MechJeb_InfoItems_StatsColumn5");
MechJeb_InfoItems_StatsColumn6 = Localizer.Format("#MechJeb_InfoItems_StatsColumn6");
MechJeb_InfoItems_StatsColumn7 = Localizer.Format("#MechJeb_InfoItems_StatsColumn7");
MechJeb_InfoItems_StatsColumn8 = Localizer.Format("#MechJeb_InfoItems_StatsColumn8");
MechJeb_InfoItems_StatsColumn9 = Localizer.Format("#MechJeb_InfoItems_StatsColumn9");
MechJeb_InfoItems_StatsColumn10 = Localizer.Format("#MechJeb_InfoItems_StatsColumn10");
MechJeb_InfoItems_StatsColumn11 = Localizer.Format("#MechJeb_InfoItems_StatsColumn11");
MechJeb_InfoItems_StatsColumn12 = Localizer.Format("#MechJeb_InfoItems_StatsColumn12");
MechJeb_InfoItems_StatsColumn13 = Localizer.Format("#MechJeb_InfoItems_StatsColumn13");

MechJeb_InfoItems_showEmpty = Localizer.Format("#MechJeb_InfoItems_showEmpty");
MechJeb_InfoItems_hideEmpty = Localizer.Format("#MechJeb_InfoItems_hideEmpty");
Expand Down
22 changes: 16 additions & 6 deletions MechJeb2/FuelFlowSimulation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,12 +123,7 @@ private FuelStats SimulateStage(float throttle, double staticPressure, double at
fuelStats.MaxAccel = fuelStats.EndMass > 0 ? fuelStats.EndThrust / fuelStats.EndMass : 0;
fuelStats.DeltaTime = 0;
fuelStats.DeltaV = 0;

// track active engines to "fingerprint" this stage
// (could improve by adding fuel tanks being drained and thereby support drop-tanks)
fuelStats.Parts = new List<Part>();
List<FuelNode> engines = FindActiveEngines().value;
for (int i = 0; i < engines.Count; i++) fuelStats.Parts.Add(_partLookup[engines[i]]);
fuelStats.MaxThrust = MaxThrust();

const int MAX_STEPS = 100;

Expand Down Expand Up @@ -200,6 +195,7 @@ private FuelStats SimulateTimeStep(double desiredDt, float throttle, double stat
fuelStats.EndMass = VesselMass(_simStage);
fuelStats.ResourceMass = fuelStats.StartMass - fuelStats.EndMass;
fuelStats.MaxAccel = fuelStats.EndMass > 0 ? fuelStats.EndThrust / fuelStats.EndMass : 0;
fuelStats.MaxThrust = MaxThrust();
fuelStats.ComputeTimeStepDeltaV();
fuelStats.Isp = fuelStats.StartMass > fuelStats.EndMass
? fuelStats.DeltaV / (9.80665f * Math.Log(fuelStats.StartMass / fuelStats.EndMass))
Expand Down Expand Up @@ -323,6 +319,20 @@ private double VesselMass(int stage)
return sum;
}

private double MaxThrust()
{
double maxThrust = 0;

using Disposable<List<FuelNode>> activeEngines = FindActiveEngines();

for (int i = 0; i < activeEngines.value.Count; i++)
{
maxThrust += activeEngines.value[i].maxThrust;
}

return maxThrust;
}

private double VesselThrustAndSpoolup(out double sumSpoolup)
{
double sumThrust = 0;
Expand Down
26 changes: 17 additions & 9 deletions MechJeb2/FuelNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,14 @@ private readonly struct EngineInfo
public readonly Vector3d thrustVector;
public readonly double moduleResiduals;
public readonly double moduleSpoolupTime;
public readonly double maxThrust;

public EngineInfo(ModuleEngines engineModule)
{
this.engineModule = engineModule;

maxThrust = engineModule.maxThrust;

thrustVector = Vector3d.zero;

for (int i = 0; i < engineModule.thrustTransforms.Count; i++)
Expand Down Expand Up @@ -102,14 +105,15 @@ public EngineInfo(ModuleEngines engineModule)

private readonly List<FuelNode> crossfeedSources = new List<FuelNode>();

public int decoupledInStage; //the stage in which this part will be decoupled from the rocket
public int inverseStage; //stage in which this part is activated
public bool isLaunchClamp; //whether this part is a launch clamp
public bool isSepratron; //whether this part is a sepratron
public bool isEngine; //whether this part is an engine
public bool isthrottleLocked;
public bool activatesEvenIfDisconnected;
public bool isDrawingResources = true; // Is the engine actually using any resources
public int decoupledInStage; //the stage in which this part will be decoupled from the rocket
public int inverseStage; //stage in which this part is activated
public bool isLaunchClamp; //whether this part is a launch clamp
public bool isSepratron; //whether this part is a sepratron
public bool isEngine; //whether this part is an engine
public bool isthrottleLocked;
public bool activatesEvenIfDisconnected;
public bool isDrawingResources = true; // Is the engine actually using any resources
public double maxThrust;

private double resourceRequestRemainingThreshold;
private int resourcePriority;
Expand Down Expand Up @@ -300,9 +304,13 @@ private void Init(Part part, bool dVLinearThrust)
engineInfos.Add(new EngineInfo(e));
}

maxThrust = 0;
// find our max maxEngineResiduals for this engine part from all the modules
foreach (EngineInfo e in engineInfos)
maxEngineResiduals = Math.Max(maxEngineResiduals, e.moduleResiduals);
{
maxEngineResiduals = Math.Max(maxEngineResiduals,e.moduleResiduals);
maxThrust += e.maxThrust;
}
}

// We are not necessarily traversing from the root part but from any interior part, so that p.parent is just another potential child node
Expand Down
7 changes: 3 additions & 4 deletions MechJeb2/FuelStats.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;

namespace MuMech
{
Expand All @@ -20,6 +19,7 @@ public struct FuelStats
public double ResourceMass;
public double Isp;
public double StagedMass;
public double MaxThrust;

public double StartTWR(double geeASL)
{
Expand All @@ -31,8 +31,6 @@ public double MaxTWR(double geeASL)
return MaxAccel / (9.80665 * geeASL);
}

public List<Part> Parts;

//Computes the deltaV from the other fields. Only valid when the thrust is constant over the time interval represented.
public void ComputeTimeStepDeltaV()
{
Expand All @@ -56,7 +54,8 @@ public FuelStats Append(FuelStats s)
MaxAccel = Math.Max(MaxAccel, s.MaxAccel),
DeltaTime = DeltaTime + (s.DeltaTime < float.MaxValue && !double.IsInfinity(s.DeltaTime) ? s.DeltaTime : 0),
DeltaV = DeltaV + s.DeltaV,
Parts = Parts,
// this is deliberately the max thrust of the last segment in order to not count burned out ullage motors
MaxThrust = s.MaxThrust > 0 ? s.MaxThrust : MaxThrust,
// ReSharper disable once CompareOfFloatsByEqualityOperator
Isp = StartMass == s.EndMass ? 0 : (DeltaV + s.DeltaV) / (9.80665f * Math.Log(StartMass / s.EndMass))
};
Expand Down
6 changes: 4 additions & 2 deletions MechJeb2/MechJebModuleInfoItems.cs
Original file line number Diff line number Diff line change
Expand Up @@ -814,6 +814,8 @@ public double CircularOrbitSpeed()
[Persistent(pass = (int)Pass.Global)]
public bool showFinalMass = false;
[Persistent(pass = (int)Pass.Global)]
public bool showMaxThrust = false;
[Persistent(pass = (int)Pass.Global)]
public bool showVacInitialTWR = true;
[Persistent(pass = (int)Pass.Global)]
public bool showAtmoInitialTWR = false; // NK
Expand Down Expand Up @@ -844,10 +846,10 @@ public double CircularOrbitSpeed()
[Persistent(pass = (int)Pass.Global)]
public bool timeSeconds = false;
private MechJebStageStatsHelper stageStatsHelper = null;

// Leave this stub here until I figure out how to properly target in the new class
[GeneralInfoItem("#MechJeb_StageStatsAll",InfoItem.Category.Vessel,showInEditor = true)]//Stage stats (all)
public void AllStageStats()
public void AllStageStats()
{
if (stageStatsHelper == null)
stageStatsHelper = new MechJebStageStatsHelper(this);
Expand Down
34 changes: 14 additions & 20 deletions MechJeb2/MechJebModuleLogicalStageTracking.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,31 +132,30 @@ public class Stage
public double DeltaV;

// burntime left in the stage in secs
public double DeltaTime;
//public double DeltaTime;

// effective isp of the stage (this is derived from the total mass loss and the total ∆v)
public double Isp;

// effective exhaust velocity of the stage
public double Ve => Isp * 9.80665;

// starting thrust of the stage
public double StartThrust;

// ending thrust (this should be the same, except for burned out ullage motors)
public double EndThrust;

// effective thrust (the "average thrust" derived from the total mdot and the v_e)
public double EffectiveThrust => Ve * (StartMass - EndMass) / DeltaTime;
//public double EffectiveThrust => Ve * (StartMass - EndMass) / DeltaTime;

// starting mass of the stage
public double StartMass;

// ending mass of the stage
public double EndMass;

// max thrust of the stage
public double MaxThrust;

public double DeltaTime => Ve * (StartMass - EndMass) / MaxThrust;

// starting acceleration of the stage (use EndThrust to avoid counting ullage motors)
private double A0 => EndThrust / StartMass;
private double A0 => MaxThrust / StartMass;

// ideal time to consume the rocket completely
public double Tau => Ve / A0;
Expand All @@ -165,7 +164,6 @@ public class Stage
public int RocketStage;

// the last parts list
private readonly List<Part> _parts = new List<Part>();

private FuelFlowSimulation.FuelStats _vacFuelStats;

Expand All @@ -176,20 +174,16 @@ public void Sync()

_vacFuelStats = _parent.core.stageStats.vacStats[KspStage];
DeltaV = _vacFuelStats.DeltaV;
DeltaTime = _vacFuelStats.DeltaTime;
Isp = _vacFuelStats.Isp;
StartThrust = _vacFuelStats.StartThrust * 1000;
EndThrust = _vacFuelStats.EndThrust * 1000;
StartMass = _vacFuelStats.StartMass * 1000;
EndMass = _vacFuelStats.EndMass * 1000;

_parts.Clear();
for (int i = 0; i < _vacFuelStats.Parts.Count; i++) _parts.Add(_vacFuelStats.Parts[i]);
//DeltaTime = _vacFuelStats.DeltaTime;
Isp = _vacFuelStats.Isp;
MaxThrust = _vacFuelStats.MaxThrust * 1000;
StartMass = _vacFuelStats.StartMass * 1000;
EndMass = _vacFuelStats.EndMass * 1000;
}

public override string ToString()
{
return "ksp_stage: " + KspStage + " rocket_stage: " + RocketStage + " isp:" + Isp + " thrust:" + StartThrust + " m0: " + StartMass +
return "ksp_stage: " + KspStage + " rocket_stage: " + RocketStage + " isp:" + Isp + " thrust:" + MaxThrust + " m0: " + StartMass +
" maxt:" + DeltaTime;
}

Expand Down
Loading

0 comments on commit 45dd09a

Please sign in to comment.