Skip to content

Commit 2f2a975

Browse files
committed
Automatic merge of T1.6-147-g31e3fe251 and 10 pull requests
- Pull request #1082 at 45c4272: Allow variable water level in glass gauge - 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 #1130 at 0f4342d: Fix F9 points to an incorrect car ID. - Pull request #1157 at 39cd994: Dynamic brake authorization by TCS - Pull request #1167 at d5c0d64: Fix: RunActivity slow to terminate because of long sleep in Host Process - Pull request #1171 at 50efb5b: no internet connection is available, not possible to open the Menu Content Form - Pull request #1169 at 6cf8c3e: Better Handling of Wagons with Invalid Bogie Configuration
12 parents d73ab5a + 31e3fe2 + 45c4272 + 1b6b22e + 492795a + 73c47b4 + e241a0d + 0f4342d + 39cd994 + d5c0d64 + 50efb5b + 6cf8c3e commit 2f2a975

File tree

1 file changed

+95
-16
lines changed

1 file changed

+95
-16
lines changed

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

Lines changed: 95 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,17 @@ public class MSTSSteamLocomotive : MSTSLocomotive
153153
float RefKInjector1Factor;
154154
float RefKInjector2Factor;
155155

156+
float MaxRefInjector1PressurePSI;
157+
float MaxRefInjector2PressurePSI;
158+
float MaxRefInjector1FlowRateUKGpH;
159+
float MaxRefInjector2FlowRateUKGpH;
160+
float UpperWaterDeliveryInjector1EfficiencyFactor;
161+
float UpperWaterDeliveryInjector2EfficiencyFactor;
162+
float UpperAlphaInjector1Factor;
163+
float UpperAlphaInjector2Factor;
164+
float UpperBetaInjector1Factor;
165+
float UpperBetaInjector2Factor;
166+
156167
float ActualInjector1NozzleSizeMM;
157168
float ActualInjector2NozzleSizeMM;
158169
float ActualInjectorTemperatureCorrectionFactor;
@@ -2080,7 +2091,7 @@ public override void Initialize()
20802091

20812092
// Set up Injectors
20822093
// To calculate the maximum combined water delivery rate from the injectors at maximum boiler pressure, the formula is used:
2083-
// WaterFlowRateUKGpM = K * A * P^0.5, k is calculated using known flow rates from manuafacturers manuals.
2094+
// WaterFlowRateUKGpM = K * A * P^0.5, k is calculated using known flow rates from manuafacturers manuals, and rearranging the formula.
20842095
// If user does not enter any values then the D&M 11mm injector is assumed to be operating at 200 psi .
20852096
// http://users.fini.net/~bersano/english-anglais/english-anglais/NZ-accessories/D&M_Type_J_Exhaust_steam_injector.pdf
20862097
//
@@ -2126,14 +2137,62 @@ public override void Initialize()
21262137
Trace.TraceInformation("RefInjector2FlowRateUKGpH not specified in ENG file. Defaulting to {0} UKG/h", RefInjector2FlowRateUKGpH);
21272138
}
21282139

2129-
// Calculate K values for injector flow rate calculations
2140+
if (MaxRefInjector1FlowRateUKGpH == 0)
2141+
{
2142+
MaxRefInjector1FlowRateUKGpH = 2600;
2143+
if (Simulator.Settings.VerboseConfigurationMessages)
2144+
Trace.TraceInformation("MaxInjector1FlowRateUKGpH not specified in ENG file. Defaulting to {0} UKG/h", MaxRefInjector1FlowRateUKGpH);
2145+
}
2146+
2147+
if (MaxRefInjector2FlowRateUKGpH == 0)
2148+
{
2149+
MaxRefInjector2FlowRateUKGpH = 2600;
2150+
if (Simulator.Settings.VerboseConfigurationMessages)
2151+
Trace.TraceInformation("MaxInjector2FlowRateUKGpH not specified in ENG file. Defaulting to {0} UKG/h", MaxRefInjector2FlowRateUKGpH);
2152+
}
2153+
2154+
if(MaxRefInjector1PressurePSI == 0)
2155+
{
2156+
MaxRefInjector1PressurePSI = 300.0f; // Default to D&M 11mm injector operating pressure
2157+
if (Simulator.Settings.VerboseConfigurationMessages)
2158+
Trace.TraceInformation("MaxRefInjector1SteamPressurePSI not specified in ENG file. Defaulting to {0} psi", MaxRefInjector1PressurePSI);
2159+
}
2160+
2161+
if (MaxRefInjector2PressurePSI == 0)
2162+
{
2163+
MaxRefInjector2PressurePSI = 300.0f; // Default to D&M 11mm injector operating pressure
2164+
if (Simulator.Settings.VerboseConfigurationMessages)
2165+
Trace.TraceInformation("MaxRefInjector2SteamPressurePSI not specified in ENG file. Defaulting to {0} psi", MaxRefInjector2PressurePSI);
2166+
}
2167+
2168+
// Calculate K values for injector delivery flow rate calculations - up to to optimum (maximum delivery rate)
21302169

