Skip to content

Commit fafecd0

Browse files
committed
Automatic merge of T1.5.1-1885-g12b1a74d5 and 7 pull requests
- Pull request #570 at 362e4e7: glTF 2.0 support with PBR lighting - Pull request #1085 at 37e2817: updates key commands for Train Operations window and also Daylight Offset - Pull request #1086 at e10390b: Add Settings Exporter tool (copy settings to INI, etc) - Pull request #1094 at e6e95f1: Blended Braking Compatibility and Effectiveness Improvements - Pull request #1082 at 5845a1a: Allow variable water level in glass gauge - Pull request #1081 at 689494b: Brake cuts power unification - Pull request #1091 at b0c622b: Automatic speed control
9 parents b0d8e07 + 12b1a74 + 362e4e7 + 37e2817 + e10390b + e6e95f1 + 5845a1a + 689494b + b0c622b commit fafecd0

File tree

3 files changed

+76
-33
lines changed

3 files changed

+76
-33
lines changed

Source/Documentation/Manual/physics.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3343,6 +3343,8 @@ the following parameters will adjust the behaviour of air brakes:
33433343
.. index::
33443344
single: DynamicBrakeHasAutoBailOff
33453345
single: ORTSDynamicBrakesHasPartialBailOff
3346+
single: ORTSDynamicBlendingRetainedPressure
3347+
single: ORTSDynamicBlendingMinimumSpeed
33463348
single: ORTSTrainDynamicBlendingTable
33473349
single: ORTSDynamicBrakeReplacementWithEngineBrake
33483350
single: ORTSDynamicBrakeReplacementWithEngineBrakeAtSpeed
@@ -3353,6 +3355,13 @@ the following parameters will adjust the behaviour of air brakes:
33533355
air brakes are released while dynamic brakes satisfy the train brake demand.
33543356
If dynamic braking is not sufficient, air brakes will be partially applied
33553357
so the combination air+dynamic provides the required brake demand.
3358+
- ``Engine(ORTSDynamicBlendingRetainedPressure`` -- Sets the brake cylinder
3359+
pressure which, when used in combination with ORTSDynamicBrakesHasPartialBailOff,
3360+
will remain applied regardless of the blended dynamic brake force. This
3361+
pressure is also the minimum pressure at which the blended braking system will activate.
3362+
- ``Engine(ORTSDynamicBlendingMinimumSpeed`` -- Below the specified speed
3363+
(default units mph, default value 5 mph / 8 kph), local dynamic brake blending
3364+
will be disabled, allowing locomotive brakes to hold the train while stopped.
33563365

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

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

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

424426
public float DynamicBrakeBlendingPercent { get; protected set; } = -1;
@@ -1098,6 +1100,7 @@ public override void Parse(string lowercasetoken, STFReader stf)
10981100
case "engine(ortsdynamicbrakeshaspartialbailoff": DynamicBrakePartialBailOff = stf.ReadBoolBlock(false); break;
10991101
case "engine(ortsdynamicbrakereplacementwithenginebrake": DynamicBrakeEngineBrakeReplacement = stf.ReadBoolBlock(false); break;
11001102
case "engine(ortsdynamicbrakereplacementwithenginebrakeatspeed": DynamicBrakeEngineBrakeReplacementSpeed = stf.ReadFloatBlock(STFReader.UNITS.SpeedDefaultMPH, null); break;
1103+
case "engine(ortsdynamicblendingminimumspeed": DynamicBrakeBlendingMinSpeedMpS = stf.ReadFloatBlock(STFReader.UNITS.SpeedDefaultMPH, null); break;
11011104
case "engine(dynamicbrakesdelaytimebeforeengaging": DynamicBrakeDelayS = stf.ReadFloatBlock(STFReader.UNITS.Time, null); break;
11021105
case "engine(dynamicbrakesresistorcurrentlimit": DynamicBrakeMaxCurrentA = stf.ReadFloatBlock(STFReader.UNITS.Current, null); break;
11031106
case "engine(numwheels": MSTSLocoNumDrvWheels = stf.ReadFloatBlock(STFReader.UNITS.None, 4.0f); if (MSTSLocoNumDrvWheels < 1) STFException.TraceWarning(stf, "Engine:NumWheels is less than 1, parts of the simulation may not function correctly"); break;
@@ -1178,6 +1181,7 @@ public override void Parse(string lowercasetoken, STFReader stf)
11781181
break;
11791182
case "engine(ortsdynamicblendingoverride": DynamicBrakeBlendingOverride = stf.ReadBoolBlock(false); break;
11801183
case "engine(ortsdynamicblendingforcematch": DynamicBrakeBlendingForceMatch = stf.ReadBoolBlock(false); break;
1184+
case "engine(ortsdynamicblendingretainedpressure": DynamicBrakeBlendingRetainedPressurePSI = stf.ReadFloatBlock(STFReader.UNITS.PressureDefaultPSI, null); break;
11811185
case "engine(vacuumbrakeshasvacuumpump": VacuumPumpFitted = stf.ReadBoolBlock(false); break;
11821186
case "engine(enginecontrollers(ortssteamheat": SteamHeatController.Parse(stf); break;
11831187
case "engine(name": stf.MustMatch("("); LocomotiveName = stf.ReadString(); break;
@@ -1264,6 +1268,7 @@ public override void Copy(MSTSWagon copy)
12641268
DynamicBrakePartialBailOff = locoCopy.DynamicBrakePartialBailOff;
12651269
DynamicBrakeEngineBrakeReplacement = locoCopy.DynamicBrakeEngineBrakeReplacement;
12661270
DynamicBrakeEngineBrakeReplacementSpeed = locoCopy.DynamicBrakeEngineBrakeReplacementSpeed;
1271+
DynamicBrakeBlendingMinSpeedMpS = locoCopy.DynamicBrakeBlendingMinSpeedMpS;
12671272
DynamicBrakeMaxCurrentA = locoCopy.DynamicBrakeMaxCurrentA;
12681273
DynamicBrakeSpeed1MpS = locoCopy.DynamicBrakeSpeed1MpS;
12691274
DynamicBrakeSpeed2MpS = locoCopy.DynamicBrakeSpeed2MpS;
@@ -1335,6 +1340,7 @@ public override void Copy(MSTSWagon copy)
13351340
DynamicBrakeCommandStartTime = locoCopy.DynamicBrakeCommandStartTime;
13361341
DynamicBrakeBlendingOverride = locoCopy.DynamicBrakeBlendingOverride;
13371342
DynamicBrakeBlendingForceMatch = locoCopy.DynamicBrakeBlendingForceMatch;
1343+
DynamicBrakeBlendingRetainedPressurePSI = locoCopy.DynamicBrakeBlendingRetainedPressurePSI;
13381344
DynamicBrakeControllerSetupLock = locoCopy.DynamicBrakeControllerSetupLock;
13391345

13401346
MainPressureUnit = locoCopy.MainPressureUnit;
@@ -2015,6 +2021,15 @@ protected void CorrectBrakingParams()
20152021
(MaxDynamicBrakeForceN / MaxContinuousForceN < 0.3f && MaxDynamicBrakeForceN == 20000))
20162022
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
20172023
}
2024+
2025+
// Define blending retained pressure if it was left undefined
2026+
if (DynamicBrakeBlendingRetainedPressurePSI < 0)
2027+
{
2028+
if (BrakeSystem is AirSinglePipe airSystem)
2029+
DynamicBrakeBlendingRetainedPressurePSI = 2.0f * airSystem.BrakeCylinderSpringPressurePSI;
2030+
else
2031+
DynamicBrakeBlendingRetainedPressurePSI = 0.0f;
2032+
}
20182033
}
20192034

