Skip to content

Commit fac2ae2

Browse files
authored
Fix survival chance per timestep calculation (#287)
TF consistently interprets the 'momentary failure rate' curve as 'instantaneous hazard rate' - the proportional failure rate of systems still working at the current time - for display purposes (e.g. the 'Reliability' and 'MTBF' displays are calculated as if it is the hazard rate). However, the conversion to a failure chance per update cycle wasn't done correctly, and the actual failure rate over time didn't match the instantaneous MTBF when the failure rate is not constant. Now, the cycle reliability curve directly specifies the hazard rate h(t) (which is the same as the 'failure rate' λ(t)), and the chance to fail over a timestep Δt is h(t)*Δt.
1 parent c6c1fa0 commit fac2ae2

File tree

1 file changed

+7
-16
lines changed

1 file changed

+7
-16
lines changed

TestFlightAPI/TestFlightAPI/TestFlightReliability.cs

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ public class TestFlightReliabilityBase : PartModule, ITestFlightReliability
1818
public FloatCurve reliabilityCurve;
1919
[KSPField(isPersistant=true)]
2020
public float lastCheck = 0;
21-
[KSPField(isPersistant=true)]
22-
public float lastReliability = 1.0f;
2321

2422

2523
public List<ConfigNode> configs = new List<ConfigNode>();
@@ -173,6 +171,7 @@ public override void OnUpdate()
173171
if (operatingTime < lastCheck + 1f)
174172
return;
175173

174+
double timestep = operatingTime - lastCheck;
176175
lastCheck = operatingTime;
177176
double baseFailureRate = core.GetBaseFailureRate();
178177
MomentaryFailureRate momentaryFailureRate = core.GetWorstMomentaryFailureRate();
@@ -183,19 +182,11 @@ public override void OnUpdate()
183182
else
184183
currentFailureRate = baseFailureRate;
185184

186-
// Given we have been operating for a given number of seconds, calculate our chance of survival to that time based on currentFailureRate
187-
// This is *not* an exact science, as the real calculations are much more complex than this, plus technically the momentary rate for
188-
// *each* second should be accounted for, but this is a simplification of the system. It provides decent enough numbers for fun gameplay
189-
// with chance of failure increasing exponentially over time as it approaches the *current* MTBF
190-
// S() is survival chance, f is currentFailureRate
191-
// S(t) = e^(-f*t)
192-
193-
float reliability = Mathf.Exp((float)-currentFailureRate * (float)operatingTime);
194-
// double survivalChance = Mathf.Pow(Mathf.Exp(1), (float)currentFailureRate * (float)operatingTime * -0.693f);
195-
double survivalChance = reliability / lastReliability;
196-
lastReliability = reliability;
197-
// float failureRoll = Mathf.Min(UnityEngine.Random.Range(0f, 1f), UnityEngine.Random.Range(0f, 1f));
198-
// float failureRoll = UnityEngine.Random.Range(0f, 1f);
185+
// The momentary failure rate, as implemented in TF, is more accurately called the 'hazard rate', h(t). This is defined as the
186+
// proportional failure rate of systems still functioning at time t.
187+
// For a working system at time t and a small interval dt, the chance to fail in the next dt seconds is approximately h(t)*dt; this
188+
// approximation is exact in the limit where dt goes to 0.
189+
double survivalChance = 1 - currentFailureRate * timestep;
199190
double failureRoll = core.RandomGenerator.NextDouble();
200191
if (verboseDebugging)
201192
{
@@ -206,7 +197,7 @@ public override void OnUpdate()
206197
// Debug.Log(String.Format("TestFlightReliability: Survival Chance at Time {0:F2} is {1:f4} -- {2:f4}^({3:f4}*{0:f2}*-1.0)", (float)operatingTime, survivalChance, Mathf.Exp(1), (float)currentFailureRate));
207198
if (verboseDebugging)
208199
{
209-
Log($"Part has failed after {operatingTime:F1} secodns of operation at MET T+{vessel.missionTime:F2} seconds with roll of {failureRoll:F4}");
200+
Log($"Part has failed after {operatingTime:F1} seconds of operation at MET T+{vessel.missionTime:F2} seconds with roll of {failureRoll:F4}");
210201
}
211202
core.TriggerFailure();
212203
}

0 commit comments

Comments
 (0)