21312170
var RefInjectorNozzle1AreaMM2 = (float)(Math.PI * Math.Pow((RefInjector1NozzleSizeMM) / 2.0f, 2));
21322171
RefKInjector1Factor = RefInjector1FlowRateUKGpH / (float)(RefInjectorNozzle1AreaMM2 * Math.Sqrt(RefInjector1PressurePSI));
21332172

21342173
var RefInjectorNozzle2AreaMM2 = (float)(Math.PI * Math.Pow((RefInjector2NozzleSizeMM) / 2.0f, 2));
21352174
RefKInjector2Factor = RefInjector2FlowRateUKGpH / (float)(RefInjectorNozzle2AreaMM2 * Math.Sqrt(RefInjector2PressurePSI));
21362175

2176+
// calculate relevant factors for delivery flow rates above optimum delivery rate
2177+
// Calculation based upon a quadratic equation to fit the known data points, with the user setting a known point above the optimum delivery rate.
2178+
// Effective delivery @ P pressure - Qeff(P)= Qbase(P)* η(P) at current Boiler Pressure
2179+
// Delivery @ P - Qbase(P) = Qopt √(P/Popt)
2180+
// Efficiency factor is calculated by η(P)=1-β(P-Popt)-α(P-Popt)^2
2181+
// Following section calculates the constants required to model the efficiency curve above optimum delivery rate
2182+
// β=1/(2 Popt )
2183+
// η(Pmax)= (Qeff(Popt))/(Qbase(Pmax))
2184+
// α= [1 - β(Pmax - Popt) - η(Pmax)] / (Pmax - Popt)^2
2185+
2186+
UpperBetaInjector1Factor = 1 / (2 * RefInjector1PressurePSI);
2187+
var DeliveryBaseInjector1Pmax = RefInjector1FlowRateUKGpH * Math.Sqrt(MaxRefInjector1PressurePSI / RefInjector1PressurePSI);
2188+
var EfficiencyBaseInjector1atMax = MaxRefInjector1FlowRateUKGpH / DeliveryBaseInjector1Pmax;
2189+
UpperAlphaInjector1Factor = (float)(1.0 - UpperBetaInjector1Factor * (MaxRefInjector1PressurePSI - RefInjector1PressurePSI) - EfficiencyBaseInjector1atMax) / (float)Math.Pow((MaxRefInjector1PressurePSI - RefInjector1PressurePSI), 2);
2190+
2191+
UpperBetaInjector2Factor = 1 / (2 * RefInjector2PressurePSI);
2192+
var DeliveryBaseInjector2Pmax = RefInjector2FlowRateUKGpH * Math.Sqrt(MaxRefInjector2PressurePSI / RefInjector2PressurePSI);
2193+
var EfficiencyBaseInjector2atMax = MaxRefInjector2FlowRateUKGpH / DeliveryBaseInjector2Pmax;
2194+
UpperAlphaInjector2Factor = (float)(1.0 - UpperBetaInjector2Factor * (MaxRefInjector2PressurePSI - RefInjector2PressurePSI) - EfficiencyBaseInjector2atMax) / (float)Math.Pow((MaxRefInjector2PressurePSI - RefInjector2PressurePSI), 2);
2195+
21372196
// Calculate Injector sizing, a single injector should be able to cope with 75% of the maximum water delivery rate required at full steam usage.
21382197

21392198
if (ActualInjector1NozzleSizeMM == 0)
@@ -7409,25 +7468,45 @@ private void UpdateWaterInjection(float elapsedClockSeconds)
74097468

74107469
// Calculate the flow rates for injector #1 based upon boiler pressure and injector nozzle size
74117470
var ActualInjector1NozzleAreaMM2 = (float)(Math.PI * Math.Pow((ActualInjector1NozzleSizeMM) / 2.0f, 2));
7412-
7471+
74137472
MaxInjectorFlowRateLBpS = ActualInjectorTemperatureCorrectionFactor * pS.FrompH(RefKInjector1Factor * ActualInjector1NozzleAreaMM2 * (float)Math.Sqrt(MaxBoilerPressurePSI)) * WaterLBpUKG;
74147473

