Skip to content

Commit 1dae11d

Browse files
authored
Merge pull request #503 from peternewell/derailment#2
Update derailment functionality
2 parents 98f46f6 + 0e9a259 commit 1dae11d

File tree

6 files changed

+342
-40
lines changed

6 files changed

+342
-40
lines changed

Source/Documentation/Manual/physics.rst

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4490,3 +4490,25 @@ Two other parameters in the Engine section of the ENG file are used by the TCS:
44904490

44914491
- ``DoesBrakeCutPower( x )`` sets whether applying brake on the locomotive cuts the traction (1 for enabled, 0 for disabled)
44924492
- ``BrakeCutsPowerAtBrakeCylinderPressure( x )`` sets the minimum pressure in the brake cylinder that cuts the traction (by default 4 PSI)
4493+
4494+
4495+
Train Derailment
4496+
----------------
4497+
4498+
Open Rails calculates when it is likely that a train derailment has occurred. The derailment modeled is based upon the wheel climbing the rail
4499+
when the train is in a curve. Light (empty wagons) can sometimes derail due to 'string lining' where the train forces attempt to pull the train
4500+
in a straight line, rather then following the curve.
4501+
4502+
OR calculates the Nadal Criteria for each wagon, and then calculates the actual L/V ratio based upon the wagon weight and the relevant
4503+
"in train" forces. Open Rails uses some calculated default parameters for the various parameters required to determine the actual L/V
4504+
ratio, however more accurate results will be obtained if actual parameters are entered into the ENG or WAG file. The derailment calculations
4505+
use information relating to the wagon dimensions, weight and wheel profile information.
4506+
4507+
Wheel profile details can be entered with the following two parameters:
4508+
4509+
- ``ORTSMaximumWheelFlangeAngle`` - Wheel flange angle is defined as the maximum angle of the wheel flange relative to the horizontal axis.
4510+
UoM - Angle (deg, radians) - default is rad. Typically this value maybe between approx 60 and 75 degrees.
4511+
4512+
- ``ORTSWheelFlangeLength`` - Wheel flange length is defined as the length of flange starting from the beginning of the maximum flange angle
4513+
to the point where flange angle reduces to 26.6 degrees. UoM - Distance (m, in, ft, etc) - default is m
4514+

Source/Orts.Parsers.Msts/STFReader.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -809,6 +809,12 @@ public enum UNITS
809809
/// </summary>
810810
Temperature = 1 << 27, // "Temperature", note above TemperatureDifference, is different
811811

812+
/// <summary>
813+
/// Valid Units: deg, rad
814+
/// <para>Scaled to Radians</para>
815+
/// </summary>
816+
Angle = 1 << 28,
817+
812818
// "Any" is used where units cannot easily be specified, such as generic routines for interpolating continuous data from point values.
813819
// or interpreting locomotive cab attributes from the ORTSExtendedCVF experimental mechanism.
814820
// "Any" should not be used where the dimensions of a unit are predictable.
@@ -1128,6 +1134,13 @@ internal double ParseUnitSuffix(ref string constant, UNITS validUnits)
11281134
return 1;
11291135
}
11301136
}
1137+
if ((validUnits & UNITS.Angle) > 0)
1138+
switch (suffix)
1139+
{
1140+
case "": return 1.0;
1141+
case "rad": return 1;
1142+
case "deg": return 0.0174533; // 1 deg = 0.0174533 radians
1143+
}
11311144
STFException.TraceWarning(this, "Found a suffix '" + suffix + "' which could not be parsed as a " + validUnits.ToString() + " unit");
11321145
return 1;
11331146
}

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

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,23 @@ public virtual void LoadFromWagFile(string wagFilePath)
500500
}
501501
}
502502

