From 57cf6be75e9e6ac00cec6a267b1b5808073f578c Mon Sep 17 00:00:00 2001
From: Markus Quaritsch <markus.quaritsch@tugraz.at>
Date: Mon, 27 Apr 2015 14:03:32 +0200
Subject: [PATCH] adding test for axlegear module

---
 .../Data/Gearbox/TransmissionLossMap.cs       |  44 ++++---
 .../SimulationComponent/Data/GearboxData.cs   | 108 +++++++++---------
 .../SimulationComponent/Impl/AxleGear.cs      |  10 +-
 .../Models/SimulationComponent/GearboxTest.cs |  58 ++++++++++
 .../GearboxDataTest.cs                        |  48 ++++++++
 VectoCoreTest/VectoCoreTest.csproj            |   1 +
 6 files changed, 189 insertions(+), 80 deletions(-)
 create mode 100644 VectoCoreTest/Models/SimulationComponent/GearboxTest.cs

diff --git a/VectoCore/Models/SimulationComponent/Data/Gearbox/TransmissionLossMap.cs b/VectoCore/Models/SimulationComponent/Data/Gearbox/TransmissionLossMap.cs
index c0d1f11fc4..8a5b759a3d 100644
--- a/VectoCore/Models/SimulationComponent/Data/Gearbox/TransmissionLossMap.cs
+++ b/VectoCore/Models/SimulationComponent/Data/Gearbox/TransmissionLossMap.cs
@@ -16,9 +16,9 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox
 		[JsonProperty] private readonly List<GearLossMapEntry> _entries;
 
 		private readonly DelauneyMap _lossMap; // Input Speed, Output Torque (to Wheels) => Input Torque (Engine)
-		private readonly DelauneyMap _reverseLossMap; // Input Speed, Input Torque (Engine) => Output Torque (Wheels)
+		//private readonly DelauneyMap _reverseLossMap; // Input Speed, Input Torque (Engine) => Output Torque (Wheels)
 
-		public static TransmissionLossMap ReadFromFile(string fileName)
+		public static TransmissionLossMap ReadFromFile(string fileName, double gearRatio)
 		{
 			var data = VectoCSVFile.Read(fileName, true);
 
@@ -44,7 +44,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox
 				entries = CreateFromColumIndizes(data);
 			}
 
-			return new TransmissionLossMap(entries);
+			return new TransmissionLossMap(entries, gearRatio);
 		}
 
 		private static bool HeaderIsValid(DataColumnCollection columns)
@@ -80,45 +80,51 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox
 				}).ToList();
 		}
 
