Skip to content

Commit ebf0879

Browse files
committed
Enhancement of injector operation
1 parent f1ade96 commit ebf0879

File tree

1 file changed

+56
-5
lines changed

1 file changed

+56
-5
lines changed

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

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,10 @@ public class MSTSSteamLocomotive : MSTSLocomotive
155155

156156
float ActualInjector1NozzleSizeMM;
157157
float ActualInjector2NozzleSizeMM;
158+
float ActualInjectorTemperatureCorrectionFactor;
159+
float ActualInjector1SteamUsedLBpS;
160+
float ActualInjector2SteamUsedLBpS;
161+
float InjectorHFGkJPkg; // Enthalpy of steam used by injector - kJ/kg
158162

159163
// Feedwater Pump
160164
float WaterMotionPump1FlowRateLBpS;
@@ -235,6 +239,7 @@ public class MSTSSteamLocomotive : MSTSLocomotive
235239
public bool AuxTenderMoveFlag = false; // Flag to indicate whether train has moved
236240
bool SteamIsAuxTenderCoupled = false;
237241
float TenderWaterPercent; // Percentage of water in tender
242+
float TenderWaterTemperatureC;
238243
public float WaterConsumptionLbpS;
239244
public float CurrentAuxTenderWaterMassKG;
240245
public float CurrentAuxTenderWaterVolumeUKG;
@@ -4074,6 +4079,15 @@ private void UpdateTender(float elapsedClockSeconds)
40744079
CoalIsExhausted = false;
40754080
}
40764081

4082+
// Calculate water temperature in tender based upon ambient temperature and water level
4083+
// Twt = Tat + 3 + 0.3 * (Tat - 10) - where wt = water temperature, at = ambient temperature, has to be capped at 50 deg C
4084+
// Check for more accurate solution later
4085+
4086+
TenderWaterTemperatureC = CarOutsideTempC + 3.0f + 0.3f * (CarOutsideTempC - 10.0f);
4087+
TenderWaterTemperatureC = MathHelper.Clamp(TenderWaterTemperatureC, 0, 50);
4088+
4089+
4090+
40774091
#region Auxiliary Water Tender Operation
40784092

