public override void Parse(string lowercasetoken, STFReader stf) { switch (lowercasetoken) { case "wagon(maxhandbrakeforce": MaxHandbrakeForceN = stf.ReadFloatBlock(STFReader.UNITS.Force, null); break; case "wagon(maxbrakeforce": MaxBrakeForceN = stf.ReadFloatBlock(STFReader.UNITS.Force, null); break; case "wagon(brakecylinderpressureformaxbrakebrakeforce": MaxCylPressurePSI = AutoCylPressurePSI = stf.ReadFloatBlock(STFReader.UNITS.PressureDefaultPSI, null); break; case "wagon(triplevalveratio": AuxCylVolumeRatio = stf.ReadFloatBlock(STFReader.UNITS.None, null); break; case "wagon(brakedistributorreleaserate": case "wagon(maxreleaserate": MaxReleaseRatePSIpS = ReleaseRatePSIpS = stf.ReadFloatBlock(STFReader.UNITS.PressureRateDefaultPSIpS, null); break; case "wagon(brakedistributorapplicationrate": case "wagon(maxapplicationrate": MaxApplicationRatePSIpS = stf.ReadFloatBlock(STFReader.UNITS.PressureRateDefaultPSIpS, null); break; case "wagon(maxauxilarychargingrate": MaxAuxilaryChargingRatePSIpS = stf.ReadFloatBlock(STFReader.UNITS.PressureRateDefaultPSIpS, null); break; case "wagon(emergencyreschargingrate": EmergResChargingRatePSIpS = stf.ReadFloatBlock(STFReader.UNITS.PressureRateDefaultPSIpS, null); break; case "wagon(emergencyresvolumemultiplier": EmergAuxVolumeRatio = stf.ReadFloatBlock(STFReader.UNITS.None, null); break; case "wagon(emergencyrescapacity": EmergResVolumeM3 = Me3.FromFt3(stf.ReadFloatBlock(STFReader.UNITS.VolumeDefaultFT3, null)); break; // OpenRails specific parameters case "wagon(brakepipevolume": BrakePipeVolumeM3 = Me3.FromFt3(stf.ReadFloatBlock(STFReader.UNITS.VolumeDefaultFT3, null)); break; } }
public override void Parse(string lowercasetoken, STFReader stf) { switch (lowercasetoken) { // OpenRails specific parameters case "wagon(brakepipevolume": BrakePipeVolumeM3 = Me3.FromFt3(stf.ReadFloatBlock(STFReader.UNITS.VolumeDefaultFT3, null)); break; } }
public static void InverseRelations() { Assert.Equal(1.2f, Me.FromMi(Me.ToMi(1.2f)), RequestedAccuracy); Assert.Equal(1.2f, Me.FromKiloM(Me.ToKiloM(1.2f)), RequestedAccuracy); Assert.Equal(1.2f, Me.FromYd(Me.ToYd(1.2f)), RequestedAccuracy); Assert.Equal(1.2f, Me.FromFt(Me.ToFt(1.2f)), RequestedAccuracy); Assert.Equal(1.2f, Me.FromIn(Me.ToIn(1.2f)), RequestedAccuracy); Assert.Equal(1.2f, Me2.FromFt2(Me2.ToFt2(1.2f)), RequestedAccuracy); Assert.Equal(1.2f, Me2.FromIn2(Me2.ToIn2(1.2f)), RequestedAccuracy); Assert.Equal(1.2f, Me3.FromFt3(Me3.ToFt3(1.2f)), RequestedAccuracy); Assert.Equal(1.2f, Me3.FromIn3(Me3.ToIn3(1.2f)), RequestedAccuracy); Assert.Equal(1.2f, MpS.FromMpH(MpS.ToMpH(1.2f)), RequestedAccuracy); Assert.Equal(1.2f, MpS.FromKpH(MpS.ToKpH(1.2f)), RequestedAccuracy); Assert.Equal(1.2f, Kg.FromLb(Kg.ToLb(1.2f)), RequestedAccuracy); Assert.Equal(1.2f, Kg.FromTUS(Kg.ToTUS(1.2f)), RequestedAccuracy); Assert.Equal(1.2f, Kg.FromTUK(Kg.ToTUK(1.2f)), RequestedAccuracy); Assert.Equal(1.2f, Kg.FromTonne(Kg.ToTonne(1.2f)), RequestedAccuracy); Assert.Equal(1.2f, N.FromLbf(N.ToLbf(1.2f)), RequestedAccuracy); Assert.Equal(1.2f, KgpS.FromLbpH(KgpS.ToLbpH(1.2f)), RequestedAccuracy); Assert.Equal(1.2f, W.FromKW(W.ToKW(1.2f)), RequestedAccuracy); Assert.Equal(1.2f, W.FromHp(W.ToHp(1.2f)), RequestedAccuracy); Assert.Equal(1.2f, W.FromBTUpS(W.ToBTUpS(1.2f)), RequestedAccuracy); Assert.Equal(1.2f, KPa.FromPSI(KPa.ToPSI(1.2f)), RequestedAccuracy); Assert.Equal(1.2f, KPa.FromInHg(KPa.ToInHg(1.2f)), RequestedAccuracy); Assert.Equal(1.2f, KPa.FromBar(KPa.ToBar(1.2f)), RequestedAccuracy); Assert.Equal(1.2f, KPa.FromKgfpCm2(KPa.ToKgfpCm2(1.2f)), RequestedAccuracy); Assert.Equal(1.2f, Bar.FromKPa(Bar.ToKPa(1.2f)), RequestedAccuracy); Assert.Equal(1.2f, Bar.FromPSI(Bar.ToPSI(1.2f)), RequestedAccuracy); Assert.Equal(1.2f, Bar.FromInHg(Bar.ToInHg(1.2f)), RequestedAccuracy); Assert.Equal(1.2f, Bar.FromKgfpCm2(Bar.ToKgfpCm2(1.2f)), RequestedAccuracy); Assert.Equal(1.2f, BarpS.FromPSIpS(BarpS.ToPSIpS(1.2f)), RequestedAccuracy); Assert.Equal(1.2f, KJpKg.FromBTUpLb(KJpKg.ToBTUpLb(1.2f)), RequestedAccuracy); Assert.Equal(1.2f, L.FromGUK(L.ToGUK(1.2f)), RequestedAccuracy); Assert.Equal(1.2f, L.FromGUS(L.ToGUS(1.2f)), RequestedAccuracy); Assert.Equal(1.2f, pS.FrompM(pS.TopM(1.2f)), RequestedAccuracy); Assert.Equal(1.2f, pS.FrompH(pS.TopH(1.2f)), RequestedAccuracy); Assert.Equal(1.2f, S.FromM(S.ToM(1.2f)), RequestedAccuracy); Assert.Equal(1.2f, S.FromH(S.ToH(1.2f)), RequestedAccuracy); Assert.Equal(1.2f, C.FromF(C.ToF(1.2f)), RequestedAccuracy); Assert.Equal(12f, C.FromK(C.ToK(12f)), RequestedAccuracy); // we loose accuracy because of the large 273.15 }
public override void Parse(string lowercasetoken, STFReader stf) { switch (lowercasetoken) { case "wagon(maxhandbrakeforce": MaxHandbrakeForceN = stf.ReadFloatBlock(STFReader.UNITS.Force, null); break; case "wagon(maxbrakeforce": MaxBrakeForceN = stf.ReadFloatBlock(STFReader.UNITS.Force, null); break; case "wagon(brakecylinderpressureformaxbrakebrakeforce": MaxForcePressurePSI = stf.ReadFloatBlock(STFReader.UNITS.PressureDefaultInHg, null); break; case "wagon(maxreleaserate": MaxReleaseRatePSIpS = stf.ReadFloatBlock(STFReader.UNITS.PressureRateDefaultInHgpS, null); break; // case "wagon(maxapplicationrate": ApplyChargingRatePSIpS = MaxApplicationRatePSIpS = stf.ReadFloatBlock(STFReader.UNITS.PressureRateDefaultInHgpS, null); break; // case "engine(pipetimefactor": PipeTimeFactorS = stf.ReadFloatBlock(STFReader.UNITS.Time, null); break; // case "engine(releasetimefactor": ReleaseTimeFactorS = stf.ReadFloatBlock(STFReader.UNITS.Time, null); break; // OpenRails specific parameters case "wagon(brakepipevolume": BrakePipeVolumeM3 = Me3.FromFt3(stf.ReadFloatBlock(STFReader.UNITS.VolumeDefaultFT3, null)); break; } }
public static void RelatedConversions() { Assert.Equal(1.44f, Me2.FromFt2((float)Math.Pow(Me.ToFt(1.2f), 2)), RequestedAccuracy); Assert.Equal(1.44f, Me2.ToFt2((float)Math.Pow(Me.FromFt(1.2f), 2)), RequestedAccuracy); Assert.Equal(1.44f, Me2.FromIn2((float)Math.Pow(Me.ToIn(1.2f), 2)), RequestedAccuracy); Assert.Equal(1.44f, Me2.ToIn2((float)Math.Pow(Me.FromIn(1.2f), 2)), RequestedAccuracy); Assert.Equal(1.728f, Me3.FromFt3((float)Math.Pow(Me.ToFt(1.2f), 3)), RequestedAccuracy); Assert.Equal(1.728f, Me3.ToFt3((float)Math.Pow(Me.FromFt(1.2f), 3)), RequestedAccuracy); Assert.Equal(1.728f, Me3.FromIn3((float)Math.Pow(Me.ToIn(1.2f), 3)), RequestedAccuracy); Assert.Equal(1.728f, Me3.ToIn3((float)Math.Pow(Me.FromIn(1.2f), 3)), RequestedAccuracy); Assert.Equal(1.2f, KPa.FromBar(Bar.FromKPa(1.2f)), RequestedAccuracy); Assert.Equal(1.2f, KPa.ToBar(Bar.ToKPa(1.2f)), RequestedAccuracy); Assert.Equal(1.2f, KPa.FromPSI(Bar.ToPSI(KPa.ToBar(1.2f))), RequestedAccuracy); Assert.Equal(1.2f, KPa.ToPSI(KPa.FromBar(Bar.FromPSI(1.2f))), RequestedAccuracy); Assert.Equal(1.2f, KPa.FromInHg(Bar.ToInHg(KPa.ToBar(1.2f))), RequestedAccuracy); Assert.Equal(1.2f, KPa.ToInHg(KPa.FromBar(Bar.FromInHg(1.2f))), RequestedAccuracy); Assert.Equal(1.2f, KPa.FromKgfpCm2(Bar.ToKgfpCm2(KPa.ToBar(1.2f))), RequestedAccuracy); Assert.Equal(1.2f, KPa.ToKgfpCm2(KPa.FromBar(Bar.FromKgfpCm2(1.2f))), RequestedAccuracy); }
// Principal Reference Materials for these two brake configurations - // Eames brake system - https://babel.hathitrust.org/cgi/pt?id=nnc1.cu50580116&view=1up&seq=7 // Hardy brake system - https://archive.org/details/hardysvacuumbre00belcgoog public override void Update(float elapsedClockSeconds) { // Two options are allowed for in this module - // i) Straight Brake operation - lead BP pressure, and brkae cylinder pressure are calculated in this module. BP pressure is reversed compared to vacuum brake, as vacuum // creation applies the brake cylinder. Some functions, such as brake pipe propagation are handled in the vacuum single pipe module, with some functions in the vacuum brake // module disabled if the lead locomotive is straight braked. // ii) Vacuum brake operation - some cars could operate as straight braked cars (ie non auto), or as auto depending upon what type of braking system the locomotive had. In // this case cars required an auxiliary reservoir. OR senses this and if a straight braked car is coupled to a auto (vacuum braked) locomotive, and it has an auxilary // reservoir fitted then it will use the vacuum single pipe module to manage brakes. In this case relevant straight brake functions are disabled in this module. var lead = (MSTSLocomotive)Car.Train.LeadLocomotive; if (lead != null) { // Adjust brake cylinder pressures as brake pipe varies // straight braked cars will have separate calculations done, if locomotive is not straight braked, then revert car to vacuum single pipe if (lead.CarBrakeSystemType == "straight_vacuum_single_pipe") { (Car as MSTSWagon).NonAutoBrakePresent = true; // Set flag to indicate that non auto brake is set in train bool skiploop = false; // In hardy brake system, BC on tender and locomotive is not changed in the StrBrkApply brake position if ((Car.WagonType == MSTSWagon.WagonTypes.Engine || Car.WagonType == MSTSWagon.WagonTypes.Tender) && (lead.TrainBrakeController.TrainBrakeControllerState == ControllerState.StrBrkApply || lead.TrainBrakeController.TrainBrakeControllerState == ControllerState.StrBrkLap)) { skiploop = true; } else { skiploop = false; } if (!skiploop) { if (BrakeLine1PressurePSI < CylPressurePSIA && lead.BrakeFlagIncrease) // Increase BP pressure, hence vacuum brakes are being released { float dp = elapsedClockSeconds * MaxReleaseRatePSIpS; var vr = NumBrakeCylinders * BrakeCylVolM3 / BrakePipeVolumeM3; if (CylPressurePSIA - dp < BrakeLine1PressurePSI + dp * vr) { dp = (CylPressurePSIA - BrakeLine1PressurePSI) / (1 + vr); } CylPressurePSIA -= dp; } else if (BrakeLine1PressurePSI > CylPressurePSIA && lead.BrakeFlagDecrease) // Decrease BP pressure, hence vacuum brakes are being applied { float dp = elapsedClockSeconds * MaxApplicationRatePSIpS; var vr = NumBrakeCylinders * BrakeCylVolM3 / BrakePipeVolumeM3; if (CylPressurePSIA + dp > BrakeLine1PressurePSI - dp * vr) { dp = (BrakeLine1PressurePSI - CylPressurePSIA) / (1 + vr); } CylPressurePSIA += dp; } } // Record HUD display values for brake cylidners depending upon whether they are wagons or locomotives/tenders (which are subject to their own engine brakes) if (Car.WagonType == MSTSWagon.WagonTypes.Engine || Car.WagonType == MSTSWagon.WagonTypes.Tender) { Car.Train.HUDLocomotiveBrakeCylinderPSI = CylPressurePSIA; Car.Train.HUDWagonBrakeCylinderPSI = Car.Train.HUDLocomotiveBrakeCylinderPSI; // Initially set Wagon value same as locomotive, will be overwritten if a wagon is attached } else { // Record the Brake Cylinder pressure in first wagon, as EOT is also captured elsewhere, and this will provide the two extremeties of the train // Identifies the first wagon based upon the previously identified UiD if (Car.UiD == Car.Train.FirstCarUiD) { Car.Train.HUDWagonBrakeCylinderPSI = CylPressurePSIA; // In Vacuum HUD BP is actually supposed to be dispalayed } } // Adjust braking force as brake cylinder pressure varies. float f; if (!Car.BrakesStuck) { float brakecylinderfraction = ((OneAtmospherePSI - CylPressurePSIA) / MaxForcePressurePSI); brakecylinderfraction = MathHelper.Clamp(brakecylinderfraction, 0, 1); f = Car.MaxBrakeForceN * brakecylinderfraction; if (f < Car.MaxHandbrakeForceN * HandbrakePercent / 100) { f = Car.MaxHandbrakeForceN * HandbrakePercent / 100; } } else { f = Math.Max(Car.MaxBrakeForceN, Car.MaxHandbrakeForceN / 2); } Car.BrakeRetardForceN = f * Car.BrakeShoeRetardCoefficientFrictionAdjFactor; // calculates value of force applied to wheel, independent of wheel skid if (Car.BrakeSkid) // Test to see if wheels are skiding due to excessive brake force { Car.BrakeForceN = f * Car.SkidFriction; // if excessive brakeforce, wheel skids, and loses adhesion } else { Car.BrakeForceN = f * Car.BrakeShoeCoefficientFrictionAdjFactor; // In advanced adhesion model brake shoe coefficient varies with speed, in simple odel constant force applied as per value in WAG file, will vary with wheel skid. } // If wagons are not attached to the locomotive, then set wagon BC pressure to same as locomotive in the Train brake line if (!Car.Train.WagonsAttached && (Car.WagonType == MSTSWagon.WagonTypes.Engine || Car.WagonType == MSTSWagon.WagonTypes.Tender)) { Car.Train.HUDWagonBrakeCylinderPSI = CylPressurePSIA; } // sound trigger checking runs every 4th update, to avoid the problems caused by the jumping BrakeLine1PressurePSI value, and also saves cpu time :) if (SoundTriggerCounter >= 4) { SoundTriggerCounter = 0; if (Math.Abs(CylPressurePSIA - prevCylPressurePSIA) > 0.001) { if (!TrainBrakePressureChanging) { if (CylPressurePSIA < prevCylPressurePSIA && lead.BrakeFlagIncrease && CylPressurePSIA > IncreaseSoundTriggerBandwidth) // Brake cylinder vacuum increases as pressure in pipe decreases { Car.SignalEvent(Event.TrainBrakePressureIncrease); TrainBrakePressureChanging = true; } else if (CylPressurePSIA > prevCylPressurePSIA && lead.BrakeFlagDecrease && CylPressurePSIA < DecreaseSoundTriggerBandwidth) // Brake cylinder vacuum decreases as pressure in pipe increases { Car.SignalEvent(Event.TrainBrakePressureDecrease); TrainBrakePressureChanging = true; } } } else if (TrainBrakePressureChanging) { Car.SignalEvent(Event.TrainBrakePressureStoppedChanging); TrainBrakePressureChanging = false; } prevCylPressurePSIA = CylPressurePSIA; if (Math.Abs(BrakeLine1PressurePSI - prevBrakePipePressurePSI) > 0.001) { if (!BrakePipePressureChanging) { if (BrakeLine1PressurePSI < prevBrakePipePressurePSI && lead.BrakeFlagIncrease && BrakeLine1PressurePSI > IncreaseSoundTriggerBandwidth) // Brakepipe vacuum increases as pressure in pipe decreases { Car.SignalEvent(Event.BrakePipePressureIncrease); BrakePipePressureChanging = true; } else if (BrakeLine1PressurePSI > prevBrakePipePressurePSI && lead.BrakeFlagDecrease && BrakeLine1PressurePSI < DecreaseSoundTriggerBandwidth) // Brakepipe vacuum decreases as pressure in pipe increases { Car.SignalEvent(Event.BrakePipePressureDecrease); BrakePipePressureChanging = true; } } } else if (BrakePipePressureChanging) { Car.SignalEvent(Event.BrakePipePressureStoppedChanging); BrakePipePressureChanging = false; } prevBrakePipePressurePSI = BrakeLine1PressurePSI; } SoundTriggerCounter++; // Straight brake is opposite of automatic brake, ie vacuum pipe goes from 14.503psi (0 InHg - Release) to 2.24 (25InHg - Apply) // Calculate train pipe pressure at lead locomotive. // Vaccum brake effectiveness decreases with increases in altitude because the atmospheric pressure increases as altitude increases. // The formula for decrease in pressure: P = P0 * Exp (- Mgh/RT) - https://www.math24.net/barometric-formula/ float massearthair = 0.02896f; // Molar mass of Earth's air = M = 0.02896 kg/mol // float sealevelpressure = 101325f; // Average sea level pressure = P0 = 101,325 kPa float sealevelpressure = 101325f; // Average sea level pressure = P0 = 101,325 kPa float gravitationalacceleration = 9.807f; // Gravitational acceleration = g = 9.807 m/s^2 float standardtemperature = 288.15f; // Standard temperature = T = 288.15 K float universalgasconstant = 8.3143f; // Universal gas constant = R = 8.3143 (N*m/mol*K) float alititudereducedvacuum = sealevelpressure * (float)Math.Exp((-1.0f * massearthair * gravitationalacceleration * Car.CarHeightAboveSeaLevelM) / (standardtemperature * universalgasconstant)); float vacuumreductionfactor = alititudereducedvacuum / sealevelpressure; float MaxVacuumPipeLevelPSI = lead.TrainBrakeController.MaxPressurePSI * vacuumreductionfactor; // To stop sound triggers "bouncing" near end of increase/decrease operation a small dead (bandwith) zone is introduced where triggers will not change state DecreaseSoundTriggerBandwidth = OneAtmospherePSI - 0.2f; IncreaseSoundTriggerBandwidth = (OneAtmospherePSI - MaxVacuumPipeLevelPSI) + 0.2f; // Set value for large ejector to operate - it will depend upon whether the locomotive is a single or twin ejector unit. float LargeEjectorChargingRateInHgpS; if (lead.TrainBrakeController.TrainBrakeControllerState == ControllerState.StrBrkApply) { LargeEjectorChargingRateInHgpS = lead == null ? 10.0f : (lead.LargeEjectorBrakePipeChargingRatePSIorInHgpS); } else { LargeEjectorChargingRateInHgpS = lead == null ? 10.0f : (lead.BrakePipeChargingRatePSIorInHgpS); // Single ejector model } float SmallEjectorChargingRateInHgpS = lead == null ? 10.0f : (lead.SmallEjectorBrakePipeChargingRatePSIorInHgpS); // Set value for small ejector to operate - fraction set in steam locomotive float TrainPipeLeakLossPSI = lead == null ? 0.0f : (lead.TrainBrakePipeLeakPSIorInHgpS); float AdjTrainPipeLeakLossPSI = 0.0f; // Calculate adjustment times for varying lengths of trains float AdjLargeEjectorChargingRateInHgpS = 0.0f; float AdjSmallEjectorChargingRateInHgpS = 0.0f; AdjLargeEjectorChargingRateInHgpS = (Me3.FromFt3(200.0f) / Car.Train.TotalTrainBrakeSystemVolumeM3) * LargeEjectorChargingRateInHgpS; AdjSmallEjectorChargingRateInHgpS = (Me3.FromFt3(200.0f) / Car.Train.TotalTrainBrakeSystemVolumeM3) * SmallEjectorChargingRateInHgpS; float AdjBrakeServiceTimeFactorS = (Me3.FromFt3(200.0f) / Car.Train.TotalTrainBrakeSystemVolumeM3) * lead.BrakeServiceTimeFactorS; AdjTrainPipeLeakLossPSI = (Car.Train.TotalTrainBrakeSystemVolumeM3 / Me3.FromFt3(200.0f)) * lead.TrainBrakePipeLeakPSIorInHgpS; // Only adjust lead pressure when locomotive car is processed, otherwise lead pressure will be "over adjusted" if (Car == lead) { // Hardy brake system if (lead.TrainBrakeController.TrainBrakeControllerState == ControllerState.StrBrkApply || lead.TrainBrakeController.TrainBrakeControllerState == ControllerState.StrBrkApplyAll) { lead.BrakeFlagIncrease = true; lead.BrakeFlagDecrease = false; // Apply brakes - brakepipe has to have vacuum increased to max vacuum value (ie decrease psi), vacuum is created by large ejector control lead.BrakeSystem.BrakeLine1PressurePSI -= elapsedClockSeconds * AdjLargeEjectorChargingRateInHgpS; if (lead.BrakeSystem.BrakeLine1PressurePSI < (OneAtmospherePSI - MaxVacuumPipeLevelPSI)) { lead.BrakeSystem.BrakeLine1PressurePSI = OneAtmospherePSI - MaxVacuumPipeLevelPSI; } // turn ejector on as required lead.LargeSteamEjectorIsOn = true; lead.LargeEjectorSoundOn = true; // turn small ejector off lead.SmallSteamEjectorIsOn = false; lead.SmallEjectorSoundOn = false; } if (lead.TrainBrakeController.TrainBrakeControllerState == ControllerState.StrBrkEmergency) { lead.BrakeFlagIncrease = true; lead.BrakeFlagDecrease = false; // Apply brakes - brakepipe has to have vacuum increased to max vacuum value (ie decrease psi), vacuum is created by large ejector control lead.BrakeSystem.BrakeLine1PressurePSI -= elapsedClockSeconds * (AdjLargeEjectorChargingRateInHgpS + AdjSmallEjectorChargingRateInHgpS); if (lead.BrakeSystem.BrakeLine1PressurePSI < (OneAtmospherePSI - MaxVacuumPipeLevelPSI)) { lead.BrakeSystem.BrakeLine1PressurePSI = OneAtmospherePSI - MaxVacuumPipeLevelPSI; } // turn ejectors on as required lead.LargeSteamEjectorIsOn = true; lead.LargeEjectorSoundOn = true; lead.SmallSteamEjectorIsOn = true; lead.SmallEjectorSoundOn = true; } if (lead.TrainBrakeController.TrainBrakeControllerState == ControllerState.StrBrkLap) { // turn ejectors off if not required lead.LargeSteamEjectorIsOn = false; lead.LargeEjectorSoundOn = false; lead.SmallSteamEjectorIsOn = false; lead.SmallEjectorSoundOn = false; } // Eames type brake with separate release and ejector operating handles if (lead.LargeEjectorControllerFitted && lead.LargeSteamEjectorIsOn) { // Apply brakes - brakepipe has to have vacuum increased to max vacuum value (ie decrease psi), vacuum is created by large ejector control lead.BrakeSystem.BrakeLine1PressurePSI -= elapsedClockSeconds * AdjLargeEjectorChargingRateInHgpS; if (lead.BrakeSystem.BrakeLine1PressurePSI < (OneAtmospherePSI - MaxVacuumPipeLevelPSI)) { lead.BrakeSystem.BrakeLine1PressurePSI = OneAtmospherePSI - MaxVacuumPipeLevelPSI; } lead.BrakeFlagIncrease = true; } // Release brakes - brakepipe has to have brake pipe decreased back to atmospheric pressure to apply brakes (ie psi increases). if (lead.TrainBrakeController.TrainBrakeControllerState == ControllerState.StrBrkReleaseOn || lead.TrainBrakeController.TrainBrakeControllerState == ControllerState.StrBrkRelease) { lead.BrakeFlagIncrease = false; lead.BrakeFlagDecrease = true; lead.BrakeSystem.BrakeLine1PressurePSI += elapsedClockSeconds / AdjBrakeServiceTimeFactorS; if (lead.BrakeSystem.BrakeLine1PressurePSI > OneAtmospherePSI) { lead.BrakeSystem.BrakeLine1PressurePSI = OneAtmospherePSI; } } // leaks in train pipe will reduce vacuum (increase pressure) lead.BrakeSystem.BrakeLine1PressurePSI += elapsedClockSeconds * AdjTrainPipeLeakLossPSI; // Keep brake line within relevant limits - ie between 21 or 25 InHg and Atmospheric pressure. lead.BrakeSystem.BrakeLine1PressurePSI = MathHelper.Clamp(lead.BrakeSystem.BrakeLine1PressurePSI, OneAtmospherePSI - MaxVacuumPipeLevelPSI, OneAtmospherePSI); } } if (((lead.CarBrakeSystemType == "vacuum_single_pipe" || lead.CarBrakeSystemType == "vacuum_twin_pipe") && (Car as MSTSWagon).AuxiliaryReservoirPresent)) { // update non calculated values using vacuum single pipe class base.Update(elapsedClockSeconds); } } }