Skip to content

Commit 1c4a84d

Browse files
authored
Merge pull request #444 from peternewell/brake-enhancements
First phase of wheel slide protection http://www.elvastower.com/forums/index.php?/topic/35332-more-brake-enhancements/
2 parents 4ee3658 + a5e559c commit 1c4a84d

File tree

9 files changed

+224
-14
lines changed

9 files changed

+224
-14
lines changed

Source/Documentation/Manual/physics.rst

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2894,6 +2894,8 @@ MaxAuxilaryChargingRate and EmergencyResChargingRate.
28942894
- ``Engine(ORTSBrakePipeTimeFactor`` -- Time in seconds for a difference in
28952895
pipe pressure between adjacent cars to equalize to about 1/3
28962896
(default .003).
2897+
- ``Engine(AirBrakeMaxMainResPipePressure`` -- Pressure in Main Reservoir
2898+
Pipe for twin pipe braking systems (default = Main Reservoir Pressure).
28972899

28982900
.. _physics-retainers:
28992901

@@ -3193,6 +3195,30 @@ To control the application and release rates on the brake use the ``EngineBrakes
31933195
The ``SteamBrakeFX`` special effect, if added to the wagon, will turn on and off with the brake operation
31943196
and can be used to model steam leakage of the steam brake cylinder, etc.
31953197

3198+
Wheel Slide Protection
3199+
----------------------
3200+
3201+
Open Rails supports the use of Wheel Slide Protection (WSP) on trains with air brakes. WSP operates as described below.
3202+
3203+
During braking wheelslide control is effected throughout the train by additional equipment on each vehicle. In the piping to each
3204+
pair of brake cylinders are fitted electrically operated dump valves. When axle rotations which are sensed electrically, differ
3205+
by a predetermined speed the dump valves are operated releasing brake cylinder pressure to both axles of the affected bogie.
3206+
3207+
Dump valve operation will cease when differences in axle rotations are within specified limits or the axle accelerates faster than
3208+
a specified rate. The dump valve will only operate for a maximum period of seven seconds after which time it will be de-energised
3209+
and the dump valve will not re-operate until the train has stopped or the throttle operated.
3210+
3211+
Dump valve operation is prevented under the following conditions:
3212+
3213+
- When the Power Controller is open.
3214+
- When Brake Pipe Pressure has been reduced below 36 psi (250 kPa).
3215+
3216+
To enable WSP ``ORTSWheelBrakeSlideProtection (1)``. If it is desired that emergency braking should not be impacted by WSP, then use
3217+
the ``ORTSEmergencyBrakingDisablesWSP (1)`` parameter.
3218+
3219+
When WSP is active the brake cylinder pressure reading will go yellow in the extended HuD on the BRAKE INFORMATION screen.
3220+
3221+
31963222
Dynamically Evolving Tractive Force
31973223
===================================
31983224

Source/Orts.Formats.Msts/CabViewFile.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ public enum CABViewControlTypes
7272
NONE,
7373
SPEEDOMETER,
7474
MAIN_RES,
75+
MAIN_RES_PIPE,
7576
EQ_RES,
7677
BRAKE_CYL,
7778
BRAKE_PIPE,

Source/Orts.Simulation/Common/Events.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,10 @@ public enum Event
240240
HeatingOn,
241241
AirConditioningOff,
242242
AirConditioningOn,
243+
244+
OverchargeBrakingOn,
245+
OverchargeBrakingOff,
246+
243247
}
244248

245249
public static class Events
@@ -496,6 +500,9 @@ public static Event From(bool mstsBinEnabled, Source source, int eventID)
496500
case 234: return Event.AirConditioningOn;
497501
case 235: return Event.AirConditioningOff;
498502

503+
case 250: return Event.OverchargeBrakingOn;
504+
case 251: return Event.OverchargeBrakingOff;
505+
499506
default: return 0;
500507
}
501508
case Source.MSTSCrossing:

