Skip to content

Commit 6286583

Browse files
committed
Automatic merge of T1.5.1-997-gb5992851e1 and 20 pull requests
- Pull request #799 at dfc715e: Consolidated wind simulation - Pull request #839 at d00beb9: First phase of https://blueprints.launchpad.net/or/+spec/additional-cruise-control-parameters - Pull request #876 at f92de76: docs: add source for documents previously on website to source Documentation folder - Pull request #882 at b3f83ed: Blueprint/train car operations UI window - Pull request #885 at 56c17fb: feat: Add notifications to Menu - Pull request #891 at 9a1d6b2: Auto save - Pull request #892 at 1f5ba4c: Signal Function OPP_SIG_ID_TRAINPATH - Pull request #896 at 5866028: First implementation of https://blueprints.launchpad.net/or/+spec/specific-sounds-for-ai-trains - Pull request #900 at c27f32d: DMI updates - Pull request #903 at 3e390b8: Downloading route content (Github, zip) - Pull request #912 at 359cfee: New Triple Valve Features Vol. 2 - Pull request #922 at abe2e52: Autopilot for timetable mode - Pull request #946 at 66f836c: Advanced track sounds - Pull request #949 at 33a3e1c: Oil Burning Locomotive - Pull request #950 at a98ff62: Ctrl-F5 showing yellow rectangles where mouse left button is active - Pull request #951 at 486081b: fix: Fix watchdog process state name - Pull request #952 at b2af1f5: Investigation - Pulsing graphics part 1 - Pull request #953 at 9b0ec01: Fix Lights Crash on Corrupt Shapes - Pull request #954 at 376e7af: Add Support for Multiple Track Profiles - Pull request #955 at 0c8e659: Copy dynamic brake speeds from other vehicles
22 parents bbe8fa2 + b599285 + dfc715e + d00beb9 + f92de76 + b3f83ed + 56c17fb + 9a1d6b2 + 1f5ba4c + 5866028 + c27f32d + 3e390b8 + 359cfee + abe2e52 + 66f836c + 33a3e1c + a98ff62 + 486081b + b2af1f5 + 9b0ec01 + 376e7af + 0c8e659 commit 6286583

File tree

1 file changed

+115
-1
lines changed

1 file changed

+115
-1
lines changed

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

Lines changed: 115 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ public class MSTSSteamLocomotive : MSTSLocomotive
230230
public float CylinderSteamUsageLBpS;
231231
public float NewCylinderSteamUsageLBpS;
232232
public float BlowerSteamUsageLBpS;
233+
public float FuelOilHeatingSteamUsageLbpS;
233234
public float EvaporationLBpS; // steam generation rate
234235
public float FireMassKG; // Mass of coal currently on grate area
235236
public float FireRatio; // Ratio of actual firemass to ideal firemass
@@ -3582,6 +3583,52 @@ protected override void UpdateControllers(float elapsedClockSeconds)
35823583

