Skip to content

Commit a80e868

Browse files
authored
Merge pull request #835 from peternewell/brake_shoe#1
Correct Brake Shoe Force Calculation
2 parents baefb6b + e632edb commit a80e868

File tree

13 files changed

+337
-148
lines changed

13 files changed

+337
-148
lines changed

Source/Documentation/Manual/physics.rst

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2739,6 +2739,34 @@ These changes introduce an extra challenge to train braking, but provide a more
27392739

27402740
For example, in a lot of normal Westinghouse brake systems, a minimum pressure reduction was applied by moving the brake controller to the LAP position. Typically Westinghouse recommended values of between 7 and 10 psi.
27412741

2742+
Brake Shoe Force
2743+
----------------
2744+
2745+
As indicated above the ``MaxBrakeForce`` parameter in the WAG file is the actual force applied to the wheel after reduction by the friction coefficient, often railway companies will provide an Net Braking Ratio (NBR) value to
2746+
specify the amount of force to be applied to the brake shoe. This force is then reduced by the brake shoe CoF to determine the actual force applied to the wheel.
2747+
2748+
To facilitate the direct usage of the NBR value in the WAG file, the following parameters can be used. NB: When using these parameters the ``MaxBrakeForce`` parameter is not required.
2749+
2750+
Brake Shoe Force - This is the current change being implemented. The following changes and parameter are included.
2751+
2752+
``ORTSMaxBrakeShoeForce`` - the force applied to the brake shoe is the main braking force.
2753+
2754+
``ORTSBrakeShoeType`` - this defines a number of different brake shoe types and curves. To provide a more realistic representation of the braking force the default CoF curves are 2D, ie
2755+
they are impacted by both the speed and Brake Shoe Force. Typically ``ORTSBrakeShoeType`` will have one of the following keywords included -
2756+
``Cast_Iron`` - cast iron brake shoe, 2D as above, ``Hi_Friction_Composite`` - high friction composite shoe, 2D as above, ``User_Defined`` - is a user defined curve
2757+
using the ORTSBrakeShoeFriction parameter, 1D (ie, speed only, see above section for the parameter format).
2758+
2759+
``ORTSNumberCarBrakeShoes`` - to facilitate the operation of the default 2D curves above it is necessary to configure the number of brake shoes for each car.
2760+
2761+
Whilst OR will attempt to set some defaults if parameters are left out, the most realistic operation will be achieved by using all the relevant parameters.
2762+
2763+
The following two legacy arrangements can be used as an alternative to the above method,
2764+
2765+
- Legacy #1 - legacy arrangements using MaxBrakeForce on its own will remain unchanged. This in effect is an old MSTS file.
2766+
2767+
- Legacy #2 - where MaxBrakeForce and ORTSBrakeShoeFriction have been set, legacy operation will remain unchanged.
2768+
2769+
27422770
Train Brake Pipe Losses
27432771
-----------------------
27442772

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5465,7 +5465,7 @@ public void UpdateCarSpeeds(float elapsedTime)
54655465
if (car is MSTSLocomotive) locoBehind = false;
54665466
if (car.SpeedMpS > 0)
54675467
{
5468-
car.SpeedMpS += car.TotalForceN / car.MassKG * elapsedTime;
5468+
car.SpeedMpS += (car.TotalForceN / car.MassKG) * elapsedTime;
54695469
if (car.SpeedMpS < 0)
54705470
car.SpeedMpS = 0;
54715471
// If car is manual braked, air_piped car or vacuum_piped, and preceeding car is at stop, then set speed to zero.
@@ -5478,7 +5478,7 @@ public void UpdateCarSpeeds(float elapsedTime)
54785478
}
54795479
else if (car.SpeedMpS < 0)
54805480
{
5481-
car.SpeedMpS += car.TotalForceN / car.MassKG * elapsedTime;
5481+
car.SpeedMpS += (car.TotalForceN / car.MassKG) * elapsedTime;
54825482
if (car.SpeedMpS > 0)
54835483
car.SpeedMpS = 0;
54845484
// If car is manual braked, air_piped car or vacuum_piped, and preceeding car is at stop, then set speed to zero.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1828,7 +1828,7 @@ public void DynamicBrakeBlending(float elapsedClockSeconds)
18281828
{
18291829
if (DynamicBrakeBlendingForceMatch)
18301830
{
1831-
float diff = target * MaxBrakeForceN - DynamicBrakeForceN;
1831+
float diff = target * FrictionBrakeBlendingMaxForceN - DynamicBrakeForceN;
18321832
float threshold = 100;
18331833
if (diff > threshold && DynamicBrakeIntervention < 1)
18341834
DynamicBrakeIntervention = Math.Min(DynamicBrakeIntervention + elapsedClockSeconds, 1);

Source/Orts.Simulation/Simulation/RollingStocks/MSTSSteamLocomotive.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6388,6 +6388,10 @@ public override string GetDebugStatus()
63886388
FormatStrings.FormatEnergy(W.FromBTUpS(BoilerHeatBTU), IsMetric)
63896389
);
63906390

6391+
// calculate values for display, so that display value doesn't go negative
6392+
var superheatTempDisplayC = C.FromF(CurrentSuperheatTempF);
6393+
superheatTempDisplayC = MathHelper.Clamp(superheatTempDisplayC, 0.0f, C.FromF(MaxSuperheatRefTempF));
6394+
63916395
status.AppendFormat("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}\t{7}\t{8}\n",
63926396
Simulator.Catalog.GetString("Temp:"),
63936397
Simulator.Catalog.GetString("Flue"),
@@ -6397,7 +6401,8 @@ public override string GetDebugStatus()
63976401
Simulator.Catalog.GetString("MaxSupH"),
63986402
FormatStrings.FormatTemperature(C.FromF(MaxSuperheatRefTempF), IsMetric, false),
63996403
Simulator.Catalog.GetString("CurSupH"),
6400-
FormatStrings.FormatTemperature(C.FromF(CurrentSuperheatTempF), IsMetric, false));
6404+
FormatStrings.FormatTemperature(superheatTempDisplayC, IsMetric, false)
6405+
);
64016406

64026407
status.AppendFormat("\n\t\t === {0} === \t\t{1}/{2}\n",
64036408
Simulator.Catalog.GetString("Steam Usage"),
@@ -6838,8 +6843,8 @@ public override string GetDebugStatus()
68386843
);
68396844
}
68406845

