Skip to content

Commit 96e2cb1

Browse files
committed
Adding gradual anglecock opening, smoothed detection of emergency application, better emergency application behavior
1 parent fc86323 commit 96e2cb1

File tree

2 files changed

+102
-9
lines changed

2 files changed

+102
-9
lines changed

Source/Orts.Simulation/Simulation/RollingStocks/SubSystems/Brakes/BrakeSystem.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ public abstract class BrakeSystem
4040
public float BrakePipeVolumeM3 = 1.4e-2f; // volume of a single brake line
4141
public bool ControllerRunningLock = false; // Stops Running controller from becoming active until BP = EQ Res, used in EQ vacuum brakes
4242
public float BrakeCylFraction;
43+
public float AngleCockOpeningTime = 30.0f; // Time taken to fully open a closed anglecock
4344

4445
/// <summary>
4546
/// Front brake hoses connection status
@@ -49,10 +50,14 @@ public abstract class BrakeSystem
4950
/// Front angle cock opened/closed status
5051
/// </summary>
5152
public bool AngleCockAOpen = true;
53+
public float AngleCockAOpenAmount = 1.0f; // 0 - anglecock fully closed, 1 - anglecock fully open, allows for partial opening
54+
public float? AngleCockAOpenTime = null; // Time elapsed since anglecock open command was sent
5255
/// <summary>
5356
/// Rear angle cock opened/closed status
5457
/// </summary>
5558
public bool AngleCockBOpen = true;
59+
public float AngleCockBOpenAmount = 1.0f; // 0 - anglecock fully closed, 1 - anglecock fully open, allows for partial opening
60+
public float? AngleCockBOpenTime = null; // Time elapsed since anglecock open command was sent
5661
/// <summary>
5762
/// Auxiliary brake reservoir vent valve open/closed status
5863
/// </summary>

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

Lines changed: 97 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ public class AirSinglePipe : MSTSBrakeSystem
9191
protected float prevBrakePipePressurePSI = 0f;
9292
protected float prevBrakePipePressurePSI_sound = 0f;
9393

94+
protected float BrakePipeChangePSIpS;
95+
protected SmoothedData SmoothedBrakePipeChangePSIpS;
96+
9497

9598
/// <summary>
9699
/// EP brake holding valve. Needs to be closed (Lap) in case of brake application or holding.
@@ -114,6 +117,8 @@ public AirSinglePipe(TrainCar car)
114117
BrakePipeVolumeM3 = (0.032f * 0.032f * (float)Math.PI / 4f) * Math.Max ( 5.0f, (1 + car.CarLengthM)); // Using DN32 (1-1/4") pipe
115118
DebugType = "1P";
116119

120+
SmoothedBrakePipeChangePSIpS = new SmoothedData(0.25f);
121+
117122
// Force graduated releasable brakes. Workaround for MSTS with bugs preventing to set eng/wag files correctly for this.
118123
if (Car.Simulator.Settings.GraduatedRelease) (Car as MSTSWagon).BrakeValve = MSTSWagon.BrakeValveType.Distributor;
119124

@@ -205,7 +210,7 @@ public override string[] GetDebugStatus(Dictionary<BrakeSystemComponent, Pressur
205210
string.Empty, // Spacer because the state above needs 2 columns.
206211
(Car as MSTSWagon).HandBrakePresent ? string.Format("{0:F0}%", HandbrakePercent) : string.Empty,
207212
FrontBrakeHoseConnected ? "I" : "T",
208-
string.Format("A{0} B{1}", AngleCockAOpen ? "+" : "-", AngleCockBOpen ? "+" : "-"),
213+
string.Format("A{0} B{1}", AngleCockAOpenAmount >= 1 ? "+" : AngleCockAOpenAmount <= 0 ? "-" : "/", AngleCockBOpenAmount >= 1 ? "+" : AngleCockBOpenAmount <= 0 ? "-" : "/"),
209214
BleedOffValveOpen ? Simulator.Catalog.GetString("Open") : string.Empty,
210215
};
211216

