public float GetNotchFraction() { if (Notches.Count == 0) { return(0); } INotchController notch = Notches[CurrentNotch]; if (!notch.Smooth) { // Respect British 3-wire EP brake configurations return((notch.NotchStateType == ControllerState.EPApply || notch.NotchStateType == ControllerState.EPOnly)? CurrentValue : 1); } float x = 1; if (CurrentNotch + 1 < Notches.Count) { x = Notches[CurrentNotch + 1].Value; } x = (CurrentValue - notch.Value) / (x - notch.Value); if (notch.NotchStateType == ControllerState.Release) { x = 1 - x; } return(x); }
public virtual string GetStatus() { if (Notches.Count == 0) { return(string.Format("{0:F0}%", 100 * CurrentValue)); } INotchController notch = Notches[CurrentNotch]; //TODO translation via (static?) Catalog //also if NotchStateType == ControllerState.Running, need to use GetParticularString using ControllerState enum description attribute for context string name = EnumExtension.GetDescription(notch.NotchStateType); if (!notch.Smooth && notch.NotchStateType == ControllerState.Dummy) { return(string.Format("{0:F0}%", 100 * CurrentValue)); } if (!notch.Smooth) { return(name); } if (!string.IsNullOrEmpty(name)) { return(string.Format("{0} {1:F0}%", name, 100 * GetNotchFraction())); } return(string.Format("{0:F0}%", 100 * GetNotchFraction())); }
public float SetPercent(float percent) { float v = (MinimumValue < 0 && percent < 0 ? -MinimumValue : MaximumValue) * percent / 100; CurrentValue = MathHelper.Clamp(v, MinimumValue, MaximumValue); if (CurrentNotch >= 0) { if (Notches[Notches.Count - 1].NotchStateType == ControllerState.Emergency) { v = Notches[Notches.Count - 1].Value * percent / 100; } for (; ;) { INotchController notch = Notches[CurrentNotch]; if (CurrentNotch > 0 && v < notch.Value) { INotchController prev = Notches[CurrentNotch - 1]; if (!notch.Smooth && !prev.Smooth && v - prev.Value > .45 * (notch.Value - prev.Value)) { break; } CurrentNotch--; continue; } if (CurrentNotch < Notches.Count - 1) { INotchController next = Notches[CurrentNotch + 1]; if (next.NotchStateType != ControllerState.Emergency) { if ((notch.Smooth || next.Smooth) && v < next.Value) { break; } if (!notch.Smooth && !next.Smooth && v - notch.Value < .55 * (next.Value - notch.Value)) { break; } CurrentNotch++; continue; } } break; } if (Notches[CurrentNotch].Smooth) { CurrentValue = v; } else { CurrentValue = Notches[CurrentNotch].Value; } } IntermediateValue = CurrentValue; return(100 * CurrentValue); }
public override float?GetStateFraction() { if (EmergencyBrakingPushButton() || TCSEmergencyBraking() || TCSFullServiceBraking() || QuickReleaseButtonPressed() || OverchargeButtonPressed()) { return(null); } else if (NotchController != null) { if (NotchController.NotchCount() == 0) { return(NotchController.CurrentValue); } else { INotchController notch = NotchController.GetCurrentNotch(); if (!notch.Smooth) { if (notch.NotchStateType == ControllerState.Dummy) { return(NotchController.CurrentValue); } else { return(null); } } else { return(NotchController.GetNotchFraction()); } } } else { return(null); } }
public virtual string GetStatus() { if (Notches.Count == 0) { return($"{100 * CurrentValue:F0}%"); } INotchController notch = Notches[CurrentNotch]; string name = notch.NotchStateType.GetLocalizedDescription(); if (!notch.Smooth && notch.NotchStateType == ControllerState.Dummy) { return($"{100 * CurrentValue:F0}%"); } if (!notch.Smooth) { return(name); } if (!string.IsNullOrEmpty(name)) { return($"{name} {100 * GetNotchFraction():F0}%"); } return($"{100 * GetNotchFraction():F0}%"); }
public MSTSNotch(INotchController other) { Value = other.Value; Smooth = other.Smooth; NotchStateType = other.NotchStateType; }
// Train Brake Controllers public override Tuple <double, double> UpdatePressure(double pressureBar, double epPressureBar, double elapsedClockSeconds) { double epState = -1.0; if (EmergencyBrakingPushButton() || TCSEmergencyBraking()) { pressureBar -= EmergencyRateBarpS() * elapsedClockSeconds; } else if (TCSFullServiceBraking()) { if (pressureBar > MaxPressureBar() - FullServReductionBar()) { pressureBar -= ApplyRateBarpS() * elapsedClockSeconds; } else if (pressureBar < MaxPressureBar() - FullServReductionBar()) { pressureBar = MaxPressureBar() - FullServReductionBar(); } } else { INotchController notch = NotchController.GetCurrentNotch(); if (!brakeControllerInitialised) // The first time around loop, PreviousNotchPosition will be set up front with current value, this will stop crashes due to vsalue not being initialised. { previousNotchPosition = NotchController.GetCurrentNotch(); brakeControllerInitialised = true; } if (notch == null) { pressureBar = MaxPressureBar() - FullServReductionBar() * CurrentValue(); } else { epState = 0; double x = NotchController.GetNotchFraction(); ControllerState notchType = notch.NotchStateType; if (OverchargeButtonPressed()) { notchType = ControllerState.Overcharge; } else if (QuickReleaseButtonPressed()) { switch (notchType) { case ControllerState.Hold: case ControllerState.Lap: case ControllerState.MinimalReduction: if (EnforceMinimalReduction) { pressureBar = DecreasePressure(pressureBar, MaxPressureBar() - MinReductionBar(), ApplyRateBarpS(), elapsedClockSeconds); } break; default: EnforceMinimalReduction = false; break; } } switch (notchType) { case ControllerState.Release: pressureBar = IncreasePressure(pressureBar, MaxPressureBar(), ReleaseRateBarpS(), elapsedClockSeconds); pressureBar = DecreasePressure(pressureBar, MaxPressureBar(), OverchargeEliminationRateBarpS(), elapsedClockSeconds); epState = -1; break; case ControllerState.FullQuickRelease: case ControllerState.SMEReleaseStart: pressureBar = IncreasePressure(pressureBar, MaxPressureBar(), QuickReleaseRateBarpS(), elapsedClockSeconds); pressureBar = DecreasePressure(pressureBar, MaxPressureBar(), OverchargeEliminationRateBarpS(), elapsedClockSeconds); epState = -1; break; case ControllerState.Overcharge: pressureBar = IncreasePressure(pressureBar, Math.Min(MaxOverchargePressureBar(), MainReservoirPressureBar()), QuickReleaseRateBarpS(), elapsedClockSeconds); epState = -1; break; case ControllerState.SlowService: if (pressureBar > MaxPressureBar() - MinReductionBar()) { pressureBar = MaxPressureBar() - MinReductionBar(); } pressureBar = DecreasePressure(pressureBar, MaxPressureBar() - FullServReductionBar(), SlowApplicationRateBarpS(), elapsedClockSeconds); break; case ControllerState.StraightLap: case ControllerState.StraightApply: case ControllerState.StraightApplyAll: case ControllerState.StraightEmergency: // Nothing is done in these positions, instead they are controlled by the steam ejector in straight brake module break; case ControllerState.StraightRelease: case ControllerState.StraightReleaseOn: // This position is an on position so pressure will be zero (reversed due to vacuum brake operation) pressureBar = 0; break; case ControllerState.StraightReleaseOff: //(reversed due to vacuum brake operation) case ControllerState.Apply: pressureBar -= x * ApplyRateBarpS() * elapsedClockSeconds; break; case ControllerState.FullServ: epState = x; EnforceMinimalReduction = true; if (pressureBar > MaxPressureBar() - MinReductionBar()) { pressureBar = MaxPressureBar() - MinReductionBar(); } pressureBar = DecreasePressure(pressureBar, MaxPressureBar() - FullServReductionBar(), ApplyRateBarpS(), elapsedClockSeconds); break; case ControllerState.Lap: // Lap position applies min service reduction when first selected, and previous contoller position was Running, then no change in pressure occurs if (previousNotchPosition.NotchStateType == ControllerState.Running) { EnforceMinimalReduction = true; epState = -1; } break; case ControllerState.MinimalReduction: // Lap position applies min service reduction when first selected, and previous contoller position was Running or Release, then no change in pressure occurs if (previousNotchPosition.NotchStateType == ControllerState.Running || previousNotchPosition.NotchStateType == ControllerState.Release || previousNotchPosition.NotchStateType == ControllerState.FullQuickRelease) { EnforceMinimalReduction = true; epState = -1; } break; case ControllerState.ManualBraking: case ControllerState.VacContServ: // Continuous service positions for vacuum brakes - allows brake to be adjusted up and down continuously between the ON and OFF position pressureBar = (1 - x) * MaxPressureBar(); epState = -1; break; case ControllerState.EPApply: case ControllerState.EPOnly: case ControllerState.SMEOnly: case ControllerState.ContServ: case ControllerState.EPFullServ: case ControllerState.SMEFullServ: epState = x; if (notch.NotchStateType == ControllerState.EPApply || notch.NotchStateType == ControllerState.ContServ) { EnforceMinimalReduction = true; x = MaxPressureBar() - MinReductionBar() * (1 - x) - FullServReductionBar() * x; if (pressureBar > MaxPressureBar() - MinReductionBar()) { pressureBar = MaxPressureBar() - MinReductionBar(); } pressureBar = DecreasePressure(pressureBar, x, ApplyRateBarpS(), elapsedClockSeconds); if (ForceControllerReleaseGraduated || notch.NotchStateType == ControllerState.EPApply) { pressureBar = IncreasePressure(pressureBar, x, ReleaseRateBarpS(), elapsedClockSeconds); } } break; case ControllerState.GSelfLapH: case ControllerState.Suppression: case ControllerState.GSelfLap: EnforceMinimalReduction = true; x = MaxPressureBar() - MinReductionBar() * (1 - x) - FullServReductionBar() * x; pressureBar = DecreasePressure(pressureBar, x, ApplyRateBarpS(), elapsedClockSeconds); if (ForceControllerReleaseGraduated || notch.NotchStateType == ControllerState.GSelfLap) { pressureBar = IncreasePressure(pressureBar, x, ReleaseRateBarpS(), elapsedClockSeconds); } break; case ControllerState.Emergency: pressureBar -= EmergencyRateBarpS() * elapsedClockSeconds; epState = 1; break; case ControllerState.Dummy: x = MaxPressureBar() - FullServReductionBar() * (notch.Smooth ? x : CurrentValue()); pressureBar = IncreasePressure(pressureBar, x, ReleaseRateBarpS(), elapsedClockSeconds); pressureBar = DecreasePressure(pressureBar, x, ApplyRateBarpS(), elapsedClockSeconds); epState = -1; break; } previousNotchPosition = NotchController.GetCurrentNotch(); } } if (pressureBar < 0) { pressureBar = 0; } return(new Tuple <double, double>(pressureBar, epState)); }
// Engine Brake Controllers public override double UpdateEngineBrakePressure(double pressureBar, double elapsedClockSeconds) { INotchController notch = NotchController.GetCurrentNotch(); if (notch == null) { pressureBar = (MaxPressureBar() - FullServReductionBar()) * CurrentValue(); } else { double x = NotchController.GetNotchFraction(); switch (notch.NotchStateType) { case ControllerState.Neutral: case ControllerState.Running: case ControllerState.Lap: break; case ControllerState.FullQuickRelease: pressureBar -= x * QuickReleaseRateBarpS() * elapsedClockSeconds; break; case ControllerState.Release: pressureBar -= x * ReleaseRateBarpS() * elapsedClockSeconds; break; case ControllerState.Apply: case ControllerState.FullServ: pressureBar = IncreasePressure(pressureBar, x * (MaxPressureBar() - FullServReductionBar()), ApplyRateBarpS(), elapsedClockSeconds); break; case ControllerState.ManualBraking: case ControllerState.VacContServ: // Continuous service positions for vacuum brakes - allows brake to be adjusted up and down continuously between the ON and OFF position pressureBar = (1 - x) * MaxPressureBar(); break; case ControllerState.BrakeNotch: // Notch position for brakes - allows brake to be adjusted up and down continuously between specified notches pressureBar = (1 - x) * MaxPressureBar(); break; case ControllerState.Emergency: pressureBar += EmergencyRateBarpS() * elapsedClockSeconds; break; case ControllerState.Dummy: pressureBar = (MaxPressureBar() - FullServReductionBar()) * CurrentValue(); break; default: x *= MaxPressureBar() - FullServReductionBar(); pressureBar = IncreasePressure(pressureBar, x, ApplyRateBarpS(), elapsedClockSeconds); pressureBar = DecreasePressure(pressureBar, x, ReleaseRateBarpS(), elapsedClockSeconds); break; } if (pressureBar > MaxPressureBar()) { pressureBar = MaxPressureBar(); } if (pressureBar < 0) { pressureBar = 0; } } return(pressureBar); }
// Train Brake Controllers public override Tuple <double, double> UpdatePressure(double pressureBar, double epPressureBar, double elapsedClockSeconds) { double epState = -1.0; if (EmergencyBrakingPushButton() || TCSEmergencyBraking()) { pressureBar -= EmergencyRateBarpS() * elapsedClockSeconds; } else if (TCSFullServiceBraking()) { if (pressureBar > MaxPressureBar() - FullServReductionBar()) { pressureBar -= ApplyRateBarpS() * elapsedClockSeconds; } else if (pressureBar < MaxPressureBar() - FullServReductionBar()) { pressureBar = MaxPressureBar() - FullServReductionBar(); } } else { INotchController notch = NotchController.GetCurrentNotch(); if (!BrakeControllerInitialised) // The first time around loop, PreviousNotchPosition will be set up front with current value, this will stop crashes due to vsalue not being initialised. { PreviousNotchPosition = NotchController.GetCurrentNotch(); BrakeControllerInitialised = true; } if (notch == null) { pressureBar = MaxPressureBar() - FullServReductionBar() * CurrentValue(); } else { epState = 0; double x = NotchController.GetNotchFraction(); switch (notch.NotchStateType) { case ControllerState.Release: pressureBar += x * ReleaseRateBarpS() * elapsedClockSeconds; epState = -1; break; case ControllerState.FullQuickRelease: pressureBar += x * QuickReleaseRateBarpS() * elapsedClockSeconds; epState = -1; break; case ControllerState.Apply: case ControllerState.FullServ: if (notch.NotchStateType == ControllerState.FullServ) { epState = x; } pressureBar -= x * ApplyRateBarpS() * elapsedClockSeconds; break; case ControllerState.Lap: // Lap position applies min service reduction when first selected, and previous contoller position was Running, then no change in pressure occurs if (PreviousNotchPosition.NotchStateType == ControllerState.Running) { pressureBar -= MinReductionBar(); epState = -1; } break; case ControllerState.MinimalReduction: // Lap position applies min service reduction when first selected, and previous contoller position was Running or Release, then no change in pressure occurs if (PreviousNotchPosition.NotchStateType == ControllerState.Running || PreviousNotchPosition.NotchStateType == ControllerState.Release || PreviousNotchPosition.NotchStateType == ControllerState.FullQuickRelease) { pressureBar -= MinReductionBar(); epState = -1; } break; case ControllerState.VacContServ: // Continuous service positions for vacuum brakes - allows brake to be adjusted up and down continuously between the ON and OFF position pressureBar = (1 - x) * MaxPressureBar(); epState = -1; break; case ControllerState.EPApply: case ControllerState.GSelfLapH: case ControllerState.Suppression: case ControllerState.ContServ: case ControllerState.GSelfLap: if (notch.NotchStateType == ControllerState.EPApply || notch.NotchStateType == ControllerState.ContServ) { epState = x; } x = MaxPressureBar() - MinReductionBar() * (1 - x) - FullServReductionBar() * x; pressureBar = DecreasePressure(pressureBar, x, ApplyRateBarpS(), elapsedClockSeconds); if (ForceControllerReleaseGraduated) { pressureBar = IncreasePressure(pressureBar, x, ReleaseRateBarpS(), elapsedClockSeconds); } break; case ControllerState.Emergency: pressureBar -= EmergencyRateBarpS() * elapsedClockSeconds; epState = 1; break; case ControllerState.Dummy: x *= MaxPressureBar() - FullServReductionBar(); pressureBar = IncreasePressure(pressureBar, x, ReleaseRateBarpS(), elapsedClockSeconds); pressureBar = DecreasePressure(pressureBar, x, ApplyRateBarpS(), elapsedClockSeconds); epState = -1; break; } PreviousNotchPosition = NotchController.GetCurrentNotch(); } } if (pressureBar > MaxPressureBar()) { pressureBar = MaxPressureBar(); } if (pressureBar < 0) { pressureBar = 0; } return(new Tuple <double, double>(pressureBar, epState)); }