From 280cfab839271c3d545b87e0f18dd6da605bbfa6 Mon Sep 17 00:00:00 2001
From: Markus Quaritsch <markus.quaritsch@tugraz.at>
Date: Wed, 23 Mar 2022 10:07:22 +0100
Subject: [PATCH] move calculation of overload buffer, continuous torque etc.
 from EM to data adapter

---
 VECTO/GUI/XMLExportJobDialog.Designer.vb      | 76 +++++++++----------
 .../ComponentData/ElectricMotorMapReader.cs   |  4 +-
 .../EngineeringDataAdapter.cs                 | 73 +++++++++++++++---
 .../EngineeringModeVectoRunDataFactory.cs     | 52 +++++++++----
 .../Data/ElectricMotor/ElectricMotorData.cs   | 33 ++++----
 .../SimulationComponent/Impl/ElectricMotor.cs | 36 +++------
 .../Impl/PEVAMTShiftStrategy.cs               |  8 +-
 .../Strategies/GensetPreprocessor.cs          |  2 +-
 .../Strategies/SerialHybridStrategy.cs        |  4 +-
 .../FileIO/JsonReadHybridTest.cs              |  2 +-
 .../Models/Declaration/ShiftPolygonTest.cs    | 12 +--
 .../SimulationComponent/ElectricMotorTest.cs  | 18 ++---
 .../Utils/MockSimulationDataFactory.cs        |  2 +-
 13 files changed, 189 insertions(+), 133 deletions(-)

diff --git a/VECTO/GUI/XMLExportJobDialog.Designer.vb b/VECTO/GUI/XMLExportJobDialog.Designer.vb
index fc21f135f3..6972a2fe18 100644
--- a/VECTO/GUI/XMLExportJobDialog.Designer.vb
+++ b/VECTO/GUI/XMLExportJobDialog.Designer.vb
@@ -1,27 +1,27 @@
-<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
-Partial Class XMLExportJobDialog
-    Inherits System.Windows.Forms.Form
-
-    'Form overrides dispose to clean up the component list.
-    <System.Diagnostics.DebuggerNonUserCode()> _
-    Protected Overrides Sub Dispose(ByVal disposing As Boolean)
-        Try
-            If disposing AndAlso components IsNot Nothing Then
-                components.Dispose()
-            End If
-        Finally
-            MyBase.Dispose(disposing)
-        End Try
-    End Sub
-
-    'Required by the Windows Form Designer
-    Private components As System.ComponentModel.IContainer
-
-    'NOTE: The following procedure is required by the Windows Form Designer
-    'It can be modified using the Windows Form Designer.  
-    'Do not modify it using the code editor.
-    <System.Diagnostics.DebuggerStepThrough()> _
-    Private Sub InitializeComponent()
+<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
+Partial Class XMLExportJobDialog
+    Inherits System.Windows.Forms.Form
+
+    'Form overrides dispose to clean up the component list.
+    <System.Diagnostics.DebuggerNonUserCode()> _
+    Protected Overrides Sub Dispose(ByVal disposing As Boolean)
+        Try
+            If disposing AndAlso components IsNot Nothing Then
+                components.Dispose()
+            End If
+        Finally
+            MyBase.Dispose(disposing)
+        End Try
+    End Sub
+
+    'Required by the Windows Form Designer
+    Private components As System.ComponentModel.IContainer
+
+    'NOTE: The following procedure is required by the Windows Form Designer
+    'It can be modified using the Windows Form Designer.  
+    'Do not modify it using the code editor.
+    <System.Diagnostics.DebuggerStepThrough()> _
+    Private Sub InitializeComponent()
         Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(XMLExportJobDialog))
         Me.lbVendor = New System.Windows.Forms.Label()
         Me.tbVendor = New System.Windows.Forms.TextBox()
@@ -173,18 +173,18 @@ Partial Class XMLExportJobDialog
         Me.ResumeLayout(false)
         Me.PerformLayout
 
-End Sub
-	Private WithEvents lbVendor As System.Windows.Forms.Label
-	Private WithEvents tbVendor As System.Windows.Forms.TextBox
-	Private WithEvents btnExport As System.Windows.Forms.Button
-	Private WithEvents cbSingleFile As System.Windows.Forms.CheckBox
-	Private WithEvents label1 As System.Windows.Forms.Label
-	Private WithEvents tbJobfile As System.Windows.Forms.TextBox
-	Private WithEvents tbMode As System.Windows.Forms.TextBox
-	Private WithEvents lblJobfile As System.Windows.Forms.Label
-	Private WithEvents lblDstDir As System.Windows.Forms.Label
-	Private WithEvents tbDestination As System.Windows.Forms.TextBox
-	Private WithEvents lblMode As System.Windows.Forms.Label
-	Private WithEvents btnCancel As System.Windows.Forms.Button
+End Sub
+	Private WithEvents lbVendor As System.Windows.Forms.Label
+	Private WithEvents tbVendor As System.Windows.Forms.TextBox
+	Private WithEvents btnExport As System.Windows.Forms.Button
+	Private WithEvents cbSingleFile As System.Windows.Forms.CheckBox
+	Private WithEvents label1 As System.Windows.Forms.Label
+	Private WithEvents tbJobfile As System.Windows.Forms.TextBox
+	Private WithEvents tbMode As System.Windows.Forms.TextBox
+	Private WithEvents lblJobfile As System.Windows.Forms.Label
+	Private WithEvents lblDstDir As System.Windows.Forms.Label
+	Private WithEvents tbDestination As System.Windows.Forms.TextBox
+	Private WithEvents lblMode As System.Windows.Forms.Label
+	Private WithEvents btnCancel As System.Windows.Forms.Button
 	Friend WithEvents BtTCfileBrowse As System.Windows.Forms.Button