7415-
ActualInjector1FlowRateLBpS = ActualInjectorTemperatureCorrectionFactor * pS.FrompH(RefKInjector1Factor * ActualInjector1NozzleAreaMM2 * (float)Math.Sqrt(BoilerPressurePSI)) * WaterLBpUKG;
7474+
// Injector #1 - calculate flow rate depending upon whether pressure is above or below optimum pressure
7475+
if (BoilerPressurePSI <= RefInjector1PressurePSI)
7476+
{
7477+
ActualInjector1FlowRateLBpS = ActualInjectorTemperatureCorrectionFactor * pS.FrompH(RefKInjector1Factor * ActualInjector1NozzleAreaMM2 * (float)Math.Sqrt(BoilerPressurePSI)) * WaterLBpUKG;
7478+
}
7479+
else
7480+
{
7481+
float InjectorDeliveryEfficincyatP = (float)(1 - UpperBetaInjector1Factor * (BoilerPressurePSI - RefInjector1PressurePSI) - UpperAlphaInjector1Factor * Math.Pow(BoilerPressurePSI - RefInjector1PressurePSI, 2));
7482+
float DeliveryBaseFlowRateatP = (float)(RefInjector1FlowRateUKGpH * Math.Sqrt(BoilerPressurePSI / RefInjector1PressurePSI));
7483+
ActualInjector1FlowRateLBpS = pS.FrompH(DeliveryBaseFlowRateatP * InjectorDeliveryEfficincyatP) * WaterLBpUKG;
7484+
}
74167485

74177486
// Calculate the flow rates for injector #2 based upon boiler pressure and injector nozzle size
74187487
var ActualInjector2NozzleAreaMM2 = (float)(Math.PI * Math.Pow((ActualInjector1NozzleSizeMM) / 2.0f, 2));
74197488

74207489
MaxInjectorFlowRateLBpS = pS.FrompH(RefKInjector2Factor * ActualInjector1NozzleAreaMM2 * (float)Math.Sqrt(MaxBoilerPressurePSI)) * WaterLBpUKG;
74217490

7422-
ActualInjector2FlowRateLBpS = pS.FrompH(RefKInjector2Factor * ActualInjector1NozzleAreaMM2 * (float)Math.Sqrt(BoilerPressurePSI)) * WaterLBpUKG;
7491+
// Injector #2 - calculate flow rate depending upon whether pressure is above or below optimum pressure
7492+
if (BoilerPressurePSI <= RefInjector2PressurePSI)
7493+
{
7494+
ActualInjector2FlowRateLBpS = pS.FrompH(RefKInjector2Factor * ActualInjector1NozzleAreaMM2 * (float)Math.Sqrt(BoilerPressurePSI)) * WaterLBpUKG;
7495+
}
7496+
else
7497+
{
7498+
float InjectorDeliveryEfficincyatP = (float)(1 - UpperBetaInjector2Factor * (BoilerPressurePSI - RefInjector2PressurePSI) - UpperAlphaInjector2Factor * Math.Pow(BoilerPressurePSI - RefInjector2PressurePSI, 2));
7499+
float DeliveryBaseFlowRateatP = (float)(RefInjector2FlowRateUKGpH * Math.Sqrt(BoilerPressurePSI / RefInjector2PressurePSI));
7500+
ActualInjector2FlowRateLBpS = pS.FrompH(DeliveryBaseFlowRateatP * InjectorDeliveryEfficincyatP) * WaterLBpUKG;
7501+
}
74237502

74247503
// Calculate the temperature correction factor as the feedwater temperature will affect the flow rate and the hence the steam used
74257504
// Actual Delivery Capacity = Base Delivery * Temperature Correction Factor
74267505
// Actual Steam used = Base Steam used * Temperature Correction Factor
74277506
// Temperature Correction Factor = (Tsat - Tfeedwater) / (Tsat - Tref), Assume ref = 20C
74287507

74297508
var ReferenceTemperature = 20.0f; // Reference temperature for injector performance
7430-
ActualInjectorTemperatureCorrectionFactor = (float)Math.Sqrt(( C.FromF(PressureToTemperaturePSItoF[BoilerPressurePSI]) - TenderWaterTemperatureC) / (C.FromF(PressureToTemperaturePSItoF[BoilerPressurePSI]) - ReferenceTemperature));
7509+
ActualInjectorTemperatureCorrectionFactor = (float)Math.Sqrt((C.FromF(PressureToTemperaturePSItoF[BoilerPressurePSI]) - TenderWaterTemperatureC) / (C.FromF(PressureToTemperaturePSItoF[BoilerPressurePSI]) - ReferenceTemperature));
74317510

