Skip to content

Commit 4cf7024

Browse files
committed
Automatic merge of T1.6-145-g7915033ac and 11 pull requests
- Pull request #1082 at ebf0879: Allow variable water level in glass gauge - Pull request #1156 at f46d5f2: Fix incorrectly disabled options in train operations window - Pull request #570 at 1b6b22e: glTF 2.0 support with PBR lighting - Pull request #1091 at 492795a: Automatic speed control - Pull request #1122 at 73c47b4: Wagon Size and Centering Controls - Pull request #1124 at e241a0d: Built-in PBL2 brake controller - Pull request #1157 at 39cd994: Dynamic brake authorization by TCS - Pull request #1167 at 115325f: Fix: RunActivity slow to terminate because of long sleep in Host Process - Pull request #1168 at 6e2942f: Fix exception when exiting with MapForm or SoundDebugForm open. - Pull request #1169 at 6cf8c3e: Better Handling of Wagons with Invalid Bogie Configuration - Pull request #1171 at 8fd2066: no internet connection is available, not possible to open the Menu Content Form
13 parents 541e4e9 + 7915033 + ebf0879 + f46d5f2 + 1b6b22e + 492795a + 73c47b4 + e241a0d + 39cd994 + 115325f + 6e2942f + 6cf8c3e + 8fd2066 commit 4cf7024

File tree

1 file changed

+55
-4
lines changed

1 file changed

+55
-4
lines changed

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

Lines changed: 55 additions & 4 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;
@@ -4086,6 +4091,15 @@ private void UpdateTender(float elapsedClockSeconds)
40864091
CoalIsExhausted = false;
40874092
}
40884093

4094+
// Calculate water temperature in tender based upon ambient temperature and water level
4095+
// Twt = Tat + 3 + 0.3 * (Tat - 10) - where wt = water temperature, at = ambient temperature, has to be capped at 50 deg C
4096+
// Check for more accurate solution later
4097+
4098+
TenderWaterTemperatureC = CarOutsideTempC + 3.0f + 0.3f * (CarOutsideTempC - 10.0f);
4099+
TenderWaterTemperatureC = MathHelper.Clamp(TenderWaterTemperatureC, 0, 50);
4100+
4101+
4102+
40894103
#region Auxiliary Water Tender Operation
40904104