-End Class
+End Class
diff --git a/VectoCore/VectoCore/InputData/Reader/ComponentData/ElectricMotorMapReader.cs b/VectoCore/VectoCore/InputData/Reader/ComponentData/ElectricMotorMapReader.cs
index b664b31c50..9f3ad4bd25 100644
--- a/VectoCore/VectoCore/InputData/Reader/ComponentData/ElectricMotorMapReader.cs
+++ b/VectoCore/VectoCore/InputData/Reader/ComponentData/ElectricMotorMapReader.cs
@@ -82,7 +82,9 @@ namespace TUGraz.VectoCore.InputData.Reader.ComponentData {
 			var torquesMinRpm = entries.Where(x => x.MotorSpeed.IsBetween(lowerSpeed, upperSpeed)).OrderBy(x => x.Torque).ToList();
 			// entries at 0 rpm grid point
 			var torquesZeroRpm = entries.Where(x => x.MotorSpeed.IsEqual(0)).OrderBy(x => x.Torque).ToList();
-
+			if (torquesZeroRpm.Count == 0) {
+				throw new VectoException("Electric Motor PowerMap contains no entries at 0 rpm!");
+			}
 
 			var entriesZero = new List<EfficiencyMap.Entry>();
 			var avgSpeed = torquesMinRpm.Average(x => x.MotorSpeed.Value()).SI<PerSecond>();
diff --git a/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/EngineeringDataAdapter.cs b/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/EngineeringDataAdapter.cs
index 142f3cdf27..e7e13c95ba 100644
--- a/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/EngineeringDataAdapter.cs
+++ b/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/EngineeringDataAdapter.cs
@@ -865,7 +865,8 @@ namespace TUGraz.VectoCore.InputData.Reader.DataObjectAdapter
 		}
 
 		public List<Tuple<PowertrainPosition, ElectricMotorData>> CreateElectricMachines(
-			IElectricMachinesEngineeringInputData electricMachines, Dictionary<PowertrainPosition, List<Tuple<Volt, TableData>>> torqueLimits)
+			IElectricMachinesEngineeringInputData electricMachines,
+			Dictionary<PowertrainPosition, List<Tuple<Volt, TableData>>> torqueLimits, Volt averageVoltage)
 		{
 			if (electricMachines == null) {
 				return null;
@@ -882,11 +883,12 @@ namespace TUGraz.VectoCore.InputData.Reader.DataObjectAdapter
 			return electricMachines.Entries
 				.Select(x => Tuple.Create(x.Position,
 					CreateElectricMachine(x.ElectricMachine, x.Count, x.RatioADC, x.RatioPerGear, x.MechanicalTransmissionEfficiency,
-						x.MechanicalTransmissionLossMap, torqueLimits?.First(t =>t.Key == x.Position).Value))).ToList();
+						x.MechanicalTransmissionLossMap, torqueLimits?.First(t =>t.Key == x.Position).Value, averageVoltage))).ToList();
 		}
 
 		private ElectricMotorData CreateElectricMachine(IElectricMotorEngineeringInputData motorData, int count,
-			double ratio, double[] ratioPerGear, double efficiency, TableData adcLossMap, List<Tuple<Volt, TableData>> torqueLimits)
+			double ratio, double[] ratioPerGear, double efficiency, TableData adcLossMap,
+			List<Tuple<Volt, TableData>> torqueLimits, Volt averageVoltage)
 		{
 			var voltageLevels = new List<ElectricMotorVoltageLevelData>();
 
@@ -901,23 +903,23 @@ namespace TUGraz.VectoCore.InputData.Reader.DataObjectAdapter
 
 				voltageLevels.Add(new ElectricMotorVoltageLevelData() {
 					Voltage = entry.VoltageLevel,
-					ContinuousTorque = entry.ContinuousTorque * count,
-					ContinuousTorqueSpeed = entry.ContinuousTorqueSpeed,
-					OverloadTorque = (entry.OverloadTorque ?? 0.SI<NewtonMeter>()) * count,
-					OverloadTestSpeed = entry.OverloadTestSpeed ?? 0.RPMtoRad(),
-					OverloadTime = entry.OverloadTime,
+					
 					FullLoadCurve = fullLoadCurveCombined,
                     // DragCurve = ElectricMotorDragCurveReader.Create(entry.DragCurve, count),
                     EfficiencyMap = ElectricMotorMapReader.Create(entry.PowerMap.First().PowerMap, count), //PowerMap
                 });
 			}
 
+			if (averageVoltage == null) {
+				// if no average voltage is provided (e.g. for supercap) use mean value of measured voltage maps
+				averageVoltage = (voltageLevels.Min(x => x.Voltage) + voltageLevels.Max(x => x.Voltage)) / 2.0;
+			}
 
 			var lossMap = adcLossMap != null
 				? TransmissionLossMapReader.CreateEmADCLossMap(adcLossMap, ratio, "EM ADC LossMap")
 				: TransmissionLossMapReader.CreateEmADCLossMap(efficiency, ratio, "EM ADC LossMap Eff");
 
