Skip to content

Commit 4981d5b

Browse files
committed
Correct Save / Restore issue, and other changes to adhesion algorithim
1 parent 2a7fb17 commit 4981d5b

File tree

3 files changed

+89
-32
lines changed

3 files changed

+89
-32
lines changed

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,8 @@ public enum SoundState
147147
public bool OnLineCabRadio;
148148
public string OnLineCabRadioURL;
149149

150+
float ZeroSpeedAdhesionBase;
151+
150152
public float FilteredBrakePipeFlowM3pS;
151153
public IIRFilter AFMFilter;
152154

@@ -2803,6 +2805,7 @@ public virtual void AdvancedAdhesion(float elapsedClockSeconds)
28032805
axle.WheelDistanceGaugeM = TrackGaugeM;
28042806
axle.CurrentCurveRadiusM = CurrentCurveRadiusM;
28052807
axle.BogieRigidWheelBaseM = RigidWheelBaseM;
2808+
axle.CurtiusKnifflerZeroSpeed = ZeroSpeedAdhesionBase;
28062809
}
28072810
LocomotiveAxles.Update(elapsedClockSeconds);
28082811
MotiveForceN = LocomotiveAxles.CompensatedForceN;
@@ -3186,6 +3189,9 @@ public virtual void UpdateFrictionCoefficient(float elapsedClockSeconds)
31863189
Train.LocomotiveCoefficientFriction = BaseuMax * BaseFrictionCoefficientFactor * AdhesionMultiplier; // Find friction coefficient factor for locomotive
31873190
Train.LocomotiveCoefficientFriction = MathHelper.Clamp(Train.LocomotiveCoefficientFriction, 0.05f, 0.8f); // Ensure friction coefficient never exceeds a "reasonable" value
31883191

3192+
float ZeroBaseuMax = (Curtius_KnifflerA / (Curtius_KnifflerB) + Curtius_KnifflerC); // Base Curtius - Kniffler equation - u = 0.33, all other values are scaled off this formula
3193+
ZeroSpeedAdhesionBase = ZeroBaseuMax * BaseFrictionCoefficientFactor * AdhesionMultiplier;
3194+
31893195
// Set adhesion conditions for diesel, electric or steam geared locomotives
31903196
if (elapsedClockSeconds > 0)
31913197
{
@@ -3194,6 +3200,7 @@ public virtual void UpdateFrictionCoefficient(float elapsedClockSeconds)
31943200
foreach (var axle in LocomotiveAxles)
31953201
{
31963202
axle.AdhesionLimit = AdhesionConditions * BaseuMax;
3203+
axle.CurtiusKnifflerZeroSpeed = ZeroBaseuMax;
31973204
}
31983205
}
31993206

Source/Orts.Simulation/Simulation/RollingStocks/SubSystems/PowerTransmissions/Axle.cs

Lines changed: 81 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,8 @@ public void Initialize()
229229
{
230230
if (axle.InertiaKgm2 <= 0) axle.InertiaKgm2 = locomotive.AxleInertiaKgm2 / AxleList.Count;
231231
if (axle.AxleWeightN <= 0) axle.AxleWeightN = 9.81f * locomotive.DrvWheelWeightKg / AxleList.Count; //remains fixed for diesel/electric locomotives, but varies for steam locomotives
232+
if (axle.NumAxles <= 0) axle.NumAxles = locomotive.LocoNumDrvAxles;
233+
if (axle.WheelRadiusM <= 0) axle.WheelRadiusM = locomotive.DriverWheelRadiusM;
232234
if (axle.DampingNs <= 0) axle.DampingNs = locomotive.MassKG / 1000.0f / AxleList.Count;
233235
if (axle.FrictionN <= 0) axle.FrictionN = locomotive.MassKG / 1000.0f / AxleList.Count;
234236
}
@@ -496,13 +498,18 @@ public float TransmissionEfficiency
496498
/// <summary>
497499
/// Axles in group of wheels
498500
/// </summary>
499-
public float NumAxles = 1;
501+
public float NumAxles;
500502

501503
/// <summary>
502504
/// Static adhesion coefficient, as given by Curtius-Kniffler formula
503505
/// </summary>
504506
public float AdhesionLimit;
505507