40914105
// If aux tender is coupled then assume that both tender and aux tender will equalise at same % water level
@@ -7390,12 +7404,15 @@ private void UpdateWaterInjection(float elapsedClockSeconds)
73907404
{
73917405
#region Calculate Injector flow rates
73927406

7407+
ActualInjector1SteamUsedLBpS = 0;
7408+
ActualInjector2SteamUsedLBpS = 0;
7409+
73937410
// Calculate the flow rates for injector #1 based upon boiler pressure and injector nozzle size
73947411
var ActualInjector1NozzleAreaMM2 = (float)(Math.PI * Math.Pow((ActualInjector1NozzleSizeMM) / 2.0f, 2));
73957412

7396-
MaxInjectorFlowRateLBpS = pS.FrompH(RefKInjector1Factor * ActualInjector1NozzleAreaMM2 * (float)Math.Sqrt(MaxBoilerPressurePSI)) * WaterLBpUKG;
7413+
MaxInjectorFlowRateLBpS = ActualInjectorTemperatureCorrectionFactor * pS.FrompH(RefKInjector1Factor * ActualInjector1NozzleAreaMM2 * (float)Math.Sqrt(MaxBoilerPressurePSI)) * WaterLBpUKG;
73977414

7398-
ActualInjector1FlowRateLBpS = pS.FrompH(RefKInjector1Factor * ActualInjector1NozzleAreaMM2 * (float)Math.Sqrt(BoilerPressurePSI)) * WaterLBpUKG;
7415+
ActualInjector1FlowRateLBpS = ActualInjectorTemperatureCorrectionFactor * pS.FrompH(RefKInjector1Factor * ActualInjector1NozzleAreaMM2 * (float)Math.Sqrt(BoilerPressurePSI)) * WaterLBpUKG;
73997416

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

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

7424+
// Calculate the temperature correction factor as the feedwater temperature will affect the flow rate and the hence the steam used
7425+
// Actual Delivery Capacity = Base Delivery * Temperature Correction Factor
7426+
// Actual Steam used = Base Steam used * Temperature Correction Factor
7427+
// Temperature Correction Factor = (Tsat - Tfeedwater) / (Tsat - Tref), Assume ref = 20C
7428+
7429+
var ReferenceTemperature = 20.0f; // Reference temperature for injector performance
7430+
ActualInjectorTemperatureCorrectionFactor = ( C.FromF(PressureToTemperaturePSItoF[BoilerPressurePSI]) - TenderWaterTemperatureC) / (C.FromF(PressureToTemperaturePSItoF[BoilerPressurePSI]) - ReferenceTemperature);
7431+
7432+
// Calculate enthalpy of injector feed water based on boiler water temperature
7433+
// hfg kJ/kg) = 2500 - 2.4 * Tsat (C) - 4% accurate, to be explored later for better accuracy
7434+
7435+
InjectorHFGkJPkg = 2500.0f - (2.4f * C.FromF(PressureToTemperaturePSItoF[BoilerPressurePSI]));
7436+
74077437
#endregion
74087438

74097439
if (WaterIsExhausted)
@@ -7421,6 +7451,7 @@ private void UpdateWaterInjection(float elapsedClockSeconds)
74217451
else
74227452
{
74237453
// Injectors to fill boiler
7454+
// // Injector #1
74247455
if (Injector1IsOn)
74257456
{
74267457
// Calculate Injector 1 delivery water temp
@@ -7441,6 +7472,12 @@ private void UpdateWaterInjection(float elapsedClockSeconds)
74417472
MaxInject1SteamUsedLbpS = InjWaterFedSteamPressureFtoPSI[BoilerPressurePSI]; // Maximum amount of steam used at actual boiler pressure
74427473
ActInject1SteamUsedLbpS = (Injector1Fraction * ActualInjector1FlowRateLBpS) / MaxInject1SteamUsedLbpS; // Lbs of steam injected into boiler to inject water.
74437474

7475+
// Actual steam used by the injector is calculated by following formula
7476+
// Steam Mass (kg/hr) = Water Mass (kg/h) * (Cp*(Tsat-Ttenderwater))/(hfg+(Cp*(Tsat-Ttenderwater))
7477+
// where Cp = specific heat of water (4.18kJ/kgK), hfg = latent heat of vaporisation at boiler pressure
7478+
7479+
ActualInjector1SteamUsedLBpS = (Injector1Fraction * ActualInjector1FlowRateLBpS) * (4.18f * (C.FromF(PressureToTemperaturePSItoF[BoilerPressurePSI]) - TenderWaterTemperatureC)) / (InjectorHFGkJPkg + (4.18f * (C.FromF(PressureToTemperaturePSItoF[BoilerPressurePSI]) - TenderWaterTemperatureC)));
7480+
74447481
// Calculate heat loss for steam injection
74457482
Inject1SteamHeatLossBTU = ActInject1SteamUsedLbpS * (BoilerSteamHeatBTUpLB - WaterHeatPSItoBTUpLB[Injector1WaterTempPressurePSI]); // Calculate heat loss for injection steam, ie steam heat to water delivery temperature
74467483

@@ -7454,6 +7491,8 @@ private void UpdateWaterInjection(float elapsedClockSeconds)
74547491
BoilerWaterInputLB += (elapsedClockSeconds * Injector1Fraction * ActualInjector1FlowRateLBpS); // Keep track of water flow into boilers from Injector 1
74557492
BoilerHeatOutBTUpS += (Inject1WaterHeatLossBTU + Inject1SteamHeatLossBTU); // Total loss of boiler heat due to water injection - inject steam and water Heat
74567493
}
7494+
7495+
// Injector #2
74577496
if (Injector2IsOn)
74587497
{
74597498
// Calculate Injector 2 delivery water temp
@@ -7473,6 +7512,12 @@ private void UpdateWaterInjection(float elapsedClockSeconds)
74737512
MaxInject2SteamUsedLbpS = InjWaterFedSteamPressureFtoPSI[BoilerPressurePSI]; // Maximum amount of steam used at boiler pressure
74747513
ActInject2SteamUsedLbpS = (Injector2Fraction * ActualInjector2FlowRateLBpS) / MaxInject2SteamUsedLbpS; // Lbs of steam injected into boiler to inject water.
74757514

7515+
// Actual steam used by the injector is calculated by following formula
7516+
// Steam Mass (kg/hr) = Water Mass (kg/h) * (Cp*(Tsat-Ttenderwater))/(hfg+(Cp*(Tsat-Ttenderwater))
7517+
// where Cp = specific heat of water (4.18kJ/kgK), hfg = latent heat of vaporisation at boiler pressure
7518+
7519+
ActualInjector2SteamUsedLBpS = (Injector1Fraction * ActualInjector2FlowRateLBpS) * (4.18f * (C.FromF(PressureToTemperaturePSItoF[BoilerPressurePSI]) - TenderWaterTemperatureC)) / (InjectorHFGkJPkg + (4.18f * (C.FromF(PressureToTemperaturePSItoF[BoilerPressurePSI]) - TenderWaterTemperatureC)));
7520+
74767521
// Calculate heat loss for steam injection
74777522
Inject2SteamHeatLossBTU = ActInject2SteamUsedLbpS * (BoilerSteamHeatBTUpLB - WaterHeatPSItoBTUpLB[Injector2WaterTempPressurePSI]); // Calculate heat loss for injection steam, ie steam heat to water delivery temperature
74787523

@@ -8528,7 +8573,7 @@ public override string GetDebugStatus()
85288573
}
85298574
else
85308575
{
8531-
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",
8576+
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",
85328577
Simulator.Catalog.GetString("Injector:"),
85338578
Simulator.Catalog.GetString("Max"),
85348579
FormatStrings.FormatFuelVolume(pS.TopH(L.FromGUK(MaxInjectorFlowRateLBpS / WaterLBpUKG)), IsMetric, IsUK),
@@ -8537,11 +8582,15 @@ public override string GetDebugStatus()
85378582
FormatStrings.FormatFuelVolume(Injector1Fraction * pS.TopH(L.FromGUK(ActualInjector1FlowRateLBpS / WaterLBpUKG)), IsMetric, IsUK),
85388583
Simulator.Catalog.GetString("Temp1"),
85398584
FormatStrings.FormatTemperature(C.FromF(Injector1WaterDelTempF), IsMetric, false),
8585+
Simulator.Catalog.GetString("Steam1"),
8586+
FormatStrings.FormatMass(pS.TopH(ActualInjector1SteamUsedLBpS), IsMetric),
85408587
Simulator.Catalog.GetString("Inj2"),
85418588
ActualInjector2NozzleSizeMM,
85428589
FormatStrings.FormatFuelVolume(Injector2Fraction * pS.TopH(L.FromGUK(ActualInjector2FlowRateLBpS / WaterLBpUKG)), IsMetric, IsUK),
85438590
Simulator.Catalog.GetString("Temp2"),
85448591
FormatStrings.FormatTemperature(C.FromF(Injector2WaterDelTempF), IsMetric, false),
8592+
Simulator.Catalog.GetString("Steam2"),
8593+
FormatStrings.FormatMass(pS.TopH(ActualInjector2SteamUsedLBpS), IsMetric),
85458594
FormatStrings.h,
85468595
FormatStrings.mm);
85478596
}
@@ -8602,14 +8651,16 @@ public override string GetDebugStatus()
86028651
}
86038652
else // default to coal
86048653
{
8605-
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",
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{10:N0}\t{11}\t\t{12:N0}\n",
86068655
Simulator.Catalog.GetString("Tender:"),
86078656
Simulator.Catalog.GetString("Coal"),
86088657
FormatStrings.FormatMass(TenderFuelMassKG, IsMetric),
86098658
TenderFuelMassKG / MaxTenderFuelMassKG * 100,
86108659
Simulator.Catalog.GetString("Water"),
86118660
FormatStrings.FormatFuelVolume(L.FromGUK(CombinedTenderWaterVolumeUKG), IsMetric, IsUK),
86128661
CombinedTenderWaterVolumeUKG / MaxTotalCombinedWaterVolumeUKG * 100,
8662+
Simulator.Catalog.GetString("Tempw"),
8663+
FormatStrings.FormatTemperature(TenderWaterTemperatureC, IsMetric, false),
86138664
Simulator.Catalog.GetString("Steam"),
86148665
FormatStrings.FormatMass(Kg.FromLb(CumulativeCylinderSteamConsumptionLbs), IsMetric),
86158666
Simulator.Catalog.GetString("TotSteam"),

0 commit comments

Comments
 (0)