@@ -572,7 +572,10 @@ public Direction Direction
572
572
public float TotalWagonLateralDerailForceN ;
573
573
public float LateralWindForceN ;
574
574
public float WagonFrontCouplerAngleRad ;
575
+ public float WagonFrontCouplerBuffAngleRad ;
575
576
public float WagonRearCouplerAngleRad ;
577
+ public float WagonRearCouplerBuffAngleRad ;
578
+ public float CarTrackPlayM = Me . FromIn ( 2.0f ) ;
576
579
public float AdjustedWagonFrontCouplerAngleRad ;
577
580
public float AdjustedWagonRearCouplerAngleRad ;
578
581
public float WagonFrontCouplerCurveExtM ;
@@ -1196,6 +1199,10 @@ public virtual void UpdateTunnelForce()
1196
1199
///
1197
1200
/// Hence these calculations provide a "generic" approach to determining whether a car will derial or not.
1198
1201
///
1202
+ /// Buff Coupler angle calculated from this publication: In-Train Force Limit Study by National Research Council Canada
1203
+ ///
1204
+ /// https://nrc-publications.canada.ca/eng/view/ft/?id=8cc206d0-5dbd-42ed-9b4e-35fd9f8b8efb
1205
+ ///
1199
1206
/// </summary>
1200
1207
1201
1208
public void UpdateTrainDerailmentRisk ( float elapsedClockSeconds )
@@ -1336,6 +1343,69 @@ public void UpdateTrainDerailmentRisk(float elapsedClockSeconds)
1336
1343
AdjustedWagonRearCouplerAngleRad = WagonRearCouplerAngleRad ;
1337
1344
CarBehind . AdjustedWagonFrontCouplerAngleRad = CarBehind . WagonFrontCouplerAngleRad ;
1338
1345
}
1346
+
1347
+ // Only process this code segment if coupler is in compression
1348
+ if ( CouplerForceU > 0 && CouplerSlackM < 0 )
1349
+ {
1350
+
1351
+ // Calculate Buff coupler angles. Car1 is current car, and Car2 is the car behind
1352
+ // Car ahead rear coupler angle
1353
+ var ThiscarCouplerlengthft = Me . ToFt ( CarCouplerFaceLengthM - CarBodyLengthM ) + CouplerSlackM / 2 ;
1354
+ var CarbehindCouplerlengthft = Me . ToFt ( CarBehind . CarCouplerFaceLengthM - CarBehind . CarBodyLengthM ) + CouplerSlackM / 2 ;
1355
+ var A1 = Math . Sqrt ( Math . Pow ( Me . ToFt ( CurrentCurveRadius ) , 2 ) - Math . Pow ( Me . ToFt ( CarBogieCentreLengthM ) , 2 ) / 4.0f ) ;
1356
+ var A2 = ( Me . ToFt ( CarCouplerFaceLengthM ) / 2.0f ) - ThiscarCouplerlengthft ;
1357
+ var A = ( float ) Math . Atan ( A1 / A2 ) ;
1358
+
1359
+ var B = ( float ) Math . Asin ( 2.0f * Me . ToFt ( CarTrackPlayM ) / Me . ToFt ( CarBogieCentreLengthM ) ) ;
1360
+ var C1 = Math . Pow ( ThiscarCouplerlengthft + CarbehindCouplerlengthft , 2 ) ;
1361
+
1362
+ var C2_1 = Math . Sqrt ( Math . Pow ( Me . ToFt ( CarCouplerFaceLengthM ) / 2.0f - ThiscarCouplerlengthft , 2 ) + Math . Pow ( Me . ToFt ( CurrentCurveRadius ) , 2 ) - Math . Pow ( Me . ToFt ( CarBogieCentreLengthM ) , 2 ) / 4.0f ) ;
1363
+ var C2_2 = ( 2.0f * Me . ToFt ( CarTrackPlayM ) * ( Me . ToFt ( CarCouplerFaceLengthM ) / 2.0f - ThiscarCouplerlengthft ) ) / Me . ToFt ( CarBogieCentreLengthM ) ;
1364
+ var C2 = Math . Pow ( ( C2_1 + C2_2 ) , 2 ) ;
1365
+
1366
+ var C3_1 = Math . Sqrt ( Math . Pow ( Me . ToFt ( CarBehind . CarCouplerFaceLengthM ) / 2.0f - CarbehindCouplerlengthft , 2 ) + Math . Pow ( Me . ToFt ( CurrentCurveRadius ) , 2 ) - Math . Pow ( Me . ToFt ( CarBehind . CarBogieCentreLengthM ) , 2 ) / 4.0f ) ;
1367
+ var C3_2 = ( 2.0f * Me . ToFt ( CarBehind . CarTrackPlayM ) * ( Me . ToFt ( CarBehind . CarCouplerFaceLengthM ) / 2.0f - CarbehindCouplerlengthft ) ) / Me . ToFt ( CarBehind . CarBogieCentreLengthM ) ;
1368
+ var C3 = Math . Pow ( ( C3_1 + C3_2 ) , 2 ) ;
1369
+
1370
+ var C4 = 2.0f * ( ThiscarCouplerlengthft + CarbehindCouplerlengthft ) * ( C2_1 + C2_2 ) ;
1371
+
1372
+ var C = ( float ) Math . Acos ( ( C1 + C2 - C3 ) / C4 ) ;
1373
+
1374
+ WagonRearCouplerBuffAngleRad = MathHelper . ToRadians ( 180.0f ) - A + B - C ;
1375
+
1376
+
1377
+ // Trace.TraceInformation("Buff - CarId {0} Carahead {1} A {2} B {3} C {4} 180 {5}", CarID, CarAhead.WagonRearCouplerBuffAngleRad, A, B, C, MathHelper.ToRadians(180.0f));
1378
+
1379
+
1380
+
1381
+ // This car front coupler angle
1382
+ var X1 = Math . Sqrt ( Math . Pow ( Me . ToFt ( CurrentCurveRadius ) , 2 ) - Math . Pow ( Me . ToFt ( CarBehind . CarBogieCentreLengthM ) , 2 ) / 4.0f ) ;
1383
+ var X2 = ( Me . ToFt ( CarBehind . CarCouplerFaceLengthM ) / 2.0f ) - CarbehindCouplerlengthft ;
1384
+ var X = ( float ) Math . Atan ( X1 / X2 ) ;
1385
+
1386
+ var Y = ( float ) Math . Asin ( 2.0f * Me . ToFt ( CarBehind . CarTrackPlayM ) / Me . ToFt ( CarBehind . CarBogieCentreLengthM ) ) ;
1387
+
1388
+ var Z1 = Math . Pow ( ThiscarCouplerlengthft + CarbehindCouplerlengthft , 2 ) ;
1389
+ var Z2_1 = Math . Sqrt ( Math . Pow ( Me . ToFt ( CarBehind . CarCouplerFaceLengthM ) / 2.0f - CarbehindCouplerlengthft , 2 ) + Math . Pow ( Me . ToFt ( CurrentCurveRadius ) , 2 ) - Math . Pow ( Me . ToFt ( CarBehind . CarBogieCentreLengthM ) , 2 ) / 4.0f ) ;
1390
+ var Z2_2 = ( 2.0f * Me . ToFt ( CarBehind . CarTrackPlayM ) * ( Me . ToFt ( CarBehind . CarCouplerFaceLengthM ) / 2.0f - CarbehindCouplerlengthft ) ) / Me . ToFt ( CarBehind . CarBogieCentreLengthM ) ;
1391
+ var Z2 = Math . Pow ( ( Z2_1 + Z2_2 ) , 2 ) ;
1392
+
1393
+ var Z3_1 = Math . Sqrt ( Math . Pow ( Me . ToFt ( CarCouplerFaceLengthM ) / 2.0f - ThiscarCouplerlengthft , 2 ) + Math . Pow ( Me . ToFt ( CurrentCurveRadius ) , 2 ) - Math . Pow ( Me . ToFt ( CarBogieCentreLengthM ) , 2 ) / 4.0f ) ;
1394
+ var Z3_2 = ( 2.0f * Me . ToFt ( CarTrackPlayM ) * ( Me . ToFt ( CarCouplerFaceLengthM ) / 2.0f - ThiscarCouplerlengthft ) ) / Me . ToFt ( CarBogieCentreLengthM ) ;
1395
+ var Z3 = Math . Pow ( ( Z3_1 + Z3_2 ) , 2 ) ;
1396
+
1397
+ var Z4 = 2.0f * ( ThiscarCouplerlengthft + CarbehindCouplerlengthft ) * ( Z2_1 + Z2_2 ) ;
1398
+
1399
+ var Z = ( float ) Math . Acos ( ( Z1 + Z2 - Z3 ) / Z4 ) ;
1400
+
1401
+ CarBehind . WagonFrontCouplerBuffAngleRad = MathHelper . ToRadians ( 180.0f ) - X + Y - Z ;
1402
+
1403
+ // Trace.TraceInformation("Buff - CarId {0} Thiscar {1} A {2} B {3} C {4} 180 {5}", CarID, WagonFrontCouplerBuffAngleRad, X, Y, Z, MathHelper.ToRadians(180.0f));
1404
+
1405
+ // Trace.TraceInformation("Buff - CarId {0} StringThis {1} StringBehind {2} BuffThis {3} BuffAhead {4}", CarID, WagonRearCouplerAngleRad, CarBehind.WagonFrontCouplerAngleRad, WagonRearCouplerBuffAngleRad, CarBehind.WagonFrontCouplerBuffAngleRad);
1406
+
1407
+ }
1408
+
1339
1409
}
1340
1410
else if ( CarAhead != null )
1341
1411
{
@@ -1344,6 +1414,9 @@ public void UpdateTrainDerailmentRisk(float elapsedClockSeconds)
1344
1414
AdjustedWagonRearCouplerAngleRad = 0.0f ;
1345
1415
CarBehind . AdjustedWagonFrontCouplerAngleRad = 0.0f ;
1346
1416
WagonRearCouplerAngleRad = 0 ;
1417
+ WagonFrontCouplerAngleRad = 0 ;
1418
+ WagonRearCouplerBuffAngleRad = 0 ;
1419
+ WagonFrontCouplerBuffAngleRad = 0 ;
1347
1420
CarBehind . WagonFrontCouplerAngleRad = 0 ;
1348
1421
CarAhead . WagonRearCouplerAngleRad = 0 ;
1349
1422
}
@@ -1424,7 +1497,16 @@ public void UpdateTrainDerailmentRisk(float elapsedClockSeconds)
1424
1497
1425
1498
if ( IsPlayerTrain )
1426
1499
{
1427
- WagonCouplerAngleDerailRad = Math . Abs ( WagonRearCouplerAngleRad ) ;
1500
+ if ( CouplerForceU > 0 && CouplerSlackM < 0 ) // If car coupler is in compression, use the buff angle
1501
+ {
1502
+ WagonCouplerAngleDerailRad = Math . Abs ( WagonRearCouplerBuffAngleRad ) ;
1503
+ }
1504
+ else // if coupler in tension, then use tension angle
1505
+ {
1506
+ WagonCouplerAngleDerailRad = Math . Abs ( WagonRearCouplerAngleRad ) ;
1507
+ }
1508
+
1509
+
1428
1510
var numAxles = LocoNumDrvAxles + WagonNumAxles ;
1429
1511
var numWheels = numAxles * 2 ;
1430
1512
@@ -1504,7 +1586,8 @@ public void UpdateTrainDerailmentRisk(float elapsedClockSeconds)
1504
1586
}
1505
1587
else
1506
1588
{
1507
- DerailmentCoefficient *= 1.4f ;
1589
+ // DerailmentCoefficient *= 1.4f;
1590
+ DerailmentCoefficient *= 2.0f ;
1508
1591
}
1509
1592
1510
1593
var wagonAdhesion = Train . WagonCoefficientFriction ;
0 commit comments