-			return new ElectricMotorData() {
+			var retVal = new ElectricMotorData() {
 				EfficiencyData = new VoltageLevelData() { VoltageLevels = voltageLevels},
 				DragCurve = ElectricMotorDragCurveReader.Create(motorData.DragCurve, count),
 				Inertia = motorData.Inertia * count,
@@ -925,7 +927,58 @@ namespace TUGraz.VectoCore.InputData.Reader.DataObjectAdapter
 				RatioADC = ratio,
 				RatioPerGear = ratioPerGear,
 				TransmissionLossMap = lossMap,
-				ContinuousTorque = voltageLevels.First().ContinuousTorque,
+			};
+			retVal.Overload = CalculateOverloadData(motorData, count, retVal.EfficiencyData, averageVoltage);
+			return retVal;
+		}
+
+		private OverloadData CalculateOverloadData(IElectricMotorEngineeringInputData motorData, int count, VoltageLevelData voltageLevels, Volt averageVoltage)
+		{
+			
+			// if average voltage is outside of the voltage-level range, do not extrapolate but take the min voltage entry, or max voltage entry
+			if (averageVoltage < motorData.VoltageLevels.Min(x => x.VoltageLevel)) {
+				return CalculateOverloadBuffer(motorData.VoltageLevels.First(), count, voltageLevels);
+			}
+			if (averageVoltage > motorData.VoltageLevels.Max(x => x.VoltageLevel)) {
+				return CalculateOverloadBuffer(motorData.VoltageLevels.Last(), count, voltageLevels);
+			}
+
+			var (vLow, vHigh) = motorData.VoltageLevels.OrderBy(x => x.VoltageLevel).GetSection(x => x.VoltageLevel < averageVoltage);
+			var ovlLo = CalculateOverloadBuffer(vLow, count, voltageLevels);
+			var ovlHi = CalculateOverloadBuffer(vHigh, count, voltageLevels);
+
+			var retVal = new OverloadData() {
+				OverloadBuffer = VectoMath.Interpolate(vLow.VoltageLevel, vHigh.VoltageLevel, ovlLo.OverloadBuffer, ovlHi.OverloadBuffer, averageVoltage),
+				ContinuousTorque = VectoMath.Interpolate(vLow.VoltageLevel, vHigh.VoltageLevel, ovlLo.ContinuousTorque, ovlHi.ContinuousTorque, averageVoltage),
+				ContinuousPowerLoss = VectoMath.Interpolate(vLow.VoltageLevel, vHigh.VoltageLevel, ovlLo.ContinuousPowerLoss, ovlHi.ContinuousPowerLoss, averageVoltage)
+			};
+			return retVal;
+		}
+
+		private OverloadData CalculateOverloadBuffer(IElectricMotorVoltageLevel voltageEntry,
+			int count, VoltageLevelData voltageLevels)
+		{
+			var continuousTorque = voltageEntry.ContinuousTorque * count;
+			var continuousTorqueSpeed = voltageEntry.ContinuousTorqueSpeed;
+			var overloadTorque = (voltageEntry.OverloadTorque ?? 0.SI<NewtonMeter>()) * count;
+			var overloadTestSpeed = voltageEntry.OverloadTestSpeed ?? 0.RPMtoRad();
+
+
+			var peakElPwr = voltageLevels.LookupElectricPower(voltageEntry.VoltageLevel, overloadTestSpeed, -overloadTorque, true)
+				.ElectricalPower;
+			var peakPwrLoss = -peakElPwr - overloadTorque * overloadTestSpeed; // losses need to be positive
+			
+			var contElPwr = voltageLevels.LookupElectricPower(voltageEntry.VoltageLevel, continuousTorqueSpeed,
+								-continuousTorque).ElectricalPower ??
+							voltageLevels.LookupElectricPower(voltageEntry.VoltageLevel, continuousTorqueSpeed,
+								voltageLevels.FullLoadDriveTorque(voltageEntry.VoltageLevel, continuousTorqueSpeed),
+								true).ElectricalPower;
+			var continuousPowerLoss = -contElPwr - continuousTorque * continuousTorqueSpeed; // loss needs to be positive
+			var overloadBuffer = (peakPwrLoss - continuousPowerLoss) * voltageEntry.OverloadTime;
+			return new OverloadData() {
+				OverloadBuffer = overloadBuffer,
+				ContinuousTorque = continuousTorque,
+				ContinuousPowerLoss = continuousPowerLoss
 			};
 		}
 
diff --git a/VectoCore/VectoCore/InputData/Reader/Impl/EngineeringModeVectoRunDataFactory.cs b/VectoCore/VectoCore/InputData/Reader/Impl/EngineeringModeVectoRunDataFactory.cs
index 76db0e47e8..e40b9957e2 100644
--- a/VectoCore/VectoCore/InputData/Reader/Impl/EngineeringModeVectoRunDataFactory.cs
+++ b/VectoCore/VectoCore/InputData/Reader/Impl/EngineeringModeVectoRunDataFactory.cs
@@ -35,12 +35,14 @@ using System.Linq;
 using System.Runtime.CompilerServices;
 using TUGraz.VectoCommon.InputData;
 using TUGraz.VectoCommon.Models;
+using TUGraz.VectoCommon.Utils;
 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.Battery;
 using TUGraz.VectoCore.Models.SimulationComponent.Impl;
 using TUGraz.VectoCore.Utils;
 
