Skip to content

Commit eb9c601

Browse files
committed
Improve battery voltage handling
1 parent 55db46f commit eb9c601

File tree

3 files changed

+70
-14
lines changed

3 files changed

+70
-14
lines changed

Source/Documentation/Manual/physics.rst

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5021,8 +5021,11 @@ It is possible for the battery switch to be switched on at the start of the simu
50215021
To activate this behaviour, you can add the optional parameter ``ORTSBattery( DefaultOn ( 1 ) )``
50225022

50235023
The voltage and energetic capacity of the battery can be indicated using the ``Voltage`` and ``MaxCapacity``
5024-
parameters. Optionally, it is possible to define a realistic capacity-voltage curve such that voltage becomes
5025-
lower when the battery is discharged, using ``ChargeVoltageCurve``.
5024+
parameters. The performance of the battery charger, which is powered by the power converters, can be
5025+
adjusted using the ``ChargerPower`` and ``ChargerVoltage`` parameters.
5026+
5027+
Optionally, it is possible to define a capacity-voltage curve such that voltage becomes
5028+
lower when the battery is discharged, using ``ChargeVoltageCurve``. Battery discharge is not implemented yet.
50265029

50275030
Example::
50285031

@@ -5039,6 +5042,8 @@ Example::
50395042
30kWh 72V
50405043
50kWh 80V
50415044
)
5045+
ChargerVoltage ( 80V )
5046+
ChargerPower ( 10kW )
50425047
)
50435048
)
50445049

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

Lines changed: 61 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
1+