6841-
if (Simulator.UseAdvancedAdhesion && !Simulator.Settings.SimpleControlPhysics && SteamEngineType != SteamEngineTypes.Geared)
6842-
// Only display slip monitor if advanced adhesion is set and simplecontrols/physics not set
6846+
if (Simulator.UseAdvancedAdhesion && !Simulator.Settings.SimpleControlPhysics && SteamEngineType != SteamEngineTypes.Geared)
6847+
// Only display slip monitor if advanced adhesion is set and simplecontrols/physics not set
68436848
{
68446849
status.AppendFormat("\n\t\t === {0} === \n", Simulator.Catalog.GetString("Slip Monitor"));
68456850
status.AppendFormat("{0}\t{1}\t{2:N0}\t{3}\t{4}\t{5}\t{6}\t{7}\t{8:N2}\t{9}\t{10}\t{11:N2}\t{12}\t{13}\t{14:N1}\n",

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

Lines changed: 81 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,7 @@ public class MSTSWagon : TrainCar
8686

8787
public bool GenericItem1;
8888
public bool GenericItem2;
89-
90-
Interpolator BrakeShoeFrictionFactor; // Factor of friction for wagon brake shoes
89+
9190
const float WaterLBpUKG = 10.0f; // lbs of water in 1 gal (uk)
9291
float TempMassDiffRatio;
9392

@@ -600,8 +599,54 @@ public virtual void LoadFromWagFile(string wagFilePath)
600599

601600
// Initialise key wagon parameters
602601
MassKG = InitialMassKG;
602+
603603
MaxHandbrakeForceN = InitialMaxHandbrakeForceN;
604-
MaxBrakeForceN = InitialMaxBrakeForceN;
604+
605+
FrictionBrakeBlendingMaxForceN = InitialMaxBrakeForceN; // set the value of braking when blended with dynamic brakes
606+
607+
if (MaxBrakeShoeForceN != 0 && BrakeShoeType != BrakeShoeTypes.Unknown)
608+
{
609+
MaxBrakeForceN = MaxBrakeShoeForceN;
610+
}
611+
else
612+
{
613+
MaxBrakeForceN = InitialMaxBrakeForceN;
614+
615+
if (Simulator.Settings.VerboseConfigurationMessages)
616+
{
617+
Trace.TraceInformation("Unknown BrakeShoeType set to OR default (Cast Iron) with a MaxBrakeForce of {0}", FormatStrings.FormatForce(MaxBrakeForceN, IsMetric));
618+
}
619+
}
620+
621+
// Initialise number of brake shoes per wagon
622+
if (NumberCarBrakeShoes == 0 && WagonType == WagonTypes.Engine)
623+
{
624+
var LocoTest = Simulator.PlayerLocomotive as MSTSLocomotive;
625+
626+
if (LocoTest != null && LocoTest.DriveWheelOnlyBrakes)
627+
{
628+
NumberCarBrakeShoes = LocoNumDrvAxles * 4; // Assume 4 brake shoes per axle on drive wheels only
629+
}
630+
else
631+
{
632+
NumberCarBrakeShoes = (LocoNumDrvAxles * 4) + (WagonNumAxles * 4); // Assume 4 brake shoes per axle on all wheels
633+
}
634+
635+
if (Simulator.Settings.VerboseConfigurationMessages && (BrakeShoeType == BrakeShoeTypes.Cast_Iron || BrakeShoeType == BrakeShoeTypes.High_Friction_Composite))
636+
{
637+
Trace.TraceInformation("Number of Locomotive Brakeshoes set to default value of {0}", NumberCarBrakeShoes);
638+
}
639+
}
640+
else if (NumberCarBrakeShoes == 0)
641+
{
642+
NumberCarBrakeShoes = WagonNumAxles * 4; // Assume 4 brake shoes per axle
643+
644+
if (Simulator.Settings.VerboseConfigurationMessages && (BrakeShoeType == BrakeShoeTypes.Cast_Iron || BrakeShoeType == BrakeShoeTypes.High_Friction_Composite))
645+
{
646+
Trace.TraceInformation("Number of Wagon Brakeshoes set to default value of {0}", NumberCarBrakeShoes);
647+
}
648+
}
649+
605650
CentreOfGravityM = InitialCentreOfGravityM;
606651

607652
if (FreightAnimations != null)
@@ -673,7 +718,11 @@ public virtual void LoadFromWagFile(string wagFilePath)
673718
LoadEmptyWagonFrontalAreaM2 = WagonFrontalAreaM2;
674719
}
675720

676-
if (FreightAnimations.EmptyMaxBrakeForceN > 0)
721+
if (FreightAnimations.EmptyMaxBrakeShoeForceN > 0)
722+
{
723+
LoadEmptyMaxBrakeForceN = FreightAnimations.EmptyMaxBrakeShoeForceN;
724+
}
725+
else if (FreightAnimations.EmptyMaxBrakeForceN > 0)
677726
{
678727
LoadEmptyMaxBrakeForceN = FreightAnimations.EmptyMaxBrakeForceN;
679728
}
@@ -749,8 +798,11 @@ public virtual void LoadFromWagFile(string wagFilePath)
749798
LoadFullWagonFrontalAreaM2 = WagonFrontalAreaM2;
750799
}
751800

