From 7930a5a7764fc90a50d8020788a5c83a53228cdf Mon Sep 17 00:00:00 2001
From: Markus Quaritsch <markus.quaritsch@tugraz.at>
Date: Thu, 22 Jul 2021 14:38:35 +0200
Subject: [PATCH] finetuning PEV shift strategy

---
 VectoCommon/VectoCommon/Models/IResponse.cs   |   1 +
 .../AbstractSimulationDataAdapter.cs          |  13 +-
 .../Models/Declaration/DeclarationData.cs     |  28 +-
 .../Data/ShiftStrategyParameters.cs           |   6 +-
 .../Data/ElectricMotor/ElectricMotorData.cs   |   2 +-
 .../ElectricMotorFullLoadCurve.cs             |  10 +-
 .../Impl/BatteryElectricMotorController.cs    |   2 +-
 .../SimulationComponent/Impl/ElectricMotor.cs |   5 +
 .../Impl/PEVAMTShiftStrategy.cs               | 909 ++++--------------
 .../BatteryElectric/BatteryElectricTest.cs    |  20 +-
 .../Models/Declaration/ShiftPolygonTest.cs    |  73 +-
 .../GenericVehicleB2/3speedEV.vgbx            |  54 ++
 .../GenericVehicleB2/BEV_ENG_3speed.vecto     |  45 +
 VectoCore/VectoCoreTest/VectoCoreTest.csproj  |   6 +
 14 files changed, 409 insertions(+), 765 deletions(-)
 create mode 100644 VectoCore/VectoCoreTest/TestData/BatteryElectric/GenericVehicleB2/3speedEV.vgbx
 create mode 100644 VectoCore/VectoCoreTest/TestData/BatteryElectric/GenericVehicleB2/BEV_ENG_3speed.vecto

diff --git a/VectoCommon/VectoCommon/Models/IResponse.cs b/VectoCommon/VectoCommon/Models/IResponse.cs
index c3ddf1fdcb..ad0e0d1d5d 100644
--- a/VectoCommon/VectoCommon/Models/IResponse.cs
+++ b/VectoCommon/VectoCommon/Models/IResponse.cs
@@ -168,6 +168,7 @@ namespace TUGraz.VectoCommon.Models
 		public NewtonMeter MaxDriveTorqueEM { get; set; }
 		public NewtonMeter MaxRecuperationTorqueEM { get; set; }
 		public NewtonMeter TorqueRequestEmMap { get; set; }
+		public bool DeRatingActive { get; set; }
 	}
 
 
diff --git a/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/AbstractSimulationDataAdapter.cs b/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/AbstractSimulationDataAdapter.cs
index e57bba3134..584a23ad1f 100644
--- a/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/AbstractSimulationDataAdapter.cs
+++ b/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/AbstractSimulationDataAdapter.cs
@@ -368,11 +368,14 @@ namespace TUGraz.VectoCore.InputData.Reader.DataObjectAdapter
 			}
 
 			// create new full-load curve with values closest to zero.
-			return new ElectricMotorFullLoadCurve(motorSpeeds.OrderBy(x => x.Value()).Distinct().Select(x => new ElectricMotorFullLoadCurve.FullLoadEntry() {
-				MotorSpeed = x,
-				FullDriveTorque = VectoMath.Max(fullLoadCurve.FullLoadDriveTorque(x), maxTorqueCurve.FullLoadDriveTorque(x)),
-				FullGenerationTorque = VectoMath.Min(fullLoadCurve.FullGenerationTorque(x), maxTorqueCurve.FullGenerationTorque(x)),
-			}).ToList());
+			return new ElectricMotorFullLoadCurve(motorSpeeds.OrderBy(x => x.Value()).Distinct().Select(x =>
+				new ElectricMotorFullLoadCurve.FullLoadEntry() {
+					MotorSpeed = x,
+					FullDriveTorque = VectoMath.Max(fullLoadCurve.FullLoadDriveTorque(x),
+						maxTorqueCurve.FullLoadDriveTorque(x)),
+					FullGenerationTorque = VectoMath.Min(fullLoadCurve.FullGenerationTorque(x),
+						maxTorqueCurve.FullGenerationTorque(x)),
+				}).ToList());
 		}
 
 		
diff --git a/VectoCore/VectoCore/Models/Declaration/DeclarationData.cs b/VectoCore/VectoCore/Models/Declaration/DeclarationData.cs
index ee8c57bc53..a60b1be4fd 100644
--- a/VectoCore/VectoCore/Models/Declaration/DeclarationData.cs
+++ b/VectoCore/VectoCore/Models/Declaration/DeclarationData.cs
@@ -622,7 +622,7 @@ namespace TUGraz.VectoCore.Models.Declaration
 
 			public static ShiftPolygon ComputeElectricMotorShiftPolygon(int gearIdx,
 				ElectricMotorFullLoadCurve fullLoadCurve, double emRatio, IList<ITransmissionInputData> gears,
-				double axlegearRatio, Meter dynamicTyreRadius)
+				double axlegearRatio, Meter dynamicTyreRadius, PerSecond downshiftMaxSpeed = null)
 			{
 				if (gears.Count < 2) {
 					throw new VectoException("ComputeShiftPolygon needs at least 2 gears. {0} gears given.", gears.Count);
@@ -631,7 +631,7 @@ namespace TUGraz.VectoCore.Models.Declaration
 				var downShift = new List<ShiftPolygon.ShiftPolygonEntry>();
 				var upShift = new List<ShiftPolygon.ShiftPolygonEntry>();
 				if (gearIdx > 0) {
-					var nMax = fullLoadCurve.NP80low;
+					var nMax = downshiftMaxSpeed ?? fullLoadCurve.NP80low;
 					var nMin = 0.1 * fullLoadCurve.RatedSpeed;
 
 					downShift.AddRange(DownshiftLineDrive(fullLoadCurve, nMin, nMax));
@@ -673,22 +673,26 @@ namespace TUGraz.VectoCore.Models.Declaration
 							nMin));
 					
 				} else {
-					if (downShiftPoints.Min(x => x.X) > nMin) {
+					retVal.Add(
+						new ShiftPolygon.ShiftPolygonEntry(
+							fullLoadCurve.MaxDriveTorque * 1.1,
+							nMax));
+					if (downShiftPoints.Max(x => x.X) < nMax) {
 						retVal.Add(
 							new ShiftPolygon.ShiftPolygonEntry(
-								fullLoadCurve.FullLoadDriveTorque(nMin) * ShiftPolygonEngineFldMargin,
+								fullLoadCurve.FullLoadDriveTorque(nMax) * ShiftPolygonEngineFldMargin,
 								nMax));
 					}
 
 					retVal.AddRange(
 						downShiftPoints.Select(
 							x => new ShiftPolygon.ShiftPolygonEntry(
-								x.Y.SI<NewtonMeter>() * ShiftPolygonEngineFldMargin, x.X.SI<PerSecond>())));
-					if (downShiftPoints.Max(x => x.X) < nMax) {
+								x.Y.SI<NewtonMeter>(), x.X.SI<PerSecond>())).OrderByDescending(x => x.AngularSpeed.Value()));
+					if (downShiftPoints.Min(x => x.X) > nMin) {
 						retVal.Add(
 							new ShiftPolygon.ShiftPolygonEntry(
-								fullLoadCurve.FullLoadDriveTorque(nMax) * ShiftPolygonEngineFldMargin,
-								nMax));
+								fullLoadCurve.FullLoadDriveTorque(nMin) * ShiftPolygonEngineFldMargin,
+								nMin));
 					}
 				}
 
@@ -724,19 +728,23 @@ namespace TUGraz.VectoCore.Models.Declaration
 						retVal.Add(
 							new ShiftPolygon.ShiftPolygonEntry(
 								fullLoadCurve.FullGenerationTorque(nMin) * ShiftPolygonEngineFldMargin,
-								nMax));
+								nMin));
 					}
 
 					retVal.AddRange(
 						downShiftPoints.Select(
 							x => new ShiftPolygon.ShiftPolygonEntry(
-								x.Y.SI<NewtonMeter>() * ShiftPolygonEngineFldMargin, x.X.SI<PerSecond>())));
+								x.Y.SI<NewtonMeter>(), x.X.SI<PerSecond>())));
 					if (downShiftPoints.Max(x => x.X) < nMax) {
 						retVal.Add(
 							new ShiftPolygon.ShiftPolygonEntry(
 								fullLoadCurve.FullGenerationTorque(nMax) * ShiftPolygonEngineFldMargin,
 								nMax));
 					}
+					retVal.Add(
+						new ShiftPolygon.ShiftPolygonEntry(
+							fullLoadCurve.MaxGenerationTorque * 1.1,
+							nMax));
 				}
 
 				return retVal;