40794093
// If aux tender is coupled then assume that both tender and aux tender will equalise at same % water level
@@ -7439,12 +7453,15 @@ private void UpdateWaterInjection(float elapsedClockSeconds)
74397453
{
74407454
#region Calculate Injector flow rates
74417455

7456+
ActualInjector1SteamUsedLBpS = 0;
7457+
ActualInjector2SteamUsedLBpS = 0;
7458+
74427459
// Calculate the flow rates for injector #1 based upon boiler pressure and injector nozzle size
74437460
var ActualInjector1NozzleAreaMM2 = (float)(Math.PI * Math.Pow((ActualInjector1NozzleSizeMM) / 2.0f, 2));
74447461

7445-
MaxInjectorFlowRateLBpS = pS.FrompH(RefKInjector1Factor * ActualInjector1NozzleAreaMM2 * (float)Math.Sqrt(MaxBoilerPressurePSI)) * WaterLBpUKG;
7462+
MaxInjectorFlowRateLBpS = ActualInjectorTemperatureCorrectionFactor * pS.FrompH(RefKInjector1Factor * ActualInjector1NozzleAreaMM2 * (float)Math.Sqrt(MaxBoilerPressurePSI)) * WaterLBpUKG;
74467463

7447-
ActualInjector1FlowRateLBpS = pS.FrompH(RefKInjector1Factor * ActualInjector1NozzleAreaMM2 * (float)Math.Sqrt(BoilerPressurePSI)) * WaterLBpUKG;
7464+
ActualInjector1FlowRateLBpS = ActualInjectorTemperatureCorrectionFactor * pS.FrompH(RefKInjector1Factor * ActualInjector1NozzleAreaMM2 * (float)Math.Sqrt(BoilerPressurePSI)) * WaterLBpUKG;
74487465

74497466
// Calculate the flow rates for injector #2 based upon boiler pressure and injector nozzle size
74507467
var ActualInjector2NozzleAreaMM2 = (float)(Math.PI * Math.Pow((ActualInjector1NozzleSizeMM) / 2.0f, 2));
@@ -7453,6 +7470,19 @@ private void UpdateWaterInjection(float elapsedClockSeconds)
74537470

74547471
ActualInjector2FlowRateLBpS = pS.FrompH(RefKInjector2Factor * ActualInjector1NozzleAreaMM2 * (float)Math.Sqrt(BoilerPressurePSI)) * WaterLBpUKG;
74557472

7473+
// Calculate the temperature correction factor as the feedwater temperature will affect the flow rate and the hence the steam used
7474+
// Actual Delivery Capacity = Base Delivery * Temperature Correction Factor
7475+
// Actual Steam used = Base Steam used * Temperature Correction Factor
7476+
// Temperature Correction Factor = (Tsat - Tfeedwater) / (Tsat - Tref), Assume ref = 20C
7477+
7478+
var ReferenceTemperature = 20.0f; // Reference temperature for injector performance
7479+
ActualInjectorTemperatureCorrectionFactor = ( C.FromF(PressureToTemperaturePSItoF[BoilerPressurePSI]) - TenderWaterTemperatureC) / (C.FromF(PressureToTemperaturePSItoF[BoilerPressurePSI]) - ReferenceTemperature);
7480+
7481+
// Calculate enthalpy of injector feed water based on boiler water temperature
7482+
// hfg kJ/kg) = 2500 - 2.4 * Tsat (C) - 4% accurate, to be explored later for better accuracy
7483+
7484+
InjectorHFGkJPkg = 2500.0f - (2.4f * C.FromF(PressureToTemperaturePSItoF[BoilerPressurePSI]));
7485+
74567486
#endregion
74577487

74587488
if (WaterIsExhausted)
@@ -7469,7 +7499,8 @@ private void UpdateWaterInjection(float elapsedClockSeconds)
74697499
}
74707500
else
74717501
{
7472-
// Injectors to fill boiler
7502+
// Injectors to fill boiler
7503+
// // Injector #1
74737504
if (Injector1IsOn)
74747505
{
74757506
// Calculate Injector 1 delivery water temp
@@ -7490,6 +7521,12 @@ private void UpdateWaterInjection(float elapsedClockSeconds)
74907521
MaxInject1SteamUsedLbpS = InjWaterFedSteamPressureFtoPSI[BoilerPressurePSI]; // Maximum amount of steam used at actual boiler pressure
74917522
ActInject1SteamUsedLbpS = (Injector1Fraction * ActualInjector1FlowRateLBpS) / MaxInject1SteamUsedLbpS; // Lbs of steam injected into boiler to inject water.
74927523

7524+
// Actual steam used by the injector is calculated by following formula
7525+
// Steam Mass (kg/hr) = Water Mass (kg/h) * (Cp*(Tsat-Ttenderwater))/(hfg+(Cp*(Tsat-Ttenderwater))
7526+
// where Cp = specific heat of water (4.18kJ/kgK), hfg = latent heat of vaporisation at boiler pressure
7527+
7528+
ActualInjector1SteamUsedLBpS = (Injector1Fraction * ActualInjector1FlowRateLBpS) * (4.18f * (C.FromF(PressureToTemperaturePSItoF[BoilerPressurePSI]) - TenderWaterTemperatureC)) / (InjectorHFGkJPkg + (4.18f * (C.FromF(PressureToTemperaturePSItoF[BoilerPressurePSI]) - TenderWaterTemperatureC)));
7529+
74937530
// Calculate heat loss for steam injection
74947531
Inject1SteamHeatLossBTU = ActInject1SteamUsedLbpS * (BoilerSteamHeatBTUpLB - WaterHeatPSItoBTUpLB[Injector1WaterTempPressurePSI]); // Calculate heat loss for injection steam, ie steam heat to water delivery temperature
74957532

@@ -7503,6 +7540,8 @@ private void UpdateWaterInjection(float elapsedClockSeconds)
75037540
BoilerWaterInputLB += (elapsedClockSeconds * Injector1Fraction * ActualInjector1FlowRateLBpS); // Keep track of water flow into boilers from Injector 1
75047541
BoilerHeatOutBTUpS += (Inject1WaterHeatLossBTU + Inject1SteamHeatLossBTU); // Total loss of boiler heat due to water injection - inject steam and water Heat
75057542
}
7543+
7544+
// Injector #2
75067545
if (Injector2IsOn)
75077546
{
75087547
// Calculate Injector 2 delivery water temp
@@ -7522,6 +7561,12 @@ private void UpdateWaterInjection(float elapsedClockSeconds)
75227561
MaxInject2SteamUsedLbpS = InjWaterFedSteamPressureFtoPSI[BoilerPressurePSI]; // Maximum amount of steam used at boiler pressure
75237562
ActInject2SteamUsedLbpS = (Injector2Fraction * ActualInjector2FlowRateLBpS) / MaxInject2SteamUsedLbpS; // Lbs of steam injected into boiler to inject water.
75247563

7564+
// Actual steam used by the injector is calculated by following formula
7565+
// Steam Mass (kg/hr) = Water Mass (kg/h) * (Cp*(Tsat-Ttenderwater))/(hfg+(Cp*(Tsat-Ttenderwater))
7566+
// where Cp = specific heat of water (4.18kJ/kgK), hfg = latent heat of vaporisation at boiler pressure
7567+
7568+
ActualInjector2SteamUsedLBpS = (Injector1Fraction * ActualInjector2FlowRateLBpS) * (4.18f * (C.FromF(PressureToTemperaturePSItoF[BoilerPressurePSI]) - TenderWaterTemperatureC)) / (InjectorHFGkJPkg + (4.18f * (C.FromF(PressureToTemperaturePSItoF[BoilerPressurePSI]) - TenderWaterTemperatureC)));
7569+
75257570
// Calculate heat loss for steam injection
75267571
Inject2SteamHeatLossBTU = ActInject2SteamUsedLbpS * (BoilerSteamHeatBTUpLB - WaterHeatPSItoBTUpLB[Injector2WaterTempPressurePSI]); // Calculate heat loss for injection steam, ie steam heat to water delivery temperature
75277572

@@ -8577,7 +8622,7 @@ public override string GetDebugStatus()
85778622
}
85788623
else
85798624
{
8580-
status.AppendFormat("{0}\t{1}\t{2}/{13}\t\t{3}\t({4:N0} {14})\t{5}/{13}\t\t{6}\t{7}\t{8}\t({9:N0} {14})\t{10}/{13}\t\t{11}\t{12}\n",
8625+
status.AppendFormat("{0}\t{1}\t{2}/{17}\t\t{3}\t({4:N0} {18})\t{5}/{17}\t\t{6}\t{7}\t{8}\t{9}/{17}\t\t{10}\t({11:N0} {18})\t{12}/{17}\t\t{13}\t{14}\t{15}\t{16:N0}/{17}\n",
85818626
Simulator.Catalog.GetString("Injector:"),
85828627
Simulator.Catalog.GetString("Max"),
85838628
FormatStrings.FormatFuelVolume(pS.TopH(L.FromGUK(MaxInjectorFlowRateLBpS / WaterLBpUKG)), IsMetric, IsUK),
@@ -8586,11 +8631,15 @@ public override string GetDebugStatus()
85868631
FormatStrings.FormatFuelVolume(Injector1Fraction * pS.TopH(L.FromGUK(ActualInjector1FlowRateLBpS / WaterLBpUKG)), IsMetric, IsUK),
85878632
Simulator.Catalog.GetString("Temp1"),
85888633
FormatStrings.FormatTemperature(C.FromF(Injector1WaterDelTempF), IsMetric, false),
8634+
Simulator.Catalog.GetString("Steam1"),
8635+
FormatStrings.FormatMass(pS.TopH(ActualInjector1SteamUsedLBpS), IsMetric),
85898636
Simulator.Catalog.GetString("Inj2"),
85908637
ActualInjector2NozzleSizeMM,
85918638
FormatStrings.FormatFuelVolume(Injector2Fraction * pS.TopH(L.FromGUK(ActualInjector2FlowRateLBpS / WaterLBpUKG)), IsMetric, IsUK),
85928639
Simulator.Catalog.GetString("Temp2"),
85938640
FormatStrings.FormatTemperature(C.FromF(Injector2WaterDelTempF), IsMetric, false),
8641+
Simulator.Catalog.GetString("Steam2"),
8642+
FormatStrings.FormatMass(pS.TopH(ActualInjector2SteamUsedLBpS), IsMetric),
85948643
FormatStrings.h,
85958644
FormatStrings.mm);
85968645
}
@@ -8651,14 +8700,16 @@ public override string GetDebugStatus()
86518700
}
86528701
else // default to coal
86538702
{
8654-
status.AppendFormat("{0}\t{1}\t{2}\t{3:N0}%\t{4}\t{5}\t\t{6:N0}%\t{7}\t{8:N0}\t{9}\t\t{10:N0}\n",
8703+
status.AppendFormat("{0}\t{1}\t{2}\t{3:N0}%\t{4}\t{5}\t\t{6:N0}%\t{7}\t{8:N0}\t{9}\t{10:N0}\t{11}\t\t{12:N0}\n",
86558704
Simulator.Catalog.GetString("Tender:"),
86568705
Simulator.Catalog.GetString("Coal"),
86578706
FormatStrings.FormatMass(TenderFuelMassKG, IsMetric),
86588707
TenderFuelMassKG / MaxTenderFuelMassKG * 100,
86598708
Simulator.Catalog.GetString("Water"),
86608709
FormatStrings.FormatFuelVolume(L.FromGUK(CombinedTenderWaterVolumeUKG), IsMetric, IsUK),
86618710
CombinedTenderWaterVolumeUKG / MaxTotalCombinedWaterVolumeUKG * 100,
8711+
Simulator.Catalog.GetString("Tempw"),
8712+
FormatStrings.FormatTemperature(TenderWaterTemperatureC, IsMetric, false),
86628713
Simulator.Catalog.GetString("Steam"),
86638714
FormatStrings.FormatMass(Kg.FromLb(CumulativeCylinderSteamConsumptionLbs), IsMetric),
86648715
Simulator.Catalog.GetString("TotSteam"),

0 commit comments

Comments
 (0)