752-
753-
if (FreightAnimations.FullPhysicsStaticOne.FullStaticMaxBrakeForceN > 0)
801+
if (FreightAnimations.FullPhysicsStaticOne.FullStaticMaxBrakeShoeForceN > 0)
802+
{
803+
LoadFullMaxBrakeForceN = FreightAnimations.FullPhysicsStaticOne.FullStaticMaxBrakeShoeForceN;
804+
}
805+
else if (FreightAnimations.FullPhysicsStaticOne.FullStaticMaxBrakeForceN > 0)
754806
{
755807
LoadFullMaxBrakeForceN = FreightAnimations.FullPhysicsStaticOne.FullStaticMaxBrakeForceN;
756808
}
@@ -836,8 +888,11 @@ public virtual void LoadFromWagFile(string wagFilePath)
836888
LoadFullWagonFrontalAreaM2 = WagonFrontalAreaM2;
837889
}
838890

839-
840-
if (FreightAnimations.FullPhysicsContinuousOne.FullMaxBrakeForceN > 0)
891+
if (FreightAnimations.FullPhysicsContinuousOne.FullMaxBrakeShoeForceN > 0)
892+
{
893+
LoadFullMaxBrakeForceN = FreightAnimations.FullPhysicsContinuousOne.FullMaxBrakeShoeForceN;
894+
}
895+
else if (FreightAnimations.FullPhysicsContinuousOne.FullMaxBrakeForceN > 0)
841896
{
842897
LoadFullMaxBrakeForceN = FreightAnimations.FullPhysicsContinuousOne.FullMaxBrakeForceN;
843898
}
@@ -957,7 +1012,6 @@ public virtual void LoadFromWagFile(string wagFilePath)
9571012
Trace.TraceInformation("Empty Values = Brake {0} Handbrake {1} DavisA {2} DavisB {3} DavisC {4} CoGY {5}", LoadEmptyMaxBrakeForceN, LoadEmptyMaxHandbrakeForceN, LoadEmptyORTSDavis_A, LoadEmptyORTSDavis_B, LoadEmptyORTSDavis_C, LoadEmptyCentreOfGravityM_Y);
9581013
Trace.TraceInformation("Full Values = Brake {0} Handbrake {1} DavisA {2} DavisB {3} DavisC {4} CoGY {5}", LoadFullMaxBrakeForceN, LoadFullMaxHandbrakeForceN, LoadFullORTSDavis_A, LoadFullORTSDavis_B, LoadFullORTSDavis_C, LoadFullCentreOfGravityM_Y);
9591014
#endif
960-
9611015
}
9621016