508+
/// <summary>
509+
/// Static adhesion coefficient, as given by Curtius-Kniffler formula, at zero speed, ie UMax
510+
/// </summary>
511+
public float CurtiusKnifflerZeroSpeed;
512+
506513
/// <summary>
507514
/// Wheel adhesion as calculated by Polach
508515
/// </summary>
@@ -560,15 +567,34 @@ public float TransmissionEfficiency
560567
public void ComputeWheelSlipThresholdMpS()
561568
{
562569
// Bisection algorithm. We assume adhesion maximum is between 0 and 4 m/s
563-
double a = 0;
570+
double a = 0.005f;
564571
double b = 4;
565572
// We have to find the zero of the derivative of adhesion curve
566573
// i.e. the point where slope changes from positive (adhesion region)
567574
// to negative (slip region)
568575
double dx = 0.001;
569576
double fa = SlipCharacteristics(a + dx) - SlipCharacteristics(a);
570577
double fb = SlipCharacteristics(b + dx) - SlipCharacteristics(b);
571-
if (fa * fb > 0)
578+
579+
double s = 0.05f;
580+
double t = 0.1f;
581+
double u = 0.25f;
582+
double v = 0.5f;
583+
double x = 0.75f;
584+
double y = 1.0f;
585+
586+
double fa1 = SlipCharacteristics(a);
587+
double fb1 = SlipCharacteristics(b);
588+
double fs = SlipCharacteristics(s);
589+
double ft = SlipCharacteristics(t);
590+
double fu = SlipCharacteristics(u);
591+
double fv = SlipCharacteristics(v);
592+
double fx = SlipCharacteristics(x);
593+
double fy = SlipCharacteristics(y);
594+
double SlipSpeedMpS = AxleSpeedMpS - TrainSpeedMpS;
595+
double fslip = SlipCharacteristics(SlipSpeedMpS);
596+
597+
if (fa * fb > 0)
572598
{
573599
// If sign does not change, bisection fails
574600
WheelSlipThresholdMpS = MpS.FromKpH(0.05f);
@@ -590,6 +616,10 @@ public void ComputeWheelSlipThresholdMpS()
590616
}
591617
}
592618
WheelSlipThresholdMpS = (float)Math.Max((a + b) / 2, MpS.FromKpH(0.2f));
619+
620+
// if (SlipSpeedMpS > 0)
621+
// Trace.TraceInformation("Fx Values - a {0} fa1 {1} b {2} fb1 {3} s {4} fs {5} t {6} ft {7} u {8} fu {9} v {10} fv {11} x {12} fx {13} y {14} fy {15} Speed {16} Threshold {17} Fslip {18} SlipSpeed {19}", a, fa1, b, fb1, s, fs, t, ft, u, fu, v, fv, x, fx, y, fy, TrainSpeedMpS, WheelSlipThresholdMpS, fslip, SlipSpeedMpS);
622+
593623
}
594624

595625
/// <summary>
@@ -752,9 +782,9 @@ public void Restore(BinaryReader inf)
752782
previousSlipPercent = inf.ReadSingle();
753783
previousSlipSpeedMpS = inf.ReadSingle();
754784
AxleForceN = inf.ReadSingle();
755-
AxleSpeedMpS = inf.ReadSingle();
785+
AxleSpeedMpS = inf.ReadDouble();
756786
NumOfSubstepsPS = inf.ReadInt32();
757-
integratorError = inf.ReadSingle();
787+
integratorError = inf.ReadDouble();
758788
}
759789

