From 6c80439e4807b913fb09567da1f609265e097ce3 Mon Sep 17 00:00:00 2001
From: Markus Quaritsch <markus.quaritsch@tugraz.at>
Date: Fri, 9 Sep 2016 14:31:20 +0200
Subject: [PATCH] TorqueConverter: compute max. available torque at TC-out
 depending on the engine's (dyn) full-load power and inertia. used to improve
 search operating point when accelerating

---
 .../Models/Connector/Ports/Impl/Response.cs   |  5 +-
 .../Simulation/Impl/PowertrainBuilder.cs      | 11 ++--
 .../Data/Gearbox/TorqueConverterData.cs       | 33 +++++++++++
 .../SimulationComponent/Impl/ATGearbox.cs     |  4 +-
 .../Impl/CombustionEngine.cs                  |  4 ++
 .../Impl/TorqueConverter.cs                   | 57 ++++++++++++++-----
 .../VectoCoreTest/Integration/ATPowerTrain.cs |  2 +-
 .../SimulationComponent/ATGearboxTest.cs      |  6 +-
 8 files changed, 95 insertions(+), 27 deletions(-)

diff --git a/VectoCore/VectoCore/Models/Connector/Ports/Impl/Response.cs b/VectoCore/VectoCore/Models/Connector/Ports/Impl/Response.cs
index ac1b528ffd..5302d1abd7 100644
--- a/VectoCore/VectoCore/Models/Connector/Ports/Impl/Response.cs
+++ b/VectoCore/VectoCore/Models/Connector/Ports/Impl/Response.cs
@@ -48,6 +48,8 @@ namespace TUGraz.VectoCore.Models.Connector.Ports.Impl
 		public PerSecond EngineSpeed { get; set; }
 
 		public Watt EnginePowerRequest { get; set; }
+		public Watt DynamicFullLoadPower { get; set; }
+
 		public Watt AngularGearPowerRequest { get; set; }
 		public Watt ClutchPowerRequest { get; set; }
 		public Watt GearboxPowerRequest { get; set; }
@@ -75,7 +77,8 @@ namespace TUGraz.VectoCore.Models.Connector.Ports.Impl
 	/// <summary>
 	/// Response when a request was successful.
 	/// </summary>
-	public class ResponseSuccess : AbstractResponse {}
+	public class ResponseSuccess : AbstractResponse {
+	}
 
 	/// <summary>
 	/// Response when the request resulted in an engine or gearbox overload. 
diff --git a/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs b/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs
index 36ea2416b6..7bfcdb22b2 100644
--- a/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs
+++ b/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs
@@ -33,6 +33,7 @@ using System;
 using System.Linq;
 using TUGraz.VectoCommon.Exceptions;
 using TUGraz.VectoCommon.Models;
+using TUGraz.VectoCommon.Utils;
 using TUGraz.VectoCore.Models.Simulation.Data;
 using TUGraz.VectoCore.Models.SimulationComponent;
 using TUGraz.VectoCore.Models.SimulationComponent.Data;
@@ -138,7 +139,7 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 				.AddComponent(new Brakes(container))
 				.AddComponent(new AxleGear(container, data.AxleGearData))
 				.AddComponent(data.AngularGearData != null ? new AngularGear(container, data.AngularGearData) : null)
-				.AddComponent(GetGearbox(container, data.GearboxData), data.Retarder, data.PTO, container);
+				.AddComponent(GetGearbox(container, data.GearboxData, data.EngineData.Inertia), data.Retarder, data.PTO, container);
 			if (data.GearboxData.Type.ManualTransmission()) {
 				powertrain = powertrain.AddComponent(new Clutch(container, data.EngineData));
 			}
@@ -169,7 +170,7 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 				.AddComponent(new Brakes(container))
 				.AddComponent(new AxleGear(container, data.AxleGearData))
 				.AddComponent(data.AngularGearData != null ? new AngularGear(container, data.AngularGearData) : null)
