internal void Load(LoadProperties properties) { Panel = properties.Panel; stationsMemory = new StationsMemory(); stationsMemory.Load(properties); trackGradientMemory = new TrackGradientMemory(); trackGradientMemory.Load(properties); driverless = new Driverless(); driverless.Load(properties); stationsMemory.OnStationDataRefreshed += new StationsMemory.NewStationDataReceiver(driverless.WriteRefreshedStationsCollection); stationsMemory.OnLastDockIndexRefreshed += new StationsMemory.LastDockIndexReceiver(driverless.WriteRefreshedLastDockedIndex); rm = new RM(); rm.Load(properties); atp2 = new ATP2(); atp2.Load(properties); stationsMemory.OnStationDataRefreshed += new StationsMemory.NewStationDataReceiver(atp2.WriteRefreshedStationsCollection); stationsMemory.OnLastDockIndexRefreshed += new StationsMemory.LastDockIndexReceiver(atp2.WriteRefreshedLastDockedIndex); ato = new ATO(); ato.Load(properties); stationsMemory.OnStationDataRefreshed += new StationsMemory.NewStationDataReceiver(ato.WriteRefreshedStationsCollection); stationsMemory.OnLastDockIndexRefreshed += new StationsMemory.LastDockIndexReceiver(ato.WriteRefreshedLastDockedIndex); trackGradientMemory.OnGradientPointsDataRefreshed += new TrackGradientMemory.NewGradientPointsDataReceiver(ato.WriteRefreshedGradientPointCollection); // driverless.OnDriverlessAvailableElapse += new CallDriverlessAvailableEventHandlers(); }
internal void Elapse(ATP2.ATPElapseData data) { vState = data.ElapseData; Handles atpHandlesResult = data.ElapseData.Handles; // UNDONE: if (vState.TotalTime.Milliseconds >= lastTimeRefreshATOAccelerationRate.Milliseconds + 100) { ATO_AccelerationRate = (vState.Vehicle.Speed.KilometersPerHour - lastTimeRefreshATOAccelerationRate_SpeedKMHS) / (vState.TotalTime.Milliseconds - lastTimeRefreshATOAccelerationRate.Milliseconds) * 1000; lastTimeRefreshATOAccelerationRate_SpeedKMHS = vState.Vehicle.Speed.KilometersPerHour; lastTimeRefreshATOAccelerationRate = vState.TotalTime; } // vState.DebugMessage = "Accel:" + ATO_AccelerationRate + "km/h/s; " + vState.DebugMessage; // fail the ATO if handles fail whilst ATO running if (ATOStarted && vState.Handles.PowerNotch != 0 && vState.Handles.BrakeNotch != vSpec.BrakeNotches) { ATOFail = true; } // reset fail only if (1) ATO is not start and (2) train is steady and (3) handles are OK and (4) ATO is on fail state if (ATOFail && !ATOStarted && vState.Vehicle.Speed.KilometersPerHour == 0 && vState.Handles.PowerNotch == 0 && vState.Handles.BrakeNotch == vSpec.BrakeNotches) { ATOFail = false; } // what will happen if ATO fails? if (ATOFail) { vState.DebugMessage = "!ATO FAIL!"; if (vState.Vehicle.Speed.KilometersPerHour == 0) { ATOFail = false; ATOStarted = false; } else { // emg beep beep beep ATOPower = 0; ATOBrake = vSpec.BrakeNotches + 1; } } // how is ATO working? else if (ATOStarted) { // jump to stop working if not powering and stopped // OK: ATOStates.START + ATOStates.POWER if (vState.Vehicle.Speed.KilometersPerHour == 0.0 && ATOCurrentState > ATOStates.POWER) { ATOStarted = false; } #region Analysis and Switch States // brake due to next speed flag if (data.CurrentTargetSpeed < prevTargetSpeed) { ATOCurrentState = ATOStates.BRAKE_SPEED; } // accelerate else if (data.CurrentPermittedSpeed > prevPermittedSpeed) { ATOCurrentState = ATOStates.POWER; } // brake due to arriving at next stop // if next stop is available else if (lastCompletedDockingIndex + 1 < Stations.Count) { // if next stop should stop if (Stations[lastCompletedDockingIndex + 1].DoorOpen > -2) { // arriving at platform // UNDONE: double BrakingDistanceByPermittedSpeed = AccelerationPhysics.GetDisplacement(data.CurrentPermittedSpeed, 0, BrakeRate[ATP2.DefaultNormalBrakeNotch]); if (Stations[lastCompletedDockingIndex + 1].StopPosition - GeneralSettings.BrakeCurveHigh_ReservingDistance - vState.Vehicle.Location <= BrakingDistanceByPermittedSpeed) { if (vState.Vehicle.Speed.KilometersPerHour < data.CurrentPermittedSpeed - 2) { // vState.DebugMessage += "S1:" + ATOStartLocation + " >= " + (Stations[lastCompletedDockingIndex + 1].StopPosition - BrakingDistanceByPermittedSpeed) + ", "; if (vState.Vehicle.Speed.KilometersPerHour < data.CurrentPermittedSpeed - 5 && ATOStartLocation >= Stations[lastCompletedDockingIndex + 1].StopPosition - BrakingDistanceByPermittedSpeed) { vState.DebugMessage += "SPower, "; ATOCurrentState = ATOStates.POWER; } else { ATOCurrentState = ATOStates.COASTING; } } else { ATOCurrentState = ATOStates.BRAKE_STOP; } } } } // remember things for analysis on next frame if (data.CurrentTargetSpeed != prevTargetSpeed) prevTargetSpeed = data.CurrentTargetSpeed; if (data.CurrentPermittedSpeed != prevPermittedSpeed) prevPermittedSpeed = data.CurrentPermittedSpeed; if (data.CurrentEmergencyBrakeSpeed != prevEmergencyBrakeSpeed) prevEmergencyBrakeSpeed = data.CurrentEmergencyBrakeSpeed; #endregion #region Behaviour if (data.ATPFail) { ATOFail = true; } else if (!data.ATPBrakeApplying) { data.ElapseData.DebugMessage += ATOCurrentState.ToString() + ", "; switch (ATOCurrentState) { case ATOStates.START: if (vState.Vehicle.Speed.KilometersPerHour >= 1) { ATOCurrentState = ATOStates.POWER; goto case ATOStates.POWER; } ATOPower = vSpec.PowerNotches; ATOBrake = 0; break; case ATOStates.POWER: if (vState.Vehicle.Speed.KilometersPerHour >= data.CurrentPermittedSpeed + atoProfiles[profileID].StopAcceleratingSpeed) { ATOCurrentState = ATOStates.COASTING; goto case ATOStates.COASTING; } ATOPower = vSpec.PowerNotches; ATOBrake = 0; break; case ATOStates.COASTING: if (atoProfiles[profileID].HoldSpeedNotCoasting) { goto case ATOStates.KEEPSPEED; } #region brake to hold speed? // if new to coasting state, reset brake notch if(lastFrame_ATOState != ATOCurrentState) ATOBrake = BrakeToHoldSpeedNotch = 0; // if notches are interrupted, then recount the timer if (lastFrame_ATOState != ATOCurrentState || last1s_PowerNotch != lastFrame_PowerNotch || last1s_BrakeNotch != lastFrame_BrakeNotch) { // System.Windows.Forms.MessageBox.Show(lastCheckSpeedCoasting + ""); lastCheckSpeedCoasting = vState.TotalTime; last1s_Speed = vState.Vehicle.Speed.KilometersPerHour; last1s_PowerNotch = lastFrame_BrakeNotch; last1s_BrakeNotch = lastFrame_BrakeNotch; } if (vState.TotalTime.Milliseconds >= lastCheckSpeedCoasting.Milliseconds + 1000) { if (vState.Vehicle.Speed.KilometersPerHour - last1s_Speed > 0) { // accelerating for (int i = BrakeRate.Length - 1; i >= 0; i--) { if (vState.Vehicle.Speed.KilometersPerHour - last1s_Speed >= BrakeRate[i] * -1) { ATOPower = 0; ATOBrake = BrakeToHoldSpeedNotch = i; break; } } } else { ATOBrake = BrakeToHoldSpeedNotch = 0; } lastCheckSpeedCoasting = vState.TotalTime; last1s_Speed = vState.Vehicle.Speed.KilometersPerHour; last1s_PowerNotch = ATOPower; last1s_BrakeNotch = ATOBrake; } #endregion #region slight slope that above command cannot detect else if (vState.Vehicle.Speed.KilometersPerHour <= data.CurrentPermittedSpeed && slightSlopeBrakeEnabled) { slightSlopeBrakeEnabled = false; ATOPower = 0; ATOBrake = BrakeToHoldSpeedNotch = 0; } else if (vState.Vehicle.Speed.KilometersPerHour >= data.CurrentPermittedSpeed + 4) { vState.DebugMessage += "(S)"; slightSlopeBrakeEnabled = true; ATOPower = 0; ATOBrake = BrakeToHoldSpeedNotch = 3; } else if (vState.Vehicle.Speed.KilometersPerHour >= data.CurrentPermittedSpeed + 3) { vState.DebugMessage += "(S)"; slightSlopeBrakeEnabled = true; ATOPower = 0; ATOBrake = BrakeToHoldSpeedNotch = 2; } else if (vState.Vehicle.Speed.KilometersPerHour >= data.CurrentPermittedSpeed + 2) { vState.DebugMessage += "(S)"; slightSlopeBrakeEnabled = true; ATOPower = 0; ATOBrake = BrakeToHoldSpeedNotch = 1; } #endregion if (BrakeToHoldSpeedNotch > 0) vState.DebugMessage += "(" + (vState.Vehicle.Speed.KilometersPerHour - last1s_Speed) + ")BrakeToHoldSpeed(" + BrakeToHoldSpeedNotch + "),"; if (slightSlopeBrakeEnabled) vState.DebugMessage += "slightSlopeBrakeEnabled,"; // TODO: power if too low speed? else if (vState.Vehicle.Speed.KilometersPerHour <= data.CurrentPermittedSpeed + atoProfiles[profileID].CoastingTooSlowForcePowerSpeed) { ATOCurrentState = ATOStates.POWER; goto case ATOStates.POWER; } else { ATOPower = 0; ATOBrake = BrakeToHoldSpeedNotch; } break; case ATOStates.KEEPSPEED: throw new NotImplementedException(); if (vState.Vehicle.Speed.KilometersPerHour >= data.CurrentPermittedSpeed + atoProfiles[profileID].StopAcceleratingSpeed) { PowerToHoldSpeedNotch = 0; } #region slight slope that above command cannot detect else if (vState.Vehicle.Speed.KilometersPerHour <= data.CurrentPermittedSpeed && slightSlopeBrakeEnabled) { slightSlopeBrakeEnabled = false; ATOPower = 0; ATOBrake = BrakeToHoldSpeedNotch = 0; } else if (vState.Vehicle.Speed.KilometersPerHour >= data.CurrentPermittedSpeed + 4) { vState.DebugMessage += "(S)"; slightSlopeBrakeEnabled = true; ATOPower = 0; ATOBrake = BrakeToHoldSpeedNotch = 3; } else if (vState.Vehicle.Speed.KilometersPerHour >= data.CurrentPermittedSpeed + 3) { vState.DebugMessage += "(S)"; slightSlopeBrakeEnabled = true; ATOPower = 0; ATOBrake = BrakeToHoldSpeedNotch = 2; } else if (vState.Vehicle.Speed.KilometersPerHour >= data.CurrentPermittedSpeed + 2) { vState.DebugMessage += "(S)"; slightSlopeBrakeEnabled = true; ATOPower = 0; ATOBrake = BrakeToHoldSpeedNotch = 1; } #endregion #region power to keep speed else if (true) { #region deceleration caused by gradient // Rate = 1000 * Y / X double pitchInPerMill_KEEPSPEED = gPtMem[gPtMem.CurrentIndex(vState.Vehicle.Location)].Pitch; // Acceleration due to gravity is 9.79 ms^-2 double accelerationCausedByGradient_KEEPSPEED = 9.79 / (1 / (-1 * pitchInPerMill_KEEPSPEED / 1000)); vState.DebugMessage += "pitch: " + pitchInPerMill_KEEPSPEED + "; DCBG: " + accelerationCausedByGradient_KEEPSPEED + ", "; #endregion #region calculation #endregion } #endregion // debug if (BrakeToHoldSpeedNotch > 0) vState.DebugMessage += "(" + (vState.Vehicle.Speed.KilometersPerHour - last1s_Speed) + ")BrakeToHoldSpeed(" + BrakeToHoldSpeedNotch + "),"; if (slightSlopeBrakeEnabled) vState.DebugMessage += "slightSlopeBrakeEnabled,"; ATOPower = PowerToHoldSpeedNotch; ATOBrake = 0; break; case ATOStates.BRAKE_SPEED: if (vState.Vehicle.Speed.KilometersPerHour <= data.CurrentTargetSpeed + atoProfiles[profileID].StopBrakingSpeed) { ATOCurrentState = ATOStates.COASTING; goto case ATOStates.COASTING; } ATOPower = 0; // TODO: deceleration baused by gradient // for (int i = 0; i < BrakeRate.Length; i++) { // brake rates are negative numbers if (Math.Abs(BrakeRate[i]) >= Math.Abs(AccelerationPhysics.GetAccelerationRate(data.CurrentTargetSpeed, vState.Vehicle.Speed.KilometersPerHour, data.NextSpeedFlag.StartingLocation - vState.Vehicle.Location))) { ATOBrake = i; break; } } if (vState.Vehicle.Speed.KilometersPerHour > data.CurrentTargetSpeed + 4) { ATOBrake = vSpec.BrakeNotches; } break; case ATOStates.BRAKE_STOP: ATOPower = 0; // TODO: more accurate calculation for gradient #region deceleration caused by gradient // Rate = 1000 * Y / X double pitchInPerMill_BRAKE_STOP = gPtMem[gPtMem.CurrentIndex(vState.Vehicle.Location)].Pitch; // Acceleration due to gravity is 9.79 ms^-2 double accelerationCausedByGradient_BRAKE_STOP = 9.79 / (1 / (-1 * pitchInPerMill_BRAKE_STOP / 1000)); vState.DebugMessage += "pitch: " + pitchInPerMill_BRAKE_STOP + "; DCBG: " + accelerationCausedByGradient_BRAKE_STOP + ", "; #endregion #region calculation for (int i = 0; i < BrakeRate.Length; i++) { if (Stations[lastCompletedDockingIndex + 1].StopPosition - vState.Vehicle.Location <= GeneralSettings.BrakeCurveHigh_ChangeToLowDistance) { // brake rates are negative numbers if (Math.Abs(BrakeRate[i]) - accelerationCausedByGradient_BRAKE_STOP >= Math.Abs(AccelerationPhysics.GetAccelerationRate(0, vState.Vehicle.Speed.KilometersPerHour, Stations[lastCompletedDockingIndex + 1].StopPosition - vState.Vehicle.Location))) { ATOBrake = i; break; } } else { // brake rates are negative numbers if (Math.Abs(BrakeRate[i]) - accelerationCausedByGradient_BRAKE_STOP >= Math.Abs(AccelerationPhysics.GetAccelerationRate(0, vState.Vehicle.Speed.KilometersPerHour, Stations[lastCompletedDockingIndex + 1].StopPosition - vState.Vehicle.Location - GeneralSettings.BrakeCurveHigh_ReservingDistance))) { ATOBrake = i; break; } } } #endregion #region don't decelerate if speed is too low if (vState.Vehicle.Speed.KilometersPerHour < data.CurrentTargetSpeed - 5) { resistBrakingNotch = vSpec.BrakeNotches; } else if (resistBrakingNotch == 2) { if (vState.Vehicle.Speed.KilometersPerHour >= data.CurrentPermittedSpeed - 3 && vState.Vehicle.Speed.KilometersPerHour < data.CurrentPermittedSpeed - 1) { resistBrakingNotch = 1; } else if (vState.Vehicle.Speed.KilometersPerHour >= data.CurrentPermittedSpeed - 1) { resistBrakingNotch = 0; } } else if (resistBrakingNotch == 1) { if (vState.Vehicle.Speed.KilometersPerHour < data.CurrentPermittedSpeed - 4) { resistBrakingNotch = 2; } else if (vState.Vehicle.Speed.KilometersPerHour >= data.CurrentPermittedSpeed - 1) { resistBrakingNotch = 0; } } else if (resistBrakingNotch == 0) { if (vState.Vehicle.Speed.KilometersPerHour < data.CurrentPermittedSpeed - 4) { resistBrakingNotch = 2; } else if (vState.Vehicle.Speed.KilometersPerHour < data.CurrentPermittedSpeed - 2) { resistBrakingNotch = 1; } } ATOBrake -= (ATOBrake - resistBrakingNotch < 0 ? 0 : resistBrakingNotch); // debug if (resistBrakingNotch > 0) vState.DebugMessage += "ForceB-" + resistBrakingNotch + ", "; #endregion break; } } #endregion } else { ATOPower = 0; ATOBrake = vSpec.BrakeNotches; } vState.Handles.PowerNotch = ATOPower; vState.Handles.BrakeNotch = ATOBrake; lastFrame_ATOState = ATOCurrentState; lastFrame_Speed = vState.Vehicle.Speed.KilometersPerHour; lastFrame_PowerNotch = ATOPower; lastFrame_BrakeNotch = ATOBrake; }