diff --git a/VectoCore/VectoCore/Models/Simulation/Data/ShiftStrategyParameters.cs b/VectoCore/VectoCore/Models/Simulation/Data/ShiftStrategyParameters.cs
index 03638744c9..bc6264d349 100644
--- a/VectoCore/VectoCore/Models/Simulation/Data/ShiftStrategyParameters.cs
+++ b/VectoCore/VectoCore/Models/Simulation/Data/ShiftStrategyParameters.cs
@@ -10,7 +10,8 @@ namespace TUGraz.VectoCore.Models.Simulation.Data {
 	{
 		public ShiftStrategyParameters()
 		{
-			TargetSpeedBrakeNorm = 0.7;
+			PEV_TargetSpeedBrakeNorm = 0.7;
+			PEV_DeRatedDownshiftSpeedFactor = 1;
 		}
 
 		public MeterPerSecond StartVelocity { get; internal set; }
@@ -106,6 +107,7 @@ namespace TUGraz.VectoCore.Models.Simulation.Data {
 		public double[] LoadStageThresoldsUp { get; set; }
 		public double[] LoadStageThresoldsDown { get; set; }
 		public double[][] ShiftSpeedsTCToLocked { get; set; }
-		public double TargetSpeedBrakeNorm { get; set; }
+		public double PEV_TargetSpeedBrakeNorm { get; set; }
+		public double PEV_DeRatedDownshiftSpeedFactor { get; set; }
 	}
 }
\ No newline at end of file
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Data/ElectricMotor/ElectricMotorData.cs b/VectoCore/VectoCore/Models/SimulationComponent/Data/ElectricMotor/ElectricMotorData.cs
index 56c6427664..e2dbfde141 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Data/ElectricMotor/ElectricMotorData.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Data/ElectricMotor/ElectricMotorData.cs
@@ -55,7 +55,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data
 			get
 			{
 				return _maxSpeed ?? (_maxSpeed = VoltageLevels
-					.Min(v => v.EfficiencyMap.MaxSpeed));
+					.Min(v => VectoMath.Min(v.EfficiencyMap.MaxSpeed, v.FullLoadCurve.MaxSpeed)));
 			}
 		}
 
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Data/ElectricMotor/ElectricMotorFullLoadCurve.cs b/VectoCore/VectoCore/Models/SimulationComponent/Data/ElectricMotor/ElectricMotorFullLoadCurve.cs
index 930d5e84b8..011f82f9c7 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Data/ElectricMotor/ElectricMotorFullLoadCurve.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Data/ElectricMotor/ElectricMotorFullLoadCurve.cs
@@ -107,7 +107,15 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.ElectricMotor {
 		{
 			var max = new Tuple<PerSecond, Watt>(0.SI<PerSecond>(), 0.SI<Watt>());
 			for (var idx = 1; idx < FullLoadEntries.Count; idx++) {
-				var currentMax = FindMaxPower(FullLoadEntries[idx - 1], FullLoadEntries[idx]);
+				var entry2 = FullLoadEntries[idx];
+				if (FullLoadEntries[idx].MotorSpeed > MaxSpeed) {
+					entry2 = new FullLoadEntry() {
+						MotorSpeed = MaxSpeed,
+						FullDriveTorque =  FullLoadDriveTorque(MaxSpeed),
+						FullGenerationTorque = FullGenerationTorque(MaxSpeed)
+					};
+				}
+				var currentMax = FindMaxPower(FullLoadEntries[idx - 1], entry2);
 				if (currentMax.Item2 > max.Item2) {
 					max = currentMax;
 				}
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/BatteryElectricMotorController.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/BatteryElectricMotorController.cs
index dbdf8745f5..9a3609cfb9 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/BatteryElectricMotorController.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/BatteryElectricMotorController.cs
@@ -32,7 +32,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl {
 					? 0.SI<NewtonMeter>()
 					: Formulas.InertiaPower(currOutAngularVelocity, prevOutAngularVelocity, ElectricMotorData.Inertia, dt) / avgSpeed;
 				//var dragTorque = ElectricMotorData.DragCurve.Lookup()
-				return (-inertiaTorqueLoss).LimitTo(maxDriveTorque, maxRecuperationTorque);
+				return (-inertiaTorqueLoss); //.LimitTo(maxDriveTorque, maxRecuperationTorque);
 			}
 			if (DataBus.DriverInfo.DrivingAction == DrivingAction.Coast ||
 				DataBus.DriverInfo.DrivingAction == DrivingAction.Roll) {
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/ElectricMotor.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/ElectricMotor.cs
index 264ba3812f..17da629f52 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/ElectricMotor.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/ElectricMotor.cs
@@ -289,6 +289,10 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 
 			IResponse retVal = null;
 			if (NextComponent == null) {
+				if (electricSupplyResponse.MaxPowerDrive.IsEqual(0.SI<Watt>(), 100.SI<Watt>())) {
+					retVal = new ResponseBatteryEmpty(this, electricSupplyResponse);
+					return retVal;
+				}
 				// electric motor only
 				var remainingPower = inTorqueDt * avgDtSpeed;
 				if (dryRun) {
@@ -344,6 +348,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 			retVal.ElectricMotor.MaxRecuperationTorqueEM = maxRecuperationTorqueEm;
 			retVal.ElectricMotor.AngularVelocity = avgEmSpeed;
 			retVal.ElectricMotor.AvgDrivetrainSpeed = avgDtSpeed;
+			retVal.ElectricMotor.DeRatingActive = DeRatingActive;
 
 			retVal.ElectricMotor.TorqueRequest = outTorque;
 			retVal.ElectricMotor.TorqueRequestEmMap = emTorqueMap;
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/PEVAMTShiftStrategy.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/PEVAMTShiftStrategy.cs
index bdaaa0702b..b0f63c7da7 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/PEVAMTShiftStrategy.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/PEVAMTShiftStrategy.cs
@@ -6,6 +6,7 @@ using TUGraz.VectoCommon.InputData;
 using TUGraz.VectoCommon.Models;
 using TUGraz.VectoCommon.Utils;
 using TUGraz.VectoCore.Configuration;
+using TUGraz.VectoCore.InputData.Reader.DataObjectAdapter;
 using TUGraz.VectoCore.Models.Connector.Ports.Impl;
 using TUGraz.VectoCore.Models.Declaration;
 using TUGraz.VectoCore.Models.Simulation;
@@ -38,9 +39,10 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 		private SI TransmissionRatio;
 		private ShiftStrategyParameters GearshiftParams;
 		private GearList GearList;
+        private Dictionary<uint, ShiftPolygon> DeRatedShiftpolygons;
 
 
-		public static string Name => "AMT - EffShift (BEV)";
+        public static string Name => "AMT - EffShift (BEV)";
 
 
 		protected bool DriveOffStandstill { get; set; }
@@ -48,6 +50,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 		public PEVAMTShiftStrategy(IVehicleContainer dataBus)
 		{
 			var runData = dataBus.RunData;
+			shiftStrategyParameters = runData.GearshiftParameters;
 			if (runData.VehicleData == null) {
 				return;
 			}
@@ -64,16 +67,20 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 			TransmissionRatio = runData.AxleGearData.AxleGear.Ratio *
 									(runData.AngledriveData?.Angledrive.Ratio ?? 1.0) /
 									runData.VehicleData.DynamicTyreRadius;
-			//var minEngineSpeed = (runData.EngineData.FullLoadCurves[0].RatedSpeed - runData.EngineData.IdleSpeed) *
-			//	Constants.SimulationSettings.ClutchClosingSpeedNorm + runData.EngineData.IdleSpeed;
+            //var minEngineSpeed = (runData.EngineData.FullLoadCurves[0].RatedSpeed - runData.EngineData.IdleSpeed) *
+            //    Constants.SimulationSettings.ClutchClosingSpeedNorm + runData.EngineData.IdleSpeed;
 
-			shiftStrategyParameters = runData.GearshiftParameters;
+            
 			
 			if (shiftStrategyParameters == null) {
 				throw new VectoException("Parameters for shift strategy missing!");
 			}
 			SetupVelocityDropPreprocessor(dataBus);
-		}
+
+            DeRatedShiftpolygons = CalculateDeratedShiftLines(runData.ElectricMachinesData.First(x => x.Item1 == PowertrainPosition.BatteryElectricE2).Item2,
+                runData.GearboxData.InputData.Gears, runData.VehicleData.DynamicTyreRadius,
+                runData.AxleGearData.AxleGear.Ratio, runData.GearboxData.Type);
+        }
 
 		private void SetupVelocityDropPreprocessor(IVehicleContainer dataBus)
 		{
@@ -106,11 +113,60 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 			IList<ITransmissionInputData> gearboxGears, CombustionEngineData engineData, double axlegearRatio, Meter dynamicTyreRadius,
 			ElectricMotorData electricMotorData = null)
 		{
-			return DeclarationData.Gearbox.ComputeElectricMotorShiftPolygon(i, electricMotorData.EfficiencyData.VoltageLevels.First().FullLoadCurve, electricMotorData.RatioADC, gearboxGears, axlegearRatio, dynamicTyreRadius);
+			return ComputeDeclarationShiftPolygon(i, gearboxGears, axlegearRatio, dynamicTyreRadius, electricMotorData,
+				null);
+		}
+
+
+		public ShiftPolygon ComputeDeclarationShiftPolygon(int i,
+			IList<ITransmissionInputData> gearboxGears, double axlegearRatio,
+			Meter dynamicTyreRadius,
+			ElectricMotorData electricMotorData , PerSecond downshiftMaxSpeed )
+		{
+			return DeclarationData.Gearbox.ComputeElectricMotorShiftPolygon(i,
+				electricMotorData.EfficiencyData.VoltageLevels.First().FullLoadCurve, electricMotorData.RatioADC,
+				gearboxGears, axlegearRatio, dynamicTyreRadius, downshiftMaxSpeed);
 		}
 
 		#endregion
 
+		protected internal Dictionary<uint, ShiftPolygon> CalculateDeratedShiftLines(ElectricMotorData em,
+			IList<ITransmissionInputData> gearData, Meter rDyn, double axleGearRatio, GearboxType gearboxType)
+		{
+			var retVal = new Dictionary<uint, ShiftPolygon>();
+			var emFld = em.EfficiencyData.VoltageLevels.First().FullLoadCurve;
+			var contTqFld = new ElectricMotorFullLoadCurve(new List<ElectricMotorFullLoadCurve.FullLoadEntry>() {
+				new ElectricMotorFullLoadCurve.FullLoadEntry() {
+					MotorSpeed = 0.RPMtoRad(),
+					FullDriveTorque = -em.ContinuousTorque,
+					FullGenerationTorque = em.ContinuousTorque
+				},
+				new ElectricMotorFullLoadCurve.FullLoadEntry() {
+					MotorSpeed = 1.1 * emFld.MaxSpeed,
+					FullDriveTorque = -em.ContinuousTorque,
+					FullGenerationTorque = em.ContinuousTorque
+				}
+			});
+			var limitedFld = AbstractSimulationDataAdapter.IntersectEMFullLoadCurves(emFld, contTqFld);
+			var limitedEm = new ElectricMotorData() {
+				EfficiencyData = new VoltageLevelData() {
+					VoltageLevels = new List<ElectricMotorVoltageLevelData>() {
+						new ElectricMotorVoltageLevelData() {
+							FullLoadCurve = limitedFld
+						}
+					}
+				}
+			};
+			for (var i = 0u; i < gearData.Count; i++) {
+				var shiftPolygon = ComputeDeclarationShiftPolygon((int)i,
+					gearData, axleGearRatio,
+					rDyn,  limitedEm, shiftStrategyParameters.PEV_DeRatedDownshiftSpeedFactor * emFld.RatedSpeed);
+				retVal[i + 1] = shiftPolygon;
+			}
+
+			return retVal;
+		}
+
 		#region Implementation of IShiftStrategy
 
 		public bool ShiftRequired(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, NewtonMeter inTorque,
@@ -205,7 +261,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 		{
 			var nextGear = currentGear;
 			// upshift
-			if (IsAboveUpShiftCurve(currentGear, inTorque, inAngularVelocity)) {
+			if (IsAboveUpShiftCurve(currentGear, inTorque, inAngularVelocity, r.ElectricMotor.DeRatingActive)) {
 				nextGear = GearList.Successor(currentGear);
 
 				while (GearList.HasSuccessor(nextGear)) {
@@ -224,7 +280,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 					var reserve = 1 - inTorque / maxTorque;
 
 					if (reserve >= 0 /*ModelData.TorqueReserve */ &&
-						IsAboveDownShiftCurve(nextGear, inTorque, inAngularVelocity)) {
+						IsAboveDownShiftCurve(nextGear, inTorque, inAngularVelocity, r.ElectricMotor.DeRatingActive)) {
 						continue;
 					}
 
@@ -236,30 +292,40 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 			return nextGear;
 		}
 
-		protected virtual GearshiftPosition CheckEarlyUpshift(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, GearshiftPosition currentGear, IResponse response1)
+		protected virtual GearshiftPosition CheckEarlyUpshift(Second absTime, Second dt, NewtonMeter outTorque,
+			PerSecond outAngularVelocity, GearshiftPosition currentGear, IResponse resp)
 		{
-			var estimatedVelocityPostShift = VelocityDropData.Interpolate(DataBus.VehicleInfo.VehicleSpeed, DataBus.DrivingCycleInfo.RoadGradient ?? 0.SI<Radian>());
-			if (!estimatedVelocityPostShift.IsGreater(DeclarationData.GearboxTCU.MIN_SPEED_AFTER_TRACTION_INTERRUPTION)) {
+			var estimatedVelocityPostShift = VelocityDropData.Interpolate(DataBus.VehicleInfo.VehicleSpeed,
+				DataBus.DrivingCycleInfo.RoadGradient ?? 0.SI<Radian>());
+			if (!estimatedVelocityPostShift.IsGreater(DeclarationData.GearboxTCU.MIN_SPEED_AFTER_TRACTION_INTERRUPTION)
+			) {
 				return currentGear;
 			}
 
 			var vDrop = DataBus.VehicleInfo.VehicleSpeed - estimatedVelocityPostShift;
-			var vehicleSpeedPostShift = DataBus.VehicleInfo.VehicleSpeed - vDrop * shiftStrategyParameters.VelocityDropFactor;
+			var vehicleSpeedPostShift =
+				DataBus.VehicleInfo.VehicleSpeed - vDrop * shiftStrategyParameters.VelocityDropFactor;
+
+			var totalTransmissionRatio =
+				DataBus.ElectricMotorInfo(PowertrainPosition.BatteryElectricE2).ElectricMotorSpeed /
+				DataBus.VehicleInfo.VehicleSpeed;
 
-			var totalTransmissionRatio = DataBus.ElectricMotorInfo(PowertrainPosition.BatteryElectricE2).ElectricMotorSpeed / DataBus.VehicleInfo.VehicleSpeed;
-			
 			var results = new List<Tuple<GearshiftPosition, double>>();
-			foreach (var tryNextGear in GearList.IterateGears(GearList.Successor(currentGear), GearList.Successor(currentGear, (uint)shiftStrategyParameters.AllowedGearRangeFC))) {
+			foreach (var tryNextGear in GearList.IterateGears(GearList.Successor(currentGear),
+				GearList.Successor(currentGear, (uint)shiftStrategyParameters.AllowedGearRangeFC))) {
 				var response = RequestDryRunWithGear(absTime, dt, outTorque, outAngularVelocity, tryNextGear);
 
 				var inAngularVelocity = GearboxModelData.Gears[tryNextGear.Gear].Ratio * outAngularVelocity;
 				var inTorque = response.ElectricMotor.PowerRequest / inAngularVelocity;
 
-				if (IsBelowDownShiftCurve(tryNextGear, inTorque, inAngularVelocity)) {
+				if (IsBelowDownShiftCurve(tryNextGear, inTorque, inAngularVelocity, resp.ElectricMotor.DeRatingActive)) {
 					continue;
 				}
 
-				var estimatedEngineSpeed = (vehicleSpeedPostShift * (totalTransmissionRatio / GearboxModelData.Gears[currentGear.Gear].Ratio * GearboxModelData.Gears[tryNextGear.Gear].Ratio)).Cast<PerSecond>();
+				var estimatedEngineSpeed = (vehicleSpeedPostShift * (totalTransmissionRatio /
+						GearboxModelData.Gears[currentGear.Gear].Ratio *
+						GearboxModelData.Gears[tryNextGear.Gear].Ratio))
+					.Cast<PerSecond>();
 				if (estimatedEngineSpeed.IsSmaller(shiftStrategyParameters.MinEngineSpeedPostUpshift)) {
 					continue;
 				}
@@ -293,9 +359,6 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 			}
 
 			return currentGear;
-			//return fcUpshiftPossible
-			//	? currentGear
-			//	: base.CheckEarlyUpshift(absTime, dt, outTorque, outAngularVelocity, currentGear, response1);
 		}
 
 
@@ -311,10 +374,13 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 				return currentGear;
 			}
 
+			if (response.ElectricMotor.DeRatingActive) {
+
+			}
 			// check with shiftline
 			if (response.ElectricMotor.TorqueRequestEmMap != null && IsBelowDownShiftCurve(currentGear,
 				response.ElectricMotor.TorqueRequestEmMap,
-				response.ElectricMotor.AngularVelocity)) {
+				response.ElectricMotor.AngularVelocity, response.ElectricMotor.DeRatingActive)) {
 
 				if (DataBus.DriverInfo.DriverBehavior == DrivingBehavior.Braking) {
 					var brakingGear = SelectBrakingGear(currentGear, response);
@@ -322,6 +388,31 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 				}
 
 				var nextGear = GearList.Predecessor(currentGear);
+
+				while (GearList.HasPredecessor(nextGear)) {
+					// check skip gears
+					nextGear = GearList.Predecessor(nextGear);
+					var resp = RequestDryRunWithGear(absTime, dt, outTorque, outAngularVelocity, nextGear);
+
+					inAngularVelocity = resp.ElectricMotor.AngularVelocity;
+					inTorque = resp.ElectricMotor.PowerRequest / inAngularVelocity;
+
+					var maxTorque = VectoMath.Min(-resp.ElectricMotor.MaxDriveTorque,
+						!nextGear.Equals(GearList.First())
+							? GearboxModelData.Gears[nextGear.Gear].ShiftPolygon
+								.InterpolateDownshift(resp.Engine.EngineSpeed)
+							: double.MaxValue.SI<NewtonMeter>());
+					var reserve = 1 - inTorque / maxTorque;
+
+					if (reserve >= 0 /*ModelData.TorqueReserve */ &&
+						IsBelowDownShiftCurve(nextGear, inTorque, inAngularVelocity, resp.ElectricMotor.DeRatingActive)) {
+						continue;
+					}
+
+					nextGear = GearList.Successor(nextGear);
+					break;
+				}
+
 				return nextGear;
 			}
 
@@ -353,7 +444,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 
 			var ratedSpeed = VoltageLevels.VoltageLevels.First().FullLoadCurve.RatedSpeed;
 			var maxSpeedNorm = VoltageLevels.MaxSpeed / ratedSpeed;
-			var targetMotor = (shiftStrategyParameters.TargetSpeedBrakeNorm * (maxSpeedNorm - 1) + 1) * ratedSpeed;
+			var targetMotor = (shiftStrategyParameters.PEV_TargetSpeedBrakeNorm * (maxSpeedNorm - 1) + 1) * ratedSpeed;
 
 			if (candidates.Any(x => x.Value > targetMotor && x.Value < VoltageLevels.MaxSpeed)) {
 				var best = candidates.Where(x => x.Value > targetMotor && x.Value < VoltageLevels.MaxSpeed)
@@ -365,21 +456,25 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 			return retVal;
 		}
 
-		protected virtual GearshiftPosition CheckEarlyDownshift(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, GearshiftPosition currentGear, IResponse response1)
+		protected virtual GearshiftPosition CheckEarlyDownshift(Second absTime, Second dt, NewtonMeter outTorque,
+			PerSecond outAngularVelocity, GearshiftPosition currentGear, IResponse resp)
 		{
-			var estimatedVelocityPostShift = VelocityDropData.Interpolate(DataBus.VehicleInfo.VehicleSpeed, DataBus.DrivingCycleInfo.RoadGradient ?? 0.SI<Radian>());
-			if (!estimatedVelocityPostShift.IsGreater(DeclarationData.GearboxTCU.MIN_SPEED_AFTER_TRACTION_INTERRUPTION)) {
+			var estimatedVelocityPostShift = VelocityDropData.Interpolate(DataBus.VehicleInfo.VehicleSpeed,
+				DataBus.DrivingCycleInfo.RoadGradient ?? 0.SI<Radian>());
+			if (!estimatedVelocityPostShift.IsGreater(DeclarationData.GearboxTCU.MIN_SPEED_AFTER_TRACTION_INTERRUPTION)
+			) {
 				return currentGear;
 			}
 
 			var results = new List<Tuple<GearshiftPosition, double>>();
-			foreach (var tryNextGear in GearList.IterateGears(GearList.Predecessor(currentGear), GearList.Predecessor(currentGear, (uint)shiftStrategyParameters.AllowedGearRangeFC))) {
+			foreach (var tryNextGear in GearList.IterateGears(GearList.Predecessor(currentGear),
+				GearList.Predecessor(currentGear, (uint)shiftStrategyParameters.AllowedGearRangeFC))) {
 
 				var response = RequestDryRunWithGear(absTime, dt, outTorque, outAngularVelocity, tryNextGear);
 				var inAngularVelocity = GearboxModelData.Gears[tryNextGear.Gear].Ratio * outAngularVelocity;
 				var inTorque = response.ElectricMotor.PowerRequest / inAngularVelocity;
 
-				if (IsAboveUpShiftCurve(tryNextGear, inTorque, inAngularVelocity)) {
+				if (IsAboveUpShiftCurve(tryNextGear, inTorque, inAngularVelocity, response.ElectricMotor.DeRatingActive)) {
 					continue;
 				}
 
@@ -399,7 +494,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 				: shiftStrategyParameters.RatingFactorCurrentGear;
 
 			if (minFc.Item2.IsGreater(fcCurrent * ratingFactor)) {
-					return minFc.Item1;
+				return minFc.Item1;
 			}
 
 			return currentGear;
@@ -460,7 +555,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 				var inTorque = response.ElectricMotor.PowerRequest / inAngularSpeed;
 
 				// if in shift curve and torque reserve is provided: return the current gear
-				if (!IsBelowDownShiftCurve(gear, inTorque, inAngularSpeed) && !IsAboveUpShiftCurve(gear, inTorque, inAngularSpeed)) {
+				if (!IsBelowDownShiftCurve(gear, inTorque, inAngularSpeed, false) && !IsAboveUpShiftCurve(gear, inTorque, inAngularSpeed, false)) {
 					_nextGear = gear;
 					return gear;
 				}
@@ -514,28 +609,47 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 		}
 
 
-		protected bool IsBelowDownShiftCurve(GearshiftPosition gear, NewtonMeter inTorque, PerSecond inEngineSpeed)
+		protected bool IsBelowDownShiftCurve(GearshiftPosition gear, NewtonMeter inTorque, PerSecond inEngineSpeed,
+			bool deRatingActive)
 		{
 			if (!GearList.HasPredecessor(gear)) {
 				return false;
 			}
-			return IsBelowDownshiftCurve(GearboxModelData.Gears[gear.Gear].ShiftPolygon, inTorque, inEngineSpeed);
+
+			var shiftPolygon = GetShiftpolygon(gear, deRatingActive);
+			return IsBelowDownshiftCurve(shiftPolygon, inTorque, inEngineSpeed);
 		}
 
-		protected bool IsAboveDownShiftCurve(GearshiftPosition gear, NewtonMeter inTorque, PerSecond inEngineSpeed)
+		
+
+		protected bool IsAboveDownShiftCurve(GearshiftPosition gear, NewtonMeter inTorque, PerSecond inEngineSpeed,
+			bool deRatingActive)
 		{
 			if (!GearList.HasPredecessor(gear)) {
 				return true;
 			}
-			return GearboxModelData.Gears[gear.Gear].ShiftPolygon.IsAboveDownshiftCurve(inTorque, inEngineSpeed);
+			var shiftPolygon = GetShiftpolygon(gear, deRatingActive);
+
+			return IsAboveDownshiftCurve(shiftPolygon, inTorque, inEngineSpeed);
 		}
 
-		protected bool IsAboveUpShiftCurve(GearshiftPosition gear, NewtonMeter inTorque, PerSecond inEngineSpeed)
+		protected bool IsAboveUpShiftCurve(GearshiftPosition gear, NewtonMeter inTorque, PerSecond inEngineSpeed,
+			bool deRatingActive)
 		{
 			if (!GearList.HasSuccessor(gear)) {
 				return false;
 			}
-			return GearboxModelData.Gears[gear.Gear].ShiftPolygon.IsAboveUpshiftCurve(inTorque, inEngineSpeed);
+
+			var shiftPolygon = GetShiftpolygon(gear, deRatingActive);
+			return shiftPolygon.IsAboveUpshiftCurve(inTorque, inEngineSpeed);
+		}
+
+		private ShiftPolygon GetShiftpolygon(GearshiftPosition gear, bool deRatingActive)
+		{
+            if (deRatingActive) {
+                return DeRatedShiftpolygons[gear.Gear];
+            }
+            return GearboxModelData.Gears[gear.Gear].ShiftPolygon;
 		}
 
 		protected bool IsBelowDownshiftCurve(ShiftPolygon shiftPolygon, NewtonMeter emTorque, PerSecond emSpeed)
@@ -554,6 +668,22 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 			return false;
 		}
 
+		protected bool IsAboveDownshiftCurve(ShiftPolygon shiftPolygon, NewtonMeter emTorque, PerSecond emSpeed)
+		{
+			foreach (var entry in shiftPolygon.Downshift.Pairwise(Tuple.Create)) {
+				if (!emTorque.IsBetween(entry.Item1.Torque, entry.Item2.Torque)) {
+					continue;
+				}
+
+				if (ShiftPolygon.IsRightOf(emSpeed, emTorque, entry)) {
+
+					return true;
+				}
+			}
+
+			return false;
+		}
+
 		public GearshiftPosition Engage(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity)
 		{
 			while (GearList.HasSuccessor(_nextGear) && SpeedTooHighForEngine(_nextGear, outAngularVelocity)) {
@@ -591,712 +721,11 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 		public void WriteModalResults(IModalDataContainer container) { }
 
 		#endregion
-	}
-
-
-	// ##########################
-
-	public class PEVAMTShiftStrategy_OLD : LoggingObject, IShiftStrategy
-	{
-		protected readonly IDataBus DataBus;
-		protected readonly GearboxData GearboxModelData;
-
-		protected Gearbox _gearbox;
-		protected GearshiftPosition _nextGear;
-
-		private ShiftStrategyParameters shiftStrategyParameters;
-		protected readonly VelocityRollingLookup VelocityDropData = new VelocityRollingLookup();
-		private SimplePowertrainContainer TestContainer;
-		private Gearbox TestContainerGbx;
-		private Kilogram vehicleMass;
-		private VoltageLevelData VoltageLevels;
-		private SI TransmissionRatio;
-		private ShiftStrategyParameters GearshiftParams;
-		private GearList GearList;
-
-		public bool EarlyShiftUp { get; }
-
-		public bool SkipGears { get; }
-
-		public static string Name => "AMT - EffShift (BEV)";
-
-		public enum GearshiftTrigger
-		{
-			NoShift = 0,
-			GearshiftBlockedTimeDelay = -2,
-			GearshiftBlockedNotAccelerating = -4,
-			AboveUpshiftLine = 10,
-			BelowDownshiftLine = -10,
-			EfficiencyShift = 5,
-			EmergencyShift = 2
-		}
-
-		public GearshiftTrigger ShiftTrigger;
-		private Second ShiftDecisionTstmp = -double.MaxValue.SI<Second>();
-
-		protected bool DriveOffStandstill = false;
-
-		public PEVAMTShiftStrategy_OLD(IVehicleContainer dataBus)
-		{
-			var runData = dataBus.RunData;
-			if (runData.VehicleData == null) {
-				return;
-			}
-			GearboxModelData = dataBus.RunData.GearboxData;
-			GearshiftParams = dataBus.RunData.GearshiftParameters;
-			GearList = GearboxModelData.GearList;
-			MaxStartGear = GearList.Reverse().First();
-
-			VoltageLevels = dataBus.RunData.ElectricMachinesData
-				.FirstOrDefault(x => x.Item1 == PowertrainPosition.BatteryElectricE2)?.Item2.EfficiencyData;
-			
-			DataBus = dataBus;
-
-			EarlyShiftUp = true;
-			SkipGears = true;
-
-			TransmissionRatio = runData.AxleGearData.AxleGear.Ratio *
-									(runData.AngledriveData?.Angledrive.Ratio ?? 1.0) /
-									runData.VehicleData.DynamicTyreRadius;
-			//var minEngineSpeed = (runData.EngineData.FullLoadCurves[0].RatedSpeed - runData.EngineData.IdleSpeed) *
-			//	Constants.SimulationSettings.ClutchClosingSpeedNorm + runData.EngineData.IdleSpeed;
-
-			shiftStrategyParameters = runData.GearshiftParameters;
-			vehicleMass = runData.VehicleData.TotalVehicleMass;
-			if (shiftStrategyParameters == null) {
-				throw new VectoException("Parameters for shift strategy missing!");
-			}
-			SetupVelocityDropPreprocessor(dataBus);
-		}
-
-		private void SetupVelocityDropPreprocessor(IVehicleContainer dataBus)
-		{
-			var runData = dataBus.RunData;
-			// MQ: 2019-11-29 - fuel used here has no effect as this is the modDatacontainer for the test-powertrain only!
-			var modData = new ModalDataContainer(runData, null, null);
-			var builder = new PowertrainBuilder(modData);
-			TestContainer = new SimplePowertrainContainer(runData);
-			builder.BuildSimplePowertrainE2(runData, TestContainer);
-			TestContainerGbx = TestContainer.GearboxCtl as Gearbox;
-			if (TestContainerGbx == null) {
-				throw new VectoException("Unknown gearboxtype: {0}", TestContainer.GearboxCtl.GetType().FullName);
-			}
 
-			// register pre-processors
-			var maxG = runData.Cycle.Entries.Max(x => Math.Abs(x.RoadGradientPercent.Value())) + 1;
-			var grad = Convert.ToInt32(maxG / 2) * 2;
-			if (grad == 0) {
-				grad = 2;
-			}
-
-			dataBus.AddPreprocessor(
-				new VelocitySpeedGearshiftPreprocessorE2(VelocityDropData, runData.GearboxData.TractionInterruption, TestContainer, -grad, grad, 2));
-
-		}
-
-		public bool ShiftRequired(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity,
-			NewtonMeter inTorque,
-			PerSecond inAngularVelocity, GearshiftPosition gear, Second lastShiftTime, IResponse response)
-		{
-			CheckGearshiftRequired = true;
-			var retVal = DoCheckShiftRequired(absTime, dt, outTorque, outAngularVelocity, inTorque, inAngularVelocity,
-				gear, lastShiftTime, response);
-			CheckGearshiftRequired = false;
-			return retVal;
-		}
-
-		private bool DoCheckShiftRequired(Second absTime, Second dt, NewtonMeter outTorque,
-			PerSecond outAngularVelocity, NewtonMeter inTorque, PerSecond inAngularVelocity, GearshiftPosition gear,
-			Second lastShiftTime, IResponse response)
-		{
-			// no shift when vehicle stands
-			if (DataBus.VehicleInfo.VehicleStopped) {
-				return false;
-			}
-
-			if (DriveOffStandstill &&
-				DataBus.VehicleInfo.VehicleSpeed.IsGreaterOrEqual(DataBus.DrivingCycleInfo.TargetSpeed)) {
-				DriveOffStandstill = false;
-			}
-			if (DriveOffStandstill && response.ElectricMotor.AngularVelocity.IsGreater(VoltageLevels.VoltageLevels.First().FullLoadCurve.NP80low)) {
-				DriveOffStandstill = false;
-			}
-
-			if (DriveOffStandstill && response.ElectricMotor.TorqueRequestEmMap != null &&
-				response.ElectricMotor.TorqueRequestEmMap.IsEqual(response.ElectricMotor.MaxDriveTorqueEM)) {
-				DriveOffStandstill = false;
-			}
-
-			// emergency shift to not stall the engine ------------------------
-			while (GearList.HasSuccessor(_nextGear) &&
-					SpeedTooHighForEngine(_nextGear, inAngularVelocity / GearboxModelData.Gears[gear.Gear].Ratio)) {
-				_nextGear = GearList.Successor(_nextGear);
-			}
-			if (_nextGear != gear) {
-				SetShiftDecision(GearshiftTrigger.EmergencyShift, absTime);
-				return true;
-			}
-
-			if (DriveOffStandstill) {
-				return false;
-			}
-
-			// normal shift when all requirements are fullfilled ------------------
-			var minimumShiftTimePassed = (lastShiftTime + GearshiftParams.TimeBetweenGearshifts).IsSmallerOrEqual(absTime);
-			if (!minimumShiftTimePassed) {
-				SetShiftDecision(GearshiftTrigger.GearshiftBlockedTimeDelay, absTime);
-				return false;
-			}
-
-			_nextGear = CheckDownshift(absTime, dt, outTorque, outAngularVelocity, inTorque, inAngularVelocity, gear, response);
-			if (_nextGear != gear) {
-				return true;
-			}
-
-			_nextGear = CheckUpshift(absTime, dt, outTorque, outAngularVelocity, inTorque, inAngularVelocity, gear, response);
-
-			//if ((ModelData.Gears[_nextGear].Ratio * outAngularVelocity - DataBus.EngineIdleSpeed) /
-			//	(DataBus.EngineRatedSpeed - DataBus.EngineIdleSpeed) <
-			//	Constants.SimulationSettings.ClutchClosingSpeedNorm && _nextGear > 1) {
-			//	_nextGear--;
-			//}
-
-			return _nextGear != gear;
-		}
-
-		protected virtual GearshiftPosition CheckUpshift(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, NewtonMeter inTorque, PerSecond inAngularVelocity, GearshiftPosition currentGear, IResponse response)
-		{
-			// if the driver's intention is _not_ to accelerate or drive along then don't upshift
-			if (DataBus.DriverInfo.DriverBehavior != DrivingBehavior.Accelerating && DataBus.DriverInfo.DriverBehavior != DrivingBehavior.Driving) {
-				SetShiftDecision(GearshiftTrigger.GearshiftBlockedNotAccelerating, absTime);
-				return currentGear;
-			}
-			if ((absTime - _gearbox.LastDownshift).IsSmaller(GearshiftParams.UpshiftAfterDownshiftDelay)) {
-				SetShiftDecision(GearshiftTrigger.GearshiftBlockedTimeDelay, absTime);
-				return currentGear;
-			}
-			var nextGear = DoCheckUpshift(absTime, dt, outTorque, outAngularVelocity, inTorque, inAngularVelocity, currentGear, response);
-			if (nextGear.Equals(currentGear)) {
-				return nextGear;
-			}
-
-			// estimate acceleration for selected gear
-			if (EstimateAccelerationForGear(nextGear, outAngularVelocity).IsSmaller(GearshiftParams.UpshiftMinAcceleration)) {
-				// if less than 0.1 for next gear, don't shift
-				if (GearList.Distance(nextGear, currentGear) == 1) {
-					return currentGear;
-				}
-				// if a gear is skipped but acceleration is less than 0.1, try for next gear. if acceleration is still below 0.1 don't shift!
-				if (nextGear > currentGear &&
-					EstimateAccelerationForGear(GearList.Successor(currentGear), outAngularVelocity)
-						.IsSmaller(GearshiftParams.UpshiftMinAcceleration)) {
-					return currentGear;
-				}
-				nextGear = GearList.Successor(currentGear);
-			}
-
-			return nextGear;
-		}
-
-		protected virtual GearshiftPosition DoCheckUpshift(Second absTime, Second dt, NewtonMeter outTorque,
-			PerSecond outAngularVelocity, NewtonMeter inTorque, PerSecond inAngularVelocity,
-			GearshiftPosition currentGear, IResponse response1)
-		{
-			// upshift
-			if (IsAboveUpShiftCurve(currentGear, inTorque, inAngularVelocity)) {
-				currentGear = GearList.Successor(currentGear);
-
-				while (SkipGears && GearList.HasSuccessor(currentGear)) {
-					currentGear = GearList.Successor(currentGear);
-					var response = RequestDryRunWithGear(absTime, dt, outTorque, outAngularVelocity, currentGear);
-
-					inAngularVelocity =
-						response.ElectricMotor
-							.AngularVelocity; //ModelData.Gears[currentGear].Ratio * outAngularVelocity;
-					inTorque = response.ElectricMotor.PowerRequest / inAngularVelocity;
-
-					var maxTorque = VectoMath.Min(-response.ElectricMotor.MaxDriveTorque,
-						!currentGear.Equals(GearList.First())
-							? GearboxModelData.Gears[currentGear.Gear].ShiftPolygon
-								.InterpolateDownshift(response.Engine.EngineSpeed)
-							: double.MaxValue.SI<NewtonMeter>());
-					var reserve = 1 - inTorque / maxTorque;
-
-					if (reserve >= 0 /*ModelData.TorqueReserve */ &&
-						IsAboveDownShiftCurve(currentGear, inTorque, inAngularVelocity)) {
-						continue;
-					}
-
-					currentGear = GearList.Predecessor(currentGear);
-					break;
-				}
-			}
-
-			// early up shift to higher gear ---------------------------------------
-			if (EarlyShiftUp && GearList.HasSuccessor(currentGear)) {
-				currentGear = CheckEarlyUpshift(absTime, dt, outTorque, outAngularVelocity, currentGear, response1);
-			}
-
-			return currentGear;
-		}
-
-		protected virtual GearshiftPosition CheckEarlyUpshift(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, GearshiftPosition currentGear, IResponse response1)
-		{
-			//var minFcGear = currentGear;
-			//var minFc = double.MaxValue;
-			//IResponse minFCResponse = null;
-			//var fcCurrent = double.NaN;
+		#region Implementation of IShiftPolygonCalculator
 
-			//var fcUpshiftPossible = true;
+		
+		#endregion
+	}
 
-			// no eff-shift if torque demand is close to ICE drag load
-			//if (response1.Engine.TorqueOutDemand.IsSmaller(DeclarationData.GearboxTCU.DragMarginFactor * fld[currentGear].DragLoadStationaryTorque(response1.Engine.EngineSpeed))) {
-			//	return currentGear;
-			//}
-
-			var estimatedVelocityPostShift = VelocityDropData.Interpolate(DataBus.VehicleInfo.VehicleSpeed, DataBus.DrivingCycleInfo.RoadGradient ?? 0.SI<Radian>());
-			if (!estimatedVelocityPostShift.IsGreater(DeclarationData.GearboxTCU.MIN_SPEED_AFTER_TRACTION_INTERRUPTION)) {
-				return currentGear;
-			}
-
-			var vDrop = DataBus.VehicleInfo.VehicleSpeed - estimatedVelocityPostShift;
-			var vehicleSpeedPostShift = DataBus.VehicleInfo.VehicleSpeed - vDrop * shiftStrategyParameters.VelocityDropFactor;
-
-			var totalTransmissionRatio = DataBus.ElectricMotorInfo(PowertrainPosition.BatteryElectricE2).ElectricMotorSpeed / DataBus.VehicleInfo.VehicleSpeed;
-			//var totalTransmissionRatio = outAngularVelocity / DataBus.VehicleSpeed;
-
-			var results = new List<Tuple<GearshiftPosition, double>>();
-			foreach (var tryNextGear in GearList.IterateGears(GearList.Successor(currentGear), GearList.Successor(currentGear, (uint)shiftStrategyParameters.AllowedGearRangeFC))) {
-				
-				//if (tryNextGear > GearboxModelData.Gears.Keys.Max() 
-				//	/*|| !(ModelData.Gears[tryNextGear].Ratio < shiftStrategyParameters.RatioEarlyUpshiftFC)*/) {
-				//	continue;
-				//}
-
-				//fcUpshiftPossible = true;
-
-				//var response = RequestDryRunWithGear(absTime, dt, vehicleSpeedPostShift, DataBus.DriverAcceleration, tryNextGear);
-				var response = RequestDryRunWithGear(absTime, dt, outTorque, outAngularVelocity, tryNextGear);
-
-				var inAngularVelocity = GearboxModelData.Gears[tryNextGear.Gear].Ratio * outAngularVelocity;
-				var inTorque = response.ElectricMotor.PowerRequest / inAngularVelocity;
-
-				// if next gear supplied enough power reserve: take it
-				// otherwise take
-				if (IsBelowDownShiftCurve(tryNextGear, inTorque, inAngularVelocity)) {
-					continue;
-				}
-
-				var estimatedEngineSpeed = (vehicleSpeedPostShift * (totalTransmissionRatio / GearboxModelData.Gears[currentGear.Gear].Ratio * GearboxModelData.Gears[tryNextGear.Gear].Ratio)).Cast<PerSecond>();
-				if (estimatedEngineSpeed.IsSmaller(shiftStrategyParameters.MinEngineSpeedPostUpshift)) {
-					continue;
-				}
-
-				//var pNextGearMax = DataBus.Engine Info.EngineStationaryFullPower(estimatedEngineSpeed);
-
-				//if (!response.Engine.PowerRequest.IsSmaller(pNextGearMax)) {
-				//	continue;
-				//}
-
-				var fullLoadPower = -response.ElectricMotor.MaxDriveTorque * response.ElectricMotor.AngularVelocity;
-				var reserve = 1 - response.ElectricMotor.PowerRequest / fullLoadPower;
-
-				//var reserve = 1 - response.EngineTorqueDemandTotal / response.EngineStationaryFullLoadTorque;
-
-				
-				//if (double.IsNaN(fcCurrent)) {
-				//	//var responseCurrent = RequestDryRunWithGear(absTime, dt, DataBus.VehicleSpeed, DataBus.DriverAcceleration, currentGear);
-				//	var responseCurrent = RequestDryRunWithGear(absTime, dt, outTorque, outAngularVelocity, currentGear);
-				//	fcCurrent = GetFCRating(responseCurrent);
-				//}
-				
-				var fcNext = GetFCRating(response);
-				results.Add(Tuple.Create(tryNextGear, fcNext));
-
-				//if (reserve < GearshiftParams.TorqueReserve ||
-				//	!fcNext.IsGreater(fcCurrent * shiftStrategyParameters.RatingFactorCurrentGear) || !fcNext.IsSmaller(minFc)) {
-				//	continue;
-				//}
-
-				//minFcGear = tryNextGear;
-				//minFc = fcNext;
-				//minFCResponse = response;
-			}
-
-			if (results.Count == 0) {
-				return currentGear;
-			}
-
-			var responseCurrent = RequestDryRunWithGear(absTime, dt, outTorque, outAngularVelocity, currentGear);
-			var fcCurrent = GetFCRating(responseCurrent);
-
-			var minFc = results.MinBy(x => x.Item2);
-
-			var ratingFactor = outTorque < 0
-				? 1 / shiftStrategyParameters.RatingFactorCurrentGear
-				: shiftStrategyParameters.RatingFactorCurrentGear;
-
-			if (minFc.Item2.IsGreater(fcCurrent * ratingFactor)) {
-				return minFc.Item1;
-			}
-
-			return currentGear;
-			//return fcUpshiftPossible
-			//	? currentGear
-			//	: base.CheckEarlyUpshift(absTime, dt, outTorque, outAngularVelocity, currentGear, response1);
-		}
-
-		
-		private double GetFCRating(ResponseDryRun response)//PerSecond engineSpeed, NewtonMeter tqCurrent)
-		{
-			var currentGear = response.Gearbox.Gear;
-
-			var maxGenTorque = VectoMath.Min(GearboxModelData.Gears[currentGear.Gear].MaxTorque, response.ElectricMotor.MaxRecuperationTorque);
-			var maxDriveTorque = GearboxModelData.Gears[currentGear.Gear].MaxTorque != null
-				? VectoMath.Max(-GearboxModelData.Gears[currentGear.Gear].MaxTorque, response.ElectricMotor.MaxDriveTorque)
-				: response.ElectricMotor.MaxDriveTorque;
-
-			var tqCurrent = (response.ElectricMotor.ElectricMotorPowerMech / response.ElectricMotor.AngularVelocity);
-			if (!tqCurrent.IsBetween(maxDriveTorque, maxGenTorque)) {
-				return double.NaN;
-			}
-			var engineSpeed = response.ElectricMotor.AngularVelocity;
-
-			
-			var fcCurRes = VoltageLevels.LookupElectricPower(DataBus.BatteryInfo.InternalVoltage, engineSpeed, tqCurrent, true);
-			if (fcCurRes.Extrapolated) {
-				Log.Warn(
-					"EffShift Strategy: Extrapolation of power consumption for current gear! n: {0}, Tq: {1}",
-					engineSpeed, tqCurrent);
-			}
-			return fcCurRes.ElectricalPower.Value();
-		}
-
-
-
-
-		protected ResponseDryRun RequestDryRunWithGear(
-			Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, GearshiftPosition tryNextGear)
-		{
-			LogEnabled = false;
-			TestContainerGbx.Disengaged = false;
-			TestContainerGbx.Gear = tryNextGear;
-
-			TestContainer.GearboxOutPort.Initialize(outTorque, outAngularVelocity);
-			var response = (ResponseDryRun)TestContainer.GearboxOutPort.Request(
-				0.SI<Second>(), dt, outTorque, outAngularVelocity, true);
-			LogEnabled = true;
-			return response;
-		}
-
-		protected MeterPerSquareSecond EstimateAccelerationForGear(GearshiftPosition gear, PerSecond gbxAngularVelocityOut)
-		{
-			if (!gear.Engaged || !GearList.Contains(gear)) {
-				throw new VectoSimulationException("EstimateAccelerationForGear: invalid gear: {0}", gear);
-			}
-
-			var vehicleSpeed = DataBus.VehicleInfo.VehicleSpeed;
-
-			var nextEngineSpeed = gbxAngularVelocityOut * GearboxModelData.Gears[gear.Gear].Ratio;
-			var maxEnginePower = -(VoltageLevels.FullLoadDriveTorque(DataBus.BatteryInfo.InternalVoltage, nextEngineSpeed) * nextEngineSpeed);
-			
-			var avgSlope =
-				((DataBus.DrivingCycleInfo.CycleLookAhead(Constants.SimulationSettings.GearboxLookaheadForAccelerationEstimation).Altitude -
-				DataBus.DrivingCycleInfo.Altitude) / Constants.SimulationSettings.GearboxLookaheadForAccelerationEstimation).Value().SI<Radian>();
-
-			var airDragLoss = DataBus.VehicleInfo.AirDragResistance(vehicleSpeed, vehicleSpeed) * DataBus.VehicleInfo.VehicleSpeed;
-			var rollResistanceLoss = DataBus.VehicleInfo.RollingResistance(avgSlope) * DataBus.VehicleInfo.VehicleSpeed;
-			var gearboxLoss = GearboxModelData.Gears[gear.Gear].LossMap.GetTorqueLoss(gbxAngularVelocityOut,
-				maxEnginePower / nextEngineSpeed * GearboxModelData.Gears[gear.Gear].Ratio).Value * nextEngineSpeed;
-			//DataBus.GearboxLoss();
-			var slopeLoss = DataBus.VehicleInfo.SlopeResistance(avgSlope) * DataBus.VehicleInfo.VehicleSpeed;
-			var axleLoss = DataBus.AxlegearInfo.AxlegearLoss();
-
-			var accelerationPower = maxEnginePower - gearboxLoss - axleLoss - airDragLoss - rollResistanceLoss - slopeLoss;
-
-			var acceleration = accelerationPower / DataBus.VehicleInfo.VehicleSpeed / (DataBus.VehicleInfo.TotalMass + DataBus.WheelsInfo.ReducedMassWheels);
-
-			return acceleration.Cast<MeterPerSquareSecond>();
-		}
-
-		protected virtual GearshiftPosition CheckDownshift(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, NewtonMeter inTorque, PerSecond inAngularVelocity, GearshiftPosition currentGear, IResponse response)
-		{
-			if ((absTime - _gearbox.LastUpshift).IsSmaller(GearshiftParams.DownshiftAfterUpshiftDelay)) {
-				SetShiftDecision(GearshiftTrigger.GearshiftBlockedTimeDelay, absTime);
-				return currentGear;
-			}
-			return DoCheckDownshift(absTime, dt, outTorque, outAngularVelocity, inTorque, inAngularVelocity, currentGear, response);
-		}
-
-		protected virtual GearshiftPosition DoCheckDownshift(
-			Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity,
-			NewtonMeter inTorque, PerSecond inAngularVelocity, GearshiftPosition currentGear, IResponse response)
-		{
-			var nextGear = BaseDoCheckDownshift(
-				absTime, dt, outTorque, outAngularVelocity, inTorque, inAngularVelocity, currentGear, response);
-
-			if (nextGear.Equals(currentGear) && !currentGear.Equals(GearList.First())) {
-				nextGear = CheckEarlyDownshift(absTime, dt, outTorque, outAngularVelocity, currentGear, response);
-				if (nextGear != currentGear) {
-					SetShiftDecision(GearshiftTrigger.EfficiencyShift, absTime);
-				}
-			}
-			return nextGear;
-		}
-
-		protected virtual GearshiftPosition BaseDoCheckDownshift(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity,
-			NewtonMeter inTorque, PerSecond inAngularVelocity, GearshiftPosition currentGear, IResponse response)
-		{
-			// down shift
-			if (response.ElectricMotor.TorqueRequestEmMap == null) {
-				// em is off - no need to shift
-				return currentGear;
-			}
-			if (IsBelowDownShiftCurve(currentGear, response.ElectricMotor.TorqueRequestEmMap, response.ElectricMotor.AngularVelocity)) {
-				currentGear = GearList.Predecessor(currentGear);
-				SetShiftDecision(GearshiftTrigger.BelowDownshiftLine, absTime);
-				//while (SkipGears && currentGear > 1) {
-				//	currentGear--;
-				//	var response = RequestDryRunWithGear(absTime, dt, outTorque, outAngularVelocity, currentGear);
-
-				//	inAngularVelocity = ModelData.Gears[currentGear].Ratio * outAngularVelocity;
-				//	inTorque = response.ClutchPowerRequest / inAngularVelocity;
-				//	var maxTorque = VectoMath.Min(response.DynamicFullLoadPower / ((DataBus.EngineSpeed + response.EngineSpeed) / 2),
-				//		currentGear > 1
-				//			? ModelData.Gears[currentGear].ShiftPolygon.InterpolateDownshift(response.EngineSpeed)
-				//			: double.MaxValue.SI<NewtonMeter>());
-				//	var reserve = maxTorque.IsEqual(0) ? -1 : (1 - inTorque / maxTorque).Value();
-				//	if (reserve >= ModelData.TorqueReserve && IsBelowUpShiftCurve(currentGear, inTorque, inAngularVelocity)) {
-				//		continue;
-				//	}
-				//	currentGear++;
-				//	break;
-				//}
-			}
-			return currentGear;
-		}
-
-
-		protected virtual GearshiftPosition CheckEarlyDownshift(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, GearshiftPosition currentGear, IResponse response1)
-		{
-			//var minFcGear = currentGear;
-			//var minFc = double.MaxValue * Math.Sign(outTorque.Value()) ;
-			//var fcCurrent = double.NaN;
-
-			var estimatedVelocityPostShift = VelocityDropData.Interpolate(DataBus.VehicleInfo.VehicleSpeed, DataBus.DrivingCycleInfo.RoadGradient ?? 0.SI<Radian>());
-			if (!estimatedVelocityPostShift.IsGreater(DeclarationData.GearboxTCU.MIN_SPEED_AFTER_TRACTION_INTERRUPTION)) {
-				return currentGear;
-			}
-
-			// no eff-shift if torque demand is close to ICE drag load
-			//if (response1.Engine.TorqueOutDemand.IsSmaller(DeclarationData.GearboxTCU.DragMarginFactor * fld[currentGear].DragLoadStationaryTorque(response1.Engine.EngineSpeed))) {
-			//	return currentGear;
-			//}
-
-			var results = new List<Tuple<GearshiftPosition, double>>();
-			foreach (var tryNextGear in GearList.IterateGears(GearList.Predecessor(currentGear), GearList.Predecessor(currentGear, (uint)shiftStrategyParameters.AllowedGearRangeFC))) {
-				
-				var response = RequestDryRunWithGear(absTime, dt, outTorque, outAngularVelocity, tryNextGear);
-
-				var inAngularVelocity = GearboxModelData.Gears[tryNextGear.Gear].Ratio * outAngularVelocity;
-				var inTorque = response.ElectricMotor.PowerRequest / inAngularVelocity;
-
-				if (IsAboveUpShiftCurve(tryNextGear, inTorque, inAngularVelocity)) {
-					continue;
-				}
-
-				var fcNext = GetFCRating(response);
-				results.Add(Tuple.Create(tryNextGear,fcNext));
-
-			}
-
-			if (results.Count == 0) {
-				return currentGear;
-			}
-
-			var responseCurrent = RequestDryRunWithGear(absTime, dt, outTorque, outAngularVelocity, currentGear);
-			var fcCurrent = GetFCRating(responseCurrent);
-
-			var minFc = results.MinBy(x => x.Item2);
-
-			var ratingFactor = outTorque < 0
-				? 1 / shiftStrategyParameters.RatingFactorCurrentGear
-				: shiftStrategyParameters.RatingFactorCurrentGear;
-
-
-			if (minFc.Item2.IsGreater(fcCurrent * ratingFactor)) {
-				return minFc.Item1;
-			}
-			
-			return currentGear;
-		}
-
-
-		public GearshiftPosition InitGear(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity)
-		{
-			if (DataBus.VehicleInfo.VehicleSpeed.IsEqual(0)) {
-				return InitStartGear(absTime, outTorque, outAngularVelocity);
-			}
-
-			foreach (var gear in GearList.Reverse()) {
-				//for (var gear = (uint)GearboxModelData.Gears.Count; gear > 1; gear--) {
-				var response = _gearbox.Initialize(absTime, gear, outTorque, outAngularVelocity);
-
-				var inAngularSpeed = outAngularVelocity * GearboxModelData.Gears[gear.Gear].Ratio;
-				var inTorque = response.ElectricMotor.PowerRequest / inAngularSpeed;
-
-				// if in shift curve and torque reserve is provided: return the current gear
-				if (!IsBelowDownShiftCurve(gear, inTorque, inAngularSpeed) && !IsAboveUpShiftCurve(gear, inTorque, inAngularSpeed)) {
-					_nextGear = gear;
-					return gear;
-				}
-			}
-			// fallback: return first gear
-			_nextGear = GearList.First();
-			return _nextGear;
-		}
-
-		private GearshiftPosition InitStartGear(Second absTime, NewtonMeter outTorque, PerSecond outAngularVelocity)
-		{
-			DriveOffStandstill = true;
-
-			var emSpeeds = new Dictionary<GearshiftPosition, Tuple<PerSecond, PerSecond, double>>();
-
-			foreach (var gear in GearList.Reverse()) {
-				//for (var gear = (uint)GearboxModelData.Gears.Count; gear >= 1; gear--) {
-				var inAngularSpeed = outAngularVelocity * GearboxModelData.Gears[gear.Gear].Ratio;
-
-				var ratedSpeed = VoltageLevels.MaxSpeed * 0.9;
-				if (inAngularSpeed > ratedSpeed || inAngularSpeed.IsEqual(0)) {
-					continue;
-				}
-
-				var response = _gearbox.Initialize(absTime, gear, outTorque, outAngularVelocity);
-
-				var fullLoadPower = -(response.ElectricMotor.MaxDriveTorque * response.ElectricMotor.AngularVelocity);
-					//.DynamicFullLoadPower; //EnginePowerRequest - response.DeltaFullLoad;
-				var reserve = 1 - response.ElectricMotor.TorqueRequestEmMap / response.ElectricMotor.MaxDriveTorqueEM;
-
-				var isBelowDownshift = gear.Gear > 1 && 
-					IsBelowDownshiftCurve(GearboxModelData.Gears[gear.Gear].ShiftPolygon, response.ElectricMotor.TorqueRequest,
-						response.ElectricMotor.AngularVelocity);
-
-				if (reserve >= GearshiftParams.StartTorqueReserve && !isBelowDownshift) {
-					//_nextGear = gear;
-					//return gear;
-					emSpeeds[gear] = Tuple.Create(response.ElectricMotor.AngularVelocity,
-						(GearshiftParams.StartSpeed * TransmissionRatio * GearboxModelData.Gears[gear.Gear].Ratio)
-						.Cast<PerSecond>(), (response.ElectricMotor.ElectricMotorPowerMech / response.ElectricSystem.RESSPowerDemand).Value());
-				}
-			}
-
-			if (emSpeeds.Any()) {
-				var optimum = emSpeeds.MaxBy(x => x.Key.Gear); //x => VectoMath.Abs(x.Value.Item2 - FullLoadCurve.MaxSpeed * 0.5));
-				_nextGear = optimum.Key;
-				return _nextGear;
-			}
-			_nextGear = GearList.First();
-			return _nextGear;
-		}
-
-		private bool IsBelowDownshiftCurve(ShiftPolygon shiftPolygon, NewtonMeter emTorque, PerSecond emSpeed)
-		{
-			foreach (var entry in shiftPolygon.Downshift.Pairwise(Tuple.Create)) {
-				if (!emTorque.IsBetween(entry.Item1.Torque, entry.Item2.Torque)) {
-					continue;
-				}
-
-				if (ShiftPolygon.IsLeftOf(emSpeed, emTorque, entry)) {
-
-					return true;
-				}
-			}
-
-			return false;
-		}
-
-		protected bool IsBelowDownShiftCurve(GearshiftPosition gear, NewtonMeter inTorque, PerSecond inEngineSpeed)
-		{
-			if (!GearList.HasPredecessor(gear)) {
-				return false;
-			}
-			return IsBelowDownshiftCurve(GearboxModelData.Gears[gear.Gear].ShiftPolygon, inTorque, inEngineSpeed);
-		}
-
-		protected bool IsAboveDownShiftCurve(GearshiftPosition gear, NewtonMeter inTorque, PerSecond inEngineSpeed)
-		{
-			if (!GearList.HasPredecessor(gear)) {
-				return true;
-			}
-			return GearboxModelData.Gears[gear.Gear].ShiftPolygon.IsAboveDownshiftCurve(inTorque, inEngineSpeed);
-		}
-
-		protected bool IsAboveUpShiftCurve(GearshiftPosition gear, NewtonMeter inTorque, PerSecond inEngineSpeed)
-		{
-			if (!GearList.HasSuccessor(gear)) {
-				return false;
-			}
-			return GearboxModelData.Gears[gear.Gear].ShiftPolygon.IsAboveUpshiftCurve(inTorque, inEngineSpeed);
-		}
-
-		public GearshiftPosition Engage(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity)
-		{
-			
-			while (GearList.HasSuccessor(_nextGear) && SpeedTooHighForEngine(_nextGear, outAngularVelocity)) {
-				_nextGear = GearList.Successor(_nextGear);
-			}
-
-			return _nextGear;
-		}
-
-		
-		protected bool SpeedTooHighForEngine(GearshiftPosition gear, PerSecond outAngularSpeed)
-		{
-			return
-				(outAngularSpeed * GearboxModelData.Gears[gear.Gear].Ratio).IsGreaterOrEqual(VectoMath.Min(GearboxModelData.Gears[gear.Gear].MaxSpeed,
-					DataBus.ElectricMotorInfo(PowertrainPosition.BatteryElectricE2).MaxSpeed));
-		}
-
-		public void Disengage(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity) { }
-
-		public IGearbox Gearbox {
-			get => _gearbox;
-			set {
-				var myGearbox = value as Gearbox;
-				if (myGearbox == null) {
-					throw new VectoException("This shift strategy can't handle gearbox of type {0}", value.GetType());
-				}
-				_gearbox = myGearbox;
-			}
-		}
-
-		public GearshiftPosition NextGear => _nextGear;
-
-
-		public bool CheckGearshiftRequired { get; protected set; }
-		public GearshiftPosition MaxStartGear { get; }
-
-		public void Request(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity)
-		{
-			if (!absTime.IsEqual(ShiftDecisionTstmp)) {
-				ShiftTrigger = GearshiftTrigger.NoShift;
-			}
-
-			ShiftDecisionTstmp = absTime;
-		}
-
-		protected void SetShiftDecision(GearshiftTrigger trigger, Second absTime)
-		{
-			ShiftTrigger = trigger;
-		}
-
-		public void WriteModalResults(IModalDataContainer container) { }
-
-		public ShiftPolygon ComputeDeclarationShiftPolygon(GearboxType gearboxType, int i, EngineFullLoadCurve engineDataFullLoadCurve, 
-			IList<ITransmissionInputData> gearboxGears, CombustionEngineData engineData, double axlegearRatio, Meter dynamicTyreRadius, ElectricMotorData electricMotorData)
-		{
-			return DeclarationData.Gearbox.ComputeElectricMotorShiftPolygon(i, electricMotorData.EfficiencyData.VoltageLevels.First().FullLoadCurve, electricMotorData.RatioADC, gearboxGears, axlegearRatio, dynamicTyreRadius);
-		}
-
-	}
 }
\ No newline at end of file
diff --git a/VectoCore/VectoCoreTest/Integration/BatteryElectric/BatteryElectricTest.cs b/VectoCore/VectoCoreTest/Integration/BatteryElectric/BatteryElectricTest.cs
index 7b5662db24..e537c19dbb 100644
--- a/VectoCore/VectoCoreTest/Integration/BatteryElectric/BatteryElectricTest.cs
+++ b/VectoCore/VectoCoreTest/Integration/BatteryElectric/BatteryElectricTest.cs
@@ -22,6 +22,7 @@ using TUGraz.VectoCore.Models.SimulationComponent.Impl;
 using TUGraz.VectoCore.Models.SimulationComponent.Strategies;
 using TUGraz.VectoCore.OutputData;
 using TUGraz.VectoCore.OutputData.FileIO;
+using TUGraz.VectoCore.Tests.Models.SimulationComponentData;
 using TUGraz.VectoCore.Tests.Utils;
 using TUGraz.VectoCore.Utils;
 using ElectricSystem = TUGraz.VectoCore.Models.SimulationComponent.ElectricSystem;
@@ -42,6 +43,7 @@ namespace TUGraz.VectoCore.Tests.Integration.BatteryElectric
 
 
 		protected const string BEV_E2_Job = @"TestData\BatteryElectric\GenericVehicleB2\BEV_ENG.vecto";
+		protected const string BEV_E2_Job_3Speed = @"TestData\BatteryElectric\GenericVehicleB2\BEV_ENG_3speed.vecto";
 		protected const string BEV_E2_Job_Cont30kW = @"TestData\BatteryElectric\GenericVehicleB2\BEV_ENG_Cont30kW.vecto";
 
 		public const string MotorFile = @"TestData\BatteryElectric\GenericVehicleB4\GenericEMotor_125kW_485Nm.vem";
@@ -565,6 +567,17 @@ namespace TUGraz.VectoCore.Tests.Integration.BatteryElectric
 			TestCase(BEV_E2_Job, 8, TestName = "PEV E2 Job Urban"),
 			TestCase(BEV_E2_Job, 9, TestName = "PEV E2 Job UrbanDelivery"),
 
+			TestCase(BEV_E2_Job_3Speed, 0, TestName = "PEV E2 3Speed Job LongHaul"),
+			TestCase(BEV_E2_Job_3Speed, 1, TestName = "PEV E2 3Speed Job Coach"),
+			TestCase(BEV_E2_Job_3Speed, 2, TestName = "PEV E2 3Speed Job Construction"),
+			TestCase(BEV_E2_Job_3Speed, 3, TestName = "PEV E2 3Speed Job HeavyUrban"),
+			TestCase(BEV_E2_Job_3Speed, 4, TestName = "PEV E2 3Speed Job Interurban"),
+			TestCase(BEV_E2_Job_3Speed, 5, TestName = "PEV E2 3Speed Job MunicipalUtility"),
+			TestCase(BEV_E2_Job_3Speed, 6, TestName = "PEV E2 3Speed Job RegionalDelivery"),
+			TestCase(BEV_E2_Job_3Speed, 7, TestName = "PEV E2 3Speed Job Suburban"),
+			TestCase(BEV_E2_Job_3Speed, 8, TestName = "PEV E2 3Speed Job Urban"),
+			TestCase(BEV_E2_Job_3Speed, 9, TestName = "PEV E2 3Speed Job UrbanDelivery"),
+
 			TestCase(BEV_E2_Job_Cont30kW, 0, TestName = "PEV E2 Cont. 30kW Job LongHaul"),
 			TestCase(BEV_E2_Job_Cont30kW, 1, TestName = "PEV E2 Cont. 30kW Job Coach"),
 			TestCase(BEV_E2_Job_Cont30kW, 2, TestName = "PEV E2 Cont. 30kW Job Construction"),
@@ -788,7 +801,12 @@ namespace TUGraz.VectoCore.Tests.Integration.BatteryElectric
 				
 				Inertia = 0.SI<KilogramSquareMeter>(),
 				TractionInterruption = 1.SI<Second>(),
-				
+				InputData = new DummyGearboxData() {
+					Gears = new List<ITransmissionInputData>() {
+						new TransmissionInputData(),
+						new TransmissionInputData(),
+					}
+				}
 			};
 		}
 
diff --git a/VectoCore/VectoCoreTest/Models/Declaration/ShiftPolygonTest.cs b/VectoCore/VectoCoreTest/Models/Declaration/ShiftPolygonTest.cs
index 1d22ae3e10..fe3bcbe008 100644
--- a/VectoCore/VectoCoreTest/Models/Declaration/ShiftPolygonTest.cs
+++ b/VectoCore/VectoCoreTest/Models/Declaration/ShiftPolygonTest.cs
@@ -43,9 +43,13 @@ using TUGraz.VectoCore.InputData.FileIO.XML;
 using TUGraz.VectoCore.InputData.Reader.ComponentData;
 using TUGraz.VectoCore.InputData.Reader.DataObjectAdapter;
 using TUGraz.VectoCore.Models.Declaration;
+using TUGraz.VectoCore.Models.Simulation.Data;
+using TUGraz.VectoCore.Models.Simulation.Impl;
 using TUGraz.VectoCore.Models.SimulationComponent.Data;
+using TUGraz.VectoCore.Models.SimulationComponent.Data.ElectricMotor;
 using TUGraz.VectoCore.Models.SimulationComponent.Data.Engine;
 using TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox;
+using TUGraz.VectoCore.Models.SimulationComponent.Impl;
 using TUGraz.VectoCore.Tests.Utils;
 using TUGraz.VectoCore.Utils;
 using Point = TUGraz.VectoCommon.Utils.Point;
@@ -922,11 +926,10 @@ namespace TUGraz.VectoCore.Tests.Models.Declaration
 			}
 		}
 
-		[TestCase()]
-		public void ComputePEVShiftLines()
+		[TestCase(@"TestData\BatteryElectric\GenericVehicleB2\BEV_ENG.vecto"),
+		TestCase(@"TestData\BatteryElectric\GenericVehicleB2\BEV_ENG_cont30kW.vecto")]
+		public void ComputePEVShiftLines(string pevE2Job)
 		{
-			var pevE2Job = @"TestData\BatteryElectric\GenericVehicleB2\BEV_ENG.vecto";
-
 			var inputData = JSONInputDataFactory.ReadJsonJob(pevE2Job) as IEngineeringInputDataProvider;
 			var gearboxData = inputData.JobInputData.Vehicle.Components.GearboxInputData;
 			var dao = new EngineeringDataAdapter();
@@ -959,5 +962,67 @@ namespace TUGraz.VectoCore.Tests.Models.Declaration
 				imageFile,
 				DeclarationData.Gearbox.TruckMaxAllowedSpeed / r_dyn * axlegearRatio * gearboxData.Gears.Last().Ratio);
 		}
+
+		[TestCase()]
+		public void ComputePEVShiftLinesDeRated()
+		{
+			var pevE2Job = @"TestData\BatteryElectric\GenericVehicleB2\BEV_ENG_cont30kW.vecto";
+
+			var inputData = JSONInputDataFactory.ReadJsonJob(pevE2Job) as IEngineeringInputDataProvider;
+			var gearboxData = inputData.JobInputData.Vehicle.Components.GearboxInputData;
+			var dao = new EngineeringDataAdapter();
+			var emData = dao.CreateElectricMachines(inputData.JobInputData.Vehicle.Components.ElectricMachines,
+				null).FirstOrDefault()?.Item2;
+			
+			var axlegearRatio = inputData.JobInputData.Vehicle.Components.AxleGearInputData.Ratio;
+			var vehicleData = dao.CreateVehicleData(inputData.JobInputData.Vehicle);
+			var r_dyn = vehicleData.DynamicTyreRadius;
+
+            //emData.ContinuousTorque = 500.SI<NewtonMeter>();
+            var contTqFld = new ElectricMotorFullLoadCurve(new List<ElectricMotorFullLoadCurve.FullLoadEntry>() {
+				new ElectricMotorFullLoadCurve.FullLoadEntry() {
+					MotorSpeed = 0.RPMtoRad(),
+					FullDriveTorque = -emData.ContinuousTorque,
+					FullGenerationTorque = emData.ContinuousTorque
+				},
+				new ElectricMotorFullLoadCurve.FullLoadEntry() {
+					MotorSpeed = 1.1 * emData.EfficiencyData.VoltageLevels.First().FullLoadCurve.MaxSpeed,
+					FullDriveTorque = -emData.ContinuousTorque,
+					FullGenerationTorque = emData.ContinuousTorque
+				}
+			});
+			var limitedFld = AbstractSimulationDataAdapter.IntersectEMFullLoadCurves(emData.EfficiencyData.VoltageLevels.First().FullLoadCurve, contTqFld);
+
+			var fullLoadCurve = limitedFld.FullLoadEntries.Select(x =>
+				new EngineFullLoadCurve.FullLoadCurveEntry() {
+					EngineSpeed = x.MotorSpeed,
+					TorqueFullLoad = -x.FullDriveTorque,
+					TorqueDrag = -x.FullGenerationTorque
+				}).ToList();
+			var fullLoadCurves = new Dictionary<uint, EngineFullLoadCurve>();
+			var engineData = new CombustionEngineData() {
+				IdleSpeed = 600.RPMtoRad()
+			};
+			fullLoadCurves[(uint)(0)] = new EngineFullLoadCurve(fullLoadCurve, null) { EngineData = engineData };
+			
+			
+			var shiftPolygons = new List<ShiftPolygon>();
+			
+			var shiftStrategy = new PEVAMTShiftStrategy(new VehicleContainer(ExecutionMode.Engineering) { RunData = new VectoRunData() { GearshiftParameters = new ShiftStrategyParameters()}});
+			var deRatedShiftLines = shiftStrategy.CalculateDeratedShiftLines(emData, gearboxData.Gears,
+				r_dyn, axlegearRatio, gearboxData.Type);
+			for (var i = 0; i < gearboxData.Gears.Count; i++) {
+
+				shiftPolygons.Add(deRatedShiftLines[(uint)(i + 1)]);
+
+				
+				fullLoadCurves[(uint)(i + 1)] = new EngineFullLoadCurve(fullLoadCurve, null) { EngineData = engineData };
+			}
+			var imageFile = Path.Combine(Path.GetDirectoryName(pevE2Job), Path.GetFileNameWithoutExtension(pevE2Job) + "_shiftlines_DeRated.png");
+
+			ShiftPolygonDrawer.DrawShiftPolygons(Path.GetDirectoryName(pevE2Job), fullLoadCurves, shiftPolygons,
+				imageFile,
+				DeclarationData.Gearbox.TruckMaxAllowedSpeed / r_dyn * axlegearRatio * gearboxData.Gears.Last().Ratio);
+		}
 	}
 }
\ No newline at end of file
diff --git a/VectoCore/VectoCoreTest/TestData/BatteryElectric/GenericVehicleB2/3speedEV.vgbx b/VectoCore/VectoCoreTest/TestData/BatteryElectric/GenericVehicleB2/3speedEV.vgbx
new file mode 100644
index 0000000000..2899660e38
--- /dev/null
+++ b/VectoCore/VectoCoreTest/TestData/BatteryElectric/GenericVehicleB2/3speedEV.vgbx
@@ -0,0 +1,54 @@
+{
+  "Header": {
+    "CreatedBy": "",
+    "Date": "2020-11-03T14:19:09.9858299Z",
+    "AppVersion": "3",
+    "FileVersion": 6
+  },
+  "Body": {
+    "SavedInDeclMode": false,
+    "ModelName": "3_speed_AMT",
+    "Inertia": 0.0,
+    "TracInt": 0.8,
+    "Gears": [
+      {
+        "Ratio": 2.64,
+        "LossMap": "Transmission\\Axle_4x2_Tractor.vtlm"
+      },
+      {
+        "Ratio": 17.5,
+        "LossMap": "Transmission\\Gear_1.vtlm",
+        "ShiftPolygon": "",
+        "MaxTorque": "",
+        "MaxSpeed": ""
+      },
+      {
+        "Ratio": 6.49,
+        "LossMap": "Transmission\\Gear_2.vtlm",
+        "ShiftPolygon": "",
+        "MaxTorque": "",
+        "MaxSpeed": ""
+      },
+      {
+        "Ratio": 2.48,
+        "LossMap": "Transmission\\Gear_3.vtlm",
+        "ShiftPolygon": "",
+        "MaxTorque": "",
+        "MaxSpeed": ""
+      }
+    ],
+    "TqReserve": 0.0,
+    "ShiftTime": 2.0,
+    "StartTqReserve": 20.0,
+    "StartSpeed": 2.22222222222222,
+    "StartAcc": 0.8,
+    "GearboxType": "AMT",
+    "TorqueConverter": {
+      "Enabled": false
+    },
+    "DownshiftAfterUpshiftDelay": 6.0,
+    "UpshiftAfterDownshiftDelay": 6.0,
+    "UpshiftMinAcceleration": 0.1,
+    "PowershiftShiftTime": 0.0
+  }
+}
\ No newline at end of file
diff --git a/VectoCore/VectoCoreTest/TestData/BatteryElectric/GenericVehicleB2/BEV_ENG_3speed.vecto b/VectoCore/VectoCoreTest/TestData/BatteryElectric/GenericVehicleB2/BEV_ENG_3speed.vecto
new file mode 100644
index 0000000000..ec266b20cc
--- /dev/null
+++ b/VectoCore/VectoCoreTest/TestData/BatteryElectric/GenericVehicleB2/BEV_ENG_3speed.vecto
@@ -0,0 +1,45 @@
+{
+  "Header": {
+    "CreatedBy": " ()",
+    "Date": "2016-10-13T08:55:18.2100810Z",
+    "AppVersion": "3",
+    "FileVersion": 9
+  },
+  "Body": {
+    "SavedInDeclMode": false,
+    "EngineOnlyMode": false,
+    "VehicleFile": "BatteryElectricVehicle.vveh",
+    "GearboxFile": "3speedEV.vgbx",
+    "TCU": "3speedEV.vgbx",
+    "Padd_electric": 3540.0,
+
+    "VACC": "Truck.vacc",
+
+    "LAC": {
+      "Enabled": true,
+      "PreviewDistanceFactor": 10.0,
+      "DF_offset": 2.5,
+      "DF_scaling": 1.5,
+      "DF_targetSpeedLookup": "",
+      "Df_velocityDropLookup": ""
+    },
+    "OverSpeedEcoRoll": {
+      "Mode": "Off",
+      "MinSpeed": 50.0,
+      "OverSpeed": 5.0,
+      "UnderSpeed": 5.0
+    },
+    "Cycles": [
+      "LongHaul",
+      "Coach",
+      "Construction",
+      "HeavyUrban",
+      "Interurban",
+      "MunicipalUtility",
+      "RegionalDelivery",
+      "Suburban",
+      "Urban",
+      "UrbanDelivery"
+    ]
+  }
+}
\ No newline at end of file
diff --git a/VectoCore/VectoCoreTest/VectoCoreTest.csproj b/VectoCore/VectoCoreTest/VectoCoreTest.csproj
index c60edb48e0..c48ad12d6f 100644
--- a/VectoCore/VectoCoreTest/VectoCoreTest.csproj
+++ b/VectoCore/VectoCoreTest/VectoCoreTest.csproj
@@ -250,6 +250,9 @@
       <SubType>Designer</SubType>
     </None>
     <None Include="default.runsettings" />
+    <None Include="TestData\BatteryElectric\GenericVehicleB2\3speedEV.vgbx">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
     <None Include="TestData\BatteryElectric\GenericVehicleB2\BatteryElectricVehicle.vveh">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </None>
@@ -259,6 +262,9 @@
     <None Include="TestData\BatteryElectric\GenericVehicleB2\BEV_ENG.vecto">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </None>
+    <None Include="TestData\BatteryElectric\GenericVehicleB2\BEV_ENG_3speed.vecto">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
     <None Include="TestData\BatteryElectric\GenericVehicleB2\BEV_ENG_Cont30kW.vecto">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </None>
-- 
GitLab