Skip to content

Commit

Permalink
Merge pull request #904 from cjakeman/fix-advanced-adhesion-downgrade…
Browse files Browse the repository at this point in the history
…-once-only

fix: adds downgrade to low precision
  • Loading branch information
cjakeman committed Dec 24, 2023
2 parents 362e836 + 71beb33 commit b90893b
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 37 deletions.
Expand Up @@ -29,6 +29,8 @@
using Orts.Simulation.RollingStocks.SubSystems.PowerTransmissions;
using SharpDX.Direct2D1;
using SharpDX.Direct3D9;
using Orts.Formats.OR;
using static Orts.Simulation.RollingStocks.SubSystems.PowerTransmissions.Axle;

namespace Orts.Simulation.RollingStocks.SubSystems.PowerTransmissions
{
Expand Down Expand Up @@ -429,7 +431,7 @@ public float InertiaKgm2
/// <summary>
/// switch between Polach and Pacha adhesion calculation
/// </summary>
bool UsePolachAdhesion = false;
public static bool UsePolachAdhesion = false; // "static" so it's shared by all axles of the Player's loco

/// <summary>
/// Pre-calculation of slip characteristics at 0 slip speed
Expand Down Expand Up @@ -996,37 +998,13 @@ void Integrate(float elapsedClockSeconds)
/// - computes axle dynamic model according to its driveType
/// - computes wheelslip indicators
/// </summary>
/// <param name="timeSpan"></param>
public virtual void Update(float timeSpan)
/// <param name="elapsedSeconds"></param>
public virtual void Update(float elapsedSeconds)
{
// Test to determine whether to use Polach or Pacha adhesion

// Switches between Polach (high performance) adhesion model and Pacha (low performance) adhesion model depending upon the PC performance
if(timeSpan < 0.025) // timespan 0.025 = 40 fps screen rate, low timeSpan and high FPS
{
UsePolachAdhesion = true;
}
else if(timeSpan > 0.033) // timespan 0.033 = 30 fps screen rate, high timeSpan and low FPS
{
UsePolachAdhesion = false;
if (TrainSpeedMpS > 0 )
{
var ScreenFrameRate = 1 / timeSpan;
Trace.TraceInformation("Advanced adhesion model switched to low performance option due to low frame rate {0} at ElapsedClockSeconds of {1}", ScreenFrameRate, timeSpan);

}

// Set values for Pacha adhesion
WheelSlipThresholdMpS = MpS.FromKpH(AdhesionK / AdhesionLimit);
WheelAdhesion = 0.99f;
MaximumPolachWheelAdhesion = 0.99f;

}

forceToAccelerationFactor = WheelRadiusM * WheelRadiusM / totalInertiaKgm2;

UsePolachAdhesion = AdhesionPrecision.IsPrecisionHigh(elapsedSeconds);
if (UsePolachAdhesion)
{
forceToAccelerationFactor = WheelRadiusM * WheelRadiusM / totalInertiaKgm2;

Polach.Update();
axleStaticForceN = AxleWeightN * SlipCharacteristicsPolach(0);
Expand All @@ -1039,6 +1017,15 @@ public virtual void Update(float timeSpan)
axleStaticForceN = AxleWeightN * SlipCharacteristicsPolach(0);
}
}
else
{
// Set values for Pacha adhesion
WheelSlipThresholdMpS = MpS.FromKpH(AdhesionK / AdhesionLimit);
WheelAdhesion = 0.99f;
MaximumPolachWheelAdhesion = 0.99f;

forceToAccelerationFactor = WheelRadiusM * WheelRadiusM / totalInertiaKgm2;
}

#if DEBUG_ADHESION
double[] spd = new double[50];
Expand All @@ -1063,9 +1050,9 @@ public virtual void Update(float timeSpan)
Console.WriteLine("");
#endif

motor?.Update(timeSpan);
motor?.Update(elapsedSeconds);

Integrate(timeSpan);
Integrate(elapsedSeconds);
// TODO: We should calculate brake force here
// Adding and substracting the brake force is correct for normal operation,
// but during wheelslip this will produce wrong results.
Expand All @@ -1084,14 +1071,14 @@ public virtual void Update(float timeSpan)
{
IsWheelSlip = IsWheelSlipWarning = true;
}
WheelSlipTimeS += timeSpan;
WheelSlipTimeS += elapsedSeconds;
}
else if (Math.Abs(SlipSpeedPercent) > SlipWarningTresholdPercent)
{
// Wait some time before indicating wheelslip to avoid false triggers
if (WheelSlipWarningTimeS > 1) IsWheelSlipWarning = true;
IsWheelSlip = false;
WheelSlipWarningTimeS += timeSpan;
WheelSlipWarningTimeS += elapsedSeconds;
}
else
{
Expand All @@ -1100,16 +1087,65 @@ public virtual void Update(float timeSpan)
WheelSlipWarningTimeS = WheelSlipTimeS = 0;
}