-				.AddComponent(GetGearbox(container, data.GearboxData), data.Retarder, data.PTO, container);
+				.AddComponent(GetGearbox(container, data.GearboxData, data.EngineData.Inertia), data.Retarder, data.PTO, container);
 			if (data.GearboxData.Type.ManualTransmission()) {
 				powertrain = powertrain.AddComponent(new Clutch(container, data.EngineData));
 			}
@@ -196,7 +197,7 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 				.AddComponent(new Brakes(container))
 				.AddComponent(new AxleGear(container, data.AxleGearData))
 				.AddComponent(data.AngularGearData != null ? new AngularGear(container, data.AngularGearData) : null)
-				.AddComponent(GetGearbox(container, data.GearboxData), data.Retarder, data.PTO, container);
+				.AddComponent(GetGearbox(container, data.GearboxData, data.EngineData.Inertia), data.Retarder, data.PTO, container);
 			if (data.GearboxData.Type.ManualTransmission()) {
 				powertrain = powertrain.AddComponent(new Clutch(container, data.EngineData));
 			}
@@ -256,7 +257,7 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 			return aux;
 		}
 
-		private static IGearbox GetGearbox(IVehicleContainer container, GearboxData data)
+		private static IGearbox GetGearbox(IVehicleContainer container, GearboxData data, KilogramSquareMeter engineInertia)
 		{
 			IShiftStrategy strategy;
 			switch (data.Type) {
@@ -269,7 +270,7 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 				case GearboxType.ATPowerSplit:
 				case GearboxType.ATSerial:
 					strategy = new ATShiftStrategy(data, container);
-					return new ATGearbox(container, data, strategy);
+					return new ATGearbox(container, data, strategy, engineInertia);
 				default:
 					throw new VectoSimulationException("Unknown Gearbox Type: {0}", data.Type);
 			}
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Data/Gearbox/TorqueConverterData.cs b/VectoCore/VectoCore/Models/SimulationComponent/Data/Gearbox/TorqueConverterData.cs
index 170b2f50f0..0626475a02 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Data/Gearbox/TorqueConverterData.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Data/Gearbox/TorqueConverterData.cs
@@ -175,6 +175,39 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox
 			}
 			return GetOutTorque(inAngularVelocity, solutions.Max().SI<PerSecond>());
 		}
+
+		public TorqueConverterOperatingPoint GetMaxPowerOperatingPoint(Watt maxPower, PerSecond prevInputSpeed,
+			PerSecond nextOutputSpeed, KilogramSquareMeter inertia, Second dt)
+		{
+			//var retVal = new TorqueConverterOperatingPoint {
+			//	OutAngularVelocity = nextOutputSpeed
+			//};
+			var solutions = new List<double>();
+			var mpNorm = ReferenceSpeed.Value();
+
+			foreach (var segment in TorqueConverterEntries.Pairwise(Tuple.Create)) {
+				var mpEdge = Edge.Create(new Point(segment.Item1.SpeedRatio, segment.Item1.Torque.Value()),
+					new Point(segment.Item2.SpeedRatio, segment.Item2.Torque.Value()));
+
+				var a = mpEdge.OffsetXY / mpNorm / mpNorm;
+				var b = inertia.Value() / 2 / dt.Value() + mpEdge.SlopeXY * nextOutputSpeed.Value() / mpNorm / mpNorm;
+				var c = 0;
+				var d = -inertia.Value() / 2 / dt.Value() * prevInputSpeed.Value() * prevInputSpeed.Value() - maxPower.Value();
+				var sol = VectoMath.CubicEquationSolver(a, b, c, d);
+
+				var selected = sol.Where(x => x > 0 && nextOutputSpeed / x >= mpEdge.P1.X && nextOutputSpeed / x < mpEdge.P2.X);
+				solutions.AddRange(selected);
+			}
+
+			if (solutions.Count == 0) {
+				throw new VectoException(
+					"Failed to find operating point for maxPower {0}, prevInputSpeed {1}, nextOutputSpeed {2}", maxPower,
+					prevInputSpeed, nextOutputSpeed);
+			}
+			solutions.Sort();
+
+			return GetOutTorque(solutions.First().SI<PerSecond>(), nextOutputSpeed);
+		}
 	}
 
 	public class TorqueConverterOperatingPoint
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/ATGearbox.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/ATGearbox.cs
index 13f4ba20f0..bfae1be4cf 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/ATGearbox.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/ATGearbox.cs
@@ -23,13 +23,13 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 
 		public Second LastShift { get; private set; }
 
