From da2d101aec740a8670e6bc01908ee7df6ef35876 Mon Sep 17 00:00:00 2001
From: Markus Quaritsch <markus.quaritsch@tugraz.at>
Date: Mon, 20 Nov 2017 08:17:26 +0100
Subject: [PATCH] refactoring of VTP engine - no speed limits, compute engine
 torque demand based on power demand and engine speed from cycle to compensate
 for wrong gear selection

---
 .../Reader/DrivingCycleDataReader.cs          |   5 +-
 .../Impl/VTPCombustionEngine.cs               | 111 +++++++++++++++++-
 .../Integration/EPTP/EPTPTest.cs              |   4 +-
 3 files changed, 116 insertions(+), 4 deletions(-)

diff --git a/VectoCore/VectoCore/InputData/Reader/DrivingCycleDataReader.cs b/VectoCore/VectoCore/InputData/Reader/DrivingCycleDataReader.cs
index fcbdcaaee9..af4cc0031b 100644
--- a/VectoCore/VectoCore/InputData/Reader/DrivingCycleDataReader.cs
+++ b/VectoCore/VectoCore/InputData/Reader/DrivingCycleDataReader.cs
@@ -725,6 +725,8 @@ namespace TUGraz.VectoCore.InputData.Reader
                 var entries = table.Rows.Cast<DataRow>().Select(row => {
 					var wheelSpeed =
 						((row.ParseDouble(Fields.WheelSpeedLeft) + row.ParseDouble(Fields.WheelSpeedRight)) / 2).RPMtoRad();
+					var wheelPower = row.ParseDouble(Fields.WheelTorqueLeft).SI<NewtonMeter>() * row.ParseDouble(Fields.WheelSpeedLeft).RPMtoRad() +
+						row.ParseDouble(Fields.WheelTorqueRight).SI<NewtonMeter>() * row.ParseDouble(Fields.WheelSpeedRight).RPMtoRad();
 					return new DrivingCycleData.DrivingCycleEntry {
 						Time = row.ParseDouble(Fields.Time).SI<Second>(),
 						VehicleTargetSpeed = row.ParseDouble(Fields.VehicleSpeed).KMPHtoMeterPerSecond(),
@@ -732,7 +734,8 @@ namespace TUGraz.VectoCore.InputData.Reader
 							row.ParseDoubleOrGetDefault(Fields.AdditionalAuxPowerDemand).SI().Kilo.Watt.Cast<Watt>(),
 						EngineSpeed = row.ParseDouble(Fields.EngineSpeedSuffix).RPMtoRad(),
 						WheelAngularVelocity = wheelSpeed,
-						Torque = wheelSpeed.IsEqual(0, 1e-3) ? 0.SI<NewtonMeter>() : (row.ParseDouble(Fields.WheelTorqueLeft).SI<NewtonMeter>() * row.ParseDouble(Fields.WheelSpeedLeft).RPMtoRad() + row.ParseDouble(Fields.WheelTorqueRight).SI<NewtonMeter>() * row.ParseDouble(Fields.WheelSpeedRight).RPMtoRad()) / wheelSpeed, 
+						Torque = wheelSpeed.IsEqual(0, 1e-3) ? 0.SI<NewtonMeter>() : wheelPower / wheelSpeed, 
+						PWheel = wheelPower,
 						FanSpeed = row.ParseDouble(Fields.FanSpeed).RPMtoRad(),
 						Gear = (uint)row.ParseDoubleOrGetDefault(Fields.Gear),
 						Fuelconsumption = row.ParseDoubleOrGetDefault(Fields.FuelConsumption).SI().Gramm.Per.Hour.ConvertTo().Kilo.Gramm.Per.Second.Cast<KilogramPerSecond>(),
diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/VTPCombustionEngine.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/VTPCombustionEngine.cs
index ea93e1afa1..0b73e0df8e 100644
--- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/VTPCombustionEngine.cs
+++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/VTPCombustionEngine.cs
@@ -1,10 +1,13 @@
 using System;
 using TUGraz.VectoCommon.Models;
 using TUGraz.VectoCommon.Utils;
+using TUGraz.VectoCore.Configuration;
+using TUGraz.VectoCore.Models.Connector.Ports.Impl;
 using TUGraz.VectoCore.Models.Simulation;
 using TUGraz.VectoCore.Models.Simulation.Data;
 using TUGraz.VectoCore.Models.SimulationComponent.Data;
 using TUGraz.VectoCore.OutputData;
+using TUGraz.VectoCore.Utils;
 
 namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 {
@@ -12,8 +15,114 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
     {
         public VTPCombustionEngine(IVehicleContainer container, CombustionEngineData modelData, bool pt1Disabled = false) : base(container, modelData, pt1Disabled) { }
 
+		protected override IResponse DoHandleRequest(Second absTime, Second dt, NewtonMeter torqueReq,
+			PerSecond angularVelocity, bool dryRun)
+		{
+			var powerDemand = angularVelocity * torqueReq;
 
-        protected override PerSecond GetEngineSpeed(PerSecond angularSpeed)
+			var avgEngineSpeed = GetEngineSpeed(angularVelocity);
+			var torqueOut = powerDemand / avgEngineSpeed;
+
+
+			var fullDragTorque = ModelData.FullLoadCurves[DataBus.Gear].DragLoadStationaryTorque(avgEngineSpeed);
+			var fullLoadTorque = ModelData.FullLoadCurves[DataBus.Gear].FullLoadStationaryTorque(angularVelocity);
+			
+			var inertiaTorqueLoss =
+				Formulas.InertiaPower(angularVelocity, PreviousState.EngineSpeed, ModelData.Inertia, dt) /
+				avgEngineSpeed;
+
+			var auxTorqueDemand = EngineAux == null
+				? 0.SI<NewtonMeter>()
+				: EngineAux.TorqueDemand(absTime, dt, torqueOut,
+					torqueOut + inertiaTorqueLoss, angularVelocity, dryRun);
+			// compute the torque the engine has to provide. powertrain + aux + its own inertia
+			var totalTorqueDemand = torqueOut + auxTorqueDemand + inertiaTorqueLoss;
+
+			Log.Debug("EngineInertiaTorque: {0}", inertiaTorqueLoss);
+			Log.Debug("Drag Curve: torque: {0}, power: {1}", fullDragTorque, fullDragTorque * avgEngineSpeed);
+
+			var deltaFull = totalTorqueDemand - fullLoadTorque;
+			var deltaDrag = totalTorqueDemand - fullDragTorque;
+
+			if (dryRun) {
+				return new ResponseDryRun {
+					DeltaFullLoad = deltaFull * avgEngineSpeed,
+					DeltaDragLoad = deltaDrag * avgEngineSpeed,
+					DeltaEngineSpeed = 0.RPMtoRad(),
+					EnginePowerRequest = torqueOut * avgEngineSpeed,
+					DynamicFullLoadPower = fullLoadTorque * avgEngineSpeed,
+					DragPower = fullDragTorque * avgEngineSpeed,
+					AuxiliariesPowerDemand = auxTorqueDemand * avgEngineSpeed,
+					EngineSpeed = angularVelocity,
+					Source = this,
+				};
+			}
+			CurrentState.dt = dt;
+			CurrentState.EngineSpeed = angularVelocity;
+			CurrentState.EngineTorqueOut = torqueOut;
+			CurrentState.FullDragTorque = fullDragTorque;
+			CurrentState.DynamicFullLoadTorque = fullLoadTorque;
+			CurrentState.StationaryFullLoadTorque = fullLoadTorque;
+			CurrentState.InertiaTorqueLoss = inertiaTorqueLoss;
+
+			if ((deltaFull * avgEngineSpeed).IsGreater(0.SI<Watt>(), Constants.SimulationSettings.LineSearchTolerance) &&
+				(deltaDrag * avgEngineSpeed).IsSmaller(0.SI<Watt>(), Constants.SimulationSettings.LineSearchTolerance)) {
+				//throw new VectoSimulationException(
+				Log.Error(
+					"Unexpected condition: requested torque_out is above gearbox full-load and engine is below drag load! deltaFull: {0}, deltaDrag: {1}",
+					deltaFull, deltaDrag);
+			}
+
+			var minTorque = CurrentState.FullDragTorque;
+			var maxTorque = CurrentState.DynamicFullLoadTorque;
+
+			CurrentState.EngineTorque = totalTorqueDemand.LimitTo(minTorque, maxTorque);
+			CurrentState.EnginePower = CurrentState.EngineTorque * avgEngineSpeed;
+
+			if (totalTorqueDemand.IsGreater(0) &&
+				(deltaFull * avgEngineSpeed).IsGreater(0, Constants.SimulationSettings.LineSearchTolerance)) {
+				Log.Debug("requested engine power exceeds fullload power: delta: {0}", deltaFull);
+				return new ResponseOverload {
+					AbsTime = absTime,
+					Delta = deltaFull * avgEngineSpeed,
+					EnginePowerRequest = totalTorqueDemand * avgEngineSpeed,
+					DynamicFullLoadPower = fullLoadTorque * avgEngineSpeed,
+					DragPower = CurrentState.FullDragTorque * avgEngineSpeed,
+					Source = this,
+					AuxiliariesPowerDemand = auxTorqueDemand * avgEngineSpeed,
+					EngineSpeed = angularVelocity,
+				};
+			}
+
+			if (totalTorqueDemand.IsSmaller(0) &&
+				(deltaDrag * avgEngineSpeed).IsSmaller(0, Constants.SimulationSettings.LineSearchTolerance)) {
+				Log.Debug("requested engine power is below drag power: delta: {0}", deltaDrag);
+				return new ResponseUnderload {
+					AbsTime = absTime,
+					Delta = deltaDrag * avgEngineSpeed,
+					EnginePowerRequest = totalTorqueDemand * avgEngineSpeed,
+					DynamicFullLoadPower = fullLoadTorque * avgEngineSpeed,
+					DragPower = CurrentState.FullDragTorque * avgEngineSpeed,
+					Source = this,
+					AuxiliariesPowerDemand = auxTorqueDemand * avgEngineSpeed,
+					EngineSpeed = angularVelocity,
+				};
+			}
+
+			//UpdateEngineState(CurrentState.EnginePower, avgEngineSpeed);
+
+			return new ResponseSuccess {
+				EnginePowerRequest = totalTorqueDemand * avgEngineSpeed,
+				DynamicFullLoadPower = fullLoadTorque * avgEngineSpeed,
+				DragPower = CurrentState.FullDragTorque * avgEngineSpeed,
+				AuxiliariesPowerDemand = auxTorqueDemand * avgEngineSpeed,
+				EngineSpeed = angularVelocity,
+				Source = this
+			};
+		}
+
+
+		protected override PerSecond GetEngineSpeed(PerSecond angularSpeed)
         {
             return DataBus.CycleData.LeftSample.EngineSpeed;
         }
diff --git a/VectoCore/VectoCoreTest/Integration/EPTP/EPTPTest.cs b/VectoCore/VectoCoreTest/Integration/EPTP/EPTPTest.cs
index ee514abd82..1bf9a7dd09 100644
--- a/VectoCore/VectoCoreTest/Integration/EPTP/EPTPTest.cs
+++ b/VectoCore/VectoCoreTest/Integration/EPTP/EPTPTest.cs
@@ -33,9 +33,9 @@ namespace TUGraz.VectoCore.Tests.Integration.EPTP
 			//Assert.IsTrue(jobContainer.Runs[i].Run.FinishedWithoutErrors);
 
 			jobContainer.Execute();
-            jobContainer.WaitFinished();
+			jobContainer.WaitFinished();
 
-            Assert.AreEqual(true, jobContainer.AllCompleted);
+			Assert.AreEqual(true, jobContainer.AllCompleted);
             
         }
 
-- 
GitLab