From cb5ba3eb73992c6711f14b7beee34ed5e703c4b7 Mon Sep 17 00:00:00 2001
From: Markus Quaritsch <markus.quaritsch@tugraz.at>
Date: Thu, 29 Aug 2019 16:30:36 +0200
Subject: [PATCH] implementing pcc usecase 2

---
 .../InputData/EngineeringInputData.cs         |   6 +-
 .../DeclarationDataAdapter.cs                 |   4 +-
 .../EngineeringDataAdapter.cs                 |   4 +-
 .../Models/Declaration/DeclarationData.cs     |   4 +-
 .../Impl/PCCEcoRollEngineStopPreprocessor.cs  |  93 +--------------
 .../Simulation/Impl/PCCSegmentPreprocessor.cs | 102 ++++++++++++++++
 .../SimulationComponent/Data/DriverData.cs    |   7 +-
 .../Impl/DefaultDriverStrategy.cs             | 112 ++++++++++++------
 VectoCore/VectoCore/VectoCore.csproj          |   1 +
 9 files changed, 201 insertions(+), 132 deletions(-)
 create mode 100644 VectoCore/VectoCore/Models/Simulation/Impl/PCCSegmentPreprocessor.cs

diff --git a/VectoCommon/VectoCommon/InputData/EngineeringInputData.cs b/VectoCommon/VectoCommon/InputData/EngineeringInputData.cs
index 8856a5f307..6db8158fcb 100644
--- a/VectoCommon/VectoCommon/InputData/EngineeringInputData.cs
+++ b/VectoCommon/VectoCommon/InputData/EngineeringInputData.cs
@@ -367,9 +367,13 @@ namespace TUGraz.VectoCommon.InputData
 
 	public interface IPCCEngineeringInputData
 	{
+		MeterPerSecond PCCEnabledSpeed { get; }
+
 		MeterPerSecond MinSpeed { get; }
 		MeterPerSecond MaxSpeed { get; }
-		Meter PreviewDistance { get; }
+		Meter PreviewDistanceUseCase1 { get; }
+		Meter PreviewDistanceUseCase2 { get; }
+
 		MeterPerSecond Underspeed { get; }
 	}
 
diff --git a/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/DeclarationDataAdapter.cs b/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/DeclarationDataAdapter.cs
index a36fe82186..56c9babc63 100644
--- a/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/DeclarationDataAdapter.cs
+++ b/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/DeclarationDataAdapter.cs
@@ -85,9 +85,11 @@ namespace TUGraz.VectoCore.InputData.Reader.DataObjectAdapter
 					AccelerationUpperLimit = DeclarationData.Driver.EcoRoll.AccelerationUpperLimit,
 				},
 				PCC = new DriverData.PCCData() {
+					PCCEnableSpeed = DeclarationData.Driver.PCC.PCCEnableSpeed,
 					MinSpeed = DeclarationData.Driver.PCC.MinSpeed,
 					MaxSpeed = DeclarationData.Driver.PCC.MaxSpeed,
-					PreviewDistance = DeclarationData.Driver.PCC.PreviewDistance,
+					PreviewDistanceUseCase1 = DeclarationData.Driver.PCC.PreviewDistanceUseCase1,
+					PreviewDistanceUseCase2 = DeclarationData.Driver.PCC.PreviewDistanceUseCase2,
 					UnderSpeed =  DeclarationData.Driver.PCC.Underspeed,
 				}
 			};