-		private TransmissionLossMap(List<GearLossMapEntry> entries)
+		private TransmissionLossMap(List<GearLossMapEntry> entries, double gearRatio)
 		{
 			_entries = entries;
 			_lossMap = new DelauneyMap();
-			_reverseLossMap = new DelauneyMap();
+			//_reverseLossMap = new DelauneyMap();
 			foreach (var entry in _entries) {
-				_lossMap.AddPoint(entry.InputSpeed.Double(), entry.InputTorque.Double() - entry.TorqueLoss.Double(),
+				_lossMap.AddPoint(entry.InputSpeed.Double(), (entry.InputTorque.Double() - entry.TorqueLoss.Double()) * gearRatio,
 					entry.InputTorque.Double());
-				_reverseLossMap.AddPoint(entry.InputSpeed.Double(), entry.InputTorque.Double(),
-					entry.InputTorque.Double() - entry.TorqueLoss.Double());
+				// @@@quam: according to Raphael, not needed for now...
+				//_reverseLossMap.AddPoint(entry.InputSpeed.Double(), entry.InputTorque.Double(),
+				//	entry.InputTorque.Double() - entry.TorqueLoss.Double());
 			}
 			_lossMap.Triangulate();
-			_reverseLossMap.Triangulate();
+			//_reverseLossMap.Triangulate();
 		}
 
 		/// <summary>
-		///		Compute the required torque at the input of the gearbox (from engine)
+		///		Compute the required torque at the input of the gear(box) (from engine)
 		/// </summary>
 		/// <param name="angularVelocity">[1/s] angular speed of the shaft</param>
 		/// <param name="gbxOutTorque">[Nm] torque requested by the previous componend (towards the wheels)</param>
 		/// <returns>[Nm] torque requested from the next component (towards the engine)</returns>
 		public NewtonMeter GearboxInTorque(PerSecond angularVelocity, NewtonMeter gbxOutTorque)
 		{
-			// TODO: extrapolate!
-			return _lossMap.Interpolate(angularVelocity.Double(), gbxOutTorque.Double()).SI<NewtonMeter>();
+			try {
+				return VectoMath.Max(_lossMap.Interpolate(angularVelocity.Double(), gbxOutTorque.Double()).SI<NewtonMeter>(),
+					0.SI<NewtonMeter>());
+			} catch (Exception e) {
+				throw new VectoSimulationException(
+					String.Format("Failed to interpolate in TransmissionLossMap. angularVelocity: {0}, torque: {1}", angularVelocity,
+						gbxOutTorque), e);
+			}
 		}
 
 		/// <summary>
-		///		Compute the available torque at the output of the gearbox (towards wheels)
+		///		Compute the available torque at the output of the gear(box) (towards wheels)
 		/// </summary>
 		/// <param name="angularVelocity">[1/s] angular speed of the shaft</param>
 		/// <param name="gbxInTorque">[Nm] torque provided by the engine at the gearbox' input shaft</param>
 		/// <returns>[Nm] torque provided to the next component (towards the wheels)</returns>
-		public NewtonMeter GearboxOutTorque(PerSecond angularVelocity, NewtonMeter gbxInTorque)
-		{
-			// TODO extrapolate!
-			return _reverseLossMap.Interpolate(angularVelocity.Double(), gbxInTorque.Double()).SI<NewtonMeter>();
-		}
-
+		//public NewtonMeter GearboxOutTorque(PerSecond angularVelocity, NewtonMeter gbxInTorque)
+		//{
+		//	// TODO extrapolate!
+		//	return _reverseLossMap.Interpolate(angularVelocity.Double(), gbxInTorque.Double()).SI<NewtonMeter>();
+		//}
 		public GearLossMapEntry this[int i]
 		{
 			get { return _entries[i]; }
diff --git a/VectoCore/Models/SimulationComponent/Data/GearboxData.cs b/VectoCore/Models/SimulationComponent/Data/GearboxData.cs
index 91ffee3d21..b88942c957 100644
--- a/VectoCore/Models/SimulationComponent/Data/GearboxData.cs
+++ b/VectoCore/Models/SimulationComponent/Data/GearboxData.cs
@@ -84,7 +84,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data
 
 		public static GearboxData ReadFromJson(string json, string basePath = "")
 		{
-			var lossMaps = new Dictionary<string, TransmissionLossMap>();
+//			var lossMaps = new Dictionary<string, TransmissionLossMap>();
 
 			var gearboxData = new GearboxData();
 
@@ -98,13 +98,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data
 			for (uint i = 0; i < d.Body.Gears.Count; i++) {
 				var gearSettings = d.Body.Gears[(int) i];
 				var lossMapPath = Path.Combine(basePath, gearSettings.LossMap);
-				TransmissionLossMap lossMap;
-				if (lossMaps.ContainsKey(lossMapPath)) {
-					lossMap = lossMaps[lossMapPath];
-					lossMaps.Add(lossMapPath, lossMap);
-				} else {
-					lossMap = TransmissionLossMap.ReadFromFile(lossMapPath);
-				}
+				TransmissionLossMap lossMap = TransmissionLossMap.ReadFromFile(lossMapPath, gearSettings.Ratio);
 
 				var shiftPolygon = !String.IsNullOrEmpty(gearSettings.ShiftPolygon)
 					? ShiftPolygon.ReadFromFile(Path.Combine(basePath, gearSettings.ShiftPolygon))
@@ -135,55 +129,55 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data
 			return gearboxData;
 		}
 
-
-		public void CalculateAverageEfficiency(CombustionEngineData engineData)
-		{
-			var angularVelocityStep = (2.0 / 3.0) * (engineData.GetFullLoadCurve(0).RatedSpeed() - engineData.IdleSpeed) / 10.0;
-
-			var axleGearEfficiencySum = 0.0;
-			var axleGearSumCount = 0;
-
-			foreach (var gearEntry in _gearData) {
-				var gearEfficiencySum = 0.0;
-				var gearSumCount = 0;
-				for (var angularVelocity = engineData.IdleSpeed + angularVelocityStep;
-					angularVelocity < engineData.GetFullLoadCurve(0).RatedSpeed();
-					angularVelocity += angularVelocityStep) {
-					var fullLoadStationaryTorque = engineData.GetFullLoadCurve(gearEntry.Key).FullLoadStationaryTorque(angularVelocity);
-					var torqueStep = (2.0 / 3.0) * fullLoadStationaryTorque / 10.0;
-					for (var engineOutTorque = (1.0 / 3.0) * fullLoadStationaryTorque;
-						engineOutTorque < fullLoadStationaryTorque;
-						engineOutTorque += torqueStep) {
-						var engineOutPower = Formulas.TorqueToPower(engineOutTorque, angularVelocity);
-						var gearboxOutPower =
-							Formulas.TorqueToPower(
-								gearEntry.Value.LossMap.GearboxOutTorque(angularVelocity, engineOutTorque), angularVelocity);
-						if (gearboxOutPower > engineOutPower) {
-							gearboxOutPower = engineOutPower;
-						}
-
-						gearEfficiencySum += ((engineOutPower - gearboxOutPower) / engineOutPower).Double();
-						gearSumCount += 1;
-
-
-						// axle gear
-						var angularVelocityAxleGear = angularVelocity / gearEntry.Value.Ratio;
-						var axlegearOutPower =
-							Formulas.TorqueToPower(
-								AxleGearData.LossMap.GearboxOutTorque(angularVelocityAxleGear,
-									Formulas.PowerToTorque(engineOutPower, angularVelocityAxleGear)),
-								angularVelocityAxleGear);
-						if (axlegearOutPower > engineOutPower) {
-							axlegearOutPower = engineOutPower;
-						}
-						axleGearEfficiencySum += (axlegearOutPower / engineOutPower).Double();
-						axleGearSumCount += 1;
-					}
-				}
-				gearEntry.Value.AverageEfficiency = gearEfficiencySum / gearSumCount;
-			}
-			AxleGearData.AverageEfficiency = axleGearEfficiencySum / axleGearSumCount;
-		}
+		// @@@quam: according to Raphael no longer required
+		//public void CalculateAverageEfficiency(CombustionEngineData engineData)
+		//{
+		//	var angularVelocityStep = (2.0 / 3.0) * (engineData.GetFullLoadCurve(0).RatedSpeed() - engineData.IdleSpeed) / 10.0;
+
+		//	var axleGearEfficiencySum = 0.0;
+		//	var axleGearSumCount = 0;
+
+		//	foreach (var gearEntry in _gearData) {
+		//		var gearEfficiencySum = 0.0;
+		//		var gearSumCount = 0;
+		//		for (var angularVelocity = engineData.IdleSpeed + angularVelocityStep;
+		//			angularVelocity < engineData.GetFullLoadCurve(0).RatedSpeed();
+		//			angularVelocity += angularVelocityStep) {
+		//			var fullLoadStationaryTorque = engineData.GetFullLoadCurve(gearEntry.Key).FullLoadStationaryTorque(angularVelocity);
+		//			var torqueStep = (2.0 / 3.0) * fullLoadStationaryTorque / 10.0;
+		//			for (var engineOutTorque = (1.0 / 3.0) * fullLoadStationaryTorque;
+		//				engineOutTorque < fullLoadStationaryTorque;
+		//				engineOutTorque += torqueStep) {
+		//				var engineOutPower = Formulas.TorqueToPower(engineOutTorque, angularVelocity);
+		//				var gearboxOutPower =
+		//					Formulas.TorqueToPower(
+		//						gearEntry.Value.LossMap.GearboxOutTorque(angularVelocity, engineOutTorque), angularVelocity);
+		//				if (gearboxOutPower > engineOutPower) {
+		//					gearboxOutPower = engineOutPower;
+		//				}
+
+		//				gearEfficiencySum += ((engineOutPower - gearboxOutPower) / engineOutPower).Double();
+		//				gearSumCount += 1;
+
+
+		//				// axle gear
+		//				var angularVelocityAxleGear = angularVelocity / gearEntry.Value.Ratio;
+		//				var axlegearOutPower =
+		//					Formulas.TorqueToPower(
+		//						AxleGearData.LossMap.GearboxOutTorque(angularVelocityAxleGear,
+		//							Formulas.PowerToTorque(engineOutPower, angularVelocityAxleGear)),
+		//						angularVelocityAxleGear);
+		//				if (axlegearOutPower > engineOutPower) {
+		//					axlegearOutPower = engineOutPower;
+		//				}
+		//				axleGearEfficiencySum += (axlegearOutPower / engineOutPower).Double();
+		//				axleGearSumCount += 1;
+		//			}
+		//		}
+		//		gearEntry.Value.AverageEfficiency = gearEfficiencySum / gearSumCount;
+		//	}
+		//	AxleGearData.AverageEfficiency = axleGearEfficiencySum / axleGearSumCount;
+		//}
 
 		public int GearsCount()
 		{
diff --git a/VectoCore/Models/SimulationComponent/Impl/AxleGear.cs b/VectoCore/Models/SimulationComponent/Impl/AxleGear.cs
index f5cd77fcf4..ce738952ff 100644
--- a/VectoCore/Models/SimulationComponent/Impl/AxleGear.cs
+++ b/VectoCore/Models/SimulationComponent/Impl/AxleGear.cs
@@ -8,11 +8,11 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 	public class AxleGear : IPowerTrainComponent, ITnInPort, ITnOutPort
 	{
 		private ITnOutPort _nextComponent;
-		private GearData _gearDataData;
+		private readonly GearData _gearData;
 
-		public AxleGear(GearData gearDataData)
+		public AxleGear(GearData gearData)
 		{
-			_gearDataData = gearDataData;
+			_gearData = gearData;
 		}
 
 		public ITnInPort InShaft()
@@ -32,7 +32,9 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl
 
 		public IResponse Request(TimeSpan absTime, TimeSpan dt, NewtonMeter torque, PerSecond angularVelocity)
 		{
-			return _nextComponent.Request(absTime, dt, torque, angularVelocity);
+			return _nextComponent.Request(absTime, dt,
+				_gearData.LossMap.GearboxInTorque(angularVelocity * _gearData.Ratio, torque),
+				angularVelocity * _gearData.Ratio);
 		}
 	}
 }
\ No newline at end of file
diff --git a/VectoCoreTest/Models/SimulationComponent/GearboxTest.cs b/VectoCoreTest/Models/SimulationComponent/GearboxTest.cs
new file mode 100644
index 0000000000..3a044a8d45
--- /dev/null
+++ b/VectoCoreTest/Models/SimulationComponent/GearboxTest.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Globalization;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using TUGraz.VectoCore.Models.Simulation.Impl;
+using TUGraz.VectoCore.Models.SimulationComponent.Data;
+using TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox;
+using TUGraz.VectoCore.Models.SimulationComponent.Impl;
+using TUGraz.VectoCore.Utils;
+
+namespace TUGraz.VectoCore.Tests.Models.SimulationComponent
+{
+	[TestClass]
+	public class GearboxTest
+	{
+		protected string GearboxDataFile = @"TestData\Components\24t Coach.vgbx";
+
+		public TestContext TestContext { get; set; }
+
+		[TestMethod]
+		public void AxleGearTest()
+		{
+			VehicleContainer vehicle = new VehicleContainer();
+			var gbxData = GearboxData.ReadFromFile(GearboxDataFile);
+			//GearData gearData = new GearData();
+			var axleGear = new AxleGear(gbxData.AxleGearData);
+
+			var mockPort = new MockTnOutPort();
+			axleGear.InShaft().Connect(mockPort);
+
+			var absTime = TimeSpan.FromSeconds(0);
+			var dt = TimeSpan.FromSeconds(1);
+
+			var rdyn = 520;
+			var speed = 20.320;
+
+
+			var angSpeed = SpeedToAngularSpeed(speed, rdyn);
+			var PvD = 279698.4.SI<Watt>();
+			// Double.Parse(TestContext.DataRow["PowerGbxOut"].ToString(), CultureInfo.InvariantCulture).SI<Watt>();
+
+			var torqueToWheels = Formulas.PowerToTorque(PvD, angSpeed);
+			//var torqueFromEngine = 0.SI<NewtonMeter>();
+
+			axleGear.Request(absTime, dt, torqueToWheels, angSpeed);
+
+			var loss = 9401.44062.SI<Watt>();
+
+			Assert.AreEqual(Formulas.PowerToTorque(PvD + loss, angSpeed * gbxData.AxleGearData.Ratio), mockPort.Torque,
+				"Torque Engine Side");
+			Assert.AreEqual(angSpeed * gbxData.AxleGearData.Ratio, mockPort.AngularVelocity, "Torque Engine Side");
+		}
+
+		protected PerSecond SpeedToAngularSpeed(double v, double r)
+		{
+			return ((60 * v) / (2 * r * Math.PI / 1000)).RPMtoRad();
+		}
+	}
+}
\ No newline at end of file
diff --git a/VectoCoreTest/Models/SimulationComponentData/GearboxDataTest.cs b/VectoCoreTest/Models/SimulationComponentData/GearboxDataTest.cs
index 49ab38abe7..f233b20357 100644
--- a/VectoCoreTest/Models/SimulationComponentData/GearboxDataTest.cs
+++ b/VectoCoreTest/Models/SimulationComponentData/GearboxDataTest.cs
@@ -1,6 +1,7 @@
 using System;
 using System.Globalization;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
+using TUGraz.VectoCore.Exceptions;
 using TUGraz.VectoCore.Models.SimulationComponent.Data;
 using TUGraz.VectoCore.Utils;
 
@@ -64,6 +65,53 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponentData
 				TestContext.DataRow["TestName"].ToString());
 		}
 
+		[TestMethod]
+		public void TestInputOutOfRange()
+		{
+			var rdyn = 520.0;
+			//var speed = double.Parse(TestContext.DataRow["v"].ToString(), CultureInfo.InvariantCulture);
+
+			var gbxData = GearboxData.ReadFromFile(GearboxFile);
+
+
+			var angSpeed = 2700.RPMtoRad();
+			var torqueToWheels = 100.SI<NewtonMeter>();
+
+			try {
+				gbxData.AxleGearData.LossMap.GearboxInTorque(angSpeed, torqueToWheels);
+				Assert.Fail("angular Speed too high");
+			} catch (Exception e) {
+				Assert.IsInstanceOfType(e, typeof (VectoSimulationException));
+			}
+
+			angSpeed = 1000.RPMtoRad();
+			torqueToWheels = 50000.SI<NewtonMeter>();
+			try {
+				gbxData.AxleGearData.LossMap.GearboxInTorque(angSpeed, torqueToWheels);
+				Assert.Fail("torque too high");
+			} catch (Exception e) {
+				Assert.IsInstanceOfType(e, typeof (VectoSimulationException));
+			}
+
+			angSpeed = 1000.RPMtoRad();
+			torqueToWheels = -5000.SI<NewtonMeter>();
+			try {
+				gbxData.AxleGearData.LossMap.GearboxInTorque(angSpeed, torqueToWheels);
+				Assert.Fail("torque too low");
+			} catch (Exception e) {
+				Assert.IsInstanceOfType(e, typeof (VectoSimulationException));
+			}
+
+			angSpeed = -1000.RPMtoRad();
+			torqueToWheels = 500.SI<NewtonMeter>();
+			try {
+				gbxData.AxleGearData.LossMap.GearboxInTorque(angSpeed, torqueToWheels);
+				Assert.Fail("negative angular speed");
+			} catch (Exception e) {
+				Assert.IsInstanceOfType(e, typeof (VectoSimulationException));
+			}
+		}
+
 		protected PerSecond SpeedToAngularSpeed(double v, double r)
 		{
 			return ((60 * v) / (2 * r * Math.PI / 1000)).RPMtoRad();
diff --git a/VectoCoreTest/VectoCoreTest.csproj b/VectoCoreTest/VectoCoreTest.csproj
index 34975ef0a7..96f4691238 100644
--- a/VectoCoreTest/VectoCoreTest.csproj
+++ b/VectoCoreTest/VectoCoreTest.csproj
@@ -75,6 +75,7 @@
     <Compile Include="Models\SimulationComponentData\GearboxDataTest.cs" />
     <Compile Include="Models\SimulationComponent\ClutchTest.cs" />
     <Compile Include="Models\SimulationComponent\CombustionEngineTest.cs" />
+    <Compile Include="Models\SimulationComponent\GearboxTest.cs" />
     <Compile Include="Models\SimulationComponent\RetarderTest.cs" />
     <Compile Include="Models\Simulation\DrivingCycleTests.cs" />
     <Compile Include="Models\SimulationComponent\MockPorts.cs" />
-- 
GitLab