Source/Orts.Simulation/Simulation/Physics/Train.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3835,7 +3835,7 @@ public void UnconditionalInitializeBrakes()
38353835
if (MUDynamicBrakePercent == 0)
38363836
MUDynamicBrakePercent = -1;
38373837
}
3838-
BrakeLine2PressurePSI = maxPressurePSI;
3838+
BrakeLine2PressurePSI = lead.MaximumMainReservoirPipePressurePSI;
38393839
ConnectBrakeHoses();
38403840
}
38413841
else

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ public enum SoundState
131131
public float MaxSpeedMpS = 1e3f;
132132
public float UnloadingSpeedMpS;
133133
public float MainResPressurePSI = 130;
134+
public float MaximumMainReservoirPipePressurePSI;
134135
public bool CompressorIsOn;
135136
public float AverageForceN;
136137
public float PowerOnDelayS;
@@ -353,6 +354,7 @@ public float OdometerM
353354
public float DynamicBrakeDelayS;
354355
public bool DynamicBrakeAutoBailOff;
355356
public bool UsingRearCab;
357+
public bool BrakeOverchargeSoundOn = false;
356358

357359
protected bool DynamicBrakeBlended; // dynamic brake blending is currently active
358360
protected bool DynamicBrakeBlendingEnabled; // dynamic brake blending is configured
@@ -843,6 +845,7 @@ public override void Parse(string lowercasetoken, STFReader stf)
843845
case "engine(enginecontrollers(combined_control": ParseCombData(lowercasetoken, stf); break;
844846
case "engine(airbrakesmainresvolume": MainResVolumeM3 = Me3.FromFt3(stf.ReadFloatBlock(STFReader.UNITS.VolumeDefaultFT3, null)); break;
845847
case "engine(airbrakesmainmaxairpressure": MainResPressurePSI = MaxMainResPressurePSI = stf.ReadFloatBlock(STFReader.UNITS.PressureDefaultPSI, null); break;
848+
case "engine(airbrakemaxmainrespipepressure": MaximumMainReservoirPipePressurePSI = stf.ReadFloatBlock(STFReader.UNITS.PressureDefaultPSI, null); break;
846849
case "engine(airbrakescompressorrestartpressure": CompressorRestartPressurePSI = stf.ReadFloatBlock(STFReader.UNITS.PressureDefaultPSI, null); break;
847850
case "engine(airbrakesaircompressorpowerrating": CompressorChargingRateM3pS = Me3.FromFt3(stf.ReadFloatBlock(STFReader.UNITS.VolumeDefaultFT3, null)); break;
848851
case "engine(trainpipeleakrate": TrainBrakePipeLeakPSIorInHgpS = stf.ReadFloatBlock(STFReader.UNITS.PressureRateDefaultPSIpS, null); break;
@@ -1027,7 +1030,8 @@ public override void Copy(MSTSWagon copy)
10271030
CompressorRestartPressurePSI = locoCopy.CompressorRestartPressurePSI;
10281031
TrainBrakePipeLeakPSIorInHgpS = locoCopy.TrainBrakePipeLeakPSIorInHgpS;
10291032
MaxMainResPressurePSI = locoCopy.MaxMainResPressurePSI;
1030-
MainResPressurePSI = MaxMainResPressurePSI;
1033+
MainResPressurePSI = locoCopy.MaxMainResPressurePSI;
1034+
MaximumMainReservoirPipePressurePSI = locoCopy.MaximumMainReservoirPipePressurePSI;
10311035
MainResVolumeM3 = locoCopy.MainResVolumeM3;
10321036
MainResChargingRatePSIpS = locoCopy.MainResChargingRatePSIpS;
10331037
BrakePipeDischargeTimeFactor = locoCopy.BrakePipeDischargeTimeFactor;
@@ -1392,6 +1396,11 @@ public override void Initialize()
13921396
}
13931397
}
13941398