diff --git a/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/EngineeringDataAdapter.cs b/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/EngineeringDataAdapter.cs
index 51f53fe48c..d5ddf9d333 100644
--- a/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/EngineeringDataAdapter.cs
+++ b/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/EngineeringDataAdapter.cs
@@ -471,9 +471,11 @@ namespace TUGraz.VectoCore.InputData.Reader.DataObjectAdapter
 					AccelerationUpperLimit = 0.15.SI<MeterPerSquareSecond>(), // DeclarationData.Driver.EcoRoll.AccelerationUpperLimit,
 				},
 				PCC = new DriverData.PCCData() {
+					PCCEnableSpeed = driver.PCCData?.PCCEnabledSpeed ?? DeclarationData.Driver.PCC.PCCEnableSpeed,
 					MinSpeed = driver.PCCData?.MinSpeed ?? DeclarationData.Driver.PCC.MinSpeed,
 					MaxSpeed = driver.PCCData?.MaxSpeed ?? DeclarationData.Driver.PCC.MaxSpeed,
-					PreviewDistance = driver.PCCData?.PreviewDistance ?? DeclarationData.Driver.PCC.PreviewDistance,
+					PreviewDistanceUseCase1 = driver.PCCData?.PreviewDistanceUseCase1 ?? DeclarationData.Driver.PCC.PreviewDistanceUseCase1,
+					PreviewDistanceUseCase2 = driver.PCCData?.PreviewDistanceUseCase2 ?? DeclarationData.Driver.PCC.PreviewDistanceUseCase2,
 					UnderSpeed = driver.PCCData?.Underspeed ?? DeclarationData.Driver.PCC.Underspeed,
 				}
 			};
diff --git a/VectoCore/VectoCore/Models/Declaration/DeclarationData.cs b/VectoCore/VectoCore/Models/Declaration/DeclarationData.cs
index 4cb88b8afa..4e2a84b855 100644
--- a/VectoCore/VectoCore/Models/Declaration/DeclarationData.cs
+++ b/VectoCore/VectoCore/Models/Declaration/DeclarationData.cs
@@ -153,9 +153,11 @@ namespace TUGraz.VectoCore.Models.Declaration
 
 			public static class PCC
 			{
+				public static readonly MeterPerSecond PCCEnableSpeed = 80.KMPHtoMeterPerSecond();
 				public static readonly MeterPerSecond MinSpeed = 50.KMPHtoMeterPerSecond();
 				public static readonly MeterPerSecond MaxSpeed = 100.KMPHtoMeterPerSecond();
-				public static readonly Meter PreviewDistance = 1500.SI<Meter>();
+				public static readonly Meter PreviewDistanceUseCase1 = 1500.SI<Meter>();
+				public static readonly Meter PreviewDistanceUseCase2 = 1000.SI<Meter>();
 				public static readonly MeterPerSecond Underspeed = 8.KMPHtoMeterPerSecond();
 			}
 		}
diff --git a/VectoCore/VectoCore/Models/Simulation/Impl/PCCEcoRollEngineStopPreprocessor.cs b/VectoCore/VectoCore/Models/Simulation/Impl/PCCEcoRollEngineStopPreprocessor.cs
index 5321308ae8..952a8bb667 100644
--- a/VectoCore/VectoCore/Models/Simulation/Impl/PCCEcoRollEngineStopPreprocessor.cs
+++ b/VectoCore/VectoCore/Models/Simulation/Impl/PCCEcoRollEngineStopPreprocessor.cs
@@ -1,13 +1,10 @@
-using System;
-using System.Collections.Generic;
+using System.Collections.Generic;
 using System.Linq;
 using TUGraz.VectoCommon.Exceptions;
-using TUGraz.VectoCommon.InputData;
 using TUGraz.VectoCommon.Utils;
 using TUGraz.VectoCore.Configuration;
 using TUGraz.VectoCore.Models.Connector.Ports.Impl;
 using TUGraz.VectoCore.Models.SimulationComponent;
-using TUGraz.VectoCore.Models.SimulationComponent.Data;
 using TUGraz.VectoCore.Models.SimulationComponent.Impl;
 using TUGraz.VectoCore.OutputData;
 using TUGraz.VectoCore.Utils;
@@ -110,94 +107,6 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 		#endregion
 	}
 