@@ -98,11 +100,18 @@ namespace TUGraz.VectoCore.InputData.Reader.Impl
 					var vehicle = InputDataProvider.JobInputData.Vehicle;
 					var engineData = dao.CreateEngineData(vehicle, engineMode);
 					engineData.FuelMode = modeIdx;
-					
+
+					var battery = dao.CreateBatteryData(vehicle.Components.ElectricStorage, vehicle.InitialSOC);
+					var superCap = dao.CreateSuperCapData(vehicle.Components.ElectricStorage, vehicle.InitialSOC);
+
+					var averageVoltage = battery != null 
+						? CalculateAverageVoltage(battery)
+							: null;
+
 					var axlegearData = vehicle.Components.AxleGearInputData != null
 						? dao.CreateAxleGearData(vehicle.Components.AxleGearInputData)
 						: null;
-					var electricMachinesData = dao.CreateElectricMachines(vehicle.Components.ElectricMachines, vehicle.ElectricMotorTorqueLimits);
+					var electricMachinesData = dao.CreateElectricMachines(vehicle.Components.ElectricMachines, vehicle.ElectricMotorTorqueLimits, averageVoltage);
 
 					GearboxData gearboxData = null;
 					ShiftStrategyParameters gearshiftParams = null;
@@ -175,12 +184,9 @@ namespace TUGraz.VectoCore.InputData.Reader.Impl
 
 					var electricMachines =
 						dao.CreateElectricMachines(vehicle.Components.ElectricMachines,
-							vehicle.ElectricMotorTorqueLimits) ??
+							vehicle.ElectricMotorTorqueLimits, averageVoltage) ??
 						new List<Tuple<PowertrainPosition, ElectricMotorData>>();
-					var battery = dao.CreateBatteryData(vehicle.Components.ElectricStorage, vehicle.InitialSOC);
-					var superCap = dao.CreateSuperCapData(vehicle.Components.ElectricStorage, vehicle.InitialSOC);
-
-
+					
 					var jobType = VectoSimulationJobType.SerialHybridVehicle;
 
 					var vehicleData = dao.CreateVehicleData(vehicle);
@@ -233,7 +239,11 @@ namespace TUGraz.VectoCore.InputData.Reader.Impl
 					? dao.CreateAxleGearData(vehicle.Components.AxleGearInputData)
 					: null;
 
-				var electricMachinesData = dao.CreateElectricMachines(vehicle.Components.ElectricMachines, vehicle.ElectricMotorTorqueLimits);
+				var batteryData = dao.CreateBatteryData(vehicle.Components.ElectricStorage, vehicle.InitialSOC);
+				var supercapData = dao.CreateSuperCapData(vehicle.Components.ElectricStorage, vehicle.InitialSOC);
+
+				var averageVoltage = batteryData != null ? CalculateAverageVoltage(batteryData) : null;
+				var electricMachinesData = dao.CreateElectricMachines(vehicle.Components.ElectricMachines, vehicle.ElectricMotorTorqueLimits, averageVoltage);
 
 				GearboxData gearboxData = null;
 				ShiftStrategyParameters gearshiftParams = null;
@@ -297,8 +307,8 @@ namespace TUGraz.VectoCore.InputData.Reader.Impl
 					ExecutionMode = ExecutionMode.Engineering,
 					ElectricMachinesData = electricMachinesData,
 					//HybridStrategyParameters = dao.CreateHybridStrategyParameters(InputDataProvider.JobInputData.HybridStrategyParameters),
-					BatteryData = dao.CreateBatteryData(vehicle.Components.ElectricStorage, vehicle.InitialSOC),
-					SuperCapData = dao.CreateSuperCapData(vehicle.Components.ElectricStorage, vehicle.InitialSOC),
+					BatteryData = batteryData,
+					SuperCapData = supercapData,
 					SimulationType = SimulationType.DistanceCycle | SimulationType.MeasuredSpeedCycle | SimulationType.PWheel,
 					GearshiftParameters = gearshiftParams,
 					ElectricAuxDemand = InputDataProvider.JobInputData.Vehicle.Components.AuxiliaryInputData.Auxiliaries.ElectricPowerDemand,
@@ -369,12 +379,15 @@ namespace TUGraz.VectoCore.InputData.Reader.Impl
 
 					var drivingCycle = CyclesCache.GetOrAdd(cycle.CycleData.Source, _=> DrivingCycleDataReader.ReadFromDataTable(cycle.CycleData, cycle.Name, crossWindRequired));
 
+					var battery = dao.CreateBatteryData(vehicle.Components.ElectricStorage, vehicle.InitialSOC);
+					var superCap = dao.CreateSuperCapData(vehicle.Components.ElectricStorage, vehicle.InitialSOC);
+					var averageVoltage = battery != null ? CalculateAverageVoltage(battery): null;
+
 					var electricMachines =
 						dao.CreateElectricMachines(vehicle.Components.ElectricMachines,
-							vehicle.ElectricMotorTorqueLimits) ??
+							vehicle.ElectricMotorTorqueLimits, averageVoltage) ??
 						new List<Tuple<PowertrainPosition, ElectricMotorData>>();
-					var battery = dao.CreateBatteryData(vehicle.Components.ElectricStorage, vehicle.InitialSOC);
-					var superCap = dao.CreateSuperCapData(vehicle.Components.ElectricStorage, vehicle.InitialSOC);
+					
 
 				   
 					var jobType = electricMachines.Count > 0 && (battery != null || superCap != null)
