diff --git a/Source/Orts.Simulation/Simulation/RollingStocks/SubSystems/PowerTransmissions/Axle.cs b/Source/Orts.Simulation/Simulation/RollingStocks/SubSystems/PowerTransmissions/Axle.cs
index b59fa7afde..c394fe796f 100644
--- a/Source/Orts.Simulation/Simulation/RollingStocks/SubSystems/PowerTransmissions/Axle.cs
+++ b/Source/Orts.Simulation/Simulation/RollingStocks/SubSystems/PowerTransmissions/Axle.cs
@@ -281,23 +281,105 @@ public void Restore(BinaryReader inf)
AxleList[i].Restore(inf);
}
}
+
+ ///
+ /// switch between Polach and Pacha adhesion calculation
+ ///
+ public static bool UsePolachAdhesion = false; // "static" so there's only one value in the program.
+ public bool PreviousUsePolachAdhesion = false; // Keep a note for each Axles so that we can tell if it changed.
+
///
/// Updates each axle on the list
///
- /// Time span within the simulation cycle
- public void Update(float elapsedClockSeconds)
+ /// Time span within the simulation cycle
+ public void Update(float elapsedSeconds)
{
+ UsePolachAdhesion = AdhesionPrecision.IsPrecisionHigh(this, elapsedSeconds, Car.Simulator.GameTime);
foreach (var axle in AxleList)
{
- axle.Update(elapsedClockSeconds);
+ if (UsePolachAdhesion != PreviousUsePolachAdhesion) // There's been a transition
+ {
+ axle.AxleSpeedMpS = axle.TrainSpeedMpS; // So the transition doesn't cause a wheelslip
+ }
+ axle.Update(elapsedSeconds);
}
+ PreviousUsePolachAdhesion = UsePolachAdhesion;
}
public List.Enumerator GetEnumerator()
{
return AxleList.GetEnumerator();
}
- }
+ static class AdhesionPrecision // "static" so all "Axles" share the same level of precision
+ {
+ enum AdhesionPrecisionLevel
+ {
+ ///
+ /// Initial level uses Polach algorithm
+ ///
+ High = 0,
+ ///
+ /// Low-performance PCs use Pacha's algorithm
+ ///
+ Low = 1,
+ ///
+ /// After frequent transitions, low-performance PCs are locked to Pacha's algorithm
+ ///
+ LowLocked = 2
+ }
+
+ // Adjustable limits
+ const float LowerLimitS = 0.025f; // timespan 0.025 = 40 fps screen rate, low timeSpan and high FPS
+ const float UpperLimitS = 0.033f; // timespan 0.033 = 30 fps screen rate, high timeSpan and low FPS
+ const double IntervalBetweenDowngradesLimitS = 5 * 60; // Locks in low precision if < 5 mins between downgrades
+
+ static AdhesionPrecisionLevel PrecisionLevel = AdhesionPrecisionLevel.High;
+ static double TimeOfLatestDowngrade = 0 - IntervalBetweenDowngradesLimitS; // Starts at -5 mins
+
+ // Tested by dropping the framerate below 30 fps interactively. Did this by opening and closing the HelpWindow after inserting
+ // Threading.Thread.Sleep(40);
+ // into HelpWindow.PrepareFrame() temporarily.
+ public static bool IsPrecisionHigh(Axles axles, float elapsedSeconds, double gameTime)
+ {
+ // 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;
+ var timeSincePreviousDowngradeS = gameTime - TimeOfLatestDowngrade;
+ if (timeSincePreviousDowngradeS < IntervalBetweenDowngradesLimitS)
+ {
+ Trace.TraceInformation($"At {gameTime:F0} secs, advanced adhesion model switched to low precision permanently after {timeSincePreviousDowngradeS:F0} secs since previous switch (less than limit of {IntervalBetweenDowngradesLimitS})");
+ PrecisionLevel = AdhesionPrecisionLevel.LowLocked;
+ }
+ else
+ {
+ TimeOfLatestDowngrade = gameTime;
+ Trace.TraceInformation($"At {gameTime:F0} secs, advanced adhesion model switched to low precision after low frame rate {screenFrameRate:F1} below limit {1 / UpperLimitS:F0}");
+ PrecisionLevel = AdhesionPrecisionLevel.Low;
+ }
+ }
+ break;
+
+ case AdhesionPrecisionLevel.Low:
+ if (elapsedSeconds > 0 // When debugging step by step, elapsedSeconds == 0, so test for that
+ && elapsedSeconds < LowerLimitS)
+ {
+ PrecisionLevel = AdhesionPrecisionLevel.High;
+ var ScreenFrameRate = 1 / elapsedSeconds;
+ Trace.TraceInformation($"At {gameTime:F0} secs, advanced adhesion model switched to high precision after high frame rate {ScreenFrameRate:F1} above limit {1 / LowerLimitS:F0}");
+ }
+ break;
+
+ case AdhesionPrecisionLevel.LowLocked:
+ break;
+ }
+ return (PrecisionLevel == AdhesionPrecisionLevel.High);
+ }
+ }
+ }
///
@@ -428,12 +510,6 @@ public float InertiaKgm2
///
float forceToAccelerationFactor;
- ///
- /// switch between Polach and Pacha adhesion calculation
- ///
- public static bool UsePolachAdhesion = false; // "static" so it's shared by all axles of the Player's loco
- public double GameTime; // Set by MSTSLocomotive and used by AdhesionPrecision.IsPrecisionHigh
-
///
/// Pre-calculation of slip characteristics at 0 slip speed
///
@@ -546,7 +622,7 @@ public float TransmissionEfficiency
///
/// Axle speed value, in metric meters per second
///
- public double AxleSpeedMpS { get; private set; }
+ public double AxleSpeedMpS { get; set; }
///
/// Axle angular position in radians
@@ -824,7 +900,7 @@ public void Save(BinaryWriter outf)
double slipSpeedMpS = axleSpeedMpS - TrainSpeedMpS;
double axleOutForceN = 0;
- if (UsePolachAdhesion)
+ if (Axles.UsePolachAdhesion)
{
axleOutForceN = Math.Sign(slipSpeedMpS) * AxleWeightN * SlipCharacteristicsPolach(slipSpeedMpS);
}
@@ -870,7 +946,7 @@ void Integrate(float elapsedClockSeconds)
if (elapsedClockSeconds <= 0) return;
double prevSpeedMpS = AxleSpeedMpS;
- if (UsePolachAdhesion)
+ if (Axles.UsePolachAdhesion)
{
float upperSubStepLimit = 100;
@@ -959,7 +1035,7 @@ void Integrate(float elapsedClockSeconds)
{
var k1 = GetAxleMotionVariation(AxleSpeedMpS, dt);
- if (i == 0 && !UsePolachAdhesion)
+ if (i == 0 && !Axles.UsePolachAdhesion)
{
if (k1.Item1 * dt > Math.Max((Math.Abs(SlipSpeedMpS) - 1) * 10, 1) / 100)
{
@@ -1002,8 +1078,7 @@ void Integrate(float elapsedClockSeconds)
///
public virtual void Update(float elapsedSeconds)
{
- UsePolachAdhesion = AdhesionPrecision.IsPrecisionHigh(elapsedSeconds, GameTime);
- if (UsePolachAdhesion)
+ if (Axles.UsePolachAdhesion)
{
forceToAccelerationFactor = WheelRadiusM * WheelRadiusM / totalInertiaKgm2;
@@ -1098,79 +1173,6 @@ public virtual void Update(float elapsedSeconds)
}
}
- static class AdhesionPrecision // "static" so all "Axle"s share the same level of precision
- {
- enum AdhesionPrecisionLevel
- {
- ///
- /// Initial level uses Polach algorithm
- ///
- High = 0,
- ///
- /// Low-performance PCs use Pacha's algorithm
- ///
- Low = 1,
- ///
- /// After frequent transitions, low-performance PCs are locked to Pacha's algorithm
- ///
- LowLocked = 2
- }
-
- // Adjustable limits
- const float LowerLimitS = 0.025f; // timespan 0.025 = 40 fps screen rate, low timeSpan and high FPS
- const float UpperLimitS = 0.033f; // timespan 0.033 = 30 fps screen rate, high timeSpan and low FPS
- const double IntervalBetweenDowngradesLimitS = 5 * 60; // Locks in low precision if < 5 mins between downgrades
-
- static AdhesionPrecisionLevel PrecisionLevel = AdhesionPrecisionLevel.High;
- static double TimeOfLatestDowngrade = 0 - IntervalBetweenDowngradesLimitS; // Starts at -5 mins
-
- // 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, double gameTime)
- {
- // 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;
- var timeSincePreviousDowngradeS = gameTime - TimeOfLatestDowngrade;
- if (timeSincePreviousDowngradeS < IntervalBetweenDowngradesLimitS)
- {
- Trace.TraceInformation($"At {gameTime:F0} secs, advanced adhesion model switched to low precision permanently after {timeSincePreviousDowngradeS:F0} secs since previous switch (less than limit of {IntervalBetweenDowngradesLimitS})");
- PrecisionLevel = AdhesionPrecisionLevel.LowLocked;
- }
- else
- {
- TimeOfLatestDowngrade = gameTime;
-
- Trace.TraceInformation($"At {gameTime:F0} secs, advanced adhesion model switched to low precision after low frame rate {screenFrameRate:F1} below limit {1 / UpperLimitS:F0}");
- PrecisionLevel = AdhesionPrecisionLevel.Low;
-
- }
- }
- break;
-
- case AdhesionPrecisionLevel.Low:
- if (elapsedSeconds > 0 // When debugging step by step, elapsedSeconds == 0, so test for that
- && elapsedSeconds < LowerLimitS)
- {
- PrecisionLevel = AdhesionPrecisionLevel.High;
- var ScreenFrameRate = 1 / elapsedSeconds;
- Trace.TraceInformation($"At {gameTime:F0} secs, advanced adhesion model switched to high precision after high frame rate {ScreenFrameRate:F1} above limit {1 / LowerLimitS:F0}");
- }
- break;
-
- case AdhesionPrecisionLevel.LowLocked:
- break;
-
- }
- return (PrecisionLevel == AdhesionPrecisionLevel.High);
- }
- }
-
class PolachCalculator
{
Axle Axle;
diff --git a/Source/RunActivity/Viewer3D/Popups/HUDWindow.cs b/Source/RunActivity/Viewer3D/Popups/HUDWindow.cs
index 521172d820..4611d83f2b 100644
--- a/Source/RunActivity/Viewer3D/Popups/HUDWindow.cs
+++ b/Source/RunActivity/Viewer3D/Popups/HUDWindow.cs
@@ -1080,7 +1080,7 @@ void TextPageForceInfo(TableData table)
if (mstsLocomotive.AdvancedAdhesionModel)
{
var text = Viewer.Catalog.GetString("(Advanced adhesion model)");
- if (Axle.UsePolachAdhesion == false) text += "???";
+ if (Axles.UsePolachAdhesion == false) text += "???";
TableAddLine(table, text);
int row0 = table.CurrentRow;
TableSetCell(table, table.CurrentRow++, table.CurrentLabelColumn, Viewer.Catalog.GetString("Wheel slip (Thres)"));