Skip to content

Commit

Permalink
Merge pull request #503 from peternewell/derailment#2
Browse files Browse the repository at this point in the history
Update derailment functionality
  • Loading branch information
cjakeman authored Oct 23, 2021
2 parents 98f46f6 + 0e9a259 commit 1dae11d
Show file tree
Hide file tree
Showing 6 changed files with 342 additions and 40 deletions.
22 changes: 22 additions & 0 deletions Source/Documentation/Manual/physics.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4490,3 +4490,25 @@ Two other parameters in the Engine section of the ENG file are used by the TCS:

- ``DoesBrakeCutPower( x )`` sets whether applying brake on the locomotive cuts the traction (1 for enabled, 0 for disabled)
- ``BrakeCutsPowerAtBrakeCylinderPressure( x )`` sets the minimum pressure in the brake cylinder that cuts the traction (by default 4 PSI)


Train Derailment
----------------

Open Rails calculates when it is likely that a train derailment has occurred. The derailment modeled is based upon the wheel climbing the rail
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
in a straight line, rather then following the curve.

OR calculates the Nadal Criteria for each wagon, and then calculates the actual L/V ratio based upon the wagon weight and the relevant
"in train" forces. Open Rails uses some calculated default parameters for the various parameters required to determine the actual L/V
ratio, however more accurate results will be obtained if actual parameters are entered into the ENG or WAG file. The derailment calculations
use information relating to the wagon dimensions, weight and wheel profile information.

Wheel profile details can be entered with the following two parameters:

- ``ORTSMaximumWheelFlangeAngle`` - Wheel flange angle is defined as the maximum angle of the wheel flange relative to the horizontal axis.
UoM - Angle (deg, radians) - default is rad. Typically this value maybe between approx 60 and 75 degrees.

- ``ORTSWheelFlangeLength`` - Wheel flange length is defined as the length of flange starting from the beginning of the maximum flange angle
to the point where flange angle reduces to 26.6 degrees. UoM - Distance (m, in, ft, etc) - default is m

13 changes: 13 additions & 0 deletions Source/Orts.Parsers.Msts/STFReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,12 @@ public enum UNITS
/// </summary>
Temperature = 1 << 27, // "Temperature", note above TemperatureDifference, is different

/// <summary>
/// Valid Units: deg, rad
/// <para>Scaled to Radians</para>
/// </summary>
Angle = 1 << 28,

// "Any" is used where units cannot easily be specified, such as generic routines for interpolating continuous data from point values.
// or interpreting locomotive cab attributes from the ORTSExtendedCVF experimental mechanism.
// "Any" should not be used where the dimensions of a unit are predictable.
Expand Down Expand Up @@ -1128,6 +1134,13 @@ internal double ParseUnitSuffix(ref string constant, UNITS validUnits)
return 1;
}
}
if ((validUnits & UNITS.Angle) > 0)
switch (suffix)
{
case "": return 1.0;
case "rad": return 1;
case "deg": return 0.0174533; // 1 deg = 0.0174533 radians
}
STFException.TraceWarning(this, "Found a suffix '" + suffix + "' which could not be parsed as a " + validUnits.ToString() + " unit");
return 1;
}
Expand Down
31 changes: 31 additions & 0 deletions Source/Orts.Simulation/Simulation/RollingStocks/MSTSWagon.cs
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,23 @@ public virtual void LoadFromWagFile(string wagFilePath)
}
}

// Should always be at least one bogie on rolling stock. If is zero then NaN error occurs.
if (WagonNumBogies == 0)
{
WagonNumBogies = 1;
}

// Set wheel flange parameters to default values.
if (MaximumWheelFlangeAngleRad == 0)
{
MaximumWheelFlangeAngleRad = 1.22173f; // Default = 70 deg - Pre 1990 AAR 1:20 wheel
}

if (WheelFlangeLengthM == 0)
{
WheelFlangeLengthM = 0.0254f; // Height = 1.00in - Pre 1990 AAR 1:20 wheel
}

// Initialise steam heat parameters
if (TrainHeatBoilerWaterUsageGalukpH == null) // If no table entered in WAG file, then use the default table
{
Expand Down Expand Up @@ -1015,6 +1032,8 @@ public virtual void Parse(string lowercasetoken, STFReader stf)
case "wagon(ortslengthairhose": CarAirHoseLengthM = stf.ReadFloatBlock(STFReader.UNITS.Distance, null); break;
case "wagon(ortshorizontallengthairhose": CarAirHoseHorizontalLengthM = stf.ReadFloatBlock(STFReader.UNITS.Distance, null); break;
case "wagon(ortslengthcouplerface": CarCouplerFaceLengthM = stf.ReadFloatBlock(STFReader.UNITS.Distance, null); break;
case "wagon(ortswheelflangelength": WheelFlangeLengthM = stf.ReadFloatBlock(STFReader.UNITS.Distance, null); break;
case "wagon(ortsmaximumwheelflangeangle": MaximumWheelFlangeAngleRad = stf.ReadFloatBlock(STFReader.UNITS.Angle, null); break;
case "wagon(ortstrackgauge":
stf.MustMatch("(");
TrackGaugeM = stf.ReadFloat(STFReader.UNITS.Distance, null);
Expand Down Expand Up @@ -1472,6 +1491,8 @@ public virtual void Copy(MSTSWagon copy)
CarCouplerFaceLengthM = copy.CarCouplerFaceLengthM;
CarAirHoseLengthM = copy.CarAirHoseLengthM;
CarAirHoseHorizontalLengthM = copy.CarAirHoseHorizontalLengthM;
MaximumWheelFlangeAngleRad = copy.MaximumWheelFlangeAngleRad;
WheelFlangeLengthM = copy.WheelFlangeLengthM;
AuxTenderWaterMassKG = copy.AuxTenderWaterMassKG;
TenderWagonMaxCoalMassKG = copy.TenderWagonMaxCoalMassKG;
TenderWagonMaxWaterMassKG = copy.TenderWagonMaxWaterMassKG;
Expand Down Expand Up @@ -1710,6 +1731,11 @@ public override void Save(BinaryWriter outf)

outf.Write(WheelBrakeSlideProtectionActive);
outf.Write(WheelBrakeSlideProtectionTimerS);
outf.Write(AngleOfAttackRad);
outf.Write(DerailClimbDistanceM);
outf.Write(DerailPossible);
outf.Write(DerailExpected);
outf.Write(DerailElapsedTimeS);

base.Save(outf);
}
Expand Down Expand Up @@ -1757,6 +1783,11 @@ public override void Restore(BinaryReader inf)

WheelBrakeSlideProtectionActive = inf.ReadBoolean();
WheelBrakeSlideProtectionTimerS = inf.ReadInt32();
AngleOfAttackRad = inf.ReadSingle();
DerailClimbDistanceM = inf.ReadSingle();
DerailPossible = inf.ReadBoolean();
DerailExpected = inf.ReadBoolean();
DerailElapsedTimeS = inf.ReadSingle();

base.Restore(inf);
}
Expand Down
Loading

0 comments on commit 1dae11d

Please sign in to comment.