-		public ATGearbox(IVehicleContainer container, GearboxData gearboxModelData, IShiftStrategy strategy)
+		public ATGearbox(IVehicleContainer container, GearboxData gearboxModelData, IShiftStrategy strategy, KilogramSquareMeter engineInertia)
 			: base(container, gearboxModelData)
 		{
 			Strategy = strategy;
 			Strategy.Gearbox = this;
 			LastShift = -double.MaxValue.SI<Second>();
-			TorqueConverter = new TorqueConverter(this, Strategy, container, gearboxModelData.TorqueConverterData);
+			TorqueConverter = new TorqueConverter(this, Strategy, container, gearboxModelData.TorqueConverterData, engineInertia);
 		}
 
 		private IIdleController _idleController;
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs
index 613672faa5..4c2e520c79 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs
@@ -216,6 +216,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 					DeltaFullLoad = deltaFull * avgEngineSpeed,
 					DeltaDragLoad = deltaDrag * avgEngineSpeed,
 					EnginePowerRequest = torqueOut * avgEngineSpeed,
+					DynamicFullLoadPower = dynamicFullLoadPower,
 					AuxiliariesPowerDemand = auxTorqueDemand * avgEngineSpeed,
 					EngineSpeed = angularVelocity,
 					EngineMaxTorqueOut =
@@ -252,6 +253,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 					AbsTime = absTime,
 					Delta = deltaFull * avgEngineSpeed,
 					EnginePowerRequest = totalTorqueDemand * avgEngineSpeed,
+					DynamicFullLoadPower = dynamicFullLoadPower,
 					Source = this,
 					AuxiliariesPowerDemand = auxTorqueDemand * avgEngineSpeed,
 					EngineSpeed = angularVelocity,
@@ -265,6 +267,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 					AbsTime = absTime,
 					Delta = deltaDrag * avgEngineSpeed,
 					EnginePowerRequest = totalTorqueDemand * avgEngineSpeed,
+					DynamicFullLoadPower = dynamicFullLoadPower,
 					Source = this,
 					AuxiliariesPowerDemand = auxTorqueDemand * avgEngineSpeed,
 					EngineSpeed = angularVelocity,