@@ -434,5 +447,18 @@ namespace TUGraz.VectoCore.InputData.Reader.Impl
 				}
 			}
 		}
+
+		private Volt CalculateAverageVoltage(BatterySystemData batteryData)
+		{
+			// use the battery system to get min/max SoC of the whole battery system (multiple batteries in series/parallel)
+			//   the battery system already contains all necessary models, no need to duplicate here the rather complex calculations
+			var tmpBattery = new BatterySystem(null, batteryData);
+			var min = tmpBattery.MinSoC;
+			var max = tmpBattery.MaxSoC;
+			var averageSoC = (min + max) / 2.0;
+
+			tmpBattery.Initialize(averageSoC);
+			return tmpBattery.InternalVoltage;
+		}
 	}
 }
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Data/ElectricMotor/ElectricMotorData.cs b/VectoCore/VectoCore/Models/SimulationComponent/Data/ElectricMotor/ElectricMotorData.cs
index 0563309743..9d0ac85e97 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Data/ElectricMotor/ElectricMotorData.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Data/ElectricMotor/ElectricMotorData.cs
@@ -26,10 +26,10 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data
 		[ValidateObject]
 		public VoltageLevelData EfficiencyData { get; internal set; }
 
-		// not read direcly from input but calculated in a pre-processing step
-		public NewtonMeter ContinuousTorque { get; internal set; }
-
 		public DragCurve DragCurve { get; internal set; }
+
+		// not read direcly from input but calculated in a pre-processing step
+		public OverloadData Overload { get; internal set; }
 	}
 
 	public class VoltageLevelData
@@ -146,23 +146,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data
 	{
 		[SIRange(0, double.MaxValue)]
 		public Volt Voltage { get; internal set; }
-
-		[SIRange(double.MinValue, double.MaxValue)]
-		public NewtonMeter ContinuousTorque { get; internal set; }
-
-		[SIRange(0, double.MaxValue)]
-		public PerSecond ContinuousTorqueSpeed { get; internal set; }
-
-		[SIRange(double.MinValue, double.MaxValue)]
-		public NewtonMeter OverloadTorque { get; set; }
-
-		[SIRange(0, double.MaxValue)]
-		public PerSecond OverloadTestSpeed { get; set; }
-
-
-		[SIRange(0, double.MaxValue)]
-		public Second OverloadTime { get; internal set; }
-
+		
 		[ValidateObject]
 		public ElectricMotorFullLoadCurve FullLoadCurve { get; internal set; }
 
@@ -171,4 +155,13 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data
 
 
 	}
+
+	public class OverloadData
+	{
+		public NewtonMeter ContinuousTorque { get; internal set; }
+
+		public Joule OverloadBuffer { get; internal set; }
+
+		public Watt ContinuousPowerLoss { get; internal set; }
+	}
 }
\ No newline at end of file
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/ElectricMotor.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/ElectricMotor.cs
index 5cb6d4c91f..630f2da8bb 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/ElectricMotor.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/ElectricMotor.cs
@@ -27,11 +27,6 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 		
 		public bool DeRatingActive { get; protected internal set; }
 
-		public Joule OverloadBuffer { get; }
-		public NewtonMeter ContinuousTorque { get; }
-
-		public Watt ContinuousPowerLoss { get; }
-
 		public BusAuxiliariesAdapter BusAux { protected get; set; }
 
 		public ElectricMotor(IVehicleContainer container, ElectricMotorData data, IElectricMotorControl control, PowertrainPosition position) : base(container)
@@ -50,20 +45,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 
 			container.AddComponent(this); // We have to do this again because in the base class the position is unknown!
 
-			var vLevel = ModelData.EfficiencyData.VoltageLevels.First();
-			ContinuousTorque = vLevel.ContinuousTorque;
-			var voltage = ModelData.EfficiencyData.VoltageLevels.First().Voltage;
-			var contElPwr =
-				ModelData.EfficiencyData.LookupElectricPower(voltage, vLevel.ContinuousTorqueSpeed, -ContinuousTorque).ElectricalPower ??
-				ModelData.EfficiencyData.LookupElectricPower(voltage, vLevel.ContinuousTorqueSpeed, ModelData.EfficiencyData.FullLoadDriveTorque(voltage, vLevel.ContinuousTorqueSpeed), true).ElectricalPower;
-			ContinuousPowerLoss = -contElPwr - ContinuousTorque * vLevel.ContinuousTorqueSpeed; // loss needs to be positive
-			
-			var peakElPwr = ModelData.EfficiencyData.LookupElectricPower(voltage, vLevel.OverloadTestSpeed, -vLevel.OverloadTorque, true)
-				.ElectricalPower;
-			var peakPwrLoss = -peakElPwr - vLevel.OverloadTorque * vLevel.OverloadTestSpeed; // losses need to be positive
-
-			OverloadBuffer = (peakPwrLoss - ContinuousPowerLoss) * vLevel.OverloadTime;
-			if (OverloadBuffer.IsSmallerOrEqual(0) && !(container is SimplePowertrainContainer)) {
+			if (ModelData.Overload.OverloadBuffer.IsSmallerOrEqual(0) && !(container is SimplePowertrainContainer)) {
 				Log.Error("Overload buffer for thermal de-rating is zero or negative! Please check electric motor data!");
 			}
 		}