503+
// Should always be at least one bogie on rolling stock. If is zero then NaN error occurs.
504+
if (WagonNumBogies == 0)
505+
{
506+
WagonNumBogies = 1;
507+
}
508+
509+
// Set wheel flange parameters to default values.
510+
if (MaximumWheelFlangeAngleRad == 0)
511+
{
512+
MaximumWheelFlangeAngleRad = 1.22173f; // Default = 70 deg - Pre 1990 AAR 1:20 wheel
513+
}
514+
515+
if (WheelFlangeLengthM == 0)
516+
{
517+
WheelFlangeLengthM = 0.0254f; // Height = 1.00in - Pre 1990 AAR 1:20 wheel
518+
}
519+
503520
// Initialise steam heat parameters
504521
if (TrainHeatBoilerWaterUsageGalukpH == null) // If no table entered in WAG file, then use the default table
505522
{
@@ -1015,6 +1032,8 @@ public virtual void Parse(string lowercasetoken, STFReader stf)
10151032
case "wagon(ortslengthairhose": CarAirHoseLengthM = stf.ReadFloatBlock(STFReader.UNITS.Distance, null); break;
10161033
case "wagon(ortshorizontallengthairhose": CarAirHoseHorizontalLengthM = stf.ReadFloatBlock(STFReader.UNITS.Distance, null); break;
10171034
case "wagon(ortslengthcouplerface": CarCouplerFaceLengthM = stf.ReadFloatBlock(STFReader.UNITS.Distance, null); break;
1035+
case "wagon(ortswheelflangelength": WheelFlangeLengthM = stf.ReadFloatBlock(STFReader.UNITS.Distance, null); break;
1036+
case "wagon(ortsmaximumwheelflangeangle": MaximumWheelFlangeAngleRad = stf.ReadFloatBlock(STFReader.UNITS.Angle, null); break;
10181037
case "wagon(ortstrackgauge":
10191038
stf.MustMatch("(");
10201039
TrackGaugeM = stf.ReadFloat(STFReader.UNITS.Distance, null);
@@ -1472,6 +1491,8 @@ public virtual void Copy(MSTSWagon copy)
14721491
CarCouplerFaceLengthM = copy.CarCouplerFaceLengthM;
14731492
CarAirHoseLengthM = copy.CarAirHoseLengthM;
14741493
CarAirHoseHorizontalLengthM = copy.CarAirHoseHorizontalLengthM;
1494+
MaximumWheelFlangeAngleRad = copy.MaximumWheelFlangeAngleRad;
1495+
WheelFlangeLengthM = copy.WheelFlangeLengthM;
14751496
AuxTenderWaterMassKG = copy.AuxTenderWaterMassKG;
14761497
TenderWagonMaxCoalMassKG = copy.TenderWagonMaxCoalMassKG;
14771498
TenderWagonMaxWaterMassKG = copy.TenderWagonMaxWaterMassKG;
@@ -1710,6 +1731,11 @@ public override void Save(BinaryWriter outf)
17101731

17111732
outf.Write(WheelBrakeSlideProtectionActive);
17121733
outf.Write(WheelBrakeSlideProtectionTimerS);
1734+
outf.Write(AngleOfAttackRad);
1735+
outf.Write(DerailClimbDistanceM);
1736+
outf.Write(DerailPossible);
1737+
outf.Write(DerailExpected);
1738+
outf.Write(DerailElapsedTimeS);
17131739

17141740
base.Save(outf);
17151741
}
@@ -1757,6 +1783,11 @@ public override void Restore(BinaryReader inf)
17571783

17581784
WheelBrakeSlideProtectionActive = inf.ReadBoolean();
17591785
WheelBrakeSlideProtectionTimerS = inf.ReadInt32();
1786+
AngleOfAttackRad = inf.ReadSingle();
1787+
DerailClimbDistanceM = inf.ReadSingle();
1788+
DerailPossible = inf.ReadBoolean();
1789+
DerailExpected = inf.ReadBoolean();
1790+
DerailElapsedTimeS = inf.ReadSingle();
17601791

17611792
base.Restore(inf);
17621793
}

0 commit comments

Comments
 (0)