Skip to content

Commit bb815cd

Browse files
committed
Ramp up and down for tractive force
1 parent 45c6a23 commit bb815cd

File tree

8 files changed

+174
-260
lines changed

8 files changed

+174
-260
lines changed

Source/Orts.Simulation/Simulation/RollingStocks/MSTSControlTrailerCar.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ public override string GetStatus()
224224
/// <summary>
225225
/// This function updates periodically the locomotive's motive force.
226226
/// </summary>
227-
protected override void UpdateTractiveForce(float elapsedClockSeconds, float t, float AbsSpeedMpS, float AbsWheelSpeedMpS)
227+
protected override void UpdateTractiveForce(float elapsedClockSeconds)
228228
{
229229
}
230230

Source/Orts.Simulation/Simulation/RollingStocks/MSTSDieselLocomotive.cs

Lines changed: 76 additions & 164 deletions
Large diffs are not rendered by default.

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

Lines changed: 61 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
using Orts.Simulation.RollingStocks.SubSystems.PowerTransmissions;
6060
using ORTS.Common;
6161
using ORTS.Scripting.Api;
62+
using SharpDX.Direct3D9;
6263
using System;
6364
using System.Collections.Generic;
6465
using System.Diagnostics;
@@ -2499,18 +2500,6 @@ protected virtual void UpdateControllers(float elapsedClockSeconds)
24992500
}
25002501
#endif
25012502
}
2502-
public void CalculateForcePowerLimit(ref float targetForceN, ref float maxForceN, float targetPowerW, float maxPowerW)
2503-
{
2504-
if (targetForceN * AbsTractionSpeedMpS > targetPowerW)
2505-
{
2506-
targetForceN = targetPowerW / AbsTractionSpeedMpS;
2507-
}
2508-
if (targetForceN > maxForceN) targetForceN = maxForceN;
2509-
if (targetForceN * AbsTractionSpeedMpS > maxPowerW)
2510-
{
2511-
targetForceN = maxForceN = maxPowerW / AbsTractionSpeedMpS;
2512-
}
2513-
}
25142503
public void UpdateForceWithRamp(ref float forceN, float elapsedClockSeconds, float targetForceN, float maxForceN, float targetPowerW, float maxPowerW, float rampUpNpS=0, float rampDownNpS=0, float rampZeroNpS=0)
25152504
{
25162505
if (targetForceN > maxForceN) targetForceN = maxForceN;
@@ -2528,6 +2517,40 @@ public void UpdateForceWithRamp(ref float forceN, float elapsedClockSeconds, flo
25282517
else forceN = targetForceN;
25292518
}
25302519
}
2520+
public virtual float GetAvailableTractionForceN(float t)
2521+
{
2522+
if (t <= 0) return 0;
2523+
float powerW = float.MaxValue;
2524+
float forceN;
2525+
if (this is MSTSElectricLocomotive electric && electric.ElectricPowerSupply.MaximumPowerW > 0)
2526+
powerW = electric.ElectricPowerSupply.MaximumPowerW * t * (1-PowerReduction);
2527+
if (TractiveForceCurves == null)
2528+
{
2529+
powerW = Math.Min(powerW, MaxPowerW * t * t * (1 - PowerReduction));
2530+
2531+
if (AbsTractionSpeedMpS > MaxSpeedMpS - 0.05f)
2532+
{
2533+
forceN = 20 * (MaxSpeedMpS - AbsTractionSpeedMpS) * MaxForceN * (1 - PowerReduction);
2534+
}
2535+
else if (AbsTractionSpeedMpS > MaxSpeedMpS)
2536+
{
2537+
forceN = 0;
2538+
}
2539+
else
2540+
{
2541+
forceN = MaxForceN * (1 - PowerReduction);
2542+
}
2543+
forceN *= t;
2544+
}
2545+
else
2546+
{
2547+
forceN = TractiveForceCurves.Get(t, AbsTractionSpeedMpS) * (1 - PowerReduction);
2548+
if (forceN < 0 && !TractiveForceCurves.AcceptsNegativeValues())
2549+
forceN = 0;
2550+
}
2551+
if (forceN * AbsSpeedMpS > powerW) forceN = powerW / AbsSpeedMpS;
2552+
return forceN;
2553+
}
25312554
protected virtual void UpdateTractionForce(float elapsedClockSeconds)
25322555
{
25332556
float t = ThrottlePercent / 100;
@@ -2536,62 +2559,40 @@ protected virtual void UpdateTractionForce(float elapsedClockSeconds)
25362559
if (t > maxthrottle) t = maxthrottle;
25372560
t = MathHelper.Clamp(t, 0, 1);
25382561

2539-
if (maxthrottle > 0 && Direction != Direction.N)
2562+
if (maxthrottle > 0 && Direction != Direction.N && LocomotivePowerSupply.MainPowerSupplyOn)
25402563
{
2541-
float maxPowerW = float.MaxValue;
2542-
float targetPowerW = float.MaxValue;
2564+
float targetForceN = GetAvailableTractionForceN(t);
2565+
float limitForceN = GetAvailableTractionForceN(maxthrottle);
25432566
float maxForceN = float.MaxValue;
2544-
float targetForceN;
2567+
if (limitForceN >= targetForceN)
2568+
maxForceN = limitForceN;
25452569
if (this is MSTSElectricLocomotive electric)
25462570
{
2547-
maxPowerW = electric.ElectricPowerSupply.AvailableTractionPowerW;
2548-
if (electric.ElectricPowerSupply.MaximumPowerW > 0)
2549-
{
2550-
maxPowerW = Math.Min(maxPowerW, electric.ElectricPowerSupply.MaximumPowerW * maxthrottle);
2551-
targetPowerW = electric.ElectricPowerSupply.MaximumPowerW * t;
2552-
}
2553-
}
2554-
if (TractiveForceCurves == null)
2555-
{
2556-
maxPowerW = Math.Min(maxPowerW, MaxPowerW * maxthrottle * maxthrottle * (1 - PowerReduction));
2557-
targetPowerW = Math.Min(targetPowerW, MaxPowerW * t * t * (1 - PowerReduction));
2558-
2559-
if (AbsTractionSpeedMpS > MaxSpeedMpS - 0.05f)
2560-
{
2561-
maxForceN = 20 * (MaxSpeedMpS - AbsTractionSpeedMpS) * MaxForceN * (1 - PowerReduction);
2562-
}
2563-
else if (AbsTractionSpeedMpS > MaxSpeedMpS)
2564-
{
2565-
maxForceN = 0;
2566-
}
2567-
else
2568-
{
2569-
maxForceN = MaxForceN * (1 - PowerReduction);
2570-
}
2571-
targetForceN = maxForceN * t;
2572-
maxForceN *= maxthrottle;
2571+
float maxPowerW = electric.ElectricPowerSupply.AvailableTractionPowerW;
2572+
if (targetForceN * AbsTractionSpeedMpS > maxPowerW) maxForceN = maxPowerW / AbsTractionSpeedMpS;
25732573
}
2574-
else
2575-
{
2576-
targetForceN = TractiveForceCurves.Get(t, AbsTractionSpeedMpS) * (1 - PowerReduction);
2577-
float limitForceN = TractiveForceCurves.Get(maxthrottle, AbsTractionSpeedMpS) * (1 - PowerReduction);
2578-
if (targetForceN < 0 && !TractiveForceCurves.AcceptsNegativeValues())
2579-
targetForceN = 0;
2580-
if (limitForceN < 0 && !TractiveForceCurves.AcceptsNegativeValues())
2581-
limitForceN = 0;
2582-
if (limitForceN >= targetForceN)
2583-
maxForceN = limitForceN;
2584-
}
2585-
CalculateForcePowerLimit(ref targetForceN, ref maxForceN, targetPowerW, maxPowerW);
2586-
CurrentMaxTractionForceN = maxForceN;
25872574
UpdateForceWithRamp(ref TractionForceN, elapsedClockSeconds, targetForceN, maxForceN, TractionForceRampUpNpS, TractionForceRampDownNpS, TractionForceRampDownToZeroNpS);
25882575
}
25892576
else
25902577
{
2591-
CurrentMaxTractionForceN = TractionForceN = 0f;
2578+
TractionForceN = 0f;
25922579
}
25932580
TractiveForceN = TractionForceN;
25942581
}
2582+
public float GetAvailableDynamicBrakeForceN(float d)
2583+
{
2584+
float forceN = 0;
2585+
if (d > 0 && DynamicBrakeForceCurves != null && AbsSpeedMpS > 0)
2586+
{
2587+
forceN = DynamicBrakeForceCurves.Get(d, AbsSpeedMpS) * (1 - PowerReduction);
2588+
if (LocomotivePowerSupply.MaximumDynamicBrakePowerW > 0)
2589+
{
2590+
float powerW = LocomotivePowerSupply.MaximumDynamicBrakePowerW * (1 - PowerReduction);
2591+
if (forceN * AbsSpeedMpS > powerW) forceN = powerW / AbsSpeedMpS;
2592+
}
2593+
}
2594+
return forceN;
2595+
}
25952596
protected virtual void UpdateDynamicBrakeForce(float elapsedClockSeconds)
25962597
{
25972598
if (ThrottlePercent <= 0 && TractionForceN <= 0 && LocomotivePowerSupply.DynamicBrakeAvailable && Direction != Direction.N)
@@ -2624,26 +2625,16 @@ protected virtual void UpdateDynamicBrakeForce(float elapsedClockSeconds)
26242625
if (dynamicLimited) d = maxdynamic;
26252626
d = MathHelper.Clamp(d, 0, 1);
26262627

2627-
if (maxdynamic > 0 && DynamicBrakeForceCurves != null && AbsSpeedMpS > 0)
2628+
if (maxdynamic > 0 && AbsSpeedMpS > 0)
26282629
{
2629-
float maxPowerW = float.MaxValue;
2630-
float targetPowerW = float.MaxValue;
2631-
float targetForceN = DynamicBrakeForceCurves.Get(d, AbsTractionSpeedMpS) * (1 - PowerReduction);
2632-
float limitForceN = DynamicBrakeForceCurves.Get(maxdynamic, AbsTractionSpeedMpS) * (1 - PowerReduction);
2630+
float limitForceN = GetAvailableDynamicBrakeForceN(maxdynamic);
2631+
float targetForceN = GetAvailableDynamicBrakeForceN(d);
26332632
float maxForceN = limitForceN >= targetForceN ? limitForceN : float.MaxValue;
2634-
if (LocomotivePowerSupply.MaximumDynamicBrakePowerW > 0)
2635-
{
2636-
maxPowerW = LocomotivePowerSupply.MaximumDynamicBrakePowerW * (1 - PowerReduction);
2637-
targetPowerW = maxPowerW * d;
2638-
maxPowerW *= maxdynamic;
2639-
}
2640-
CalculateForcePowerLimit(ref targetForceN, ref maxForceN, targetPowerW, maxPowerW);
2641-
CurrentMaxDynamicBrakeForceN = maxForceN;
26422633
UpdateForceWithRamp(ref DynamicBrakeForceN, elapsedClockSeconds, targetForceN, maxForceN, DynamicBrakeForceRampUpNpS, DynamicBrakeForceRampDownNpS, DynamicBrakeForceRampDownToZeroNpS);
26432634
}
26442635
else
26452636
{
2646-
CurrentMaxDynamicBrakeForceN = DynamicBrakeForceN = 0; // Set dynamic brake force to zero if in Notch 0 position
2637+
DynamicBrakeForceN = 0; // Set dynamic brake force to zero if in Notch 0 position
26472638
}
26482639
TractiveForceN -= (SpeedMpS > 0 ? 1 : SpeedMpS < 0 ? -1 : Direction == Direction.Reverse ? -1 : 1) * DynamicBrakeForceN;
26492640
}