@@ -399,7 +381,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 
 		private NewtonMeter GetMaxRecuperationTorque(Volt volt, Second dt, PerSecond avgSpeed)
 		{
-			var tqContinuousPwr = DeRatingActive ? ContinuousTorque : null;
+			var tqContinuousPwr = DeRatingActive ? ModelData.Overload.ContinuousTorque : null;
 			
 			var maxEmTorque = VectoMath.Min(tqContinuousPwr, ModelData.EfficiencyData.FullGenerationTorque(volt, avgSpeed));
 			var electricSystemResponse = ElectricPower.Request(0.SI<Second>(), dt, 0.SI<Watt>(), true);
@@ -427,7 +409,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 
 		private NewtonMeter GetMaxDriveTorque(Volt volt, Second dt, PerSecond avgSpeed)
 		{
-			var tqContinuousPwr = DeRatingActive ? -ContinuousTorque : null;
+			var tqContinuousPwr = DeRatingActive ? -ModelData.Overload.ContinuousTorque : null;
 			
 			var maxEmTorque = VectoMath.Max(tqContinuousPwr ,ModelData.EfficiencyData.FullLoadDriveTorque(volt, avgSpeed));
 			var electricSystemResponse = ElectricPower.Request(0.SI<Second>(), dt, 0.SI<Watt>(), true);
@@ -522,9 +504,9 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 			container[ModalResultField.EM_Off_, Position] = CurrentState.EMTorque == null ? 1.SI<Scalar>() : 0.SI<Scalar>();
 
 			var losses = (CurrentState.EmTorqueMap ?? 0.SI<NewtonMeter>()) * avgEMSpeed - CurrentState.ElectricPowerToBattery;
-			var contribution = (losses - ContinuousPowerLoss) * simulationInterval;
-			if (OverloadBuffer.Value() != 0) { // mk2021-08-03 overloadbuffer was 0 in Test Case: "ADASTestPEV.TestPCCEngineeringSampleCases G5Eng PCC12 Case A"
-				container[ModalResultField.ElectricMotor_OvlBuffer_, Position] = VectoMath.Max(0, (ThermalBuffer + contribution) / OverloadBuffer);
+			var contribution = (losses - ModelData.Overload.ContinuousPowerLoss) * simulationInterval;
+			if (ModelData.Overload.OverloadBuffer.Value() != 0) { // mk2021-08-03 overloadbuffer was 0 in Test Case: "ADASTestPEV.TestPCCEngineeringSampleCases G5Eng PCC12 Case A"
+				container[ModalResultField.ElectricMotor_OvlBuffer_, Position] = VectoMath.Max(0, (ThermalBuffer + contribution) / ModelData.Overload.OverloadBuffer);
 			}
 				
 			if (NextComponent == null && BusAux != null) {
@@ -536,17 +518,17 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 		{
 			var avgSpeed = (PreviousState.EMSpeed + CurrentState.EMSpeed) / 2;
 			var losses = (CurrentState.EMTorque ?? 0.SI<NewtonMeter>()) * avgSpeed - CurrentState.ElectricPowerToBattery;
-			ThermalBuffer += (losses - ContinuousPowerLoss) * simulationInterval;
+			ThermalBuffer += (losses - ModelData.Overload.ContinuousPowerLoss) * simulationInterval;
 			if (ThermalBuffer < 0) {
 				ThermalBuffer = 0.SI<Joule>();
 			}
 
 			if (DeRatingActive) {
-				if (ThermalBuffer.IsSmallerOrEqual(OverloadBuffer * ModelData.OverloadRegenerationFactor)) {
+				if (ThermalBuffer.IsSmallerOrEqual(ModelData.Overload.OverloadBuffer * ModelData.OverloadRegenerationFactor)) {
 					DeRatingActive = false;
 				}
 			} else {
-				if (ThermalBuffer.IsGreater(OverloadBuffer)) {
+				if (ThermalBuffer.IsGreater(ModelData.Overload.OverloadBuffer)) {
 					DeRatingActive = true;
 				}
 			}
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/PEVAMTShiftStrategy.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/PEVAMTShiftStrategy.cs
index 9505ec1ede..f15e669cb1 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/PEVAMTShiftStrategy.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/PEVAMTShiftStrategy.cs
@@ -161,13 +161,13 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 			var contTqFld = new ElectricMotorFullLoadCurve(new List<ElectricMotorFullLoadCurve.FullLoadEntry>() {
 				new ElectricMotorFullLoadCurve.FullLoadEntry() {
 					MotorSpeed = 0.RPMtoRad(),
-					FullDriveTorque = -em.ContinuousTorque,
-					FullGenerationTorque = em.ContinuousTorque
+					FullDriveTorque = -em.Overload.ContinuousTorque,
+					FullGenerationTorque = em.Overload.ContinuousTorque
 				},
 				new ElectricMotorFullLoadCurve.FullLoadEntry() {
 					MotorSpeed = 1.1 * emFld.MaxSpeed,
-					FullDriveTorque = -em.ContinuousTorque,
-					FullGenerationTorque = em.ContinuousTorque
+					FullDriveTorque = -em.Overload.ContinuousTorque,
+					FullGenerationTorque = em.Overload.ContinuousTorque
 				}
 			});
 			var limitedFld = AbstractSimulationDataAdapter.IntersectEMFullLoadCurves(emFld, contTqFld);
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Strategies/GensetPreprocessor.cs b/VectoCore/VectoCore/Models/SimulationComponent/Strategies/GensetPreprocessor.cs
index 7f6ba0eaee..dce109a26a 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Strategies/GensetPreprocessor.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Strategies/GensetPreprocessor.cs
@@ -47,7 +47,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies
 
 		private void MaxElectricPower(Volt voltage, bool emDerated)
 		{
-			var continuousTq = emDerated ? Genset.ElectricMotor.ContinuousTorque : double.MaxValue.SI<NewtonMeter>();
+			var continuousTq = emDerated ? EmData.Overload.ContinuousTorque : double.MaxValue.SI<NewtonMeter>();
 			var maxSpeed = VectoMath.Min(EmData.EfficiencyData.MaxSpeed,
 				IceData.FullLoadCurves[0].FullLoadEntries.Select(x => x.EngineSpeed).Max());
 			var emFldDrivetrain = new ElectricMotorFullLoadCurve(EmData.EfficiencyData.VoltageLevels[0].FullLoadCurve
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Strategies/SerialHybridStrategy.cs b/VectoCore/VectoCore/Models/SimulationComponent/Strategies/SerialHybridStrategy.cs
index 3ba4c0729c..f64706e76e 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Strategies/SerialHybridStrategy.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Strategies/SerialHybridStrategy.cs
@@ -294,8 +294,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies
 				retVal.MechanicalAssistPower[em.Item1] = null;
 			}
 
-			GenSetCharacteristics.ContinuousTorque =
-				(DataBus.ElectricMotorInfo(PowertrainPosition.GEN) as ElectricMotor).ContinuousTorque;
+			GenSetCharacteristics.ContinuousTorque = ModelData.ElectricMachinesData
+				.FirstOrDefault(x => x.Item1 == EmPosition)?.Item2.Overload.ContinuousTorque ?? 0.SI<NewtonMeter>(); 
 
 			PreviousState.AngularVelocity = outAngularVelocity;
 			PreviousState.SMState = DataBus.BatteryInfo.StateOfCharge > StrategyParameters.TargetSoC
diff --git a/VectoCore/VectoCoreTest/FileIO/JsonReadHybridTest.cs b/VectoCore/VectoCoreTest/FileIO/JsonReadHybridTest.cs
index 0859bde7a6..2e0bf3c6ed 100644
--- a/VectoCore/VectoCoreTest/FileIO/JsonReadHybridTest.cs
+++ b/VectoCore/VectoCoreTest/FileIO/JsonReadHybridTest.cs
@@ -145,7 +145,7 @@ namespace TUGraz.VectoCore.Tests.FileIO
 				new JSONComponentInputData(@"TestData\Hybrids\ElectricMotor\GenericEMotorV3.vem", null,
 					false);
 			var daa = new EngineeringDataAdapter();
-			var emData = daa.CreateElectricMachines(inputProvider.ElectricMachines, null).First().Item2;
+			var emData = daa.CreateElectricMachines(inputProvider.ElectricMachines, null, null).First().Item2;
 
 
 			Assert.AreEqual(26, emData.DragCurve.Lookup(2000.RPMtoRad()).Value());
diff --git a/VectoCore/VectoCoreTest/Models/Declaration/ShiftPolygonTest.cs b/VectoCore/VectoCoreTest/Models/Declaration/ShiftPolygonTest.cs
index cc0bc9807e..89c56a1bfa 100644
--- a/VectoCore/VectoCoreTest/Models/Declaration/ShiftPolygonTest.cs
+++ b/VectoCore/VectoCoreTest/Models/Declaration/ShiftPolygonTest.cs
@@ -938,7 +938,7 @@ namespace TUGraz.VectoCore.Tests.Models.Declaration
 			var gearboxData = inputData.JobInputData.Vehicle.Components.GearboxInputData;
 			var dao = new EngineeringDataAdapter();
 			var emData = dao.CreateElectricMachines(inputData.JobInputData.Vehicle.Components.ElectricMachines,
-				null).FirstOrDefault()?.Item2;
+				null, null).FirstOrDefault()?.Item2;
 			var axlegearRatio = inputData.JobInputData.Vehicle.Components.AxleGearInputData.Ratio;
 			var vehicleData = dao.CreateVehicleData(inputData.JobInputData.Vehicle);
 			var r_dyn = vehicleData.DynamicTyreRadius;
@@ -989,7 +989,7 @@ namespace TUGraz.VectoCore.Tests.Models.Declaration
 			var gearboxData = inputData.JobInputData.Vehicle.Components.GearboxInputData;
 			var dao = new EngineeringDataAdapter();
 			var emData = dao.CreateElectricMachines(inputData.JobInputData.Vehicle.Components.ElectricMachines,
-				null).FirstOrDefault()?.Item2;
+				null, null).FirstOrDefault()?.Item2;
 			
 			var axlegearRatio = inputData.JobInputData.Vehicle.Components.AxleGearInputData.Ratio;
 			var vehicleData = dao.CreateVehicleData(inputData.JobInputData.Vehicle);
@@ -999,13 +999,13 @@ namespace TUGraz.VectoCore.Tests.Models.Declaration
             var contTqFld = new ElectricMotorFullLoadCurve(new List<ElectricMotorFullLoadCurve.FullLoadEntry>() {
 				new ElectricMotorFullLoadCurve.FullLoadEntry() {
 					MotorSpeed = 0.RPMtoRad(),
-					FullDriveTorque = -emData.ContinuousTorque,
-					FullGenerationTorque = emData.ContinuousTorque
+					FullDriveTorque = -emData.Overload.ContinuousTorque,
+					FullGenerationTorque = emData.Overload.ContinuousTorque
 				},
 				new ElectricMotorFullLoadCurve.FullLoadEntry() {
 					MotorSpeed = 1.1 * emData.EfficiencyData.VoltageLevels.First().FullLoadCurve.MaxSpeed,
-					FullDriveTorque = -emData.ContinuousTorque,
-					FullGenerationTorque = emData.ContinuousTorque
+					FullDriveTorque = -emData.Overload.ContinuousTorque,
+					FullGenerationTorque = emData.Overload.ContinuousTorque
 				}
 			});
 			var limitedFld = AbstractSimulationDataAdapter.IntersectEMFullLoadCurves(emData.EfficiencyData.VoltageLevels.First().FullLoadCurve, contTqFld);
diff --git a/VectoCore/VectoCoreTest/Models/SimulationComponent/ElectricMotorTest.cs b/VectoCore/VectoCoreTest/Models/SimulationComponent/ElectricMotorTest.cs
index a955efe4cf..bbe9cd9cb8 100644
--- a/VectoCore/VectoCoreTest/Models/SimulationComponent/ElectricMotorTest.cs
+++ b/VectoCore/VectoCoreTest/Models/SimulationComponent/ElectricMotorTest.cs
@@ -55,13 +55,13 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponent
 					}
 				}
 			};
-			var data = dao.CreateElectricMachines(electricMachine, null);
+			var data = dao.CreateElectricMachines(electricMachine, null, null);
 			var emModelData = data.First().Item2;
 
 			Assert.AreEqual(0.15 * count, emModelData.Inertia.Value(), 1e-3);
 
 			//Assert.AreEqual(2000, emModelData.ContinuousTorqueSpeed.AsRPM, 1e-3);
-			Assert.AreEqual(238.7323 * count, emModelData.ContinuousTorque.Value(), 1e-3);
+			Assert.AreEqual(238.7323 * count, emModelData.Overload.ContinuousTorque.Value(), 1e-3);
 
 			Assert.AreEqual(334.23 * count, -emModelData.EfficiencyData.VoltageLevels.First().FullLoadCurve.FullLoadDriveTorque(2000.RPMtoRad()).Value(), 1e-3);
 			Assert.AreEqual(-334.23 * count, -emModelData.EfficiencyData.VoltageLevels.First().FullLoadCurve.FullGenerationTorque(2000.RPMtoRad()).Value(), 1e-3);
@@ -99,7 +99,7 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponent
 					}
 				}
 			};