20202035
/// <summary>
@@ -2023,24 +2038,43 @@ protected void CorrectBrakingParams()
20232038
public void DynamicBrakeBlending(float elapsedClockSeconds)
20242039
{
20252040
// Local blending
2026-
if (Math.Abs(SpeedMpS) > DynamicBrakeSpeed1MpS && airPipeSystem != null && airPipeSystem.AutoCylPressurePSI > 0.1f
2041+
if (airPipeSystem == null)
2042+
{
2043+
DynamicBrakeBlendingPercent = -1;
2044+
return;
2045+
}
2046+
float autoDemandedPressurePSI = airPipeSystem.AutoCylPressurePSI * airPipeSystem.RelayValveRatio;
2047+
2048+
if (Math.Abs(SpeedMpS) > DynamicBrakeBlendingMinSpeedMpS && autoDemandedPressurePSI > DynamicBrakeBlendingRetainedPressurePSI
20272049
&& ThrottlePercent == 0 && !(DynamicBrakeController != null && DynamicBrakeBlendingOverride && DynamicBrakeController.SavedValue > 0))
20282050
{
2029-
float maxCylPressurePSI = airPipeSystem.GetMaxCylPressurePSI();
2030-
float target = airPipeSystem.AutoCylPressurePSI * airPipeSystem.RelayValveRatio / maxCylPressurePSI;
2051+
float target = (autoDemandedPressurePSI - DynamicBrakeBlendingRetainedPressurePSI) /
2052+
(airPipeSystem.ReferencePressurePSI - DynamicBrakeBlendingRetainedPressurePSI);
20312053

20322054
if (DynamicBrakeBlendingForceMatch)
20332055
{
2056+
if (DynamicBrake)
2057+
{
20342058
float diff = target * FrictionBrakeBlendingMaxForceN - DynamicBrakeForceN;
2035-
float threshold = 100;
2036-
if (diff > threshold && DynamicBrakePercent < 100)
2037-
DynamicBrakeBlendingPercent = Math.Min(DynamicBrakePercent + 100 * elapsedClockSeconds, 100);
2038-
else if (diff < -threshold && DynamicBrakePercent > 1)
2039-
DynamicBrakeBlendingPercent = Math.Max(DynamicBrakePercent - 100 * elapsedClockSeconds, 1);
2059+
float normDiff = diff / MaxDynamicBrakeForceN;
2060+
2061+
if (Math.Abs(diff) > 100.0f)
2062+
{
2063+
// Limit rate of change to reduce overshoots
2064+
if (diff > 0 && DynamicBrakeForceRampUpNpS > 0)
2065+
normDiff = Math.Min(normDiff, DynamicBrakeForceRampUpNpS / MaxDynamicBrakeForceN);
2066+
if (diff < 0 && DynamicBrakeForceRampDownNpS > 0)
2067+
normDiff = Math.Max(normDiff, -DynamicBrakeForceRampDownNpS / MaxDynamicBrakeForceN);
2068+
2069+
DynamicBrakeBlendingPercent = MathHelper.Clamp(DynamicBrakePercent + 100.0f * normDiff * elapsedClockSeconds, 1f, 100f);
2070+
}
2071+
}
2072+
else // Don't increase dynamic brake setting until set-up has completed
2073+
DynamicBrakeBlendingPercent = 1.0f;
20402074
}
20412075
else
20422076
{
2043-
DynamicBrakeBlendingPercent = target * 100;
2077+
DynamicBrakeBlendingPercent = MathHelper.Clamp(target * 100, 1f, 100f);
20442078
}
20452079
}
20462080
else

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

Lines changed: 24 additions & 24 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;
@@ -1733,25 +1733,21 @@ public override void Update(float elapsedClockSeconds)
17331733
if (loco.Train.DetermineDPLeadLocomotive(loco) is MSTSLocomotive lead && (lead.BailOff || (lead.EngineBrakeController != null && lead.EngineBrakeController.TrainBrakeControllerState == ControllerState.BailOff)))
17341734
{
17351735
if (BrakeValve == BrakeValveType.Distributor)
1736-
{
17371736
ControlResPressurePSI = 0;
17381737

1739-
if (loco.AttachedTender?.BrakeSystem is AirSinglePipe tenderBrakes)
1740-
tenderBrakes.ControlResPressurePSI = 0;
1741-
}
1742-
else
1738+
float dp = Math.Max(MaxReleaseRatePSIpS, loco.EngineBrakeReleaseRatePSIpS) * elapsedClockSeconds;
1739+
AutoCylPressurePSI -= dp;
1740+
if (AutoCylPressurePSI < 0)
1741+
AutoCylPressurePSI = 0;
1742+
1743+
if (loco.AttachedTender?.BrakeSystem is AirSinglePipe tenderBrakes)
17431744
{
1744-
float dp = Math.Max(MaxReleaseRatePSIpS, loco.EngineBrakeReleaseRatePSIpS) * elapsedClockSeconds;
1745-
AutoCylPressurePSI -= dp;
1746-
if (AutoCylPressurePSI < 0)
1747-
AutoCylPressurePSI = 0;
1745+
if (tenderBrakes.BrakeValve == BrakeValveType.Distributor)
1746+
tenderBrakes.ControlResPressurePSI = 0;
17481747

1749-
if (loco.AttachedTender?.BrakeSystem is AirSinglePipe tenderBrakes)
1750-
{
1751-
tenderBrakes.AutoCylPressurePSI -= dp;
1752-
if (tenderBrakes.AutoCylPressurePSI < 0)
1753-
tenderBrakes.AutoCylPressurePSI = 0;
1754-
}
1748+
tenderBrakes.AutoCylPressurePSI -= dp;
1749+
if (tenderBrakes.AutoCylPressurePSI < 0)
1750+
tenderBrakes.AutoCylPressurePSI = 0;
17551751
}
17561752
}
17571753
}
@@ -1762,19 +1758,23 @@ public override void Update(float elapsedClockSeconds)
17621758
{
17631759
if (loco.DynamicBrakePartialBailOff)
17641760
{
1765-
var requiredBrakeForceN = MathHelper.Max((AutoCylPressurePSI * RelayValveRatio - BrakeCylinderSpringPressurePSI)
1766-
/ (ReferencePressurePSI - BrakeCylinderSpringPressurePSI), 0) * Car.FrictionBrakeBlendingMaxForceN;
1767-
var localBrakeForceN = loco.DynamicBrakeForceN + MathHelper.Max((CylPressurePSI - BrakeCylinderSpringPressurePSI)
1768-
/ (ReferencePressurePSI - BrakeCylinderSpringPressurePSI), 0) * Car.FrictionBrakeBlendingMaxForceN;
1761+
var requiredBrakeForceN = (AutoCylPressurePSI * RelayValveRatio - loco.DynamicBrakeBlendingRetainedPressurePSI)
1762+
/ (ReferencePressurePSI - loco.DynamicBrakeBlendingRetainedPressurePSI) * Car.FrictionBrakeBlendingMaxForceN;
1763+
var localBrakeForceN = loco.DynamicBrakeForceN + (CylPressurePSI - loco.DynamicBrakeBlendingRetainedPressurePSI)
1764+
/ (ReferencePressurePSI - loco.DynamicBrakeBlendingRetainedPressurePSI) * Car.FrictionBrakeBlendingMaxForceN;
17691765
if (localBrakeForceN > requiredBrakeForceN - 0.15f * Car.FrictionBrakeBlendingMaxForceN)
17701766
{
1771-
demandedPressurePSI = Math.Min(Math.Max((requiredBrakeForceN - loco.DynamicBrakeForceN) / Car.FrictionBrakeBlendingMaxForceN * ReferencePressurePSI
1772-
+ BrakeCylinderSpringPressurePSI, 0), MaxCylPressurePSI);
1767+
demandedPressurePSI = MathHelper.Clamp((requiredBrakeForceN - loco.DynamicBrakeForceN) / Car.FrictionBrakeBlendingMaxForceN *
1768+
(ReferencePressurePSI - loco.DynamicBrakeBlendingRetainedPressurePSI) + loco.DynamicBrakeBlendingRetainedPressurePSI,
1769+
loco.DynamicBrakeBlendingRetainedPressurePSI, MaxCylPressurePSI);
17731770
if (demandedPressurePSI > CylPressurePSI && demandedPressurePSI < CylPressurePSI + 4) // Allow some margin for unnecessary air brake application
17741771
{
17751772
demandedPressurePSI = CylPressurePSI;
17761773
}
17771774
demandedPressurePSI /= RelayValveRatio;
1775+
1776+
if (demandedPressurePSI > AutoCylPressurePSI)
1777+
demandedPressurePSI = AutoCylPressurePSI;
17781778
}
17791779
}
17801780
else if (loco.DynamicBrakeAutoBailOff)
@@ -1938,7 +1938,7 @@ public override void Update(float elapsedClockSeconds)
19381938
}
19391939

19401940
}
1941-
1941+
19421942
if (Car is MSTSLocomotive) UpdateTractionCutoff();
19431943

19441944
// Record HUD display values for brake cylinders depending upon whether they are wagons or locomotives/tenders (which are subject to their own engine brakes)

0 commit comments

Comments
 (0)