35833584
private void UpdateTender(float elapsedClockSeconds)
35843585
{
3586+
// Calculate steam usage required to heat fuel oil in oil fired locomotive
3587+
if (SteamLocomotiveFuelType == SteamLocomotiveFuelTypes.Oil )
3588+
{
3589+
// The following calculations are based upon the interpretation of information in
3590+
// https://www.spiraxsarco.com/learn-about-steam/steam-engineering-principles-and-heat-transfer/heating-with-coils-and-jackets#article-top
3591+
// and movement of the locomotive is described in this article
3592+
// https://www.spiraxsarco.com/learn-about-steam/steam-engineering-principles-and-heat-transfer/energy-consumption-of-tanks-and-vats
3593+
// Currently due to the difficulty of finding input information some assumptions have be made, and will be described through the calculation process.
3594+
//
3595+
// The first step is to calculate the amount of heat lost through the sides of the oil tank on the tender (this loss will ultimately need to be
3596+
// compensated by steam heating
3597+
// This can be calculated by Q (heat Loss) = Txf Coeff for tank sides * Area of Sides * Temp Diff (external vs internal)
3598+
// The most accurate calculation could be made if the bottom, sides and top of oil tank area was known, and also if the aount of exposed surface
3599+
// (subject to wind effect)
3600+
float TankSurfaceAreatoMassRatio = 0.015f; // based upon the inspection of the oil masses in a couple of known locomotives
3601+
float AssumedSurfaceAreaFt2 = Kg.ToLb(MaxTenderOilMassL * OilSpecificGravity) * TankSurfaceAreatoMassRatio;
3602+
float AreaExposedtoWindMovementFraction = 0.42f;
3603+
float OilTempRequired = 150; // Oil to be heated to 150degF
3604+
float HeatDiff = OilTempRequired - C.ToF(CarOutsideTempC);
3605+
float HeatTransferCoefficientBtuphft2F = 0.00001263f * HeatDiff * HeatDiff + 0.001175f * HeatDiff + 1.776f;
3606+
3607+
float HeatLossNoWindBTUph = (1- AreaExposedtoWindMovementFraction) * HeatTransferCoefficientBtuphft2F * AssumedSurfaceAreaFt2 * HeatDiff;
3608+
3609+
// To compensate for the train movement we need to add a wind factor
3610+
float WindCoeff = -0.0074f * absSpeedMpS * absSpeedMpS + 0.3817f * absSpeedMpS + 1f;
3611+
WindCoeff = MathHelper.Clamp(WindCoeff, 1.0f, 5.78f); // Wind speed effect will not cause any more impact once over about 25 m/s
3612+
3613+
float HeatLossWindBTUph = (1 - AreaExposedtoWindMovementFraction) * HeatTransferCoefficientBtuphft2F * AssumedSurfaceAreaFt2 * HeatDiff * WindCoeff;
3614+
3615+
float HeatLossTotalBTUph = HeatLossWindBTUph + HeatLossNoWindBTUph;
3616+
3617+
float HeatingCoilEfficiency = 0.12f;
3618+
float SteamEnthalpyBTUpLb = 980;
3619+
FuelOilHeatingSteamUsageLbpS = pS.FrompH(HeatLossTotalBTUph / (HeatingCoilEfficiency * SteamEnthalpyBTUpLb));
3620+
3621+
// adjust boiler heat and volume due to steam usage
3622+
BoilerMassLB -= elapsedClockSeconds * FuelOilHeatingSteamUsageLbpS; // Reduce boiler mass to reflect steam usage by fuel oil heating coils
3623+
BoilerHeatBTU -= elapsedClockSeconds * FuelOilHeatingSteamUsageLbpS * (BoilerSteamHeatBTUpLB - BoilerWaterHeatBTUpLB); // Reduce boiler Heat to reflect steam usage by fuel oil heating coils
3624+
BoilerHeatOutBTUpS += FuelOilHeatingSteamUsageLbpS * (BoilerSteamHeatBTUpLB - BoilerWaterHeatBTUpLB); // Reduce boiler Heat to reflect steam usage by mecahnical stoker
3625+
TotalSteamUsageLBpS += FuelOilHeatingSteamUsageLbpS;
3626+
3627+
// Increase tender water mass as steam heating condensate feed back into tender
3628+
CombinedTenderWaterVolumeUKG += (elapsedClockSeconds * FuelOilHeatingSteamUsageLbpS) / WaterLBpUKG;
3629+
3630+
}
3631+
35853632
TenderWaterLevelFraction = CombinedTenderWaterVolumeUKG / MaxTotalCombinedWaterVolumeUKG;
35863633
float TempCylinderSteamUsageLbpS = CylinderSteamUsageLBpS;
35873634
// Limit Cylinder steam usage to the maximum boiler evaporation rate, lower limit is for when the locomotive is at rest and "no steam" is being used by cylinder, ensures some coal is used.
@@ -7603,6 +7650,8 @@ public override string GetDebugStatus()
76037650

76047651
if (!(BrakeSystem is Orts.Simulation.RollingStocks.SubSystems.Brakes.MSTS.VacuumSinglePipe))
76057652
{
7653+
if (SteamLocomotiveFuelType == SteamLocomotiveFuelTypes.Oil)
7654+
{
76067655
// Display air compressor information
76077656
status.AppendFormat("{0}\t{1}\t{2}/{23}\t{3}\t{4}/{23}\t{5}\t{6}/{23}\t{7}\t{8}/{23}\t{9}\t{10}/{23}\t{11}\t{12}/{23}\t{13}\t{14}/{23}\t{15}\t{16}/{23}\t{17}\t{18}/{23}\t{19}\t{20}/{23}\t({21}x{22:N1}\")\n",
76087657
Simulator.Catalog.GetString("Usage:"),
@@ -7618,6 +7667,35 @@ public override string GetDebugStatus()
76187667
FormatStrings.FormatMass(pS.TopH(Kg.FromLb(CylCockSteamUsageDisplayLBpS)), IsMetric),
76197668
Simulator.Catalog.GetString("Genertr"),
76207669
FormatStrings.FormatMass(pS.TopH(Kg.FromLb(GeneratorSteamUsageLBpS)), IsMetric),
7670+
Simulator.Catalog.GetString("OilHeat"),
7671+
FormatStrings.FormatMass(pS.TopH(Kg.FromLb(FuelOilHeatingSteamUsageLbpS)), IsMetric),
7672+
Simulator.Catalog.GetString("BlowD"),
7673+
FormatStrings.FormatMass(pS.TopH(Kg.FromLb(BlowdownSteamUsageLBpS)), IsMetric),
7674+
Simulator.Catalog.GetString("Booster"),
7675+
FormatStrings.FormatMass(pS.TopH(Kg.FromLb(HuDBoosterSteamConsumptionLbpS)), IsMetric),
7676+
Simulator.Catalog.GetString("MaxSafe"),
7677+
FormatStrings.FormatMass(pS.TopH(Kg.FromLb(MaxSafetyValveDischargeLbspS)), IsMetric),
7678+
NumSafetyValves,
7679+
SafetyValveSizeIn,
7680+
FormatStrings.h);
7681+
}
7682+
else
7683+
{
7684+
// Display air compressor information with stoker fired locomotive
7685+
status.AppendFormat("{0}\t{1}\t{2}/{23}\t{3}\t{4}/{23}\t{5}\t{6}/{23}\t{7}\t{8}/{23}\t{9}\t{10}/{23}\t{11}\t{12}/{23}\t{13}\t{14}/{23}\t{15}\t{16}/{23}\t{17}\t{18}/{23}\t{19}\t{20}/{23}\t({21}x{22:N1}\")\n",
7686+
Simulator.Catalog.GetString("Usage:"),
7687+
Simulator.Catalog.GetString("Cyl"),
7688+
FormatStrings.FormatMass(pS.TopH(Kg.FromLb(CylinderSteamUsageLBpS)), IsMetric),
7689+
Simulator.Catalog.GetString("Blower"),
7690+
FormatStrings.FormatMass(pS.TopH(Kg.FromLb(BlowerSteamUsageLBpS)), IsMetric),
7691+
Simulator.Catalog.GetString("Comprsr"),
7692+
FormatStrings.FormatMass(pS.TopH(Kg.FromLb(CompSteamUsageLBpS)), IsMetric),
7693+
Simulator.Catalog.GetString("SafetyV"),
7694+
FormatStrings.FormatMass(pS.TopH(Kg.FromLb(SafetyValveUsageLBpS)), IsMetric),
7695+
Simulator.Catalog.GetString("CylCock"),
7696+
FormatStrings.FormatMass(pS.TopH(Kg.FromLb(CylCockSteamUsageDisplayLBpS)), IsMetric),
7697+
Simulator.Catalog.GetString("Genertr"),
7698+
FormatStrings.FormatMass(pS.TopH(Kg.FromLb(GeneratorSteamUsageLBpS)), IsMetric),
76217699
Simulator.Catalog.GetString("Stoker"),
76227700
FormatStrings.FormatMass(pS.TopH(Kg.FromLb(StokerSteamUsageLBpS)), IsMetric),
76237701
Simulator.Catalog.GetString("BlowD"),
@@ -7630,9 +7708,44 @@ public override string GetDebugStatus()
76307708
SafetyValveSizeIn,
76317709
FormatStrings.h);
76327710
}
7711+
}
76337712
else
76347713
{
7635-
// Display steam ejector information instead of air compressor
7714+
7715+
if (SteamLocomotiveFuelType == SteamLocomotiveFuelTypes.Oil)
7716+
{
7717+
// Display steam ejector information instead of air compressor with stoker
7718+
status.AppendFormat("{0}\t{1}\t{2}/{23}\t{3}\t{4}/{23}\t{5}\t{6}/{23}\t{7}\t{8}/{23}\t{9}\t{10}/{23}\t{11}\t{12}/{23}\t{13}\t{14}/{23}\t{15}\t{16}/{23}\t{17}\t{18}/{23}\t{19}\t{20}/{23}\t({21}x{22:N1}\")\n",
7719+
Simulator.Catalog.GetString("Usage:"),
7720+
Simulator.Catalog.GetString("Cyl"),
7721+
FormatStrings.FormatMass(pS.TopH(Kg.FromLb(CylinderSteamUsageLBpS)), IsMetric),
7722+
Simulator.Catalog.GetString("Blower"),
7723+
FormatStrings.FormatMass(pS.TopH(Kg.FromLb(BlowerSteamUsageLBpS)), IsMetric),
7724+
Simulator.Catalog.GetString("Ejector"),
7725+
FormatStrings.FormatMass(pS.TopH(Kg.FromLb(EjectorTotalSteamConsumptionLbpS)), IsMetric),
7726+
Simulator.Catalog.GetString("SafetyV"),
7727+
FormatStrings.FormatMass(pS.TopH(Kg.FromLb(SafetyValveUsageLBpS)), IsMetric),
7728+
Simulator.Catalog.GetString("CylCock"),
7729+
FormatStrings.FormatMass(pS.TopH(Kg.FromLb(CylCockSteamUsageDisplayLBpS)), IsMetric),
7730+
Simulator.Catalog.GetString("Genertr"),
7731+
FormatStrings.FormatMass(pS.TopH(Kg.FromLb(GeneratorSteamUsageLBpS)), IsMetric),
7732+
Simulator.Catalog.GetString("OilHeat"),
7733+
FormatStrings.FormatMass(pS.TopH(Kg.FromLb(FuelOilHeatingSteamUsageLbpS)), IsMetric),
7734+
Simulator.Catalog.GetString("BlowD"),
7735+
FormatStrings.FormatMass(pS.TopH(Kg.FromLb(BlowdownSteamUsageLBpS)), IsMetric),
7736+
Simulator.Catalog.GetString("Booster"),
7737+
FormatStrings.FormatMass(pS.TopH(Kg.FromLb(HuDBoosterSteamConsumptionLbpS)), IsMetric),
7738+
Simulator.Catalog.GetString("MaxSafe"),
7739+
FormatStrings.FormatMass(pS.TopH(Kg.FromLb(MaxSafetyValveDischargeLbspS)), IsMetric),
7740+
NumSafetyValves,
7741+
SafetyValveSizeIn,
7742+
FormatStrings.h);
7743+
7744+
}
7745+
else
7746+
{
7747+
7748+
// Display steam ejector information instead of air compressor with stoker
76367749
status.AppendFormat("{0}\t{1}\t{2}/{23}\t{3}\t{4}/{23}\t{5}\t{6}/{23}\t{7}\t{8}/{23}\t{9}\t{10}/{23}\t{11}\t{12}/{23}\t{13}\t{14}/{23}\t{15}\t{16}/{23}\t{17}\t{18}/{23}\t{19}\t{20}/{23}\t({21}x{22:N1}\")\n",
76377750
Simulator.Catalog.GetString("Usage:"),
76387751
Simulator.Catalog.GetString("Cyl"),
@@ -7659,6 +7772,7 @@ public override string GetDebugStatus()
76597772
SafetyValveSizeIn,
76607773
FormatStrings.h);
76617774
}
7775+
}
76627776

76637777

76647778
#if DEBUG_STEAM_CYLINDER_EVENTS

0 commit comments

Comments
 (0)