@@ -275,6 +278,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 
 			return new ResponseSuccess {
 				EnginePowerRequest = totalTorqueDemand * avgEngineSpeed,
+				DynamicFullLoadPower = dynamicFullLoadPower,
 				AuxiliariesPowerDemand = auxTorqueDemand * avgEngineSpeed,
 				EngineSpeed = angularVelocity,
 				Source = this
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/TorqueConverter.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/TorqueConverter.cs
index de33055ce3..83c481351b 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/TorqueConverter.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/TorqueConverter.cs
@@ -14,22 +14,24 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 	public class TorqueConverter : StatefulVectoSimulationComponent<TorqueConverter.TorqueConverterComponentState>,
 		ITnInPort, ITnOutPort
 	{
-		protected ATGearbox Gearbox;
+		protected readonly ATGearbox Gearbox;
 
-		protected IShiftStrategy ShiftStrategy;
+		protected readonly IShiftStrategy ShiftStrategy;
 
 		protected TorqueConverterData ModelData;
+		private KilogramSquareMeter EngineInertia;
 
 		//protected bool SearchingTcOperatingPoint;
 
 		public ITnOutPort NextComponent { protected internal get; set; }
 
 		public TorqueConverter(ATGearbox gearbox, IShiftStrategy shiftStrategy, IVehicleContainer container,
-			TorqueConverterData tcData) : base(container)
+			TorqueConverterData tcData, KilogramSquareMeter engineInertia) : base(container)
 		{
 			Gearbox = gearbox;
 			ShiftStrategy = shiftStrategy;
 			ModelData = tcData;
+			EngineInertia = engineInertia;
 		}
 
 		public void Connect(ITnOutPort other)
@@ -52,12 +54,17 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 		{
 			if (dryRun) {
 				var dryOperatingPoint = FindOperatingPoint(outTorque, outAngularVelocity);
-				var deltaTorqueConverter = (outTorque - dryOperatingPoint.OutTorque) *
-											(PreviousState.OutAngularVelocity + dryOperatingPoint.OutAngularVelocity) / 2.0;
-				// operatingPoint.inAngularVelocity is for sure between engine idle speed and max TC speed
 				var engineResponse =
 					(ResponseDryRun)NextComponent.Request(absTime, dt, dryOperatingPoint.InTorque, dryOperatingPoint.InAngularVelocity,
 						true);
+
+				//var dryOperatingPoint = FindOperatingPoint(outTorque, outAngularVelocity);
+				var deltaTorqueConverter = (outTorque - dryOperatingPoint.OutTorque) *
+											(PreviousState.OutAngularVelocity + dryOperatingPoint.OutAngularVelocity) / 2.0;
+				//// operatingPoint.inAngularVelocity is for sure between engine idle speed and max TC speed
+				//var engineResponse =
+				//	(ResponseDryRun)NextComponent.Request(absTime, dt, dryOperatingPoint.InTorque, dryOperatingPoint.InAngularVelocity,
+				//		true);
 				var deltaEngine = (engineResponse.DeltaFullLoad > 0 ? engineResponse.DeltaFullLoad : 0.SI<Watt>()) +
 								(engineResponse.DeltaDragLoad < 0 ? -engineResponse.DeltaDragLoad : 0.SI<Watt>());
 				if (deltaTorqueConverter.IsEqual(0) && deltaEngine.IsEqual(0)) {
@@ -68,15 +75,19 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 						TorqueConverterOperatingPoint = dryOperatingPoint
 					};
 				}
-				if (engineResponse.DeltaFullLoad > 0 || engineResponse.DeltaDragLoad < 0) {
-					// engine is overloaded with current operating point, reduce torque...
-					dryOperatingPoint =
-						ModelData.GetOutTorqueAndSpeed(
-							outTorque > 0 ? engineResponse.EngineMaxTorqueOut : engineResponse.EngineDragTorque,
-							dryOperatingPoint.InAngularVelocity, null);
-				}
-
 
+				dryOperatingPoint = GetMaxPowerOperatingPoint(dt, outAngularVelocity, engineResponse);
+				engineResponse = (ResponseDryRun)NextComponent.Request(absTime, dt, dryOperatingPoint.InTorque,
+					dryOperatingPoint.InAngularVelocity, true);
+
+				//if (engineResponse.DeltaFullLoad > 0 || engineResponse.DeltaDragLoad < 0)
+				//{
+				//	// engine is overloaded with current operating point, reduce torque...
+				//	dryOperatingPoint =
+				//		ModelData.GetOutTorqueAndSpeed(
+				//			outTorque > 0 ? engineResponse.EngineMaxTorqueOut : engineResponse.EngineDragTorque,
+				//			dryOperatingPoint.InAngularVelocity, null);
+				//}
 				var delta = (outTorque - dryOperatingPoint.OutTorque) *
 							(PreviousState.OutAngularVelocity + dryOperatingPoint.OutAngularVelocity) / 2.0;
 				//deltaTorqueConverter.Value() * (deltaEngine.IsEqual(0) ? 1 : deltaEngine.Value());
@@ -110,6 +121,23 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 			return retVal;
 		}
 
+		private TorqueConverterOperatingPoint GetMaxPowerOperatingPoint(Second dt, PerSecond outAngularVelocity,
+			ResponseDryRun engineResponse)
+		{
+			try {
+				var operatingPoint =
+					ModelData.GetMaxPowerOperatingPoint(engineResponse.DynamicFullLoadPower - engineResponse.AuxiliariesPowerDemand,
+						DataBus.EngineSpeed, outAngularVelocity, EngineInertia, dt);
+				if (operatingPoint.InAngularVelocity.IsGreater(DataBus.EngineRatedSpeed)) {
+					operatingPoint = ModelData.GetOutTorque(DataBus.EngineRatedSpeed, outAngularVelocity);
+				}
+				return operatingPoint;
+			} catch (VectoException ve) {
+				Log.Error(ve, "failed to find torque converter operating point for MaxPower");
+				throw;
+			}
+		}
+
 		protected internal TorqueConverterOperatingPoint FindOperatingPoint(NewtonMeter outTorque,
 			PerSecond outAngularVelocity)
 		{
@@ -120,7 +148,6 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 						operatingPoint.InAngularVelocity);
 				}
 				if (operatingPoint.InAngularVelocity.IsGreater(DataBus.EngineRatedSpeed)) {
-					//ModelData.TorqueConverterSpeedLimit)) {
 					operatingPoint = ModelData.GetOutTorque(DataBus.EngineRatedSpeed, outAngularVelocity);
 				}
 				return operatingPoint;