Source/Orts.Simulation/Simulation/RollingStocks/MSTSSteamLocomotive.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2764,7 +2764,7 @@ public override void Update(float elapsedClockSeconds)
27642764

27652765
}
27662766

2767-
UpdateTractiveForce(elapsedClockSeconds, ThrottlePercent / 100f, AbsSpeedMpS, AbsWheelSpeedMpS);
2767+
UpdateTractiveForce(elapsedClockSeconds);
27682768

27692769
#endregion
27702770

@@ -6518,8 +6518,9 @@ private void UpdateSteamTractiveForce(float elapsedClockSeconds, float locomotiv
65186518
/// <summary>
65196519
/// Averages the tractive force for the steam locomotive as tractive force varies throught the full wheel revolution
65206520
/// </summary>
6521-
protected override void UpdateTractiveForce(float elapsedClockSeconds, float locomotivethrottle, float AbsSpeedMpS, float AbsWheelSpeedMpS)
6521+
protected override void UpdateTractiveForce(float elapsedClockSeconds)
65226522
{
6523+
float locomotivethrottle = ThrottlePercent / 100;
65236524
TractiveForceN = 0; // reset tractiveforceN in preparation to calculating a new value
65246525
if (!Simulator.UseAdvancedAdhesion && Simulator.Settings.SimpleControlPhysics)
65256526
{

Source/Orts.Simulation/Simulation/RollingStocks/SubSystems/PowerSupplies/DieselEngine.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
using Microsoft.Xna.Framework;
1919
using Orts.Parsers.Msts;
20+
using Orts.Simulation.Physics;
2021
using Orts.Simulation.RollingStocks.SubSystems.PowerTransmissions;
2122
using ORTS.Common;
2223
using ORTS.Scripting.Api;

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

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,6 @@ public ElectricMotor(Axle axle, MSTSLocomotive locomotive)
5656
AxleConnected.Motor = this;
5757
AxleConnected.TransmissionRatio = 1;
5858
}
59-
public virtual void UpdateTractiveForce(float elapsedClockSeconds, float t)
60-
{
61-
62-
}
6359

6460
public virtual double GetDevelopedTorqueNm(double motorSpeedRadpS)
6561
{

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

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,16 +44,13 @@ public override void Initialize()
4444
{
4545
base.Initialize();
4646
}
47-
public override void UpdateTractiveForce(float elapsedClockSeconds, float t)
48-
{
49-
TargetForceN = Locomotive.TractiveForceN / Locomotive.LocomotiveAxles.Count;
50-
}
5147
public override double GetDevelopedTorqueNm(double motorSpeedRadpS)
5248
{
5349
return requiredTorqueNm * MathHelper.Clamp((float)(DriveSpeedRadpS - motorSpeedRadpS) / OptimalAsyncSpeedRadpS, -1, 1);
5450
}
5551
public override void Update(float timeSpan)
5652
{
53+
TargetForceN = Locomotive.TractiveForceN / Locomotive.LocomotiveAxles.Count;
5754
EngineMaxSpeedMpS = Locomotive.MaxSpeedMpS;
5855
SlipControl = Locomotive.SlipControlSystem == MSTSLocomotive.SlipControlType.Full;
5956
float linToAngFactor = AxleConnected.TransmissionRatio / AxleConnected.WheelRadiusM;

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

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,30 @@ public float AccelerationMpSS
424424
}
425425

426426
public float LocalThrottlePercent;
427+
public float MaxThrottlePercent
428+
{
429+
get
430+
{
431+
float percent = 100;
432+
if (RemoteControlGroup == 0 && Train != null && Train.LeadLocomotive is MSTSLocomotive locomotive)
433+
{
434+
if (!locomotive.TrainControlSystem.TractionAuthorization)
435+
{
436+
percent = 0;
437+
}
438+
else if (percent > locomotive.TrainControlSystem.MaxThrottlePercent)
439+
{
440+
percent = Math.Max(locomotive.TrainControlSystem.MaxThrottlePercent, 0);
441+
}
442+
}
443+
if (this is MSTSLocomotive loco)
444+
{
445+
if (percent > 100 - loco.LocomotivePowerSupply.ThrottleReductionPercent) percent = 100 - loco.LocomotivePowerSupply.ThrottleReductionPercent;
446+
if (percent > loco.LocomotivePowerSupply.MaxThrottlePercent) percent = loco.LocomotivePowerSupply.MaxThrottlePercent / 100;
447+
}
448+
return percent;
449+
}
450+
}
427451
// represents the MU line travelling through the train. Uncontrolled locos respond to these commands.
428452
public float ThrottlePercent
429453
{
@@ -433,18 +457,6 @@ public float ThrottlePercent
433457
if (RemoteControlGroup == 0 && Train != null)
434458
{
435459
percent = Train.MUThrottlePercent;
436-
if (Train.LeadLocomotive is MSTSLocomotive locomotive)
437-
{
438-
if (!locomotive.TrainControlSystem.TractionAuthorization
439-
|| percent <= 0)
440-
{
441-
percent = 0;
442-
}
443-
else if (percent > locomotive.TrainControlSystem.MaxThrottlePercent)
444-
{
445-
percent = Math.Max(locomotive.TrainControlSystem.MaxThrottlePercent, 0);
446-
}
447-
}
448460
}
449461
else if (RemoteControlGroup == 1 && Train != null)
450462
{
@@ -456,10 +468,9 @@ public float ThrottlePercent
456468
}
457469
if (this is MSTSLocomotive loco)
458470
{
459-
if (loco.LocomotivePowerSupply.ThrottleReductionPercent > 0) percent *= 1-loco.LocomotivePowerSupply.ThrottleReductionPercent/100;
460-
if (loco.LocomotivePowerSupply.MaxThrottlePercent < percent) percent = Math.Max(loco.LocomotivePowerSupply.MaxThrottlePercent, 0);
471+
if (loco.LocomotivePowerSupply.ThrottleReductionPercent > 0) percent *= 1 - loco.LocomotivePowerSupply.ThrottleReductionPercent / 100;
461472
}
462-
return percent;
473+
return Math.Min(percent, MaxThrottlePercent);
463474
}
464475
set
465476
{
@@ -574,6 +585,7 @@ public Direction Direction
574585
public float GravityForceN; // Newtons - signed relative to direction of car.
575586
public float CurveForceN; // Resistive force due to curve, in Newtons
576587
public float WindForceN; // Resistive force due to wind
588+
public float TractionForceN = 0f;
577589
public float DynamicBrakeForceN = 0f; // Raw dynamic brake force for diesel and electric locomotives
578590

579591
// Derailment variables
@@ -2172,6 +2184,8 @@ public virtual void Save(BinaryWriter outf)
21722184
outf.Write(UiD);
21732185
outf.Write(CarID);
21742186
BrakeSystem.Save(outf);
2187+
outf.Write(TractionForceN);
2188+
outf.Write(DynamicBrakeForceN);
21752189
outf.Write(MotiveForceN);
21762190
outf.Write(FrictionForceN);
21772191
outf.Write(SpeedMpS);
@@ -2194,6 +2208,8 @@ public virtual void Restore(BinaryReader inf)
21942208
UiD = inf.ReadInt32();
21952209
CarID = inf.ReadString();
21962210
BrakeSystem.Restore(inf);
2211+
TractionForceN = inf.ReadSingle();
2212+
DynamicBrakeForceN = inf.ReadSingle();
21972213
MotiveForceN = inf.ReadSingle();
21982214
FrictionForceN = inf.ReadSingle();
21992215
SpeedMpS = inf.ReadSingle();

0 commit comments

Comments
 (0)