if (timeSpan > 0.0f)
if (elapsedSeconds > 0.0f)
{
slipDerivationMpSS = (SlipSpeedMpS - previousSlipSpeedMpS) / timeSpan;
slipDerivationMpSS = (SlipSpeedMpS - previousSlipSpeedMpS) / elapsedSeconds;
previousSlipSpeedMpS = SlipSpeedMpS;

slipDerivationPercentpS = (SlipSpeedPercent - previousSlipPercent) / timeSpan;
slipDerivationPercentpS = (SlipSpeedPercent - previousSlipPercent) / elapsedSeconds;
previousSlipPercent = SlipSpeedPercent;
}
}

static class AdhesionPrecision // "static" so all "Axle"s share the same level of precision
{
enum AdhesionPrecisionLevel
{
/// <summary>
/// Initial level uses Polach algorithm
/// </summary>
High,
/// <summary>
/// Low-performance PCs use Pacha's algorithm
/// </summary>
Low
}

static AdhesionPrecisionLevel PrecisionLevel = AdhesionPrecisionLevel.High;
static double TimeOfLatestDowngrade = 0;

// Adjustable limits
const float UpperLimitS = 0.033f; // timespan 0.033 = 30 fps screen rate, high timeSpan and low FPS

// Tested by varying the framerate interactively. Did this by opening and closing the HelpWindow after inserting
// Threading.Thread.Sleep(40);
// into HelpWindow.PrepareFrame() temporarily.
public static bool IsPrecisionHigh(float elapsedSeconds)
{
if (elapsedSeconds > 0) // Ignore period with elapsedSeconds == 0 until user starts game.
{
// Switches between Polach (high precision) adhesion model and Pacha (low precision) adhesion model depending upon the PC performance
switch (PrecisionLevel)
{
case AdhesionPrecisionLevel.High:
if (elapsedSeconds > UpperLimitS)
{
var screenFrameRate = 1 / elapsedSeconds;
{
Trace.TraceInformation($"Advanced adhesion model switched to low precision permanently after low frame rate {screenFrameRate:F1} below limit {1 / UpperLimitS:F0}");
PrecisionLevel = AdhesionPrecisionLevel.Low;
}
}
break;

case AdhesionPrecisionLevel.Low:
break;
}
}
return (PrecisionLevel == AdhesionPrecisionLevel.High);
}
}

class PolachCalculator
{
Axle Axle;
Expand Down Expand Up @@ -1200,6 +1236,7 @@ public void Update()
polach_Ks = (1.2 * zeroSpeedAdhesion) - 0.26;
if (polach_Ks < 0.1) polach_Ks = 0.1f;
}

public double SlipCharacteristics(double slipSpeedMpS)
{
var polach_uadhesion = zeroSpeedAdhesion * (((1 - polach_A) * Math.Exp(-polach_B * slipSpeedMpS)) + polach_A);
Expand Down
5 changes: 4 additions & 1 deletion Source/RunActivity/Viewer3D/Popups/HUDWindow.cs
Expand Up @@ -27,6 +27,7 @@
using Orts.Simulation.RollingStocks.SubSystems.Brakes;
using Orts.Simulation.RollingStocks.SubSystems.Brakes.MSTS;
using Orts.Simulation.RollingStocks.SubSystems.PowerSupplies;
using Orts.Simulation.RollingStocks.SubSystems.PowerTransmissions;
using Orts.Viewer3D.Processes;
using ORTS.Common;
using ORTS.Scripting.Api;
Expand Down Expand Up @@ -1078,7 +1079,9 @@ void TextPageForceInfo(TableData table)
{
if (mstsLocomotive.AdvancedAdhesionModel)
{
TableAddLine(table, Viewer.Catalog.GetString("(Advanced adhesion model)"));
var text = Viewer.Catalog.GetString("(Advanced adhesion model)");
if (Axle.UsePolachAdhesion == false) text += "???";
TableAddLine(table, text);
int row0 = table.CurrentRow;
TableSetCell(table, table.CurrentRow++, table.CurrentLabelColumn, Viewer.Catalog.GetString("Wheel slip (Thres)"));
TableSetCell(table, table.CurrentRow++, table.CurrentLabelColumn, Viewer.Catalog.GetString("Conditions"));
Expand Down
2 changes: 2 additions & 0 deletions Source/RunActivity/Viewer3D/Popups/HelpWindow.cs
Expand Up @@ -1216,6 +1216,8 @@ public TabData(Tab tab, string tabLabel, Action<ControlLayout> layout)

public override void PrepareFrame(ElapsedTime elapsedTime, bool updateFull)
{
// Uncomment this statement to reduce framerate during play for testing
//System.Threading.Thread.Sleep(40); // Press F1 to force framerate below 25 fps

base.PrepareFrame(elapsedTime, updateFull);

Expand Down

0 comments on commit b90893b

Please sign in to comment.