1399+
if (MaximumMainReservoirPipePressurePSI == 0)
1400+
{
1401+
MaximumMainReservoirPipePressurePSI = MaxMainResPressurePSI;
1402+
}
1403+
13951404
// Check TrainBrakesControllerMaxSystemPressure parameter for "correct" value
13961405
// This is only done for vacuum brakes as the UoM can be confusing - it defaults to psi due to way parameter is read, and if units are entered then a InHG value can be incorrectly converted.
13971406
if ((BrakeSystem is VacuumSinglePipe))
@@ -4444,6 +4453,11 @@ public virtual float GetDataOf(CabViewControl cvc)
44444453
data = ConvertFromPSI(cvc, MainResPressurePSI);
44454454
break;
44464455
}
4456+
case CABViewControlTypes.MAIN_RES_PIPE:
4457+
{
4458+
data = ConvertFromPSI(cvc, this.BrakeSystem.BrakeLine2PressurePSI);
4459+
break;
4460+
}
44474461
case CABViewControlTypes.BRAKE_PIPE:
44484462
{
44494463
data = ConvertFromPSI(cvc, this.BrakeSystem.BrakeLine1PressurePSI);

Source/Orts.Simulation/Simulation/RollingStocks/MSTSWagon.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,6 +1068,30 @@ public virtual void Parse(string lowercasetoken, STFReader stf)
10681068
case "wagon(ortsbrakeshoefriction": BrakeShoeFrictionFactor = new Interpolator(stf); break;
10691069
case "wagon(maxhandbrakeforce": InitialMaxHandbrakeForceN = stf.ReadFloatBlock(STFReader.UNITS.Force, null); break;
10701070
case "wagon(maxbrakeforce": InitialMaxBrakeForceN = stf.ReadFloatBlock(STFReader.UNITS.Force, null); break;
1071+
case "wagon(ortswheelbrakeslideprotection":
1072+
// stf.MustMatch("(");
1073+
var brakeslideprotection = stf.ReadFloatBlock(STFReader.UNITS.None, null);
1074+
if (brakeslideprotection == 1)
1075+
{
1076+
WheelBrakeSlideProtectionFitted = true;
1077+
}
1078+
else
1079+
{
1080+
WheelBrakeSlideProtectionFitted = false;
1081+
}
1082+
break;
1083+
case "wagon(ortswheelbrakesslideprotectionlimitdisable":
1084+
// stf.MustMatch("(");
1085+
var brakeslideprotectiondisable = stf.ReadFloatBlock(STFReader.UNITS.None, null);
1086+
if (brakeslideprotectiondisable == 1)
1087+
{
1088+
WheelBrakeSlideProtectionLimitDisabled = true;
1089+
}
1090+
else
1091+
{
1092+
WheelBrakeSlideProtectionLimitDisabled = false;
1093+
}
1094+
break;
10711095
case "wagon(ortsdavis_a": DavisAN = stf.ReadFloatBlock(STFReader.UNITS.Force, null); break;
10721096
case "wagon(ortsdavis_b": DavisBNSpM = stf.ReadFloatBlock(STFReader.UNITS.Resistance, null); break;
10731097
case "wagon(ortsdavis_c": DavisCNSSpMM = stf.ReadFloatBlock(STFReader.UNITS.ResistanceDavisC, null); break;
@@ -1458,6 +1482,8 @@ public virtual void Copy(MSTSWagon copy)
14581482
DriverWheelRadiusM = copy.DriverWheelRadiusM;
14591483
MainSoundFileName = copy.MainSoundFileName;
14601484
BrakeShoeFrictionFactor = copy.BrakeShoeFrictionFactor;
1485+
WheelBrakeSlideProtectionFitted = copy.WheelBrakeSlideProtectionFitted;
1486+
WheelBrakeSlideProtectionLimitDisabled = copy.WheelBrakeSlideProtectionLimitDisabled;
14611487
InitialMaxBrakeForceN = copy.InitialMaxBrakeForceN;
14621488
InitialMaxHandbrakeForceN = copy.InitialMaxHandbrakeForceN;
14631489
MaxBrakeForceN = copy.MaxBrakeForceN;
@@ -1680,6 +1706,9 @@ public override void Save(BinaryWriter outf)
16801706
outf.Write(CarInsideTempC);
16811707
outf.Write(CurrentCarSteamHeatBoilerWaterCapacityL);
16821708

1709+
outf.Write(WheelBrakeSlideProtectionActive);
1710+
outf.Write(WheelBrakeSlideProtectionTimerS);
1711+
16831712
base.Save(outf);
16841713
}
16851714

