@@ -148,6 +148,10 @@ public class MSTSSteamLocomotive : MSTSLocomotive
148148 float BoosterMaxIdleChokeSizeIn = 0.625f;
149149 float CabSteamBoosterPressurePSI;
150150 float PrevCabSteamBoosterPressurePSI;
151+ float BoosterAxlePositionRad;
152+ float BoosterCylinderExhaustOpenFactor;
153+ float BoosterEngineSpeedRpM;
154+ bool BoosterAirisLow = false;
151155
152156 /// <summary>
153157 /// Grate limit of locomotive exceedeed?
@@ -2292,13 +2296,12 @@ public override void Update(float elapsedClockSeconds)
22922296 else if (SteamEngines[i].AuxiliarySteamEngineType == SteamEngine.AuxiliarySteamEngineTypes.Booster) // Booster Engine
22932297 {
22942298 // Air pressure must be greater then 70psi to ensure sufficient supply for the Booster engine
2295- bool BoosterAirisLow = false;
22962299 if (MainResPressurePSI < 70)
22972300 {
22982301 BoosterAirisLow = true;
22992302 }
23002303
2301- var boostercutoff = SteamEngines[i].BoosterCutoff;
2304+ BoosterCylinderExhaustOpenFactor = SteamEngines[i].BoosterCutoff;
23022305
23032306 // Confirm that Latch is on
23042307 if (SteamBoosterLatchOn && cutoff > SteamEngines[i].BoosterThrottleCutoff)
@@ -2332,7 +2335,7 @@ public override void Update(float elapsedClockSeconds)
23322335 BoosterGearEngageTimerS = 0;
23332336 BoosterCylinderSteamExhaustOn = true;
23342337 BoosterCylinderCocksOn = true;
2335- BoosterSteamFraction = 0.2f ;
2338+ BoosterSteamFraction = 0.5f ;
23362339 enginethrottle = 0.0f;
23372340
23382341 // Steam consumption based upon steam flow through choke
@@ -2350,7 +2353,6 @@ public override void Update(float elapsedClockSeconds)
23502353 BoosterGearEngageTimePeriodS = BoosterIdleHeatingTimePeriodS + BoosterGearSyncTimePeriodS - BoosterIdleHeatingTimerS;
23512354 }
23522355
2353- // Trace.TraceInformation("Idle Mode - Timer {0} GearPeriod {1} Reset {2} BoosterHeating {3} Sync {4}", BoosterIdleHeatingTimerS, BoosterGearEngageTimePeriodS, BoosterIdleHeatingTimerReset, BoosterIdleHeatingTimePeriodS, BoosterGearSyncTimePeriodS);
23542356 }
23552357 // Run mode - Gears not engaged
23562358 else if (SteamBoosterAirOpen && SteamBoosterIdle && !BoosterAirisLow && !BoosterGearsEngaged)
@@ -2365,14 +2367,11 @@ public override void Update(float elapsedClockSeconds)
23652367
23662368 // Steam consumption based upon steam flow through choke
23672369
2368- // Trace.TraceInformation("Run Mode - Timer {0} GearPeriod {1}", BoosterGearEngageTimeS, BoosterGearEngageTimePeriodS);
2369-
23702370 if (!BoosterGearsEngaged && BoosterGearEngageTimerS > BoosterGearEngageTimePeriodS && SteamBoosterLatchedLocked && cutoff > SteamEngines[i].BoosterThrottleCutoff) // Booster gears engaged
23712371 {
23722372 BoosterGearsEngaged = true;
23732373 BoosterIdleHeatingTimerReset = false;
23742374 BoosterIdleHeatingTimerS = 0;
2375- // Trace.TraceInformation("Run Mode - " );
23762375 }
23772376 BoosterGearEngageTimerS += elapsedClockSeconds;
23782377 }
@@ -2381,6 +2380,7 @@ public override void Update(float elapsedClockSeconds)
23812380 {
23822381 SteamBoosterIdleMode = false;
23832382 SteamBoosterRunMode = true;
2383+ BoosterEngineSpeedRpM = 0.0f;
23842384
23852385 if (SteamBoosterLatchedLocked && cutoff > SteamEngines[i].BoosterThrottleCutoff)
23862386 {
@@ -2394,9 +2394,7 @@ public override void Update(float elapsedClockSeconds)
23942394 {
23952395 BoosterGearsEngaged = false;
23962396 BoosterGearEngageTimerS = 0;
2397-
23982397 }
2399-
24002398 }
24012399 // Turn Booster off completely
24022400 else if (!SteamBoosterAirOpen || BoosterAirisLow)
@@ -2412,10 +2410,10 @@ public override void Update(float elapsedClockSeconds)
24122410 BoosterGearEngageTimerS = 0;
24132411 BoosterIdleHeatingTimerS = 0;
24142412 BoosterSteamFraction = 0.0f;
2415-
2413+ BoosterEngineSpeedRpM = 0.0f;
24162414 }
24172415
2418- UpdateCylinders(elapsedClockSeconds, enginethrottle, boostercutoff , absSpeedMpS, i);
2416+ UpdateCylinders(elapsedClockSeconds, enginethrottle, BoosterCylinderExhaustOpenFactor , absSpeedMpS, i);
24192417
24202418 // Update Booster steam consumption
24212419 if (SteamBoosterIdleMode)
@@ -2908,23 +2906,32 @@ private void UpdateFX(float elapsedClockSeconds)
29082906 }
29092907
29102908 // Booster steam exhaust
2911- if (BoosterCylinderSteamExhaustOn) // For Booster engine
2909+ if (BoosterCylinderSteamExhaustOn) // For Booster engine // ToDo - link to the number of cylinders defined in ENG file
29122910 {
2913-
2914- for (int i = 0; i < 1; i++)
2911+ for (int i = 0; i < 2; i++)
29152912 {
29162913 var crankAngleDiffRad = BoosterWheelCrankAngleDiffRad[i];
2917- float normalisedCrankAngleRad = NormalisedCrankAngle(i, crankAngleDiffRad);
2914+
2915+ float normalisedCrankAngleRad = 0;
2916+
2917+ if (BoosterGearsEngaged)
2918+ {
2919+ normalisedCrankAngleRad = NormalisedCrankAngle(i, crankAngleDiffRad);
2920+ }
2921+ else
2922+ {
2923+ normalisedCrankAngleRad = NormalisedBoosterIdleCrankAngle(i, crankAngleDiffRad, elapsedClockSeconds);
2924+ }
29182925
29192926 // Exhaust crank angle
29202927 float exhaustCrankAngleRad = 0;
29212928 if (normalisedCrankAngleRad <= MathHelper.Pi)
29222929 {
2923- exhaustCrankAngleRad = CylinderExhaustOpenFactor * (float)Math.PI;
2930+ exhaustCrankAngleRad = BoosterCylinderExhaustOpenFactor * (float)Math.PI;
29242931 }
29252932 else
29262933 {
2927- exhaustCrankAngleRad = CylinderExhaustOpenFactor * (float)Math.PI + (float)Math.PI;
2934+ exhaustCrankAngleRad = BoosterCylinderExhaustOpenFactor * (float)Math.PI + (float)Math.PI;
29282935 }
29292936
29302937 if (i == 0 && ((normalisedCrankAngleRad <= MathHelper.Pi && normalisedCrankAngleRad >= exhaustCrankAngleRad) || (normalisedCrankAngleRad < 2 * MathHelper.Pi && normalisedCrankAngleRad >= exhaustCrankAngleRad)))
@@ -2944,19 +2951,27 @@ private void UpdateFX(float elapsedClockSeconds)
29442951 {
29452952 BoosterCylinderSteamExhaust02On = false;
29462953 }
2947-
29482954 }
29492955 }
29502956
29512957 // Booster steam cylinder cock exhaust
29522958 if (BoosterCylinderCocksOn) // For Booster engine
29532959 {
29542960
2955- for (int i = 0; i < 1 ; i++)
2961+ for (int i = 0; i < 2 ; i++) // ToDo - link to the number of cylinders defined in ENG file
29562962 {
2957-
29582963 var crankAngleDiffRad = BoosterWheelCrankAngleDiffRad[i];
2959- float normalisedCrankAngleRad = NormalisedCrankAngle(i, crankAngleDiffRad);
2964+
2965+ float normalisedCrankAngleRad = 0;
2966+
2967+ if (BoosterGearsEngaged)
2968+ {
2969+ normalisedCrankAngleRad = NormalisedCrankAngle(i, crankAngleDiffRad);
2970+ }
2971+ else
2972+ {
2973+ normalisedCrankAngleRad = NormalisedBoosterIdleCrankAngle(i, crankAngleDiffRad, elapsedClockSeconds);
2974+ }
29602975
29612976 if (i == 0)
29622977 {
@@ -3148,8 +3163,6 @@ private void UpdateFX(float elapsedClockSeconds)
31483163 StackSteamVolumeM3pS = Kg.FromLb(CylinderSteamUsageLBpS + BlowerSteamUsageLBpS + RadiationSteamLossLBpS + CompSteamUsageLBpS + GeneratorSteamUsageLBpS) * smokeVolumeVariationFactor * SteamVaporSpecVolumeAt100DegC1BarM3pKG;
31493164 StackSteamVolumeM3pS = StackSteamVolumeM3pS / StackCount;
31503165 StackParticleDurationS = Throttlepercent + FireRatio;
3151- // Trace.TraceInformation("Puff - cutoff {0} Throttle {1} Velocity {2} Volume {3} Duration {4}", cutoff, throttle, StackSteamVelocityMpS.Value, StackSteamVolumeM3pS, StackParticleDurationS);
3152-
31533166 }
31543167 else // when not exhausting
31553168 {
@@ -3163,7 +3176,6 @@ private void UpdateFX(float elapsedClockSeconds)
31633176 StackSteamVolumeM3pS = Kg.FromLb(BlowerSteamUsageLBpS + RadiationSteamLossLBpS + CompSteamUsageLBpS + GeneratorSteamUsageLBpS) * smokeRestVolumeVariationFactor * SteamVaporSpecVolumeAt100DegC1BarM3pKG;
31643177 StackSteamVolumeM3pS = StackSteamVolumeM3pS / StackCount + FireRatio;
31653178 StackParticleDurationS = Throttlepercent + FireRatio;
3166- // Trace.TraceInformation("Rest - cutoff {0} Velocity {1} Volume {2} Duration {3} VelocityRate {4} Throttle% {5}", cutoff, StackSteamVelocityMpS.SmoothedValue, StackSteamVolumeM3pS, StackParticleDurationS, velocityRate, Throttlepercent);
31673179 }
31683180 }
31693181
@@ -3175,7 +3187,6 @@ private void UpdateFX(float elapsedClockSeconds)
31753187 StackSteamVolumeM3pS = Kg.FromLb(CylinderSteamUsageLBpS + BlowerSteamUsageLBpS + RadiationSteamLossLBpS + CompSteamUsageLBpS + GeneratorSteamUsageLBpS) * SteamVaporSpecVolumeAt100DegC1BarM3pKG;
31763188 StackSteamVolumeM3pS = StackSteamVolumeM3pS / StackCount + FireRatio;
31773189 StackParticleDurationS = Throttlepercent + FireRatio;
3178- // Trace.TraceInformation("Legacy - cutoff {0} Throttle {1} Velocity {2} Volume {3} Duration {4} VelocityRate {5}", cutoff, throttle, StackSteamVelocityMpS.SmoothedValue, StackSteamVolumeM3pS, StackParticleDurationS, velocityRate);
31793190 }
31803191
31813192
@@ -3198,7 +3209,14 @@ private void UpdateFX(float elapsedClockSeconds)
31983209 {
31993210 variable[i] = Math.Abs((float)SteamEngines[i].AttachedAxle.AxleSpeedMpS / SteamEngines[i].AttachedAxle.WheelRadiusM / MathHelper.Pi * 5);
32003211 }
3201- variable[i] = ThrottlePercent == 0 ? 0 : variable[i];
3212+
3213+ // overwrite Booster variable if in Idle or Run mode - gears not engaged
3214+ if (SteamEngines[i].AuxiliarySteamEngineType != SteamEngine.AuxiliarySteamEngineTypes.Booster && (SteamBoosterRunMode && !BoosterGearsEngaged) || SteamBoosterIdleMode)
3215+ {
3216+ variable[i] = BoosterEngineSpeedRpM;
3217+ }
3218+
3219+ variable[i] = ThrottlePercent == 0 ? 0 : variable[i];
32023220 }
32033221
32043222 // Set variables for each engine
@@ -3207,17 +3225,19 @@ private void UpdateFX(float elapsedClockSeconds)
32073225 Variable3_1 = variable[2];
32083226 Variable4_1 = variable[3];
32093227
3210- // Trace.TraceInformation("Variable1 {0} Variable2_1 {1} Variable3_1 {2} Variable4_1 {3}", Variable1, Variable2_1, Variable3_1, Variable4_1);
3211-
32123228 Variable2 = MathHelper.Clamp((CylinderCocksPressureAtmPSI - OneAtmospherePSI) / BoilerPressurePSI * 100f, 0, 100);
32133229
3214- if (SteamBoosterAirOpen && SteamBoosterRunMode && BoosterCylinderSteamExhaustOn && throttle > 0.0)
3230+ if (! SteamBoosterAirOpen || BoosterAirisLow) // Booster is off
32153231 {
3216- Variable2_Booster = SteamChestPressurePSI / MaxBoilerPressurePSI ;
3232+ Variable2_Booster = 0 ;
32173233 }
3218- else
3234+ else if ((SteamBoosterRunMode && !BoosterGearsEngaged) || SteamBoosterIdleMode) // Run mode - gears not engaged, and Idle mode
32193235 {
3220- Variable2_Booster = 0;
3236+ Variable2_Booster = CabSteamBoosterPressurePSI / MaxBoilerPressurePSI;
3237+ }
3238+ else if (SteamBoosterRunMode && BoosterGearsEngaged) // Run mode - gears engaged
3239+ {
3240+ Variable2_Booster = CabSteamChestPressurePSI / MaxBoilerPressurePSI;
32213241 }
32223242
32233243 Variable3 = FuelRateSmoothed * 100;
@@ -6101,10 +6121,49 @@ protected override void UpdateTractiveForce(float elapsedClockSeconds, float loc
61016121
61026122 }
61036123
6104- /// <summary>
6105- /// Normalise crank angle so that it is a value between 0 and 360 starting at the real crank angle difference
6106- /// </summary>
6107- private float NormalisedCrankAngle(int cylinderNumber, float crankAngleRad)
6124+
6125+ /// <summary>
6126+ /// Normalise booster engine crank angle so that it is a value between 0 and 360 starting at the real crank angle difference
6127+ /// </summary>
6128+ private float NormalisedBoosterIdleCrankAngle(int cylinderNumber, float crankAngleRad, float elapsedClockSeconds)
6129+ {
6130+ float MaxBoosterIdleRpm = 375;
6131+ float MaxBoosterIdlePressure = (BoosterIdleChokeSizeIn / BoosterMaxIdleChokeSizeIn) * MaxBoilerPressurePSI;
6132+ float TargetBoosterIdleRpm = (CabSteamBoosterPressurePSI / MaxBoosterIdlePressure) * MaxBoosterIdleRpm;
6133+
6134+ if (TargetBoosterIdleRpm > BoosterEngineSpeedRpM)
6135+ {
6136+ BoosterEngineSpeedRpM += 0.05f;
6137+ }
6138+
6139+ BoosterEngineSpeedRpM = MathHelper.Clamp(BoosterEngineSpeedRpM, 0, MaxBoosterIdleRpm);
6140+
6141+ float RevTimepS = 1 / (BoosterEngineSpeedRpM / 60); //
6142+
6143+ float RotationDiffRad = (float)(2 * Math.PI * (elapsedClockSeconds / RevTimepS)); //
6144+
6145+ BoosterAxlePositionRad += RotationDiffRad;
6146+
6147+ if (BoosterAxlePositionRad > (float)(2 * Math.PI))
6148+ {
6149+ BoosterAxlePositionRad -= (float)(2 * Math.PI);
6150+ }
6151+
6152+ float normalisedCrankAngleRad = (float)MathHelper.WrapAngle(BoosterAxlePositionRad + crankAngleRad);
6153+
6154+ if (normalisedCrankAngleRad < 0)
6155+ {
6156+ normalisedCrankAngleRad += (float)(2 * Math.PI);
6157+ }
6158+
6159+ return normalisedCrankAngleRad;
6160+ }
6161+
6162+
6163+ /// <summary>
6164+ /// Normalise crank angle so that it is a value between 0 and 360 starting at the real crank angle difference
6165+ /// </summary>
6166+ private float NormalisedCrankAngle(int cylinderNumber, float crankAngleRad)
61086167 {
61096168 float normalisedCrankAngleRad = (float)MathHelper.WrapAngle((float)LocomotiveAxles[0].AxlePositionRad + crankAngleRad);
61106169
@@ -7357,7 +7416,7 @@ public override string GetDebugStatus()
73577416 );
73587417
73597418 // Temporary debug script.
7360- status.AppendFormat("{0}\t{1}\t{2:N2}\t{3}\t{4:N2}\t{5}\t{6:N2}\t{7}\t{8}\n",
7419+ status.AppendFormat("{0}\t{1}\t{2:N2}\t{3}\t{4:N2}\t{5}\t{6:N2}\t{7}\t{8}\t{9}\t{10}\ n",
73617420 Simulator.Catalog.GetString("Boost:"),
73627421 Simulator.Catalog.GetString("GearT"),
73637422 BoosterGearEngageTimerS,
@@ -7366,7 +7425,9 @@ public override string GetDebugStatus()
73667425 Simulator.Catalog.GetString("IdleT"),
73677426 BoosterIdleHeatingTimerS,
73687427 Simulator.Catalog.GetString("IdleP"),
7369- BoosterIdleHeatingTimePeriodS
7428+ BoosterIdleHeatingTimePeriodS,
7429+ Simulator.Catalog.GetString("Speed"),
7430+ BoosterEngineSpeedRpM
73707431 );
73717432
73727433#if DEBUG_LOCO_STEAM_USAGE
0 commit comments