@@ -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