diff --git a/VectoCore/VectoCoreTest/Integration/ATPowerTrain.cs b/VectoCore/VectoCoreTest/Integration/ATPowerTrain.cs
index 1c3c96f780..cb5971d3e6 100644
--- a/VectoCore/VectoCoreTest/Integration/ATPowerTrain.cs
+++ b/VectoCore/VectoCoreTest/Integration/ATPowerTrain.cs
@@ -70,7 +70,7 @@ namespace TUGraz.VectoCore.Tests.Integration
 				.AddComponent(new Brakes(container))
 				.AddComponent(new AxleGear(container, axleGearData))
 				.AddComponent(new DummyRetarder(container))
-				.AddComponent(new ATGearbox(container, gearboxData, new ATShiftStrategy(gearboxData, container)))
+				.AddComponent(new ATGearbox(container, gearboxData, new ATShiftStrategy(gearboxData, container), engineData.Inertia))
 				.AddComponent(engine);
 
 			var aux = new EngineAuxiliary(container);
diff --git a/VectoCore/VectoCoreTest/Models/SimulationComponent/ATGearboxTest.cs b/VectoCore/VectoCoreTest/Models/SimulationComponent/ATGearboxTest.cs
index 32533e33e9..8f62fa8781 100644
--- a/VectoCore/VectoCoreTest/Models/SimulationComponent/ATGearboxTest.cs
+++ b/VectoCore/VectoCoreTest/Models/SimulationComponent/ATGearboxTest.cs
@@ -38,10 +38,10 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponent
 		public void TestATGearInitialize(double vehicleSpeed, double torque, int expectedGear)
 		{
 			var vehicleContainer = new MockVehicleContainer(); //(ExecutionMode.Engineering);
-			vehicleContainer.Engine = new CombustionEngine(vehicleContainer,
-				MockSimulationDataFactory.CreateEngineDataFromFile(EngineDataFile));
+			var engineData = MockSimulationDataFactory.CreateEngineDataFromFile(EngineDataFile);
+			vehicleContainer.Engine = new CombustionEngine(vehicleContainer,engineData);
 			var gearboxData = MockSimulationDataFactory.CreateGearboxDataFromFile(GearboxDataFile, EngineDataFile, false);
-			var gearbox = new ATGearbox(vehicleContainer, gearboxData, new ATShiftStrategy(gearboxData, vehicleContainer));
+			var gearbox = new ATGearbox(vehicleContainer, gearboxData, new ATShiftStrategy(gearboxData, vehicleContainer), engineData.Inertia);
 
 			vehicleContainer.VehicleSpeed = vehicleSpeed.KMPHtoMeterPerSecond();
 
-- 
GitLab