-			var data = dao.CreateElectricMachines(electricMachine, null);
+			var data = dao.CreateElectricMachines(electricMachine, null, null);
 			var strategy = new MockHybridControl();
 
 			var battery = new MockBattery();
@@ -146,7 +146,7 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponent
 					}
 				}
 			};
-			var data = dao.CreateElectricMachines(electricMachine, null);
+			var data = dao.CreateElectricMachines(electricMachine, null, null);
 			var strategy = new MockHybridControl();
 
 			var battery = new MockBattery();
@@ -193,7 +193,7 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponent
 					}
 				}
 			};
-			var data = dao.CreateElectricMachines(electricMachine, null);
+			var data = dao.CreateElectricMachines(electricMachine, null, null);
 			var strategy = new MockHybridControl();
 
 			var battery = new MockBattery();
@@ -243,7 +243,7 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponent
 					}
 				}
 			};
-			var data = dao.CreateElectricMachines(electricMachine, null);
+			var data = dao.CreateElectricMachines(electricMachine, null, null);
 			var strategy = new MockHybridControl();
 
 			var battery = new MockBattery();
@@ -288,7 +288,7 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponent
 					}
 				}
 			};
-			var data = dao.CreateElectricMachines(electricMachine, null);
+			var data = dao.CreateElectricMachines(electricMachine, null, null);
 			var strategy = new MockHybridControl();
 
 			var batInput = JSONInputDataFactory.ReadREESSData(BatFile, false);
