Skip to content

Commit 18c3e9c

Browse files
committed
Improve blended braking response when using advanced brake cylinders and dynamic brake ramp up
1 parent 12b1a74 commit 18c3e9c

File tree

3 files changed

+64
-33
lines changed

3 files changed

+64
-33
lines changed

Source/Documentation/Manual/physics.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3343,6 +3343,7 @@ the following parameters will adjust the behaviour of air brakes:
33433343
.. index::
33443344
single: DynamicBrakeHasAutoBailOff
33453345
single: ORTSDynamicBrakesHasPartialBailOff
3346+
single: ORTSDynamicBlendingRetainedPressure
33463347
single: ORTSTrainDynamicBlendingTable
33473348
single: ORTSDynamicBrakeReplacementWithEngineBrake
33483349
single: ORTSDynamicBrakeReplacementWithEngineBrakeAtSpeed
@@ -3353,6 +3354,10 @@ the following parameters will adjust the behaviour of air brakes:
33533354
air brakes are released while dynamic brakes satisfy the train brake demand.
33543355
If dynamic braking is not sufficient, air brakes will be partially applied
33553356
so the combination air+dynamic provides the required brake demand.
3357+
- ``Engine(ORTSDynamicBlendingRetainedPressure`` -- Sets the brake cylinder
3358+
pressure which, when used in combination with ORTSDynamicBrakesHasPartialBailOff,
3359+
will remain applied regardless of the blended dynamic brake force. This
3360+
pressure is also the minimum pressure at which the blended braking system will activate.
33563361

33573362
Sometimes the train brake controller is capable to apply the dynamic
33583363
brakes for the whole consist, usually as a first step before air brakes

Source/Orts.Simulation/Simulation/RollingStocks/MSTSLocomotive.cs

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,7 @@ public float OdometerM
420420
public double? DynamicBrakeCommandStartTime;
421421
protected bool DynamicBrakeBlendingOverride; // true when DB lever >0% should always override the blending. When false, the bigger command is applied.
422422
protected bool DynamicBrakeBlendingForceMatch = true; // if true, dynamic brake blending tries to achieve the same braking force as the airbrake would have.
423+
public float DynamicBrakeBlendingRetainedPressurePSI { get; private set; } = -1.0f; // the amount of pressure that will always be retained in the brake cylinders during blended braking
423424
protected bool DynamicBrakeControllerSetupLock; // if true if dynamic brake lever will lock until dynamic brake is available
424425

425426
public float DynamicBrakeBlendingPercent { get; protected set; } = -1;
@@ -1177,6 +1178,7 @@ public override void Parse(string lowercasetoken, STFReader stf)
11771178
break;
11781179
case "engine(ortsdynamicblendingoverride": DynamicBrakeBlendingOverride = stf.ReadBoolBlock(false); break;
11791180
case "engine(ortsdynamicblendingforcematch": DynamicBrakeBlendingForceMatch = stf.ReadBoolBlock(false); break;
1181+
case "engine(ortsdynamicblendingretainedpressure": DynamicBrakeBlendingRetainedPressurePSI = stf.ReadFloatBlock(STFReader.UNITS.PressureDefaultPSI, null); break;
11801182
case "engine(vacuumbrakeshasvacuumpump": VacuumPumpFitted = stf.ReadBoolBlock(false); break;
11811183
case "engine(enginecontrollers(ortssteamheat": SteamHeatController.Parse(stf); break;
11821184
case "engine(name": stf.MustMatch("("); LocomotiveName = stf.ReadString(); break;
@@ -1334,6 +1336,7 @@ public override void Copy(MSTSWagon copy)
13341336
DynamicBrakeCommandStartTime = locoCopy.DynamicBrakeCommandStartTime;
13351337
DynamicBrakeBlendingOverride = locoCopy.DynamicBrakeBlendingOverride;
13361338
DynamicBrakeBlendingForceMatch = locoCopy.DynamicBrakeBlendingForceMatch;
1339+
DynamicBrakeBlendingRetainedPressurePSI = locoCopy.DynamicBrakeBlendingRetainedPressurePSI;
13371340
DynamicBrakeControllerSetupLock = locoCopy.DynamicBrakeControllerSetupLock;
13381341

13391342
MainPressureUnit = locoCopy.MainPressureUnit;
@@ -2014,6 +2017,15 @@ protected void CorrectBrakingParams()
20142017
(MaxDynamicBrakeForceN / MaxContinuousForceN < 0.3f && MaxDynamicBrakeForceN == 20000))
20152018
MaxDynamicBrakeForceN = Math.Min (MaxContinuousForceN * 0.5f, 150000); // 20000 is suggested as standard value in the MSTS documentation, but in general it is a too low value
20162019
}
2020+
2021+
// Define blending retained pressure if it was left undefined
2022+
if (DynamicBrakeBlendingRetainedPressurePSI < 0)
2023+
{
2024+
if (BrakeSystem is AirSinglePipe airSystem)
2025+
DynamicBrakeBlendingRetainedPressurePSI = 2.0f * airSystem.BrakeCylinderSpringPressurePSI;
2026+
else
2027+
DynamicBrakeBlendingRetainedPressurePSI = 0.0f;
2028+
}
20172029
}
20182030