@@ -329,7 +334,9 @@ public override void Save(BinaryWriter outf)
329334
outf.Write((int)TripleValveState);
330335
outf.Write(FrontBrakeHoseConnected);
331336
outf.Write(AngleCockAOpen);
337+
outf.Write(AngleCockAOpenAmount);
332338
outf.Write(AngleCockBOpen);
339+
outf.Write(AngleCockBOpenAmount);
333340
outf.Write(BleedOffValveOpen);
334341
outf.Write((int)HoldingValve);
335342
outf.Write(UniformChargingActive);
@@ -352,7 +359,9 @@ public override void Restore(BinaryReader inf)
352359
TripleValveState = (ValveState)inf.ReadInt32();
353360
FrontBrakeHoseConnected = inf.ReadBoolean();
354361
AngleCockAOpen = inf.ReadBoolean();
362+
AngleCockAOpenAmount = inf.ReadSingle();
355363
AngleCockBOpen = inf.ReadBoolean();
364+
AngleCockBOpenAmount = inf.ReadSingle();
356365
BleedOffValveOpen = inf.ReadBoolean();
357366
HoldingValve = (ValveState)inf.ReadInt32();
358367
UniformChargingActive = inf.ReadBoolean();
@@ -380,6 +389,8 @@ public override void Initialize(bool handbrakeOn, float maxPressurePSI, float fu
380389
{
381390
loco.MainResPressurePSI = loco.MaxMainResPressurePSI;
382391
}
392+
393+
SmoothedBrakePipeChangePSIpS.ForceSmoothValue(0);
383394
}
384395

385396
public override void Initialize()
@@ -455,12 +466,15 @@ public void UpdateTripleValveState(float elapsedClockSeconds)
455466
var prevState = TripleValveState;
456467
var valveType = (Car as MSTSWagon).BrakeValve;
457468
bool disableGradient = !(Car.Train.LeadLocomotive is MSTSLocomotive) && Car.Train.TrainType != Orts.Simulation.Physics.Train.TRAINTYPE.STATIC;
469+
// Small workaround to allow trains to more reliably go into emergency after uncoupling
470+
bool emergencyTripped = (Car.Train.TrainType == Orts.Simulation.Physics.Train.TRAINTYPE.STATIC) ?
471+
BrakeLine1PressurePSI <= EmergResPressurePSI * AuxCylVolumeRatio / (AuxCylVolumeRatio + 1) : Math.Max(-SmoothedBrakePipeChangePSIpS.SmoothedValue, 0) > EmergencyValveActuationRatePSIpS;
458472