-	public class PCCSegmentPreprocessor : ISimulationPreprocessor
-	{
-		protected SimplePowertrainContainer Container;
-		protected PCCSegments PCCSegments;
-		protected DriverData.PCCData PCCDriverData;
-
-		public PCCSegmentPreprocessor(
-			SimplePowertrainContainer simpleContainer, PCCSegments segments, DriverData.PCCData driverDataPCC)
-		{
-			Container = simpleContainer;
-			PCCSegments = segments;
-			PCCDriverData = driverDataPCC;
-		}
-
-		#region Implementation of ISimulationPreprocessor
-
-		public void RunPreprocessing()
-		{
-			var slopes = new Dictionary<MeterPerSecond, Radian>();
-			new PCCEcoRollEngineStopPreprocessor(
-				Container, slopes, PCCDriverData.MinSpeed, PCCDriverData.MaxSpeed).RunPreprocessing();
-
-			var runData = Container.RunData;
-			var engineDrag = runData.EngineData.FullLoadCurves[0].FullLoadEntries
-									.Average(x => (x.EngineSpeed * x.TorqueDrag).Value()).SI<Watt>();
-
-			var slopeEngineDrag = runData.VehicleData.ADAS.EcoRoll == EcoRollType.WithEngineStop
-				? 0
-				: (engineDrag / Physics.GravityAccelleration / runData.VehicleData.TotalVehicleWeight).Value();
-
-			PCCSegment pccSegment = null;
-			var targetspeedChanged = 0.SI<Meter>();
-			foreach (var tuple in Container.RunData.Cycle.Entries.Pairwise(Tuple.Create)) {
-				if (!tuple.Item1.Highway) {
-					continue;
-				}
-				if (tuple.Item1.Distance.IsEqual(tuple.Item2.Distance)) {
-					// can't calculate avg slope if difference between two entries is 0
-					continue;
-				}
-
-				if (!tuple.Item1.VehicleTargetSpeed.IsEqual(tuple.Item2.VehicleTargetSpeed)) {
-					// target speed must not change within PCC segment
-					targetspeedChanged = tuple.Item2.Distance;
-					continue;
-				}
-
-				if (pccSegment != null && !tuple.Item1.VehicleTargetSpeed.IsEqual(pccSegment.TargetSpeed)) {
-					// target speed must not change within PCC segment
-					pccSegment = null;
-					continue;
-				}
-
-				var minSlope = (slopes.Interpolate(x => x.Key.Value(), y => y.Value.Value(), tuple.Item1.VehicleTargetSpeed.Value())
-								+ slopeEngineDrag / tuple.Item1.VehicleTargetSpeed.Value()).SI<Radian>();
-
-				var slope = VectoMath.InclinationToAngle(
-					(tuple.Item2.Altitude - tuple.Item1.Altitude) / (tuple.Item2.Distance - tuple.Item1.Distance));
-
-				if (pccSegment == null && slope < minSlope &&
-					(tuple.Item1.Distance - targetspeedChanged).IsGreater(PCCDriverData.PreviewDistance)) {
-					pccSegment = new PCCSegment() {
-						DistanceMinSpeed = tuple.Item1.Distance,
-						StartDistance = tuple.Item1.Distance - PCCDriverData.PreviewDistance,
-						TargetSpeed = tuple.Item1.VehicleTargetSpeed,
-						Altitude = tuple.Item1.Altitude,
-						EnergyMinSpeed = (runData.VehicleData.TotalVehicleWeight * Physics.GravityAccelleration * tuple.Item1.Altitude)
-										.Cast<Joule>() +
-										runData.VehicleData.TotalVehicleWeight * (tuple.Item1.VehicleTargetSpeed - PCCDriverData.UnderSpeed) *
-										(tuple.Item1.VehicleTargetSpeed - PCCDriverData.UnderSpeed) / 2,
-					};
-				}
-
-				if (pccSegment != null && slope > minSlope) {
-					pccSegment.EndDistance = tuple.Item1.Distance;
-					pccSegment.EnergyEnd =
-						(runData.VehicleData.TotalVehicleWeight * Physics.GravityAccelleration * tuple.Item1.Altitude).Cast<Joule>() +
-						runData.VehicleData.TotalVehicleWeight * tuple.Item1.VehicleTargetSpeed *
-						tuple.Item1.VehicleTargetSpeed / 2;
-					PCCSegments.Segments.Add(pccSegment);
-					pccSegment = null;
-				}
-			}
-		}
-
-		#endregion
-	}
-
 	public class PCCSegments
 	{
 		public PCCSegments()
diff --git a/VectoCore/VectoCore/Models/Simulation/Impl/PCCSegmentPreprocessor.cs b/VectoCore/VectoCore/Models/Simulation/Impl/PCCSegmentPreprocessor.cs
new file mode 100644
index 0000000000..535ae78647
--- /dev/null
+++ b/VectoCore/VectoCore/Models/Simulation/Impl/PCCSegmentPreprocessor.cs
@@ -0,0 +1,102 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using TUGraz.VectoCommon.InputData;
+using TUGraz.VectoCommon.Utils;
+using TUGraz.VectoCore.Models.SimulationComponent.Data;
+using TUGraz.VectoCore.Utils;
+
+namespace TUGraz.VectoCore.Models.Simulation.Impl {
+	public class PCCSegmentPreprocessor : ISimulationPreprocessor
+	{
+		protected SimplePowertrainContainer Container;
+		protected PCCSegments PCCSegments;
+		protected DriverData.PCCData PCCDriverData;
+
+		public PCCSegmentPreprocessor(
+			SimplePowertrainContainer simpleContainer, PCCSegments segments, DriverData.PCCData driverDataPCC)
+		{
+			Container = simpleContainer;
+			PCCSegments = segments;
+			PCCDriverData = driverDataPCC;
+		}
+
+		#region Implementation of ISimulationPreprocessor
+
+		public void RunPreprocessing()
+		{
+			var slopes = new Dictionary<MeterPerSecond, Radian>();
+			new PCCEcoRollEngineStopPreprocessor(
+				Container, slopes, PCCDriverData.MinSpeed, PCCDriverData.MaxSpeed).RunPreprocessing();
+
+			var runData = Container.RunData;
+			var engineDrag = runData.EngineData.FullLoadCurves[0].FullLoadEntries
+									.Average(x => (x.EngineSpeed * x.TorqueDrag).Value()).SI<Watt>();
+
+			var slopeEngineDrag = runData.VehicleData.ADAS.EcoRoll == EcoRollType.WithEngineStop
+				? 0
+				: (engineDrag / Physics.GravityAccelleration / runData.VehicleData.TotalVehicleWeight).Value();
+
+			PCCSegment pccSegment = null;
+			var targetspeedChanged = 0.SI<Meter>();
+			foreach (var tuple in Container.RunData.Cycle.Entries.Pairwise(Tuple.Create)) {
+				if (!tuple.Item1.Highway) {
+					continue;
+				}
+
+				if (!tuple.Item1.VehicleTargetSpeed.IsGreaterOrEqual(PCCDriverData.PCCEnableSpeed)) {
+					// only consider pcc segments where the target speed is at least the pcc-enable speed
+					continue;
+				}
+				if (tuple.Item1.Distance.IsEqual(tuple.Item2.Distance)) {
+					// can't calculate avg slope if difference between two entries is 0
+					continue;
+				}
+
+				if (!tuple.Item1.VehicleTargetSpeed.IsEqual(tuple.Item2.VehicleTargetSpeed)) {
+					// target speed must not change within PCC segment
+					targetspeedChanged = tuple.Item2.Distance;
+					continue;
+				}
+
+				if (pccSegment != null && !tuple.Item1.VehicleTargetSpeed.IsEqual(pccSegment.TargetSpeed)) {
+					// target speed must not change within PCC segment
+					pccSegment = null;
+					continue;
+				}
+
+				var minSlope = (slopes.Interpolate(x => x.Key.Value(), y => y.Value.Value(), tuple.Item1.VehicleTargetSpeed.Value())
+								+ slopeEngineDrag / tuple.Item1.VehicleTargetSpeed.Value()).SI<Radian>();
+
+				var slope = VectoMath.InclinationToAngle(
+					(tuple.Item2.Altitude - tuple.Item1.Altitude) / (tuple.Item2.Distance - tuple.Item1.Distance));
+
+				if (pccSegment == null && slope < minSlope &&
+					(tuple.Item1.Distance - targetspeedChanged).IsGreater(PCCDriverData.PreviewDistanceUseCase1)) {
+					pccSegment = new PCCSegment() {
+						DistanceMinSpeed = tuple.Item1.Distance,
+						StartDistance = tuple.Item1.Distance - PCCDriverData.PreviewDistanceUseCase1,
+						TargetSpeed = tuple.Item1.VehicleTargetSpeed,
+						Altitude = tuple.Item1.Altitude,
+						EnergyMinSpeed = (runData.VehicleData.TotalVehicleWeight * Physics.GravityAccelleration * tuple.Item1.Altitude)
+										.Cast<Joule>() +
+										runData.VehicleData.TotalVehicleWeight * (tuple.Item1.VehicleTargetSpeed - PCCDriverData.UnderSpeed) *
+										(tuple.Item1.VehicleTargetSpeed - PCCDriverData.UnderSpeed) / 2,
+					};
+				}
+
+				if (pccSegment != null && slope > minSlope) {
+					pccSegment.EndDistance = tuple.Item1.Distance;
+					pccSegment.EnergyEnd =
+						(runData.VehicleData.TotalVehicleWeight * Physics.GravityAccelleration * tuple.Item1.Altitude).Cast<Joule>() +
+						runData.VehicleData.TotalVehicleWeight * tuple.Item1.VehicleTargetSpeed *
+						tuple.Item1.VehicleTargetSpeed / 2;
+					PCCSegments.Segments.Add(pccSegment);
+					pccSegment = null;
+				}
+			}
+		}
+
+		#endregion
+	}
+}
\ No newline at end of file
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Data/DriverData.cs b/VectoCore/VectoCore/Models/SimulationComponent/Data/DriverData.cs
index 8c85f5af3b..2d3b64e658 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Data/DriverData.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Data/DriverData.cs
@@ -124,9 +124,14 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data
 
 			public MeterPerSecond MaxSpeed;
 
-			public Meter PreviewDistance;
+			public Meter PreviewDistanceUseCase1;
+
+			public Meter PreviewDistanceUseCase2;
 
 			public MeterPerSecond UnderSpeed;
+
+			public MeterPerSecond PCCEnableSpeed;
+			
 		}
 	}
 }