@@ -352,7 +352,7 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponent
 					}
 				}
 			};
-			var data = dao.CreateElectricMachines(electricMachine, null);
+			var data = dao.CreateElectricMachines(electricMachine, null, null);
 			var strategy = new MockHybridControl();
 
 			var tmp = new MockBatteryInputData()
@@ -407,7 +407,7 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponent
 					}
 				}
 			};
-			var data = dao.CreateElectricMachines(electricMachine, null);
+			var data = dao.CreateElectricMachines(electricMachine, null, null);
 			var strategy = new MockHybridControl();
 
 			var tmp = new MockBatteryInputData()
diff --git a/VectoCore/VectoCoreTest/Utils/MockSimulationDataFactory.cs b/VectoCore/VectoCoreTest/Utils/MockSimulationDataFactory.cs
index 8d7345564e..3c89b0fe24 100644
--- a/VectoCore/VectoCoreTest/Utils/MockSimulationDataFactory.cs
+++ b/VectoCore/VectoCoreTest/Utils/MockSimulationDataFactory.cs
@@ -190,7 +190,7 @@ namespace TUGraz.VectoCore.Tests.Utils
 						Count = count, ElectricMachine = inputData, Position = pos, RatioADC = ratio, MechanicalTransmissionEfficiency = efficiency,
 					}
 				}
-			}, null);
+			}, null, null);
 		}
 	
 
-- 
GitLab