@@ -1724,6 +1753,9 @@ public override void Restore(BinaryReader inf)
17241753
CarInsideTempC = inf.ReadSingle();
17251754
CurrentCarSteamHeatBoilerWaterCapacityL = inf.ReadSingle();
17261755

1756+
WheelBrakeSlideProtectionActive = inf.ReadBoolean();
1757+
WheelBrakeSlideProtectionTimerS = inf.ReadInt32();
1758+
17271759
base.Restore(inf);
17281760
}
17291761

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

Lines changed: 90 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ public override string[] GetDebugStatus(Dictionary<BrakeSystemComponent, Pressur
144144
{
145145
return new string[] {
146146
DebugType,
147-
FormatStrings.FormatPressure(CylPressurePSI, PressureUnit.PSI, units[BrakeSystemComponent.BrakeCylinder], true),
147+
string.Format("{0}{1}",FormatStrings.FormatPressure(CylPressurePSI, PressureUnit.PSI, units[BrakeSystemComponent.BrakeCylinder], true), (Car as MSTSWagon).WheelBrakeSlideProtectionActive ? "???" : ""),
148148
FormatStrings.FormatPressure(BrakeLine1PressurePSI, PressureUnit.PSI, units[BrakeSystemComponent.BrakePipe], true),
149149
FormatStrings.FormatPressure(AuxResPressurePSI, PressureUnit.PSI, units[BrakeSystemComponent.AuxiliaryReservoir], true),
150150
(Car as MSTSWagon).EmergencyReservoirPresent ? FormatStrings.FormatPressure(EmergResPressurePSI, PressureUnit.PSI, units[BrakeSystemComponent.EmergencyReservoir], true) : string.Empty,
@@ -377,7 +377,7 @@ public override void Update(float elapsedClockSeconds)
377377
UpdateTripleValveState(threshold);
378378

379379
// triple valve is set to charge the brake cylinder
380-
if (TripleValveState == ValveState.Apply || TripleValveState == ValveState.Emergency)
380+
if ((TripleValveState == ValveState.Apply || TripleValveState == ValveState.Emergency) && !Car.WheelBrakeSlideProtectionActive)
381381
{
382382
float dp = elapsedClockSeconds * MaxApplicationRatePSIpS;
383383
if (AuxResPressurePSI - dp / AuxCylVolumeRatio < AutoCylPressurePSI + dp)
@@ -452,6 +452,8 @@ public override void Update(float elapsedClockSeconds)
452452
BrakeLine1PressurePSI += dp * AuxBrakeLineVolumeRatio;
453453
}
454454
}
455+
456+
// Charge Auxiliary reservoir for MRP
455457
if (TwoPipes
456458
&& !NoMRPAuxResCharging
457459
&& AuxResPressurePSI < BrakeLine2PressurePSI
@@ -487,6 +489,45 @@ public override void Update(float elapsedClockSeconds)
487489
else
488490
CylPressurePSI = AutoCylPressurePSI;
489491

492+
// During braking wheelslide control is effected throughout the train by additional equipment on each vehicle. In the piping to each pair of brake cylinders are fitted electrically operated
493+
// dump valves. When axle rotations which are sensed electrically, differ by a predetermined speed the dump valves are operated releasing brake cylinder pressure to both axles of the affected
494+
// bogie.
495+
496+
// Dump valve operation will cease when differences in axle rotations arewithin specified limits or the axle accelerates faster than a specified rate. The dump valve resets whenever the wheel
497+
// creep speed drops to normal. The dump valve will only operate continuously for a maximum period of seven seconds after which time it will be de-energised and the dump valve will not
498+
// re-operate until the train has stopped or the throttle operated.
499+
500+
// Dump valve operation is prevented under the following conditions:-
501+
// (i) When the Power Controller is open.
502+
503+
// (ii) When Brake Pipe Pressure has been reduced below 250 kPa (36.25psi).
504+
505+
if (Car.WheelBrakeSlideProtectionFitted && Car.Train.IsPlayerDriven)
506+
{
507+
// WSP dump valve active
508+
if ((Car.BrakeSkidWarning || Car.BrakeSkid) && CylPressurePSI > 0 && !Car.WheelBrakeSlideProtectionDumpValveLockout && ( (!Car.WheelBrakeSlideProtectionLimitDisabled && BrakeLine1PressurePSI > 36.25) || Car.WheelBrakeSlideProtectionLimitDisabled) )
509+
{
510+
Car.WheelBrakeSlideProtectionActive = true;
511+
AutoCylPressurePSI -= elapsedClockSeconds * MaxReleaseRatePSIpS;
512+
CylPressurePSI = AutoCylPressurePSI;
513+
Car.WheelBrakeSlideProtectionTimerS -= elapsedClockSeconds;
514+
515+
// Lockout WSP dump valve if it is open for greater then 7 seconds continuously
516+
if (Car.WheelBrakeSlideProtectionTimerS <= 0)
517+
{
518+
Car.WheelBrakeSlideProtectionDumpValveLockout = true;
519+
}
520+
521+
}
522+
else if (!Car.WheelBrakeSlideProtectionDumpValveLockout)
523+
{
524+
// WSP dump valve stops
525+
Car.WheelBrakeSlideProtectionActive = false;
526+
Car.WheelBrakeSlideProtectionTimerS = Car.wheelBrakeSlideTimerResetValueS; // Reset WSP timer if
527+
}
528+
529+
}
530+
490531
// Record HUD display values for brake cylinders depending upon whether they are wagons or locomotives/tenders (which are subject to their own engine brakes)
491532
if (Car.WagonType == MSTSWagon.WagonTypes.Engine || Car.WagonType == MSTSWagon.WagonTypes.Tender)
492533
{
@@ -569,6 +610,23 @@ public override void Update(float elapsedClockSeconds)
569610
}
570611
prevCylPressurePSI = AutoCylPressurePSI;
571612
prevBrakePipePressurePSI = BrakeLine1PressurePSI;
613+
614+
var lead = Car as MSTSLocomotive;
615+
616+
if (lead != null && Car.WagonType == MSTSWagon.WagonTypes.Engine)
617+
{
618+
if (lead.TrainBrakeController.TrainBrakeControllerState == ControllerState.Overcharge && !lead.BrakeOverchargeSoundOn)
619+
{
620+
Car.SignalEvent(Event.OverchargeBrakingOn);
621+
lead.BrakeOverchargeSoundOn = true;
622+
}
623+
else if (lead.TrainBrakeController.TrainBrakeControllerState != ControllerState.Overcharge && lead.BrakeOverchargeSoundOn)
624+
{
625+
Car.SignalEvent(Event.OverchargeBrakingOff);
626+
lead.BrakeOverchargeSoundOn = false;
627+
}
628+
}
629+
572630
}
573631
SoundTriggerCounter = SoundTriggerCounter + elapsedClockSeconds;
574632
}
@@ -740,7 +798,9 @@ protected static void PropagateBrakeLinePressures(float elapsedClockSeconds, Tra
740798
int last = -1;
741799
train.FindLeadLocomotives(ref first, ref last);
742800
float sumpv = 0;
801+
float summainrespv = 0;
743802
float sumv = 0;
803+
float summainresv = 0;
744804
int continuousFromInclusive = 0;
745805
int continuousToExclusive = train.Cars.Count;
746806
for (int i = 0; i < train.Cars.Count; i++)
@@ -767,11 +827,22 @@ protected static void PropagateBrakeLinePressures(float elapsedClockSeconds, Tra
767827
{
768828
sumv += brakeSystem.BrakePipeVolumeM3;
769829
sumpv += brakeSystem.BrakePipeVolumeM3 * brakeSystem.BrakeLine2PressurePSI;
830+
831+
summainresv += brakeSystem.BrakePipeVolumeM3;
832+
833+
if (lead != null)
834+
{
835+
summainrespv += brakeSystem.BrakePipeVolumeM3 * lead.MainResPressurePSI;
836+
}
837+
770838
var eng = train.Cars[i] as MSTSLocomotive;
771839
if (eng != null)
772840
{
773841
sumv += eng.MainResVolumeM3;
774842
sumpv += eng.MainResVolumeM3 * eng.MainResPressurePSI;
843+
844+
summainresv += eng.MainResVolumeM3;
845+
summainrespv += eng.MainResVolumeM3 * eng.MainResPressurePSI;
775846
}
776847
}
777848

@@ -820,24 +891,39 @@ protected static void PropagateBrakeLinePressures(float elapsedClockSeconds, Tra
820891
}
821892
}
822893
if (sumv > 0)
894+
{
823895
sumpv /= sumv;
896+
summainrespv /= summainresv;
897+
}
824898

825899
if (!train.Cars[continuousFromInclusive].BrakeSystem.FrontBrakeHoseConnected && train.Cars[continuousFromInclusive].BrakeSystem.AngleCockAOpen
826900
|| (continuousToExclusive == train.Cars.Count || !train.Cars[continuousToExclusive].BrakeSystem.FrontBrakeHoseConnected) && train.Cars[continuousToExclusive - 1].BrakeSystem.AngleCockBOpen)
901+
{
827902
sumpv = 0;
903+
summainrespv = 0;
904+
}
828905

829906
// Propagate main reservoir pipe (2) data
830907
train.BrakeLine2PressurePSI = sumpv;
831908
for (int i = 0; i < train.Cars.Count; i++)
832909
{
833910
if (first <= i && i <= last || twoPipes && continuousFromInclusive <= i && i < continuousToExclusive)
834911
{
912+
913+
if (lead != null && sumpv > lead.MaximumMainReservoirPipePressurePSI)
914+
{
915+
sumpv = lead.MaximumMainReservoirPipePressurePSI;
916+
}
917+
835918
train.Cars[i].BrakeSystem.BrakeLine2PressurePSI = sumpv;
836919
if (sumpv != 0 && train.Cars[i] is MSTSLocomotive)
837-
(train.Cars[i] as MSTSLocomotive).MainResPressurePSI = sumpv;
920+
(train.Cars[i] as MSTSLocomotive).MainResPressurePSI = summainrespv;
838921
}
839922
else
840-
train.Cars[i].BrakeSystem.BrakeLine2PressurePSI = train.Cars[i] is MSTSLocomotive ? (train.Cars[i] as MSTSLocomotive).MainResPressurePSI : 0;
923+
{
924+
// train.Cars[i].BrakeSystem.BrakeLine2PressurePSI = train.Cars[i] is MSTSLocomotive ? (train.Cars[i] as MSTSLocomotive).MainResPressurePSI : 0;
925+
train.Cars[i].BrakeSystem.BrakeLine2PressurePSI = train.Cars[i] is MSTSLocomotive ? (train.Cars[i] as MSTSLocomotive).MaximumMainReservoirPipePressurePSI : 0;
926+
}
841927
}
842928
}
843929

0 commit comments

Comments
 (0)