20192031
/// <summary>
@@ -2022,24 +2034,38 @@ protected void CorrectBrakingParams()
20222034
public void DynamicBrakeBlending(float elapsedClockSeconds)
20232035
{
20242036
// Local blending
2025-
if (Math.Abs(SpeedMpS) > DynamicBrakeSpeed1MpS && airPipeSystem != null && airPipeSystem.AutoCylPressurePSI > 0.1f
2037+
float autoDemandedPressurePSI = airPipeSystem.AutoCylPressurePSI * airPipeSystem.RelayValveRatio;
2038+
2039+
if (Math.Abs(SpeedMpS) > DynamicBrakeSpeed1MpS && airPipeSystem != null && autoDemandedPressurePSI > DynamicBrakeBlendingRetainedPressurePSI
20262040
&& ThrottlePercent == 0 && !(DynamicBrakeController != null && DynamicBrakeBlendingOverride && DynamicBrakeController.SavedValue > 0))
20272041
{
2028-
float maxCylPressurePSI = airPipeSystem.GetMaxCylPressurePSI();
2029-
float target = airPipeSystem.AutoCylPressurePSI * airPipeSystem.RelayValveRatio / maxCylPressurePSI;
2042+
float target = (autoDemandedPressurePSI - DynamicBrakeBlendingRetainedPressurePSI) /
2043+
(airPipeSystem.ReferencePressurePSI - DynamicBrakeBlendingRetainedPressurePSI);
20302044

20312045
if (DynamicBrakeBlendingForceMatch)
20322046
{
2033-
float diff = target * FrictionBrakeBlendingMaxForceN - DynamicBrakeForceN;
2034-
float threshold = 100;
2035-
if (diff > threshold && DynamicBrakePercent < 100)
2036-
DynamicBrakeBlendingPercent = Math.Min(DynamicBrakePercent + 100 * elapsedClockSeconds, 100);
2037-
else if (diff < -threshold && DynamicBrakePercent > 1)
2038-
DynamicBrakeBlendingPercent = Math.Max(DynamicBrakePercent - 100 * elapsedClockSeconds, 1);
2047+
if (DynamicBrake)
2048+
{
2049+
float diff = target * FrictionBrakeBlendingMaxForceN - DynamicBrakeForceN;
2050+
float normDiff = diff / MaxDynamicBrakeForceN;
2051+
2052+
if (Math.Abs(diff) > 100.0f)
2053+
{
2054+
// Limit rate of change to reduce overshoots
2055+
if (diff > 0 && DynamicBrakeForceRampUpNpS > 0)
2056+
normDiff = Math.Min(normDiff, DynamicBrakeForceRampUpNpS / MaxDynamicBrakeForceN);
2057+
if (diff < 0 && DynamicBrakeForceRampDownNpS > 0)
2058+
normDiff = Math.Max(normDiff, -DynamicBrakeForceRampDownNpS / MaxDynamicBrakeForceN);
2059+
2060+
DynamicBrakeBlendingPercent = MathHelper.Clamp(DynamicBrakePercent + 100.0f * normDiff * elapsedClockSeconds, 1f, 100f);
2061+
}
2062+
}
2063+
else // Don't increase dynamic brake setting until set-up has completed
2064+
DynamicBrakeBlendingPercent = 1.0f;
20392065
}
20402066
else
20412067
{
2042-
DynamicBrakeBlendingPercent = target * 100;
2068+
DynamicBrakeBlendingPercent = MathHelper.Clamp(target * 100, 1f, 100f);
20432069
}
20442070
}
20452071
else

Source/Orts.Simulation/Simulation/RollingStocks/SubSystems/Brakes/MSTS/AirSinglePipe.cs

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ public enum BrakeValveType
8181
protected float ControlResPressurePSI = 64;
8282
protected float FullServPressurePSI = 50;
8383
protected float MaxCylPressurePSI;
84-
protected float ReferencePressurePSI;
84+
public float ReferencePressurePSI { get; protected set; }
8585
protected float MaxTripleValveCylPressurePSI;
8686
protected float AuxResVolumeM3;
8787
protected float AuxCylVolumeRatio;
@@ -143,7 +143,7 @@ public enum BrakeValveType
143143
protected float AcceleratedApplicationLimitPSIpS = 5.0f;
144144
protected float InitialApplicationThresholdPSI;
145145
protected float TripleValveSensitivityPSI;
146-
protected float BrakeCylinderSpringPressurePSI;
146+
public float BrakeCylinderSpringPressurePSI { get; protected set; }
147147
protected float ServiceMaxCylPressurePSI;
148148
protected float ServiceApplicationRatePSIpS;
149149
protected float TwoStageLowPressurePSI;
@@ -1721,25 +1721,21 @@ public override void Update(float elapsedClockSeconds)
17211721
if (loco.Train.DetermineDPLeadLocomotive(loco) is MSTSLocomotive lead && (lead.BailOff || (lead.EngineBrakeController != null && lead.EngineBrakeController.TrainBrakeControllerState == ControllerState.BailOff)))
17221722
{
17231723
if (BrakeValve == BrakeValveType.Distributor)
1724-
{
17251724
ControlResPressurePSI = 0;
17261725

1727-
if (loco.AttachedTender?.BrakeSystem is AirSinglePipe tenderBrakes)
1728-
tenderBrakes.ControlResPressurePSI = 0;
1729-
}
1730-
else
1726+
float dp = Math.Max(MaxReleaseRatePSIpS, loco.EngineBrakeReleaseRatePSIpS) * elapsedClockSeconds;
1727+
AutoCylPressurePSI -= dp;
1728+
if (AutoCylPressurePSI < 0)
1729+
AutoCylPressurePSI = 0;
1730+
1731+
if (loco.AttachedTender?.BrakeSystem is AirSinglePipe tenderBrakes)
17311732
{
1732-
float dp = Math.Max(MaxReleaseRatePSIpS, loco.EngineBrakeReleaseRatePSIpS) * elapsedClockSeconds;
1733-
AutoCylPressurePSI -= dp;
1734-
if (AutoCylPressurePSI < 0)
1735-
AutoCylPressurePSI = 0;
1733+
if (tenderBrakes.BrakeValve == BrakeValveType.Distributor)
1734+
tenderBrakes.ControlResPressurePSI = 0;
17361735

1737-
if (loco.AttachedTender?.BrakeSystem is AirSinglePipe tenderBrakes)
1738-
{
1739-
tenderBrakes.AutoCylPressurePSI -= dp;
1740-
if (tenderBrakes.AutoCylPressurePSI < 0)
1741-
tenderBrakes.AutoCylPressurePSI = 0;
1742-
}
1736+
tenderBrakes.AutoCylPressurePSI -= dp;
1737+
if (tenderBrakes.AutoCylPressurePSI < 0)
1738+
tenderBrakes.AutoCylPressurePSI = 0;
17431739
}
17441740
}
17451741
}
@@ -1750,19 +1746,23 @@ public override void Update(float elapsedClockSeconds)
17501746
{
17511747
if (loco.DynamicBrakePartialBailOff)
17521748
{
1753-
var requiredBrakeForceN = MathHelper.Max((AutoCylPressurePSI * RelayValveRatio - BrakeCylinderSpringPressurePSI)
1754-
/ (ReferencePressurePSI - BrakeCylinderSpringPressurePSI), 0) * Car.FrictionBrakeBlendingMaxForceN;
1755-
var localBrakeForceN = loco.DynamicBrakeForceN + MathHelper.Max((CylPressurePSI - BrakeCylinderSpringPressurePSI)
1756-
/ (ReferencePressurePSI - BrakeCylinderSpringPressurePSI), 0) * Car.FrictionBrakeBlendingMaxForceN;
1749+
var requiredBrakeForceN = (AutoCylPressurePSI * RelayValveRatio - loco.DynamicBrakeBlendingRetainedPressurePSI)
1750+
/ (ReferencePressurePSI - loco.DynamicBrakeBlendingRetainedPressurePSI) * Car.FrictionBrakeBlendingMaxForceN;
1751+
var localBrakeForceN = loco.DynamicBrakeForceN + (CylPressurePSI - loco.DynamicBrakeBlendingRetainedPressurePSI)
1752+
/ (ReferencePressurePSI - loco.DynamicBrakeBlendingRetainedPressurePSI) * Car.FrictionBrakeBlendingMaxForceN;
17571753
if (localBrakeForceN > requiredBrakeForceN - 0.15f * Car.FrictionBrakeBlendingMaxForceN)
17581754
{
1759-
demandedPressurePSI = Math.Min(Math.Max((requiredBrakeForceN - loco.DynamicBrakeForceN) / Car.FrictionBrakeBlendingMaxForceN * ReferencePressurePSI
1760-
+ BrakeCylinderSpringPressurePSI, 0), MaxCylPressurePSI);
1755+
demandedPressurePSI = MathHelper.Clamp((requiredBrakeForceN - loco.DynamicBrakeForceN) / Car.FrictionBrakeBlendingMaxForceN *
1756+
(ReferencePressurePSI - loco.DynamicBrakeBlendingRetainedPressurePSI) + loco.DynamicBrakeBlendingRetainedPressurePSI,
1757+
loco.DynamicBrakeBlendingRetainedPressurePSI, MaxCylPressurePSI);
17611758
if (demandedPressurePSI > CylPressurePSI && demandedPressurePSI < CylPressurePSI + 4) // Allow some margin for unnecessary air brake application
17621759
{
17631760
demandedPressurePSI = CylPressurePSI;
17641761
}
17651762
demandedPressurePSI /= RelayValveRatio;
1763+
1764+
if (demandedPressurePSI > AutoCylPressurePSI)
1765+
demandedPressurePSI = AutoCylPressurePSI;
17661766
}
17671767
}
17681768
else if (loco.DynamicBrakeAutoBailOff)

0 commit comments

Comments
 (0)