\ No newline at end of file
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/DefaultDriverStrategy.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/DefaultDriverStrategy.cs
index 9d6463d944..58037f0c86 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/DefaultDriverStrategy.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/DefaultDriverStrategy.cs
@@ -80,7 +80,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 
 		protected EcoRoll EcoRollState;
 		protected PCCSegments PCCSegments;
-		protected internal PCCStates PCCState;
+		protected internal PCCStates PCCState = PCCStates.OutsideSegment;
 
 
 		public DefaultDriverStrategy(IVehicleContainer container = null)
@@ -176,6 +176,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 			if (PCCSegments.Count > 0) {
 				if (Driver.DataBus.Distance > PCCSegments.Current.EndDistance) {
 					PCCSegments.MoveNext();
+					PCCState = PCCStates.OutsideSegment;
 				}
 			}
 		}
@@ -187,8 +188,9 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 			if (ADAS.PredictiveCruiseControl != PredictiveCruiseControlType.None) {
 				HandlePCC(absTime, targetVelocity);
 			}
-			if ((ADAS.PredictiveCruiseControl != PredictiveCruiseControlType.None && (PCCState == PCCStates.OutsideSegment || PCCState == PCCStates.WithinSegment)) ||
-				ADAS.EcoRoll != EcoRollType.None) {
+			if (ADAS.EcoRoll != EcoRollType.None &&
+				(PCCState == PCCStates.OutsideSegment || PCCState == PCCStates.WithinSegment)
+				) {
 				HandleEcoRoll(absTime, targetVelocity);
 			}
 
@@ -247,49 +249,64 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 		{
 			var dataBus = Driver.DataBus;
 			var distance = dataBus.Distance;
-			if (PCCSegments.Current != null && PCCSegments.Current.StartDistance < distance && PCCSegments.Current.EndDistance > distance) {
-				// within pcc-segment
-				PCCState = PCCStates.WithinSegment;
-			} else {
-				PCCState = PCCStates.OutsideSegment;
-			}
+			var withinPCCSegment = PCCSegments.Current != null && PCCSegments.Current.StartDistance < distance &&
+									PCCSegments.Current.EndDistance > distance;
+			//if (PCCSegments.Current != null && PCCSegments.Current.StartDistance < distance && PCCSegments.Current.EndDistance > distance) {
+			//	// within pcc-segment
+			//	//PCCState = PCCStates.WithinSegment;
+			//} else {
+			//	//PCCState = PCCStates.OutsideSegment;
+			//}
 			var vehicleSpeed = dataBus.VehicleSpeed;
-			if (PCCState == PCCStates.WithinSegment) {
+			if (withinPCCSegment) {
 				var currentEnergy = CalculateEnergy(dataBus.Altitude, vehicleSpeed, dataBus.TotalMass);
 
-				var end = PCCSegments.Current.EndDistance;
-				var endEnergy = PCCSegments.Current.EnergyEnd;
-				if ((distance + Driver.DriverData.PCC.PreviewDistance).IsSmallerOrEqual(end)) {
-					end = distance + Driver.DriverData.PCC.PreviewDistance;
-					var endCycleEntry = dataBus.CycleLookAhead(Driver.DriverData.PCC.PreviewDistance);
-					endEnergy = CalculateEnergy(endCycleEntry.Altitude, endCycleEntry.VehicleTargetSpeed, dataBus.TotalMass);
+				var endUseCase1 = PCCSegments.Current.EndDistance;
+				var endEnergyUseCase1 = PCCSegments.Current.EnergyEnd;
+				if ((distance + Driver.DriverData.PCC.PreviewDistanceUseCase1).IsSmallerOrEqual(endUseCase1)) {
+					endUseCase1 = distance + Driver.DriverData.PCC.PreviewDistanceUseCase1;
+					var endCycleEntry = dataBus.CycleLookAhead(Driver.DriverData.PCC.PreviewDistanceUseCase1);
+					endEnergyUseCase1 = CalculateEnergy(endCycleEntry.Altitude, endCycleEntry.VehicleTargetSpeed, dataBus.TotalMass);
 				}
 				var lowEnergy = PCCSegments.Current.EnergyMinSpeed;
 
-				var airDragForce = Driver.DataBus.AirDragResistance(vehicleSpeed, targetVelocity);
-
-				//var rollResistanceForce = Driver.DataBus.RollingResistance(
-				//	((targetAltitude - vehicleAltitude) / (actionEntry.Distance - Driver.DataBus.Distance))
-				//	.Value().SI<Radian>());
-				var rollResistanceForce = Driver.DataBus.RollingResistance(dataBus.RoadGradient);
-				var engineDragLoss = ADAS.EcoRoll == EcoRollType.None
-					? Driver.DataBus.EngineDragPower(Driver.DataBus.EngineSpeed)
-					: 0.SI<Watt>();
-				var gearboxLoss = Driver.DataBus.GearboxLoss();
-				var axleLoss = Driver.DataBus.AxlegearLoss();
-
-				var coastingForce = airDragForce + rollResistanceForce +
-									(gearboxLoss + axleLoss - engineDragLoss) / vehicleSpeed;
+				var coastingForce = CoastingForce(targetVelocity, vehicleSpeed);
 
 				var energyCoastingLow = (coastingForce * (PCCSegments.Current.DistanceMinSpeed - distance)).Cast<Joule>();
-				var energyCoastingEnd = (coastingForce * (end - distance)).Cast<Joule>();
+				var energyCoastingEndUseCase1 = (coastingForce * (endUseCase1 - distance)).Cast<Joule>();
 
 				var speedSufficient = vehicleSpeed.IsGreaterOrEqual(targetVelocity - Driver.DriverData.PCC.UnderSpeed);
 				var currentEnergyHigherThanMin = currentEnergy.IsGreaterOrEqual(lowEnergy + energyCoastingLow);
-				var currentEnergyHigherThanEnd = currentEnergy.IsGreaterOrEqual(endEnergy + energyCoastingEnd);
-				if (speedSufficient && currentEnergyHigherThanEnd && currentEnergyHigherThanMin) {
+				var currentEnergyHigherThanEndUseCase1 = currentEnergy.IsGreaterOrEqual(endEnergyUseCase1 + energyCoastingEndUseCase1);
+
+
+				var endUseCase2 = PCCSegments.Current.EndDistance;
+				var endEnergyUseCase2 = PCCSegments.Current.EnergyEnd;
+				if ((distance + Driver.DriverData.PCC.PreviewDistanceUseCase2).IsSmallerOrEqual(endUseCase1)) {
+					endUseCase2 = distance + Driver.DriverData.PCC.PreviewDistanceUseCase2;
+					var endCycleEntry = dataBus.CycleLookAhead(Driver.DriverData.PCC.PreviewDistanceUseCase2);
+					endEnergyUseCase2 = CalculateEnergy(endCycleEntry.Altitude, endCycleEntry.VehicleTargetSpeed, dataBus.TotalMass);
+				}
+
+				var energyCoastingEndUseCase2 = (coastingForce * (endUseCase2 - distance)).Cast<Joule>();
+
+				var beyondVLow = distance.IsGreaterOrEqual(PCCSegments.Current.DistanceMinSpeed);
+				var speedSufficientUseCase2 = vehicleSpeed.IsGreaterOrEqual(VectoMath.Max(targetVelocity - Driver.DriverData.PCC.UnderSpeed, Driver.DriverData.PCC.MinSpeed));
+				var currentEnergyHigherThanEndUseCase2 = currentEnergy.IsGreaterOrEqual(endEnergyUseCase2 + energyCoastingEndUseCase2);
+				
+
+				if (PCCState == PCCStates.OutsideSegment) {
+					PCCState = PCCStates.WithinSegment;
+				}
+				if (PCCState == PCCStates.WithinSegment && speedSufficient && currentEnergyHigherThanEndUseCase1 &&
+					currentEnergyHigherThanMin) {
 					PCCState = PCCStates.UseCase1;
 				}
+				if (PCCState == PCCStates.WithinSegment && speedSufficientUseCase2 && beyondVLow && currentEnergyHigherThanEndUseCase2) {
+					PCCState = PCCStates.UseCase2;
+				}
+			} else {
+				PCCState = PCCStates.OutsideSegment;
 			}
 			if (PCCState == PCCStates.UseCase1) {
 				if (vehicleSpeed <= targetVelocity - Driver.DriverData.PCC.UnderSpeed * 1.05) {
@@ -299,6 +316,11 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 					PCCState = PCCStates.WithinSegment;
 				}
 			}
+			if (PCCState == PCCStates.UseCase2) {
+				if (vehicleSpeed < Driver.DriverData.PCC.MinSpeed || vehicleSpeed > targetVelocity + 1.KMPHtoMeterPerSecond()) {
+					PCCState = PCCStates.WithinSegment;
+				}
+			}
 			if (PCCState == PCCStates.PCCinterrupt) {
 				if (vehicleSpeed >= targetVelocity - Driver.DriverData.PCC.UnderSpeed * 0.95) {
 					PCCState = PCCStates.UseCase1;
@@ -307,6 +329,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 
 			switch (PCCState) {
 				case PCCStates.UseCase1:
+				case PCCStates.UseCase2:
 					switch (ADAS.EcoRoll) {
 						case EcoRollType.None: break;
 						case EcoRollType.WithoutEngineStop:
@@ -320,7 +343,6 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 					}
 
 					break;
-				case PCCStates.UseCase2: break;
 				case PCCStates.OutsideSegment:
 				case PCCStates.WithinSegment:
 				case PCCStates.PCCinterrupt:
@@ -331,6 +353,26 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 			}
 		}
 
+		private Newton CoastingForce(MeterPerSecond targetVelocity, MeterPerSecond vehicleSpeed)
+		{
+			var dataBus = Driver.DataBus;
+			var airDragForce = Driver.DataBus.AirDragResistance(vehicleSpeed, targetVelocity);
+
+			//var rollResistanceForce = Driver.DataBus.RollingResistance(
+			//	((targetAltitude - vehicleAltitude) / (actionEntry.Distance - Driver.DataBus.Distance))
+			//	.Value().SI<Radian>());
+			var rollResistanceForce = Driver.DataBus.RollingResistance(dataBus.RoadGradient);
+			var engineDragLoss = ADAS.EcoRoll == EcoRollType.None
+				? Driver.DataBus.EngineDragPower(Driver.DataBus.EngineSpeed)
+				: 0.SI<Watt>();
+			var gearboxLoss = Driver.DataBus.GearboxLoss();
+			var axleLoss = Driver.DataBus.AxlegearLoss();
+
+			var coastingForce = airDragForce + rollResistanceForce +
+								(gearboxLoss + axleLoss - engineDragLoss) / vehicleSpeed;
+			return coastingForce;
+		}
+
 		private Joule CalculateEnergy(Meter altitude, MeterPerSecond velocity, Kilogram mass)
 		{
 			return (mass * Physics.GravityAccelleration * altitude).Cast<Joule>() + mass * velocity * velocity / 2;
@@ -892,7 +934,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 			Second absTime, Meter ds, MeterPerSecond targetVelocity, Radian gradient,
 			bool prohibitOverspeed, MeterPerSecond velocityWithOverspeed, DebugData debug)
 		{
-			if (DriverStrategy.PCCState == DefaultDriverStrategy.PCCStates.UseCase1) {
+			if (DriverStrategy.PCCState == DefaultDriverStrategy.PCCStates.UseCase1 || DriverStrategy.PCCState == DefaultDriverStrategy.PCCStates.UseCase2) {
 				return Driver.DrivingActionCoast(absTime, ds, targetVelocity, gradient);
 			}
 			IResponse first;
diff --git a/VectoCore/VectoCore/VectoCore.csproj b/VectoCore/VectoCore/VectoCore.csproj
index 48d4d39853..f7b4ea736b 100644
--- a/VectoCore/VectoCore/VectoCore.csproj
+++ b/VectoCore/VectoCore/VectoCore.csproj
@@ -262,6 +262,7 @@
     <Compile Include="Models\SimulationComponent\Impl\StopStartCombustionEngine.cs" />
     <Compile Include="Models\Simulation\DataBus\IEngineControl.cs" />
     <Compile Include="Models\Simulation\Impl\PCCEcoRollEngineStopPreprocessor.cs" />
+    <Compile Include="Models\Simulation\Impl\PCCSegmentPreprocessor.cs" />
     <Compile Include="Models\Simulation\Impl\SimplePowertrainContainer.cs" />
     <Compile Include="Models\Simulation\ISimulationPreprocessor.cs" />
     <Compile Include="Models\Simulation\ISimulatorFactory.cs" />
-- 
GitLab