459473
if (valveType == MSTSWagon.BrakeValveType.Distributor)
460474
{
461475
float applicationPSI = ControlResPressurePSI - BrakeLine1PressurePSI;
462476
float targetPressurePSI = applicationPSI * AuxCylVolumeRatio;
463-
if (!disableGradient && EmergencyValveActuationRatePSIpS > 0 && (prevBrakePipePressurePSI - BrakeLine1PressurePSI) > Math.Max(elapsedClockSeconds, 0.0001f) * EmergencyValveActuationRatePSIpS)
477+
if (!disableGradient && EmergencyValveActuationRatePSIpS > 0 && emergencyTripped)
464478
{
465479
if (prevState == ValveState.Release) // If valve transitions from release to emergency, quick service activates
466480
{
@@ -497,7 +511,7 @@ public void UpdateTripleValveState(float elapsedClockSeconds)
497511
}
498512
else if (valveType == MSTSWagon.BrakeValveType.TripleValve || valveType == MSTSWagon.BrakeValveType.DistributingValve)
499513
{
500-
if (!disableGradient && EmergencyValveActuationRatePSIpS > 0 && (prevBrakePipePressurePSI - BrakeLine1PressurePSI) > Math.Max(elapsedClockSeconds, 0.0001f) * EmergencyValveActuationRatePSIpS)
514+
if (!disableGradient && EmergencyValveActuationRatePSIpS > 0 && emergencyTripped)
501515
{
502516
if (prevState == ValveState.Release) // If valve transitions from release to emergency, quick service activates
503517
{
@@ -547,11 +561,53 @@ public void UpdateTripleValveState(float elapsedClockSeconds)
547561
else EmergencyDumpStartTime = null;
548562
}
549563

564+
public void UpdateAngleCockState(bool AngleCockOpen, ref float AngleCockOpenAmount, ref float? AngleCockOpenTime)
565+
{
566+
float currentTime = (float)this.Car.Simulator.GameTime;
567+
568+
if (AngleCockOpen && AngleCockOpenAmount < 1.0f)
569+
{
570+
if (AngleCockOpenTime == null)
571+
{
572+
AngleCockOpenTime = currentTime;
573+
}
574+
else if (currentTime - AngleCockOpenTime > AngleCockOpeningTime)
575+
{
576+
// Finish opening anglecock at a faster rate once time has elapsed
577+
AngleCockOpenAmount = (currentTime - ((float)AngleCockOpenTime + AngleCockOpeningTime)) / 5 + 0.3f;
578+
579+
if (AngleCockOpenAmount >= 1.0f)
580+
{
581+
AngleCockOpenAmount = 1.0f;
582+
AngleCockOpenTime = null;
583+
}
584+
}
585+
else
586+
{
587+
// Gradually open anglecock toward 30% over 30 seconds
588+
AngleCockOpenAmount = 0.3f * (currentTime - (float)AngleCockOpenTime) / AngleCockOpeningTime;
589+
}
590+
}
591+
else if (!AngleCockOpen && AngleCockOpenAmount > 0.0f)
592+
{
593+
AngleCockOpenAmount = 0.0f;
594+
AngleCockOpenTime = null;
595+
}
596+
}
597+
550598
public override void Update(float elapsedClockSeconds)
551599
{
552600
var valveType = (Car as MSTSWagon).BrakeValve;
553601
float threshold = valveType == MSTSWagon.BrakeValveType.Distributor ? Math.Max((ControlResPressurePSI - BrakeLine1PressurePSI) * AuxCylVolumeRatio, 0) : 0;
554602

603+
BrakePipeChangePSIpS = (BrakeLine1PressurePSI - prevBrakePipePressurePSI) / Math.Max(elapsedClockSeconds, 0.0001f);
604+
SmoothedBrakePipeChangePSIpS.Update(Math.Max(elapsedClockSeconds, 0.0001f), BrakePipeChangePSIpS);
605+
606+
// Update anglecock opening. Anglecocks set to gradually open over 30 seconds, but close instantly.
607+
// Gradual opening prevents undesired emergency applications
608+
UpdateAngleCockState(AngleCockAOpen, ref AngleCockAOpenAmount, ref AngleCockAOpenTime);
609+
UpdateAngleCockState(AngleCockBOpen, ref AngleCockBOpenAmount, ref AngleCockBOpenTime);
610+
555611
if (BleedOffValveOpen)
556612
{
557613
if (valveType == MSTSWagon.BrakeValveType.Distributor)
@@ -591,7 +647,6 @@ public override void Update(float elapsedClockSeconds)
591647
{
592648
float dp = 0;
593649
float dpPipe = 0;
594-
float brakePipeChange = Math.Max(prevBrakePipePressurePSI - BrakeLine1PressurePSI, 0);
595650
if (QuickServiceActive) // Quick service: Brake pipe pressure is locally reduced to speed up initial reduction
596651
{
597652
if (QuickServiceVentRatePSIpS > 0)
@@ -608,7 +663,8 @@ public override void Update(float elapsedClockSeconds)
608663
{
609664
if (AcceleratedApplicationFactor > 0) // Accelerated application: Air is vented from the brake pipe to speed up service applications
610665
{
611-
dpPipe = Math.Min(brakePipeChange * AcceleratedApplicationFactor, elapsedClockSeconds * AcceleratedApplicationLimitPSIpS); // Amount of air vented is proportional to pressure reduction from external sources
666+
// Amount of air vented is proportional to pressure reduction from external sources
667+
dpPipe = MathHelper.Clamp(-SmoothedBrakePipeChangePSIpS.SmoothedValue * AcceleratedApplicationFactor, 0, AcceleratedApplicationLimitPSIpS) * elapsedClockSeconds;
612668
}
613669
dp = elapsedClockSeconds * MaxApplicationRatePSIpS;
614670
}
@@ -1116,7 +1172,8 @@ protected static void PropagateBrakeLinePressures(float elapsedClockSeconds, Tra
11161172
int nSteps = (int)(elapsedClockSeconds / brakePipeTimeFactorS + 1);
11171173
float trainPipeTimeVariationS = elapsedClockSeconds / nSteps;
11181174
float trainPipeLeakLossPSI = lead == null ? 0.0f : (trainPipeTimeVariationS * lead.TrainBrakePipeLeakPSIorInHgpS);
1119-
float serviceTimeFactor = lead != null ? lead.TrainBrakeController != null && lead.TrainBrakeController.EmergencyBraking ? lead.BrakeEmergencyTimeFactorPSIpS : lead.BrakeServiceTimeFactorPSIpS : 0;
1175+
float serviceTimeFactor = lead != null && lead.TrainBrakeController != null ? lead.BrakeServiceTimeFactorPSIpS : 0.001f;
1176+
float emergencyTimeFactor = lead != null && lead.TrainBrakeController != null ? lead.BrakeEmergencyTimeFactorPSIpS : 0.001f;
11201177
for (int i = 0; i < nSteps; i++)
11211178
{
11221179
if (lead != null)
@@ -1127,7 +1184,17 @@ protected static void PropagateBrakeLinePressures(float elapsedClockSeconds, Tra
11271184
lead.BrakeSystem.BrakeLine1PressurePSI -= trainPipeLeakLossPSI;
11281185
}
11291186

1130-
if (lead.TrainBrakeController.TrainBrakeControllerState != ControllerState.Neutral)
1187+
// Emergency brake - vent brake pipe to 0 psi regardless of equalizing res pressure
1188+
if (lead.TrainBrakeController.EmergencyBraking)
1189+
{
1190+
float emergencyVariationFactor = Math.Min(trainPipeTimeVariationS / emergencyTimeFactor, 0.95f);
1191+
float pressureDiffPSI = emergencyVariationFactor * lead.BrakeSystem.BrakeLine1PressurePSI;
1192+
1193+
if (lead.BrakeSystem.BrakeLine1PressurePSI - pressureDiffPSI < 0)
1194+
pressureDiffPSI = lead.BrakeSystem.BrakeLine1PressurePSI;
1195+
lead.BrakeSystem.BrakeLine1PressurePSI -= pressureDiffPSI;
1196+
}
1197+
else if (lead.TrainBrakeController.TrainBrakeControllerState != ControllerState.Neutral)
11311198
{
11321199
// Charge train brake pipe - adjust main reservoir pressure, and lead brake pressure line to maintain brake pipe equal to equalising resevoir pressure - release brakes
11331200
if (lead.BrakeSystem.BrakeLine1PressurePSI < train.EqualReservoirPressurePSIorInHg)
@@ -1203,6 +1270,13 @@ protected static void PropagateBrakeLinePressures(float elapsedClockSeconds, Tra
12031270
// The sign in the equation determines the direction of air flow.
12041271
float trainPipePressureDiffPropagationPSI = pressureDiffPSI * Math.Min(trainPipeTimeVariationS / brakePipeTimeFactorS, 1);
12051272

1273+
// Flow is restricted when either anglecock is not opened fully
1274+
if (car.BrakeSystem.AngleCockAOpenAmount < 1 || prevCar.BrakeSystem.AngleCockBOpenAmount < 1)
1275+
{
1276+
trainPipePressureDiffPropagationPSI *= MathHelper.Min((float)Math.Pow(car.BrakeSystem.AngleCockAOpenAmount * prevCar.BrakeSystem.AngleCockBOpenAmount, 2), 1.0f);
1277+
1278+
}
1279+
12061280
// Air flows from high pressure to low pressure, until pressure is equal in both cars.
12071281
// Brake pipe volumes of both cars are taken into account, so pressure increase/decrease is proportional to relative volumes.
12081282
// If TrainPipePressureDiffPropagationPSI equals to p1-p0 the equalization is achieved in one step.
@@ -1221,11 +1295,25 @@ protected static void PropagateBrakeLinePressures(float elapsedClockSeconds, Tra
12211295
// Empty the brake pipe if the brake hose is not connected and angle cocks are open
12221296
if (!car.BrakeSystem.FrontBrakeHoseConnected && car.BrakeSystem.AngleCockAOpen)
12231297
{
1224-
car.BrakeSystem.BrakeLine1PressurePSI = Math.Max(car.BrakeSystem.BrakeLine1PressurePSI * (1 - trainPipeTimeVariationS / brakePipeTimeFactorS), 0);
1298+
float dp = car.BrakeSystem.BrakeLine1PressurePSI * trainPipeTimeVariationS / brakePipeTimeFactorS;
1299+
1300+
if (car.BrakeSystem.AngleCockAOpenAmount < 1)
1301+
dp *= MathHelper.Clamp((float)Math.Pow(car.BrakeSystem.AngleCockAOpenAmount, 2), 0.0f, 1.0f);
1302+
1303+
if (car.BrakeSystem.BrakeLine1PressurePSI - dp < 0)
1304+
dp = car.BrakeSystem.BrakeLine1PressurePSI;
1305+
car.BrakeSystem.BrakeLine1PressurePSI -= dp;
12251306
}
12261307
if ((nextCar == null || !nextCar.BrakeSystem.FrontBrakeHoseConnected) && car.BrakeSystem.AngleCockBOpen)
12271308
{
1228-
car.BrakeSystem.BrakeLine1PressurePSI = Math.Max(car.BrakeSystem.BrakeLine1PressurePSI * (1 - trainPipeTimeVariationS / brakePipeTimeFactorS), 0);
1309+
float dp = car.BrakeSystem.BrakeLine1PressurePSI * trainPipeTimeVariationS / brakePipeTimeFactorS;
1310+
1311+
if (car.BrakeSystem.AngleCockBOpenAmount < 1)
1312+
dp *= MathHelper.Clamp((float)Math.Pow(car.BrakeSystem.AngleCockBOpenAmount, 2), 0.0f, 1.0f);
1313+
1314+
if (car.BrakeSystem.BrakeLine1PressurePSI - dp < 0)
1315+
dp = car.BrakeSystem.BrakeLine1PressurePSI;
1316+
car.BrakeSystem.BrakeLine1PressurePSI -= dp;
12291317
}
12301318
}
12311319
#if DEBUG_TRAIN_PIPE_LEAK

0 commit comments

Comments
 (0)