From 099db5cf3cb0ee8864905c288f47cbc1655fe1f5 Mon Sep 17 00:00:00 2001
From: Michael Krisper <michael.krisper@tugraz.at>
Date: Wed, 31 Aug 2016 17:01:17 +0200
Subject: [PATCH] DistanceBasedDrivingCycle: Implemented PTOCycle Stop,
 refactored GetStopTimeInterval to own function.

---
 .../Impl/DistanceBasedDrivingCycle.cs         | 162 ++++++++++++------
 1 file changed, 106 insertions(+), 56 deletions(-)

diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/DistanceBasedDrivingCycle.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/DistanceBasedDrivingCycle.cs
index c2ceae2d3b..ff9086628f 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/DistanceBasedDrivingCycle.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/DistanceBasedDrivingCycle.cs
@@ -59,6 +59,16 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 		private bool _intervalProlonged;
 		internal IdleControllerSwitcher IdleController;
 
+		private DrivingCycleData.DrivingCycleEntry Left
+		{
+			get { return CycleIntervalIterator.LeftSample; }
+		}
+
+		private DrivingCycleData.DrivingCycleEntry Right
+		{
+			get { return CycleIntervalIterator.RightSample; }
+		}
+
 		public DistanceBasedDrivingCycle(IVehicleContainer container, DrivingCycleData cycle) : base(container)
 		{
 			_data = cycle;
@@ -77,16 +87,16 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 
 		public IResponse Initialize()
 		{
-			if (CycleIntervalIterator.LeftSample.VehicleTargetSpeed.IsEqual(0)) {
+			if (Left.VehicleTargetSpeed.IsEqual(0)) {
 				var retVal = NextComponent.Initialize(DataBus.StartSpeed,
-					CycleIntervalIterator.LeftSample.RoadGradient, DataBus.StartAcceleration);
+					Left.RoadGradient, DataBus.StartAcceleration);
 				if (!(retVal is ResponseSuccess)) {
 					throw new UnexpectedResponseException("Couldn't find start gear.", retVal);
 				}
 			}
 
-			return NextComponent.Initialize(CycleIntervalIterator.LeftSample.VehicleTargetSpeed,
-				CycleIntervalIterator.LeftSample.RoadGradient);
+			return NextComponent.Initialize(Left.VehicleTargetSpeed,
+				Left.RoadGradient);
 		}
 
 		public IResponse Request(Second absTime, Second dt)
@@ -96,50 +106,23 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 
 		public IResponse Request(Second absTime, Meter ds)
 		{
-			if (CycleIntervalIterator.LeftSample.Distance.IsEqual(PreviousState.Distance.Value())) {
-				// exactly on an entry in the cycle...
-				if (!CycleIntervalIterator.LeftSample.StoppingTime.IsEqual(0)
-					&& CycleIntervalIterator.LeftSample.StoppingTime > PreviousState.WaitTime) {
-					// stop for certain time unless we've already waited long enough...
-					if (!CycleIntervalIterator.LeftSample.VehicleTargetSpeed.IsEqual(0)) {
+			if (Left.Distance.IsEqual(PreviousState.Distance.Value())) {
+				// we are exactly on an entry in the cycle.
+				var stopTime = Left.PTOActive && IdleController != null
+					? Left.StoppingTime + IdleController.Duration
+					: Left.StoppingTime;
+
+				if (stopTime.IsGreater(0) && PreviousState.WaitTime.IsSmaller(stopTime)) {
+					// stop for certain time unless we've already waited long enough ...
+
+					// we are stopping: ensure that velocity is 0.
+					if (!Left.VehicleTargetSpeed.IsEqual(0)) {
 						Log.Warn("Stopping Time requested in cycle but target-velocity not zero. distance: {0}, target speed: {1}",
-							CycleIntervalIterator.LeftSample.StoppingTime, CycleIntervalIterator.LeftSample.VehicleTargetSpeed);
+							Left.StoppingTime, Left.VehicleTargetSpeed);
 						throw new VectoSimulationException("Stopping Time only allowed when target speed is zero!");
 					}
-					var dt = CycleIntervalIterator.LeftSample.StoppingTime - PreviousState.WaitTime;
 
-					if (CycleIntervalIterator.LeftSample.PTOActive) {
-						if (PreviousState.WaitTime.IsEqual(0)) {
-							// waiting just started. Activate PTO
-							IdleController.Reset();
-							IdleController.ActivatePTO();
-						} else {
-							// we already started pto cycle and are now in the follow up call.
-							// So we have to manually commit the previous simulation step to go further.
-							IdleController.CommitSimulationStep();
-						}
-						var nextCycleTime = IdleController.GetNextCycleTime();
-						if (nextCycleTime == null) {
-							// PTO Cycle has finished. Switch to normal idle controller.
-							IdleController.ActivateIdle();
-							dt = Constants.SimulationSettings.TargetTimeInterval;
-						} else {
-							// set dt to the next time interval in the pto cycle (to synchronize driving cycle with pto cycle)
-							dt = nextCycleTime - PreviousState.WaitTime;
-						}
-					} else {
-						if (CycleIntervalIterator.LeftSample.StoppingTime.IsGreater(3 * Constants.SimulationSettings.TargetTimeInterval)) {
-							// split into 3 parts or use idle controller time intervals
-							if (PreviousState.WaitTime.IsEqual(0)) {
-								dt = Constants.SimulationSettings.TargetTimeInterval;
-							} else {
-								if (dt > Constants.SimulationSettings.TargetTimeInterval) {
-									dt -= Constants.SimulationSettings.TargetTimeInterval;
-								}
-							}
-						}
-					}
-					CurrentState.Response = DriveTimeInterval(absTime, dt);
+					CurrentState.Response = DriveTimeInterval(absTime, GetStopTimeInterval());
 					return CurrentState.Response;
 				}
 			}
@@ -180,14 +163,66 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 			return CurrentState.Response;
 		}
 
+		private Second GetStopTimeInterval()
+		{
+			if (Left.PTOActive && IdleController != null) {
+				if (Left.StoppingTime.IsGreater(0)) {
+					// we have a pto cycle with stopping time: split into 3 parts: 1/2 stoptime, pto duration, 1/2 stoptime
+					if (PreviousState.WaitTime.IsEqual(0)) {
+						// first step: set dt to 1/2 stopping time
+						return Left.StoppingTime / 2;
+					} else {
+						if (PreviousState.WaitTime.IsEqual(Left.StoppingTime / 2)) {
+							// begining the second step: activate pto
+							IdleController.ActivatePTO();
+						}
+						// second step: drive pto cycle intervals
+						var dt = IdleController.GetNextCycleTime();
+						if (dt == null) {
+							// third step: pto has finished. activate normal idle controller and drive 1/2 stopping time again.
+							IdleController.ActivateIdle();
+							return Left.StoppingTime / 2;
+						}
+						return dt;
+					}
+				} else {
+					// we have a pto cycle without stopping time.
+					if (PreviousState.WaitTime.IsEqual(0)) {
+						// begininng: activate pto
+						IdleController.ActivatePTO();
+					}
+
+					return IdleController.GetNextCycleTime();
+				}
+			} else {
+				if (Left.StoppingTime.IsGreater(3 * Constants.SimulationSettings.TargetTimeInterval)) {
+					// split into 3 parts: targettime, stoptime-2*targettime, targettime
+					if (PreviousState.WaitTime.IsEqual(0)) {
+						// first step: just started waiting: set dt to targettime
+						return Constants.SimulationSettings.TargetTimeInterval;
+					} else {
+						// continue waiting with rest time
+						var dt = Left.StoppingTime - PreviousState.WaitTime;
+						// in second step dt is stoptime - targettime, therefore 1 targettime still has to be subtracted.
+						// in third step dt is exactly targettime.
+						if (dt.IsGreater(Constants.SimulationSettings.TargetTimeInterval)) {
+							dt -= Constants.SimulationSettings.TargetTimeInterval;
+						}
+						return dt;
+					}
+				}
+				return Left.StoppingTime;
+			}
+		}
+
 		private IResponse DriveTimeInterval(Second absTime, Second dt)
 		{
 			CurrentState.AbsTime = PreviousState.AbsTime + dt;
 			CurrentState.WaitTime = PreviousState.WaitTime + dt;
 			CurrentState.Gradient = ComputeGradient(0.SI<Meter>());
-			CurrentState.VehicleTargetSpeed = CycleIntervalIterator.LeftSample.VehicleTargetSpeed;
+			CurrentState.VehicleTargetSpeed = Left.VehicleTargetSpeed;
 
-			return NextComponent.Request(absTime, dt, CycleIntervalIterator.LeftSample.VehicleTargetSpeed, CurrentState.Gradient);
+			return NextComponent.Request(absTime, dt, Left.VehicleTargetSpeed, CurrentState.Gradient);
 		}
 
 		private IResponse DriveDistance(Second absTime, Meter ds)
@@ -205,7 +240,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 
 			CurrentState.Distance = PreviousState.Distance + ds;
 			CurrentState.SimulationDistance = ds;
-			CurrentState.VehicleTargetSpeed = CycleIntervalIterator.LeftSample.VehicleTargetSpeed;
+			CurrentState.VehicleTargetSpeed = Left.VehicleTargetSpeed;
 			CurrentState.Gradient = ComputeGradient(ds);
 
 			var retVal = NextComponent.Request(absTime, ds, CurrentState.VehicleTargetSpeed, CurrentState.Gradient);
@@ -237,23 +272,38 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 			CurrentState = CurrentState.Clone();
 			_intervalProlonged = false;
 
-			if (!CycleIntervalIterator.LeftSample.StoppingTime.IsEqual(0) &&
-				CycleIntervalIterator.LeftSample.StoppingTime.IsEqual(PreviousState.WaitTime)) {
+			if (IdleController != null) {
+				IdleController.CommitSimulationStep();
+			}
+			var stopTime = Left.PTOActive && IdleController != null
+				? Left.StoppingTime + IdleController.Duration
+				: Left.StoppingTime;
+
+			if (!stopTime.IsEqual(0) && stopTime.IsEqual(PreviousState.WaitTime)) {
 				// we needed to stop at the current interval in the cycle and have already waited enough time, move on..
+				if (IdleController != null)
+					IdleController.ActivateIdle();
 				CycleIntervalIterator.MoveNext();
 			}
 
+			stopTime = Left.PTOActive && IdleController != null ? Left.StoppingTime + IdleController.Duration : Left.StoppingTime;
+
 			// separately test for equality and greater than to have tolerance for equality comparison
-			if (CycleIntervalIterator.LeftSample.StoppingTime.IsEqual(0)) {
-				while (CycleIntervalIterator.LeftSample.StoppingTime.IsEqual(0) &&
-						CurrentState.Distance.IsGreaterOrEqual(CycleIntervalIterator.RightSample.Distance) &&
+			if (stopTime.IsEqual(0)) {
+				while (stopTime.IsEqual(0) && CurrentState.Distance.IsGreaterOrEqual(CycleIntervalIterator.RightSample.Distance) &&
 						!CycleIntervalIterator.LastEntry) {
 					// we have reached the end of the current interval in the cycle, move on...
 					CycleIntervalIterator.MoveNext();
+
+					stopTime = Left.PTOActive && IdleController != null
+						? Left.StoppingTime + IdleController.Duration
+						: Left.StoppingTime;
 				}
 			} else {
-				if (CycleIntervalIterator.LeftSample.StoppingTime.IsEqual(PreviousState.WaitTime)) {
+				if (stopTime.IsEqual(PreviousState.WaitTime)) {
 					// we needed to stop at the current interval in the cycle and have already waited enough time, move on..
+					if (IdleController != null)
+						IdleController.ActivateIdle();
 					CycleIntervalIterator.MoveNext();
 				}
 			}
@@ -261,7 +311,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 
 		private Radian ComputeGradient(Meter ds)
 		{
-			//var leftSamplePoint = CycleIntervalIterator.LeftSample;
+			//var leftSamplePoint = Left;
 
 			var cycleIterator = CycleIntervalIterator.Clone();
 			while (cycleIterator.RightSample.Distance < PreviousState.Distance + ds && !cycleIterator.LastEntry) {
@@ -287,7 +337,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 
 		private Meter GetSpeedChangeWithinSimulationInterval(Meter ds)
 		{
-			var leftSamplePoint = CycleIntervalIterator.LeftSample;
+			var leftSamplePoint = Left;
 			var cycleIterator = CycleIntervalIterator.Clone();
 
 			do {
@@ -364,7 +414,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 				return new CycleData {
 					AbsTime = CurrentState.AbsTime,
 					AbsDistance = CurrentState.Distance,
-					LeftSample = CycleIntervalIterator.LeftSample,
+					LeftSample = Left,
 					RightSample = CycleIntervalIterator.RightSample
 				};
 			}
-- 
GitLab