From 5e0f94ae89bb4610d7a27ef9cf39a77b513abc98 Mon Sep 17 00:00:00 2001 From: Markus Quaritsch <markus.quaritsch@tugraz.at> Date: Tue, 5 Nov 2019 10:47:54 +0100 Subject: [PATCH] removed inverted lossmap in transmission loss map class (forward calculation) as the triangulation may cause errors due to limited numerical accuracy (even with double precision) --- .../Models/Simulation/Data/VectoRunData.cs | 42 +++-- .../Data/Gearbox/TransmissionLossMap.cs | 33 +--- VectoCore/VectoCore/Utils/DelaunayMap.cs | 2 +- .../GearboxDataTest.cs | 178 +++++++++--------- 4 files changed, 114 insertions(+), 141 deletions(-) diff --git a/VectoCore/VectoCore/Models/Simulation/Data/VectoRunData.cs b/VectoCore/VectoCore/Models/Simulation/Data/VectoRunData.cs index e20a564588..5cca01b4d0 100644 --- a/VectoCore/VectoCore/Models/Simulation/Data/VectoRunData.cs +++ b/VectoCore/VectoCore/Models/Simulation/Data/VectoRunData.cs @@ -209,39 +209,43 @@ namespace TUGraz.VectoCore.Models.Simulation.Data return null; } - private static ValidationResult CheckLossMapsEntries(KeyValuePair<uint, GearData> gear, PerSecond angularVelocity, + private static ValidationResult CheckLossMapsEntries(KeyValuePair<uint, GearData> gear, PerSecond engineSpeed, NewtonMeter inTorque, AngledriveData angledriveData, AxleGearData axleGearData, MeterPerSecond velocity) { var hasAngleDrive = angledriveData != null && angledriveData.Angledrive != null; var angledriveRatio = hasAngleDrive && angledriveData.Type == AngledriveType.SeparateAngledrive ? angledriveData.Angledrive.Ratio : 1.0; - NewtonMeter angledriveTorque; - try { - angledriveTorque = gear.Value.LossMap.GetOutTorque(angularVelocity, inTorque); - } catch (VectoException) { + + var tqLoss = gear.Value.LossMap.GetTorqueLoss(engineSpeed / gear.Value.Ratio, inTorque * gear.Value.Ratio); + if (tqLoss.Extrapolated) { return new ValidationResult( string.Format("Interpolation of Gear-{0}-LossMap failed with torque={1} and angularSpeed={2}", gear.Key, - inTorque, angularVelocity.ConvertToRoundsPerMinute())); + inTorque, engineSpeed.ConvertToRoundsPerMinute())); + } + var angledriveTorque = (inTorque - tqLoss.Value) / gear.Value.Ratio; + + var axlegearTorque = angledriveTorque; - try { - if (hasAngleDrive) { - axlegearTorque = angledriveData.Angledrive.LossMap.GetOutTorque(angularVelocity / gear.Value.Ratio, - angledriveTorque); + if (hasAngleDrive) { + var anglTqLoss = angledriveData.Angledrive.LossMap.GetTorqueLoss( + engineSpeed / gear.Value.Ratio / angledriveRatio, + angledriveTorque * angledriveRatio); + if (anglTqLoss.Extrapolated) { + return new ValidationResult( + string.Format( + "Interpolation of Angledrive-LossMap failed with torque={0} and angularSpeed={1}", + angledriveTorque, (engineSpeed / gear.Value.Ratio).ConvertToRoundsPerMinute())); } - } catch (VectoException) { - return new ValidationResult( - string.Format("Interpolation of Angledrive-LossMap failed with torque={0} and angularSpeed={1}", - angledriveTorque, (angularVelocity / gear.Value.Ratio).ConvertToRoundsPerMinute())); } if (axleGearData != null) { - var axleAngularVelocity = angularVelocity / gear.Value.Ratio / angledriveRatio; - try { - axleGearData.AxleGear.LossMap.GetOutTorque(axleAngularVelocity, axlegearTorque); - } catch (VectoException) { - return + var axleAngularVelocity = engineSpeed / gear.Value.Ratio / angledriveRatio / axleGearData.AxleGear.Ratio; + + var axlTqLoss = axleGearData.AxleGear.LossMap.GetTorqueLoss(axleAngularVelocity, axlegearTorque * axleGearData.AxleGear.Ratio); + if (axlTqLoss.Extrapolated) { + return new ValidationResult( string.Format( "Interpolation of AxleGear-LossMap failed with torque={0} and angularSpeed={1} (gear={2}, velocity={3})", diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Data/Gearbox/TransmissionLossMap.cs b/VectoCore/VectoCore/Models/SimulationComponent/Data/Gearbox/TransmissionLossMap.cs index 7d1e6f7890..2d4ed2d806 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Data/Gearbox/TransmissionLossMap.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Data/Gearbox/TransmissionLossMap.cs @@ -51,11 +51,6 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox /// </summary> private readonly DelaunayMap _lossMap; - /// <summary> - /// The inverted loss map for range sanity checks. [X=Input EngineSpeed, Y=Input Torque] => Z=Output Torque - /// </summary> - private readonly DelaunayMap _invertedLossMap; - public string GearName { get; private set; } public TransmissionLossMap(IReadOnlyList<GearLossMapEntry> entries, double gearRatio, string gearName) @@ -64,14 +59,11 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox _ratio = gearRatio; _entries = entries; _lossMap = new DelaunayMap("TransmissionLossMap " + GearName); - _invertedLossMap = new DelaunayMap("TransmissionLossMapInv. " + GearName); foreach (var entry in _entries) { _lossMap.AddPoint(entry.InputSpeed.Value(), (entry.InputTorque - entry.TorqueLoss).Value(), entry.TorqueLoss.Value()); - _invertedLossMap.AddPoint(entry.InputSpeed.Value(), entry.InputTorque.Value(), entry.TorqueLoss.Value()); } _lossMap.Triangulate(); - _invertedLossMap.Triangulate(); } /// <summary> @@ -104,30 +96,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox public NewtonMeter Value; } - /// <summary> - /// Computes the OUTPUT torque given by the input engineSpeed and the input torque. - /// </summary> - /// <param name="inAngularVelocity">Angular speed at input side.</param> - /// <param name="inTorque">Torque at input side.</param> - /// <param name="allowExtrapolation"></param> - /// <returns>Torque needed at output side (towards the wheels).</returns> - public NewtonMeter GetOutTorque(PerSecond inAngularVelocity, NewtonMeter inTorque, bool allowExtrapolation = false) - { - var torqueLoss = _invertedLossMap.Interpolate(inAngularVelocity.Value(), inTorque.Value()); - if (torqueLoss.HasValue) { - return (inTorque - torqueLoss.Value.SI<NewtonMeter>()) / _ratio; - } - - if (allowExtrapolation) { - torqueLoss = _invertedLossMap.Extrapolate(inAngularVelocity.Value(), inTorque.Value()); - return (inTorque - torqueLoss.Value.SI<NewtonMeter>()) / _ratio; - } - - throw new VectoException("TransmissionLossMap {0}: Interpolation failed. inTorque: {1}, inAngularVelocity: {2}", - GearName, inTorque, - inAngularVelocity.AsRPM); - } - + public GearLossMapEntry this[int i] { get { return _entries[i]; } diff --git a/VectoCore/VectoCore/Utils/DelaunayMap.cs b/VectoCore/VectoCore/Utils/DelaunayMap.cs index d147ce127b..c662782595 100644 --- a/VectoCore/VectoCore/Utils/DelaunayMap.cs +++ b/VectoCore/VectoCore/Utils/DelaunayMap.cs @@ -139,7 +139,7 @@ namespace TUGraz.VectoCore.Utils // k...points on convex hull (exactly 3 --> supertriangle) if (triangles.Count != 2 * (pointCount + 3) - 2 - 3) { throw new VectoException( - "Delaunay-Triangulation invariant violated! Triangle count and point count doesn't fit together."); + "{0} Delaunay-Triangulation invariant violated! Triangle count and point count doesn't fit together.", _mapName); } } diff --git a/VectoCore/VectoCoreTest/Models/SimulationComponentData/GearboxDataTest.cs b/VectoCore/VectoCoreTest/Models/SimulationComponentData/GearboxDataTest.cs index 5e810dde26..18de49f589 100644 --- a/VectoCore/VectoCoreTest/Models/SimulationComponentData/GearboxDataTest.cs +++ b/VectoCore/VectoCoreTest/Models/SimulationComponentData/GearboxDataTest.cs @@ -167,49 +167,49 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponentData AssertHelper.AreRelativeEqual(10, map.GetTorqueLoss(120.RPMtoRad(), 50.SI<NewtonMeter>()).Value); } - [TestCase] - public void TestLossMap_OUT_10_CONST_Interpolation_Extrapolation() - { - var data = new DataTable(); - data.Columns.Add(""); - data.Columns.Add(""); - data.Columns.Add(""); - data.Rows.Add("0", "0", "10"); // (0,100):10 -- (100,100):10 - data.Rows.Add("0", "100", "10"); // | \ | - data.Rows.Add("100", "0", "10"); // | \ | - data.Rows.Add("100", "100", "10"); // (0,0):10 ----- (100,10):10 - - var map = TransmissionLossMapReader.Create(data, 1.0, "1"); - - // test inside the triangles - AssertHelper.AreRelativeEqual(15, map.GetOutTorque(25.RPMtoRad(), 25.SI<NewtonMeter>(), true)); - AssertHelper.AreRelativeEqual(40, map.GetOutTorque(75.RPMtoRad(), 50.SI<NewtonMeter>(), true)); - - // test interpolation on edges - AssertHelper.AreRelativeEqual(-15, map.GetOutTorque(50.RPMtoRad(), -5.SI<NewtonMeter>(), true)); - AssertHelper.AreRelativeEqual(35, map.GetOutTorque(0.RPMtoRad(), 45.SI<NewtonMeter>(), true)); - AssertHelper.AreRelativeEqual(30, map.GetOutTorque(50.RPMtoRad(), 40.SI<NewtonMeter>(), true)); - AssertHelper.AreRelativeEqual(65, map.GetOutTorque(50.RPMtoRad(), 75.SI<NewtonMeter>(), true)); - AssertHelper.AreRelativeEqual(15, map.GetOutTorque(100.RPMtoRad(), 25.SI<NewtonMeter>(), true)); - - // test interpolation on corner points - AssertHelper.AreRelativeEqual(-10, map.GetOutTorque(0.RPMtoRad(), 0.SI<NewtonMeter>(), true)); - AssertHelper.AreRelativeEqual(80, map.GetOutTorque(0.RPMtoRad(), 90.SI<NewtonMeter>(), true)); - AssertHelper.AreRelativeEqual(-20, map.GetOutTorque(100.RPMtoRad(), -10.SI<NewtonMeter>(), true)); - AssertHelper.AreRelativeEqual(50, map.GetOutTorque(100.RPMtoRad(), 60.SI<NewtonMeter>(), true)); - - // test outside the corners - AssertHelper.AreRelativeEqual(-30, map.GetOutTorque(-20.RPMtoRad(), -20.SI<NewtonMeter>(), true)); - AssertHelper.AreRelativeEqual(110, map.GetOutTorque(-20.RPMtoRad(), 120.SI<NewtonMeter>(), true)); - AssertHelper.AreRelativeEqual(-30, map.GetOutTorque(120.RPMtoRad(), -20.SI<NewtonMeter>(), true)); - AssertHelper.AreRelativeEqual(110, map.GetOutTorque(120.RPMtoRad(), 120.SI<NewtonMeter>(), true)); - - // test outside the edges - AssertHelper.AreRelativeEqual(40, map.GetOutTorque(-20.RPMtoRad(), 50.SI<NewtonMeter>(), true)); - AssertHelper.AreRelativeEqual(110, map.GetOutTorque(50.RPMtoRad(), 120.SI<NewtonMeter>(), true)); - AssertHelper.AreRelativeEqual(-30, map.GetOutTorque(50.RPMtoRad(), -20.SI<NewtonMeter>(), true)); - AssertHelper.AreRelativeEqual(40, map.GetOutTorque(120.RPMtoRad(), 50.SI<NewtonMeter>(), true)); - } + //[TestCase] + //public void TestLossMap_OUT_10_CONST_Interpolation_Extrapolation() + //{ + // var data = new DataTable(); + // data.Columns.Add(""); + // data.Columns.Add(""); + // data.Columns.Add(""); + // data.Rows.Add("0", "0", "10"); // (0,100):10 -- (100,100):10 + // data.Rows.Add("0", "100", "10"); // | \ | + // data.Rows.Add("100", "0", "10"); // | \ | + // data.Rows.Add("100", "100", "10"); // (0,0):10 ----- (100,10):10 + + // var map = TransmissionLossMapReader.Create(data, 1.0, "1"); + + // // test inside the triangles + // AssertHelper.AreRelativeEqual(15, map.GetOutTorque(25.RPMtoRad(), 25.SI<NewtonMeter>(), true)); + // AssertHelper.AreRelativeEqual(40, map.GetOutTorque(75.RPMtoRad(), 50.SI<NewtonMeter>(), true)); + + // // test interpolation on edges + // AssertHelper.AreRelativeEqual(-15, map.GetOutTorque(50.RPMtoRad(), -5.SI<NewtonMeter>(), true)); + // AssertHelper.AreRelativeEqual(35, map.GetOutTorque(0.RPMtoRad(), 45.SI<NewtonMeter>(), true)); + // AssertHelper.AreRelativeEqual(30, map.GetOutTorque(50.RPMtoRad(), 40.SI<NewtonMeter>(), true)); + // AssertHelper.AreRelativeEqual(65, map.GetOutTorque(50.RPMtoRad(), 75.SI<NewtonMeter>(), true)); + // AssertHelper.AreRelativeEqual(15, map.GetOutTorque(100.RPMtoRad(), 25.SI<NewtonMeter>(), true)); + + // // test interpolation on corner points + // AssertHelper.AreRelativeEqual(-10, map.GetOutTorque(0.RPMtoRad(), 0.SI<NewtonMeter>(), true)); + // AssertHelper.AreRelativeEqual(80, map.GetOutTorque(0.RPMtoRad(), 90.SI<NewtonMeter>(), true)); + // AssertHelper.AreRelativeEqual(-20, map.GetOutTorque(100.RPMtoRad(), -10.SI<NewtonMeter>(), true)); + // AssertHelper.AreRelativeEqual(50, map.GetOutTorque(100.RPMtoRad(), 60.SI<NewtonMeter>(), true)); + + // // test outside the corners + // AssertHelper.AreRelativeEqual(-30, map.GetOutTorque(-20.RPMtoRad(), -20.SI<NewtonMeter>(), true)); + // AssertHelper.AreRelativeEqual(110, map.GetOutTorque(-20.RPMtoRad(), 120.SI<NewtonMeter>(), true)); + // AssertHelper.AreRelativeEqual(-30, map.GetOutTorque(120.RPMtoRad(), -20.SI<NewtonMeter>(), true)); + // AssertHelper.AreRelativeEqual(110, map.GetOutTorque(120.RPMtoRad(), 120.SI<NewtonMeter>(), true)); + + // // test outside the edges + // AssertHelper.AreRelativeEqual(40, map.GetOutTorque(-20.RPMtoRad(), 50.SI<NewtonMeter>(), true)); + // AssertHelper.AreRelativeEqual(110, map.GetOutTorque(50.RPMtoRad(), 120.SI<NewtonMeter>(), true)); + // AssertHelper.AreRelativeEqual(-30, map.GetOutTorque(50.RPMtoRad(), -20.SI<NewtonMeter>(), true)); + // AssertHelper.AreRelativeEqual(40, map.GetOutTorque(120.RPMtoRad(), 50.SI<NewtonMeter>(), true)); + //} [TestCase] public void TestLossMap_IN_Interpolation_Extrapolation() @@ -255,52 +255,52 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponentData AssertHelper.AreRelativeEqual(25, map.GetTorqueLoss(120.RPMtoRad(), 50.SI<NewtonMeter>()).Value); } - [TestCase] - public void TestLossMap_OUT_Interpolation_Extrapolation() - { - var data = new DataTable(); - data.Columns.Add(""); - data.Columns.Add(""); - data.Columns.Add(""); - data.Rows.Add("0", "0", "0"); // (0,100):10 -- (100,100):40 - data.Rows.Add("0", "100", "10"); // | \ | - data.Rows.Add("100", "0", "10"); // | \ | - data.Rows.Add("100", "100", "40"); // (0,0):0 ----- (100,0):10 - - var map = TransmissionLossMapReader.Create(data, 1.0, "1"); - - // test inside the triangles - AssertHelper.AreRelativeEqual(20, map.GetOutTorque(25.RPMtoRad(), 25.SI<NewtonMeter>())); - AssertHelper.AreRelativeEqual(32.5, map.GetOutTorque(75.RPMtoRad(), 50.SI<NewtonMeter>())); - - // test interpolation on edges - AssertHelper.AreRelativeEqual(-5, map.GetOutTorque(50.RPMtoRad(), 0.SI<NewtonMeter>())); - AssertHelper.AreRelativeEqual(40.5, map.GetOutTorque(0.RPMtoRad(), 45.SI<NewtonMeter>())); - AssertHelper.AreRelativeEqual(31, map.GetOutTorque(50.RPMtoRad(), 40.SI<NewtonMeter>())); - AssertHelper.AreRelativeEqual(57.5, map.GetOutTorque(50.RPMtoRad(), 75.SI<NewtonMeter>())); - AssertHelper.AreRelativeEqual(7.5, map.GetOutTorque(100.RPMtoRad(), 25.SI<NewtonMeter>())); - - // test interpolation on corner points - AssertHelper.AreRelativeEqual(0, map.GetTorqueLoss(0.RPMtoRad(), 0.SI<NewtonMeter>()).Value); - AssertHelper.AreRelativeEqual(10, map.GetTorqueLoss(0.RPMtoRad(), 90.SI<NewtonMeter>()).Value); - AssertHelper.AreRelativeEqual(10, map.GetTorqueLoss(100.RPMtoRad(), -10.SI<NewtonMeter>()).Value); - AssertHelper.AreRelativeEqual(40, map.GetTorqueLoss(100.RPMtoRad(), 60.SI<NewtonMeter>()).Value); - - // test outside the corners - AssertHelper.AreRelativeEqual(-20, map.GetOutTorque(-20.RPMtoRad(), -20.SI<NewtonMeter>(), true)); - AssertHelper.AreRelativeEqual(110, map.GetOutTorque(-20.RPMtoRad(), 120.SI<NewtonMeter>(), true)); - AssertHelper.AreRelativeEqual(-30, map.GetOutTorque(120.RPMtoRad(), -20.SI<NewtonMeter>(), true)); - AssertHelper.AreRelativeEqual(80, map.GetOutTorque(120.RPMtoRad(), 120.SI<NewtonMeter>(), true)); - - // test outside the edges - AssertHelper.AreRelativeEqual(45, map.GetOutTorque(-20.RPMtoRad(), 50.SI<NewtonMeter>(), true)); - AssertHelper.AreRelativeEqual(95, map.GetOutTorque(50.RPMtoRad(), 120.SI<NewtonMeter>(), true)); - AssertHelper.AreRelativeEqual(-25, map.GetOutTorque(50.RPMtoRad(), -20.SI<NewtonMeter>(), true)); - AssertHelper.AreRelativeEqual(25, map.GetOutTorque(120.RPMtoRad(), 50.SI<NewtonMeter>(), true)); - - // test extrapolation not allowed - AssertHelper.Exception<VectoException>(() => { map.GetOutTorque(120.RPMtoRad(), 50.SI<NewtonMeter>()); }); - } + //[TestCase] + //public void TestLossMap_OUT_Interpolation_Extrapolation() + //{ + // var data = new DataTable(); + // data.Columns.Add(""); + // data.Columns.Add(""); + // data.Columns.Add(""); + // data.Rows.Add("0", "0", "0"); // (0,100):10 -- (100,100):40 + // data.Rows.Add("0", "100", "10"); // | \ | + // data.Rows.Add("100", "0", "10"); // | \ | + // data.Rows.Add("100", "100", "40"); // (0,0):0 ----- (100,0):10 + + // var map = TransmissionLossMapReader.Create(data, 1.0, "1"); + + // // test inside the triangles + // AssertHelper.AreRelativeEqual(20, map.GetOutTorque(25.RPMtoRad(), 25.SI<NewtonMeter>())); + // AssertHelper.AreRelativeEqual(32.5, map.GetOutTorque(75.RPMtoRad(), 50.SI<NewtonMeter>())); + + // // test interpolation on edges + // AssertHelper.AreRelativeEqual(-5, map.GetOutTorque(50.RPMtoRad(), 0.SI<NewtonMeter>())); + // AssertHelper.AreRelativeEqual(40.5, map.GetOutTorque(0.RPMtoRad(), 45.SI<NewtonMeter>())); + // AssertHelper.AreRelativeEqual(31, map.GetOutTorque(50.RPMtoRad(), 40.SI<NewtonMeter>())); + // AssertHelper.AreRelativeEqual(57.5, map.GetOutTorque(50.RPMtoRad(), 75.SI<NewtonMeter>())); + // AssertHelper.AreRelativeEqual(7.5, map.GetOutTorque(100.RPMtoRad(), 25.SI<NewtonMeter>())); + + // // test interpolation on corner points + // AssertHelper.AreRelativeEqual(0, map.GetTorqueLoss(0.RPMtoRad(), 0.SI<NewtonMeter>()).Value); + // AssertHelper.AreRelativeEqual(10, map.GetTorqueLoss(0.RPMtoRad(), 90.SI<NewtonMeter>()).Value); + // AssertHelper.AreRelativeEqual(10, map.GetTorqueLoss(100.RPMtoRad(), -10.SI<NewtonMeter>()).Value); + // AssertHelper.AreRelativeEqual(40, map.GetTorqueLoss(100.RPMtoRad(), 60.SI<NewtonMeter>()).Value); + + // // test outside the corners + // AssertHelper.AreRelativeEqual(-20, map.GetOutTorque(-20.RPMtoRad(), -20.SI<NewtonMeter>(), true)); + // AssertHelper.AreRelativeEqual(110, map.GetOutTorque(-20.RPMtoRad(), 120.SI<NewtonMeter>(), true)); + // AssertHelper.AreRelativeEqual(-30, map.GetOutTorque(120.RPMtoRad(), -20.SI<NewtonMeter>(), true)); + // AssertHelper.AreRelativeEqual(80, map.GetOutTorque(120.RPMtoRad(), 120.SI<NewtonMeter>(), true)); + + // // test outside the edges + // AssertHelper.AreRelativeEqual(45, map.GetOutTorque(-20.RPMtoRad(), 50.SI<NewtonMeter>(), true)); + // AssertHelper.AreRelativeEqual(95, map.GetOutTorque(50.RPMtoRad(), 120.SI<NewtonMeter>(), true)); + // AssertHelper.AreRelativeEqual(-25, map.GetOutTorque(50.RPMtoRad(), -20.SI<NewtonMeter>(), true)); + // AssertHelper.AreRelativeEqual(25, map.GetOutTorque(120.RPMtoRad(), 50.SI<NewtonMeter>(), true)); + + // // test extrapolation not allowed + // AssertHelper.Exception<VectoException>(() => { map.GetOutTorque(120.RPMtoRad(), 50.SI<NewtonMeter>()); }); + //} [TestCase] public void TestFullLoadCurveIntersection() -- GitLab