9631017
// Determine whether or not to use the Davis friction model. Must come after freight animations are initialized.
@@ -1134,6 +1188,21 @@ public virtual void Parse(string lowercasetoken, STFReader stf)
11341188
case "wagon(ortsbrakeshoefriction": BrakeShoeFrictionFactor = new Interpolator(stf); break;
11351189
case "wagon(maxhandbrakeforce": InitialMaxHandbrakeForceN = stf.ReadFloatBlock(STFReader.UNITS.Force, null); break;
11361190
case "wagon(maxbrakeforce": InitialMaxBrakeForceN = stf.ReadFloatBlock(STFReader.UNITS.Force, null); break;
1191+
case "wagon(ortsmaxbrakeshoeforce": MaxBrakeShoeForceN = stf.ReadFloatBlock(STFReader.UNITS.Force, null); break;
1192+
case "wagon(ortsnumbercarbrakeshoes": NumberCarBrakeShoes = stf.ReadIntBlock(null); break;
1193+
case "wagon(ortsbrakeshoetype":
1194+
stf.MustMatch("(");
1195+
var brakeShoeType = stf.ReadString();
1196+
try
1197+
{
1198+
BrakeShoeType = (BrakeShoeTypes)Enum.Parse(typeof(BrakeShoeTypes), brakeShoeType);
1199+
}
1200+
catch
1201+
{
1202+
STFException.TraceWarning(stf, "Assumed unknown brake shoe type " + brakeShoeType);
1203+
}
1204+
break;
1205+
11371206
case "wagon(ortswheelbrakeslideprotection":
11381207
// stf.MustMatch("(");
11391208
var brakeslideprotection = stf.ReadFloatBlock(STFReader.UNITS.None, null);
@@ -1461,6 +1530,7 @@ public virtual void Copy(MSTSWagon copy)
14611530
HasPassengerCapacity = copy.HasPassengerCapacity;
14621531
WagonType = copy.WagonType;
14631532
WagonSpecialType = copy.WagonSpecialType;
1533+
BrakeShoeType = copy.BrakeShoeType;
14641534
FreightShapeFileName = copy.FreightShapeFileName;
14651535
FreightAnimMaxLevelM = copy.FreightAnimMaxLevelM;
14661536
FreightAnimMinLevelM = copy.FreightAnimMinLevelM;
@@ -1503,6 +1573,8 @@ public virtual void Copy(MSTSWagon copy)
15031573
InitialMaxBrakeForceN = copy.InitialMaxBrakeForceN;
15041574
InitialMaxHandbrakeForceN = copy.InitialMaxHandbrakeForceN;
15051575
MaxBrakeForceN = copy.MaxBrakeForceN;
1576+
MaxBrakeShoeForceN = copy.MaxBrakeShoeForceN;
1577+
NumberCarBrakeShoes = copy.NumberCarBrakeShoes;
15061578
MaxHandbrakeForceN = copy.MaxHandbrakeForceN;
15071579
WindowDeratingFactor = copy.WindowDeratingFactor;
15081580
DesiredCompartmentTempSetpointC = copy.DesiredCompartmentTempSetpointC;
@@ -3968,46 +4040,6 @@ public override float GetFilledFraction(uint pickupType)
39684040
if (FreightAnimations.LoadedOne != null) fraction = FreightAnimations.LoadedOne.LoadPerCent / 100;
39694041
return fraction;
39704042
}
3971-
3972-
/// <summary>
3973-
/// Returns the Brake shoe coefficient.
3974-
/// </summary>
3975-
3976-
public override float GetUserBrakeShoeFrictionFactor()
3977-
{
3978-
var frictionfraction = 0.0f;
3979-
if ( BrakeShoeFrictionFactor == null)
3980-
{
3981-
frictionfraction = 0.0f;
3982-
}
3983-
else
3984-
{
3985-
frictionfraction = BrakeShoeFrictionFactor[MpS.ToKpH(AbsSpeedMpS)];
3986-
}
3987-
3988-
return frictionfraction;
3989-
}
3990-
3991-
/// <summary>
3992-
/// Returns the Brake shoe coefficient at zero speed.
3993-
/// </summary>
3994-
3995-
public override float GetZeroUserBrakeShoeFrictionFactor()
3996-
{
3997-
var frictionfraction = 0.0f;
3998-
if (BrakeShoeFrictionFactor == null)
3999-
{
4000-
frictionfraction = 0.0f;
4001-
}
4002-
else
4003-
{
4004-
frictionfraction = BrakeShoeFrictionFactor[0.0f];
4005-
}
4006-
4007-
return frictionfraction;
4008-
}
4009-
4010-
40114043

40124044
/// <summary>
40134045
/// Starts a continuous increase in controlled value.

0 commit comments

Comments
 (0)