74327511
// Calculate enthalpy of injector feed water based on boiler water temperature
74337512
// hfg kJ/kg) = 2500 - 2.4 * Tsat (C) - 4% accurate, to be explored later for better accuracy
@@ -7645,25 +7724,25 @@ private void UpdateFiring(float absSpeedMpS)
76457724
StopInjector1Sound();
76467725
StopInjector2Sound();
76477726
}
7648-
else if (CurrentWaterGaugeFraction <= 0.55 && CurrentWaterGaugeFraction > 0.525 && !InjectorLockedOut)
7727+
else if (CurrentWaterGaugeFraction <= 0.55 && CurrentWaterGaugeFraction > 0.50 && !InjectorLockedOut)
76497728
{
76507729
Injector1IsOn = true;
7651-
Injector1Fraction = 0.25f;
7730+
Injector1Fraction = 0.5f;
76527731
Injector2IsOn = false;
76537732
Injector2Fraction = 0.0f;
76547733
InjectorLockedOut = true;
76557734
PlayInjector1SoundIfStarting();
76567735
}
7657-
else if (CurrentWaterGaugeFraction <= 0.525 && CurrentWaterGaugeFraction > 0.5 && !InjectorLockedOut)
7736+
else if (CurrentWaterGaugeFraction <= 0.50 && CurrentWaterGaugeFraction > 0.45 && !InjectorLockedOut)
76587737
{
76597738
Injector1IsOn = true;
7660-
Injector1Fraction = 0.5f;
7739+
Injector1Fraction = 0.75f;
76617740
Injector2IsOn = false;
76627741
Injector2Fraction = 0.0f;
76637742
InjectorLockedOut = true;
76647743
PlayInjector1SoundIfStarting();
76657744
}
7666-
else if (CurrentWaterGaugeFraction <= 0.5 && CurrentWaterGaugeFraction > 0.475 && !InjectorLockedOut)
7745+
else if (CurrentWaterGaugeFraction <= 0.45 && CurrentWaterGaugeFraction > 0.40 && !InjectorLockedOut)
76677746
{
76687747
Injector1IsOn = true;
76697748
Injector1Fraction = 1.0f;
@@ -7674,26 +7753,26 @@ private void UpdateFiring(float absSpeedMpS)
76747753
}
76757754
else if (BoilerPressurePSI > (MaxBoilerPressurePSI - 100.0)) // If boiler pressure is not too low then turn on injector 2 as well
76767755
{
7677-
if (CurrentWaterGaugeFraction <= 0.475 && CurrentWaterGaugeFraction > 0.45 && !InjectorLockedOut)
7756+
if (CurrentWaterGaugeFraction <= 0.40 && CurrentWaterGaugeFraction > 0.35 && !InjectorLockedOut)
76787757
{
76797758

76807759
Injector1IsOn = true;
76817760
Injector1Fraction = 1.0f;
76827761
Injector2IsOn = true;
7683-
Injector2Fraction = 0.25f;
7762+
Injector2Fraction = 0.5f;
76847763
InjectorLockedOut = true;
76857764
PlayInjector2SoundIfStarting();
76867765
}
7687-
else if (CurrentWaterGaugeFraction <= 0.45 && CurrentWaterGaugeFraction > 0.425 && !InjectorLockedOut)
7766+
else if (CurrentWaterGaugeFraction <= 0.35 && CurrentWaterGaugeFraction > 0.3 && !InjectorLockedOut)
76887767
{
76897768
Injector1IsOn = true;
76907769
Injector1Fraction = 1.0f;
76917770
Injector2IsOn = true;
7692-
Injector2Fraction = 0.5f;
7771+
Injector2Fraction = 0.75f;
76937772
InjectorLockedOut = true;
76947773
PlayInjector2SoundIfStarting();
76957774
}
7696-
else if (CurrentWaterGaugeFraction <= 0.425 && !InjectorLockedOut)
7775+
else if (CurrentWaterGaugeFraction <= 0.3 && !InjectorLockedOut)
76977776
{
76987777
Injector1IsOn = true;
76997778
Injector1Fraction = 1.0f;

0 commit comments

Comments
 (0)