@@ -416,34 +416,23 @@ public void Save(BinaryWriter outf)
416416 }
417417
418418 /// <summary>
419- /// Compute variation in axle dynamics. Calculates axle speed, axle angular position and rail force .
419+ /// Compute variation in axle dynamics. Calculates axle speed, axle angular position and in/out forces .
420420 /// </summary>
421- public ( float , float , float ) GetAxleMotionVariation ( float axleSpeedMpS )
421+ public ( float , float , float , float ) GetAxleMotionVariation ( float axleSpeedMpS )
422422 {
423- float axleForceN = AxleWeightN * SlipCharacteristics ( axleSpeedMpS - TrainSpeedMpS , TrainSpeedMpS , AdhesionK , AdhesionLimit ) ;
423+ float axleOutForceN = AxleWeightN * SlipCharacteristics ( axleSpeedMpS - TrainSpeedMpS , TrainSpeedMpS , AdhesionK , AdhesionLimit ) ;
424424
425- float motiveAxleForceN = - axleForceN - dampingNs * ( axleSpeedMpS - TrainSpeedMpS ) ; // Force transmitted to rail + heat losses
425+ float axleInForceN = 0 ;
426426 if ( DriveType == AxleDriveType . ForceDriven )
427- motiveAxleForceN + = DriveForceN * transmissionEfficiency ;
427+ axleInForceN = DriveForceN * transmissionEfficiency ;
428428 else if ( DriveType == AxleDriveType . MotorDriven )
429- motiveAxleForceN + = motor . GetDevelopedTorqueNm ( axleSpeedMpS * transmissionRatio / WheelRadiusM ) * transmissionEfficiency / WheelRadiusM ;
429+ axleInForceN = motor . GetDevelopedTorqueNm ( axleSpeedMpS * transmissionRatio / WheelRadiusM ) * transmissionEfficiency / WheelRadiusM ;
430430
431- // Dissipative forces: they will never increase wheel speed
432- float frictionalForceN = BrakeRetardForceN + frictionN ;
433-
434- float totalAxleForceN = motiveAxleForceN - Math . Sign ( axleSpeedMpS ) * frictionalForceN ;
435- if ( Math . Abs ( axleSpeedMpS ) < 0.01f )
436- {
437- if ( motiveAxleForceN > frictionalForceN ) totalAxleForceN = motiveAxleForceN - frictionalForceN ;
438- else if ( motiveAxleForceN < - frictionalForceN ) totalAxleForceN = motiveAxleForceN + frictionalForceN ;
439- else
440- {
441- totalAxleForceN = 0 ;
442- axleForceN = 0 ;
443- frictionalForceN -= Math . Abs ( motiveAxleForceN ) ;
444- }
445- }
446- return ( totalAxleForceN * forceToAccelerationFactor , axleSpeedMpS / WheelRadiusM , axleForceN ) ;
431+ float totalAxleForceN = axleInForceN - axleOutForceN - dampingNs * ( axleSpeedMpS - TrainSpeedMpS ) ; // Force transmitted to rail + heat losses
432+
433+ totalAxleForceN -= Math . Sign ( axleSpeedMpS ) * ( BrakeRetardForceN + frictionN ) ; // Dissipative forces: they will never increase wheel speed
434+
435+ return ( totalAxleForceN * forceToAccelerationFactor , axleSpeedMpS / WheelRadiusM , axleOutForceN , axleInForceN ) ;
447436 }
448437
449438 /// <summary>
@@ -473,30 +462,40 @@ void Integrate(float elapsedClockSeconds)
473462 NumOfSubstepsPS = Math . Max ( Math . Min ( NumOfSubstepsPS , 50 ) , 1 ) ;
474463 float dt = elapsedClockSeconds / NumOfSubstepsPS ;
475464 float hdt = dt / 2.0f ;
476- float axleForceSumN = 0 ;
465+ float axleInForceSumN = 0 ;
466+ float axleOutForceSumN = 0 ;
477467 for ( int i = 0 ; i < NumOfSubstepsPS ; i ++ )
478468 {
479469 var k1 = GetAxleMotionVariation ( AxleSpeedMpS ) ;
480- if ( i == 0 && k1 . Item1 * dt > Math . Max ( ( Math . Abs ( SlipSpeedMpS ) - 1 ) * 10 , 1 ) / 100 )
470+ if ( i == 0 )
481471 {
482- NumOfSubstepsPS = Math . Min ( NumOfSubstepsPS + 5 , 50 ) ;
483- dt = elapsedClockSeconds / NumOfSubstepsPS ;
484- hdt = dt / 2 ;
472+ if ( k1 . Item1 * dt > Math . Max ( ( Math . Abs ( SlipSpeedMpS ) - 1 ) * 10 , 1 ) / 100 )
473+ {
474+ NumOfSubstepsPS = Math . Min ( NumOfSubstepsPS + 5 , 50 ) ;
475+ dt = elapsedClockSeconds / NumOfSubstepsPS ;
476+ hdt = dt / 2 ;
477+ }
478+ if ( Math . Sign ( AxleSpeedMpS + k1 . Item1 * dt ) != Math . Sign ( AxleSpeedMpS ) && BrakeRetardForceN + frictionN > Math . Abs ( driveForceN - k1 . Item3 ) )
479+ {
480+ AxlePositionRad += AxleSpeedMpS * hdt ;
481+ AxlePositionRad = MathHelper . WrapAngle ( AxlePositionRad ) ;
482+ AxleSpeedMpS = 0 ;
483+ AxleForceN = 0 ;
484+ DriveForceN = k1 . Item4 ;
485+ return ;
486+ }
485487 }
486488 var k2 = GetAxleMotionVariation ( AxleSpeedMpS + k1 . Item1 * hdt ) ;
487489 var k3 = GetAxleMotionVariation ( AxleSpeedMpS + k2 . Item1 * hdt ) ;
488490 var k4 = GetAxleMotionVariation ( AxleSpeedMpS + k3 . Item1 * dt ) ;
489491 AxleSpeedMpS += ( integratorError = ( k1 . Item1 + 2 * ( k2 . Item1 + k3 . Item1 ) + k4 . Item1 ) * dt / 6.0f ) ;
490492 AxlePositionRad += ( k1 . Item2 + 2 * ( k2 . Item2 + k3 . Item2 ) + k4 . Item2 ) * dt / 6.0f ;
491- axleForceSumN += ( k1 . Item3 + 2 * ( k2 . Item3 + k3 . Item3 ) + k4 . Item3 ) ;
493+ axleOutForceSumN += ( k1 . Item3 + 2 * ( k2 . Item3 + k3 . Item3 ) + k4 . Item3 ) ;
494+ axleInForceSumN += ( k1 . Item4 + 2 * ( k2 . Item4 + k3 . Item4 ) + k4 . Item4 ) ;
492495 }
493- AxleForceN = axleForceSumN / ( NumOfSubstepsPS * 6 ) ;
496+ AxleForceN = axleOutForceSumN / ( NumOfSubstepsPS * 6 ) ;
497+ DriveForceN = axleInForceSumN / ( NumOfSubstepsPS * 6 ) ;
494498 AxlePositionRad = MathHelper . WrapAngle ( AxlePositionRad ) ;
495-
496- if ( ( prevSpeedMpS > 0 && AxleSpeedMpS <= 0 ) || ( prevSpeedMpS < 0 && AxleSpeedMpS >= 0 ) )
497- {
498- if ( Math . Max ( BrakeRetardForceN , frictionN ) > Math . Abs ( driveForceN - AxleForceN ) ) Reset ( ) ;
499- }
500499 }
501500
502501 /// <summary>
@@ -540,6 +539,9 @@ void StationaryCalculation(float elapsedClockSeconds)
540539 public virtual void Update ( float timeSpan )
541540 {
542541 forceToAccelerationFactor = WheelRadiusM * WheelRadiusM / totalInertiaKgm2 ;
542+
543+ motor ? . Update ( timeSpan ) ;
544+
543545 Integrate ( timeSpan ) ;
544546 // TODO: We should calculate brake force here
545547 // Adding and substracting the brake force is correct for normal operation,
@@ -551,8 +553,6 @@ public virtual void Update(float timeSpan)
551553 CompensatedAxleForceN = AxleForceN + Math . Sign ( TrainSpeedMpS ) * BrakeRetardForceN ;
552554 if ( AxleForceN == 0 ) CompensatedAxleForceN = 0 ;
553555
554- motor ? . Update ( timeSpan ) ;
555-
556556 if ( timeSpan > 0.0f )
557557 {
558558 slipDerivationMpSS = ( SlipSpeedMpS - previousSlipSpeedMpS ) / timeSpan ;
0 commit comments