22
using Microsoft.CodeAnalysis.VisualBasic.Syntax;
33
using Microsoft.Xna.Framework;
44
using Orts.Common;
5+
using Orts.Formats.Msts;
56
using Orts.Parsers.Msts;
67
using ORTS.Scripting.Api;
78
using System;
@@ -15,16 +16,35 @@ namespace Orts.Simulation.RollingStocks.SubSystems.PowerSupplies
1516
{
1617
public class Battery : ISubSystem<Battery>
1718
{
19+
TrainCar Car;
1820
public BatterySwitch BatterySwitch { get; protected set; }
1921
public float NominalVoltageV = 72;
2022
public float VoltageV { get; protected set; }
2123
public float CurrentCapacityJ { get; protected set; }
2224
public float MaxCapacityJ = 3.6e7f;
23-
protected float EnergyFlowW; // < 0 discharging, > 0 charging
25+
protected float PowerW; // Power demanded by the power supply, not implemented
26+
protected float MaxChargingPowerW = 10000;
27+
protected float ChargingVoltageV;
28+
protected bool IsCharging
29+
{
30+
get
31+
{
32+
if (Car is MSTSLocomotive locomotive)
33+
{
34+
return locomotive.LocomotivePowerSupply.AuxiliaryPowerSupplyOn;
35+
}
36+
else if (Car.PowerSupply != null)
37+
{
38+
return Car.PowerSupply.ElectricTrainSupplyOn;
39+
}
40+
return false;
41+
}
42+
}
2443
public Interpolator ChargeVoltageCurve;
2544
public PowerSupplyState State;
2645
public Battery(MSTSWagon wagon)
2746
{
47+
Car = wagon;
2848
BatterySwitch = new BatterySwitch(wagon);
2949
}
3050
public virtual void Parse(string lowercasetoken, STFReader stf)
@@ -45,6 +65,12 @@ public virtual void Parse(string lowercasetoken, STFReader stf)
4565
case "maxcapacity":
4666
MaxCapacityJ = stf.ReadFloatBlock(STFReader.UNITS.Energy, MaxCapacityJ);
4767
break;
68+
case "chargerpower":
69+
MaxChargingPowerW = stf.ReadFloatBlock(STFReader.UNITS.Power, MaxChargingPowerW);
70+
break;
71+
case "chargervoltage":
72+
ChargingVoltageV = stf.ReadFloatBlock(STFReader.UNITS.Voltage, 0);
73+
break;
4874
case "chargevoltagecurve":
4975
ChargeVoltageCurve = new Interpolator(stf);
5076
break;
@@ -70,10 +96,13 @@ public virtual void Copy(Battery other)
7096
}
7197
public virtual void Initialize()
7298
{
73-
CurrentCapacityJ = MaxCapacityJ;
99+
CurrentCapacityJ = 0.7f * MaxCapacityJ;
100+
if (ChargingVoltageV == 0) ChargingVoltageV = NominalVoltageV * 1.15f;
74101
if (ChargeVoltageCurve == null)
75102
{
76-
ChargeVoltageCurve = new Interpolator(new float[] {0, MaxCapacityJ}, new float[] {0, NominalVoltageV});
103+
ChargeVoltageCurve = new Interpolator(
104+
new float[] {0, MaxCapacityJ * 0.1f, MaxCapacityJ},
105+
new float[] {0, 0.95f * NominalVoltageV, 1.05f * NominalVoltageV});
77106
}
78107

79108
BatterySwitch.Initialize();
@@ -86,21 +115,43 @@ public virtual void Save(BinaryWriter outf)
86115
{
87116
BatterySwitch.Save(outf);
88117
outf.Write(CurrentCapacityJ);
89-
outf.Write(EnergyFlowW);
90118
}
91119
public virtual void Restore(BinaryReader inf)
92120
{
93121
BatterySwitch.Restore(inf);
94122
CurrentCapacityJ = inf.ReadSingle();
95-
EnergyFlowW = inf.ReadSingle();
96123
}
97124
public virtual void Update(float elapsedClockSeconds)
98125
{
99126
BatterySwitch.Update(elapsedClockSeconds);
100127

101-
CurrentCapacityJ = MathHelper.Clamp(CurrentCapacityJ + EnergyFlowW * elapsedClockSeconds, 0, MaxCapacityJ);
102-
VoltageV = ChargeVoltageCurve[CurrentCapacityJ];
128+
if (IsCharging)
129+
{
130+
if (ChargeVoltageCurve[CurrentCapacityJ] < ChargingVoltageV && CurrentCapacityJ < MaxCapacityJ)
131+
{
132+
// Charge the battery
133+
float energyJ = MaxChargingPowerW * elapsedClockSeconds;
134+
if (CurrentCapacityJ + energyJ > MaxCapacityJ)
135+
energyJ = MaxCapacityJ - CurrentCapacityJ;
136+
CurrentCapacityJ += energyJ;
137+
}
138+
// When charging, voltage is that of the battery charger
139+
VoltageV = ChargingVoltageV;
140+
}
141+
else
142+
{
143+
if (PowerW > 0 && State == PowerSupplyState.PowerOn)
144+
{
145+
// Discharge the battery
146+
float energyJ = PowerW * elapsedClockSeconds;
147+
if (CurrentCapacityJ - energyJ > 0)
148+
energyJ = CurrentCapacityJ;
149+
CurrentCapacityJ -= energyJ;
150+
}
151+
// If battery is draining, voltage will depend on the total charge
152+
// Voltage also depends on power drawn, not implemented
153+
VoltageV = ChargeVoltageCurve[CurrentCapacityJ];
154+
}
103155
}
104-
105156
}
106-
}
157+
}

Source/RunActivity/Viewer3D/Popups/HUDWindow.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// COPYRIGHT 2011, 2012, 2013 by the Open Rails project.
1+
// COPYRIGHT 2011, 2012, 2013 by the Open Rails project.
22
//
33
// This file is part of Open Rails.
44
//
@@ -847,7 +847,7 @@ void TextPagePowerSupplyInfo(TableData table)
847847
tractionCutOffRelayState,
848848
mainPowerSupplyState,
849849
auxiliaryPowerSupplyState,
850-
Viewer.Catalog.GetParticularString("PowerSupply", GetStringAttribute.GetPrettyName(car.PowerSupply.BatteryState)),
850+
String.Format("{0} {1}", Viewer.Catalog.GetParticularString("PowerSupply", GetStringAttribute.GetPrettyName(car.PowerSupply.BatteryState)), FormatStrings.FormatVoltage(car.PowerSupply.BatteryVoltageV)),
851851
Viewer.Catalog.GetParticularString("PowerSupply", GetStringAttribute.GetPrettyName(car.PowerSupply.LowVoltagePowerSupplyState)),
852852
locomotivePowerSupply != null ? Viewer.Catalog.GetParticularString("PowerSupply", GetStringAttribute.GetPrettyName(locomotivePowerSupply.CabPowerSupplyState)) : string.Empty,
853853
electricTrainSupplyState,

0 commit comments

Comments
 (0)