Esempio n. 1
0
        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;
            }
        }
Esempio n. 2
0
 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;
     }
 }
Esempio n. 3
0
        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
        }
Esempio n. 4
0
        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;
            }
        }
Esempio n. 5
0
        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);
        }
Esempio n. 6
0
        // 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);
                }
            }
        }