760790
/// <summary>
@@ -955,82 +985,99 @@ public virtual void Update(float timeSpan)
955985
class PolachCalculator
956986
{
957987
Axle Axle;
958-
double StiffnessPreFactors;
988+
double StiffnessPreFactors1;
989+
double StiffnessPreFactors2;
959990
double polach_A;
991+
double wheelLoadN;
960992
double polach_B;
961993
double polach_Ka;
962994
double polach_Ks;
963995
double umax;
964-
double speedMpS;
996+
double trainSpeedMpS;
965997
double spinM1;
966998
double Sy = 0;
967999
double Sy2 = 0;
1000+
double Syc = 0;
9681001
double Syc2 = 0;
9691002
double kalker_C11;
9701003
double kalker_C22;
1004+
double zeroSpeedAdhesion;
1005+
double a_HertzianMM;
1006+
9711007
public PolachCalculator(Axle axle)
9721008
{
9731009
Axle = axle;
9741010
}
9751011
public void Update()
9761012
{
9771013
umax = Axle.AdhesionLimit;
978-
speedMpS = Math.Abs(Axle.TrainSpeedMpS);
1014+
trainSpeedMpS = Math.Abs(Axle.TrainSpeedMpS);
1015+
zeroSpeedAdhesion = Axle.CurtiusKnifflerZeroSpeed;
9791016

9801017
var wheelRadiusMM = Axle.WheelRadiusM * 1000;
9811018
var wheelDistanceGaugeMM = Axle.WheelDistanceGaugeM * 1000;
9821019
var GNm2 = 8.40E+10;
983-
var wheelLoadN = Axle.AxleWeightN / (Axle.NumAxles * 2); // Assume two wheels per axle, and thus wheel weight will be have the value - multiple axles????
1020+
wheelLoadN = Axle.AxleWeightN / (Axle.NumAxles * 2); // Assume two wheels per axle, and thus wheel weight will be have the value - multiple axles????
9841021
var wheelLoadkN = Axle.AxleWeightN / (Axle.NumAxles * 2 * 1000); // Assume two wheels per axle, and thus wheel weight will be have the value - multiple axles????
9851022
var Young_ModulusMPa = 207000;
9861023

1024+
// Trace.TraceInformation("Wheel Load - WheelLoad {0} AxleWeight {1} AxleNumbers {2}", wheelLoadN, Axle.AxleWeightN, Axle.NumAxles);
1025+
9871026
// Calculate Hertzian values - assume 2b = 12mm.
9881027
var b_HertzianMM = 6.0;
989-
var a_HertzianMM = (3.04f / 2) * Math.Sqrt(((wheelLoadkN * wheelRadiusMM) / (2 * b_HertzianMM * Young_ModulusMPa)));
1028+
a_HertzianMM = (3.04f / 2) * Math.Sqrt(((wheelLoadkN * wheelRadiusMM * 1000) / (2 * b_HertzianMM * Young_ModulusMPa)));
9901029

9911030
var hertzianMM = a_HertzianMM / b_HertzianMM;
9921031
var hertzianMM2 = hertzianMM * hertzianMM;
9931032
// Calculate Kalker values
9941033
kalker_C11 = 0.32955 * hertzianMM2 + 0.48538 * hertzianMM + 3.4992;
9951034
kalker_C22 = 0.90909 * hertzianMM2 + 1.2594 * hertzianMM + 2.3853;
9961035

997-
StiffnessPreFactors = (GNm2 * Math.PI * a_HertzianMM * b_HertzianMM) / (4.0 * wheelLoadN);
1036+
StiffnessPreFactors1 = (GNm2 * Math.PI * a_HertzianMM * b_HertzianMM) / (4.0 * wheelLoadN);
1037+
1038+
1039+
1040+
// Trace.TraceInformation("Prefactor 2 - Stiffness2 {0} WheelLoadN {1} AxleWeight {2} NumAxles {3}", StiffnessPreFactors2, wheelLoadN, Axle.AxleWeightN, Axle.NumAxles);
9981041

9991042
// Calculate slip and creep values
1000-
var wheelProfileConicityRad = 0.5;
1001-
var wheelCentreDeviationMM = 3.0;
1043+
var wheelProfileConicityRad = 0.5f;
1044+
var wheelCentreDeviationMM = 3.0f;
10021045
double YawAngleRad = 0;
10031046
if (Axle.CurrentCurveRadiusM > 0)
10041047
{
10051048
YawAngleRad = Math.Asin(2.0f * Axle.BogieRigidWheelBaseM / Axle.CurrentCurveRadiusM);
10061049
}
1007-
var lateralSlipVelocityMpS = speedMpS * (Axle.CurrentCurveRadiusM * wheelProfileConicityRad * wheelCentreDeviationMM * YawAngleRad) / (wheelDistanceGaugeMM * wheelRadiusMM);
1008-
spinM1 = Math.Sin(wheelProfileConicityRad) / wheelRadiusMM;
1009-
Sy = lateralSlipVelocityMpS / speedMpS;
1050+
1051+
var supplenessFactor = (wheelDistanceGaugeMM * wheelRadiusMM) / (wheelProfileConicityRad * wheelCentreDeviationMM);
1052+
var lateralSlipVelocityMpS = Math.Abs(((-1 * Axle.CurrentCurveRadiusM * YawAngleRad) / supplenessFactor) * trainSpeedMpS);
1053+
Sy = lateralSlipVelocityMpS / trainSpeedMpS;
1054+
if (float.IsNaN((float)Sy)) Sy = 0;//avoid NaN on HuD display when first starting OR
10101055
Sy2 = Sy * Sy;
1011-
var Syc = Sy + spinM1 * a_HertzianMM;
1056+
1057+
spinM1 = Math.Sin(wheelProfileConicityRad) / wheelRadiusMM;
1058+
Syc = Sy + (spinM1 * a_HertzianMM);
10121059
Syc2 = Syc * Syc;
10131060

10141061
// calculate "standard" Polach adhesion parameters as straight line approximations as u varies - these values are capped at the moment at the u=0.3 level
10151062
// Taking them lower may reduce the stability of the calculations
10161063
polach_A = 0.4;
1017-
polach_B = (1.6 * umax) - 0.28;
1064+
polach_B = (1.6 * zeroSpeedAdhesion) - 0.28;
10181065
if (polach_B < 0.2) polach_B = 0.2f;
10191066

1020-
polach_Ka = (2.8 * umax) - 0.54;
1067+
polach_Ka = (2.8 * zeroSpeedAdhesion) - 0.54;
10211068
if (polach_Ka < 0.3) polach_Ka = 0.3f;
10221069

1023-
polach_Ks = (1.2 * umax) - 0.26;
1070+
polach_Ks = (1.2 * zeroSpeedAdhesion) - 0.26;
10241071
if (polach_Ks < 0.1) polach_Ks = 0.1f;
10251072
}
10261073
public double SlipCharacteristics(double slipSpeedMpS)
10271074
{
1028-
var polach_uadhesion = umax * ((1 - polach_A) * Math.Exp(-polach_B * slipSpeedMpS) + polach_A);
1075+
var polach_uadhesion = zeroSpeedAdhesion * (((1 - polach_A) * Math.Exp(-polach_B * slipSpeedMpS)) + polach_A);
10291076

1030-
if (speedMpS < 0.05f)
1077+
if (trainSpeedMpS < 0.05f)
10311078
return polach_uadhesion;
10321079

1033-
var Sx = slipSpeedMpS / speedMpS;
1080+
var Sx = slipSpeedMpS / trainSpeedMpS;
10341081
var Sx2 = Sx * Sx;
10351082
var S = Math.Sqrt(Sx2 + Sy2);
10361083
var Sc = Math.Sqrt(Sx2 + Syc2);
@@ -1043,19 +1090,22 @@ public double SlipCharacteristics(double slipSpeedMpS)
10431090
kalker_Cjj = Math.Sqrt(coef1 * coef1 + coef2 * coef2);
10441091
}
10451092

1046-
var Stiffness = StiffnessPreFactors * kalker_Cjj * Sc / polach_uadhesion;
1093+
// Calculate adhesion forces
1094+
var Stiffness = StiffnessPreFactors1 * kalker_Cjj * Sc / polach_uadhesion;
1095+
StiffnessPreFactors2 = (2.0f * wheelLoadN) / Math.PI;
1096+
var Stiffness2 = StiffnessPreFactors2 * polach_uadhesion;
10471097
var KaStiffness = polach_Ka * Stiffness;
1048-
var adhesionComponent = KaStiffness / (1 + KaStiffness * KaStiffness);
1098+
var adhesionComponent = KaStiffness / (1 + (polach_Ka * Stiffness * Stiffness));
10491099
var slipComponent = Math.Atan(polach_Ks * Stiffness);
1050-
var f = polach_uadhesion / (Math.PI / 2) * (adhesionComponent + slipComponent);
1051-
var fx = f * Sx / Sc;
1052-
/*
1053-
if (fx < 0)
1100+
var f = Stiffness2 * (adhesionComponent + slipComponent);
1101+
1102+
var fx = (f * Sx / Sc) / wheelLoadN;
1103+
1104+
// if (fx < 0)
10541105
{
1055-
Trace.TraceInformation("Negative Fx - Fx {0} Speed {1} SlipSpeed {2} Sx {3} PolachAdhesion {4} adhesionComponent {5} slipComponent {6} Polach_Ks {7}", fx, MpS.ToMpH((float)speedMpS), MpS.ToMpH((float)slipSpeedMpS), MpS.ToMpH((float)Sx), polach_uadhesion, adhesionComponent, slipComponent, polach_Ks);
1106+
// Trace.TraceInformation("Negative Fx - Fx {0} Speed {1} SlipSpeed {2} Sx {3} PolachAdhesion {4} adhesionComponent {5} slipComponent {6} Polach_Ks {7} Stiffness2 {8} SlipForce {9} Sc {10} WheelLoad {11} Syc {12} Hertz_a {13}", fx, (float)trainSpeedMpS, (float)slipSpeedMpS, (float)Sx, polach_uadhesion, adhesionComponent, slipComponent, polach_Ks, Stiffness2, f, Sc, wheelLoadN, Syc, a_HertzianMM);
10561107

10571108
}
1058-
*/
10591109

10601110
return fx;
10611111
}

Source/Orts.Simulation/Simulation/RollingStocks/TrainCar.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -638,7 +638,7 @@ public Direction Direction
638638
protected int WagonNumAxles; // Number of axles on a wagon
639639
protected int InitWagonNumAxles; // Initial read of number of axles on a wagon
640640
protected float MSTSWagonNumWheels; // Number of axles on a wagon - used to read MSTS value as default
641-
protected int LocoNumDrvAxles; // Number of drive axles on locomotive
641+
public int LocoNumDrvAxles; // Number of drive axles on locomotive
642642
protected float MSTSLocoNumDrvWheels; // Number of drive axles on locomotive - used to read MSTS value as default
643643
public float DriverWheelRadiusM = Me.FromIn(30.0f); // Drive wheel radius of locomotive wheels - Wheel radius of loco drive wheels can be anywhere from about 10" to 40".
644644

0 commit comments

Comments
 (0)