diff --git a/VectoCore/VectoCore/InputData/Reader/ComponentData/TorqueConverterDataReader.cs b/VectoCore/VectoCore/InputData/Reader/ComponentData/TorqueConverterDataReader.cs index f6deb29f19ec7c964b1aa1db4a02d30776e3187e..8031ec1ffe5c940ded2a403d058f566377478550 100644 --- a/VectoCore/VectoCore/InputData/Reader/ComponentData/TorqueConverterDataReader.cs +++ b/VectoCore/VectoCore/InputData/Reader/ComponentData/TorqueConverterDataReader.cs @@ -8,7 +8,8 @@ using TUGraz.VectoCore.Utils; namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox { - public class TorqueConverterDataReader { + public class TorqueConverterDataReader + { public static TorqueConverterData ReadFromFile(string filename) { return Create(VectoCSVFile.Read(filename)); @@ -28,36 +29,25 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox throw new VectoException("TorqueConverter Characteristics data must contain at least 2 lines with numeric values"); } - List<TorqueRatioCurveEntry> torqueRatio; - List<CharacteristicTorqueEntry> characteristicTorque; + List<TorqueConverterEntry> characteristicTorque; if (HeaderIsValid(data.Columns)) { - torqueRatio = (from DataRow row in data.Rows - select - new TorqueRatioCurveEntry() { - SpeedRatio = DataTableExtensionMethods.ParseDouble(row, (string)Fields.SpeedRatio), - TorqueRatio = DataTableExtensionMethods.ParseDouble(row, (string)Fields.TorqueRatio) - }).ToList(); characteristicTorque = (from DataRow row in data.Rows select - new CharacteristicTorqueEntry() { - SpeedRatio = DataTableExtensionMethods.ParseDouble(row, (string)Fields.SpeedRatio), - Torque = DataTableExtensionMethods.ParseDouble(row, (string)Fields.CharacteristicTorque).SI<NewtonMeter>() + new TorqueConverterEntry() { + SpeedRatio = row.ParseDouble((string)Fields.SpeedRatio), + Torque = row.ParseDouble((string)Fields.CharacteristicTorque).SI<NewtonMeter>(), + TorqueRatio = row.ParseDouble((string)Fields.TorqueRatio) }).ToList(); } else { - torqueRatio = (from DataRow row in data.Rows - select - new TorqueRatioCurveEntry() { - SpeedRatio = row.ParseDouble(0), - TorqueRatio = row.ParseDouble(1) - }).ToList(); characteristicTorque = (from DataRow row in data.Rows select - new CharacteristicTorqueEntry() { + new TorqueConverterEntry() { SpeedRatio = row.ParseDouble(0), - Torque = row.ParseDouble(2).SI<NewtonMeter>() + Torque = row.ParseDouble(2).SI<NewtonMeter>(), + TorqueRatio = row.ParseDouble(1) }).ToList(); } - return new TorqueConverterData(torqueRatio, characteristicTorque); + return new TorqueConverterData(characteristicTorque); } private static bool HeaderIsValid(DataColumnCollection columns) diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Data/Gearbox/TorqueConverterData.cs b/VectoCore/VectoCore/Models/SimulationComponent/Data/Gearbox/TorqueConverterData.cs index 2aea92cf5e187893d4697120f7a23e55c7fddb9d..1bbcf718f5c1a3fc4e074d644e2a138b61d4e80b 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Data/Gearbox/TorqueConverterData.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Data/Gearbox/TorqueConverterData.cs @@ -43,14 +43,11 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox { public class TorqueConverterData { - public List<TorqueRatioCurveEntry> TorqueRatio; - public List<CharacteristicTorqueEntry> CharacteristicTorque; + public List<TorqueConverterEntry> TorqueConverterEntries; - protected internal TorqueConverterData(List<TorqueRatioCurveEntry> torqueRatio, - List<CharacteristicTorqueEntry> characteristicTorque) + protected internal TorqueConverterData(List<TorqueConverterEntry> torqueConverterEntries) { - TorqueRatio = torqueRatio; - CharacteristicTorque = characteristicTorque; + TorqueConverterEntries = torqueConverterEntries; } public void GetInputTorqueAndAngularSpeed(NewtonMeter torqueOut, PerSecond angularSpeedOut, out NewtonMeter torqueIn, @@ -59,43 +56,55 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox var solutions = new List<double>(); var mpNorm = 1000.RPMtoRad().Value(); - foreach ( - var muEdge in TorqueRatio.Pairwise((item1, item2) => Edge.Create(new Point(item1.SpeedRatio, item1.TorqueRatio), - new Point(item2.SpeedRatio, item2.TorqueRatio)))) { - foreach ( - var mpEdge in - CharacteristicTorque.Pairwise((item1, item2) => Edge.Create(new Point(item1.SpeedRatio, item1.Torque.Value()), - new Point(item2.SpeedRatio, item2.Torque.Value())))) { - var a = muEdge.OffsetXY * mpEdge.OffsetXY / (mpNorm * mpNorm); - var b = angularSpeedOut.Value() * (muEdge.SlopeXY * mpEdge.OffsetXY + mpEdge.SlopeXY * muEdge.OffsetXY) / mpNorm; - var c = angularSpeedOut.Value() * angularSpeedOut.Value() * mpEdge.SlopeXY * muEdge.SlopeXY / mpNorm - - torqueOut.Value(); - var sol = VectoMath.QuadraticEquationSolver(a, b, c); + // Find analytic solution for torque converter operating point + // mu = f(nu) = f(n_out / n_in) = T_out / T_in + // MP1000 = f(nu) = f(n_out / n_in) + // Tq_in = MP1000(nu) * (n_in/1000)^2 = T_out / mu + // + // mu(nu) and MP1000(nu) are provided as piecewise linear functions (y = k*x+d) + // solving the equation above for n_in results in a quadratic equation + 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 muEdge = Edge.Create(new Point(segment.Item1.SpeedRatio, segment.Item1.TorqueRatio), + new Point(segment.Item2.SpeedRatio, segment.Item2.TorqueRatio)); - var edge1 = muEdge; - var edge2 = mpEdge; - var selected = - sol.Where(x => x > 0 && angularSpeedOut.Value() / x >= edge1.P1.X && angularSpeedOut.Value() / x < edge1.P2.X - && angularSpeedOut.Value() / x >= edge2.P1.X && angularSpeedOut.Value() / x < edge2.P2.X); - solutions.AddRange(selected); - } + var a = muEdge.OffsetXY * mpEdge.OffsetXY / (mpNorm * mpNorm); + var b = angularSpeedOut.Value() * (muEdge.SlopeXY * mpEdge.OffsetXY + mpEdge.SlopeXY * muEdge.OffsetXY) / + (mpNorm * mpNorm); + var c = angularSpeedOut.Value() * angularSpeedOut.Value() * mpEdge.SlopeXY * muEdge.SlopeXY / (mpNorm * mpNorm) - + torqueOut.Value(); + var sol = VectoMath.QuadraticEquationSolver(a, b, c); + + var selected = sol.Where(x => x > 0 + && angularSpeedOut.Value() / x >= muEdge.P1.X && angularSpeedOut.Value() / x < muEdge.P2.X + && angularSpeedOut.Value() / x >= mpEdge.P1.X && angularSpeedOut.Value() / x < mpEdge.P2.X); + solutions.AddRange(selected); + } + if (solutions.Count == 0) { + throw new VectoException("No solution for input torque/input speed found! n_out: {0}, tq_out: {1}", angularSpeedOut, torqueOut); } angularSpeedIn = solutions.Min().SI<PerSecond>(); - torqueIn = 0.SI<NewtonMeter>(); + var mu = MuLookup(angularSpeedOut / angularSpeedIn); + torqueIn = torqueOut / mu; + } + + private double MuLookup(double nu) + { + int index; + TorqueConverterEntries.GetSection(x => x.SpeedRatio > nu, out index); + var muEdge = Edge.Create(new Point(TorqueConverterEntries[index].SpeedRatio, TorqueConverterEntries[index].TorqueRatio), + new Point(TorqueConverterEntries[index + 1].SpeedRatio, TorqueConverterEntries[index + 1].TorqueRatio)); + return muEdge.SlopeXY * nu + muEdge.OffsetXY; } } - public class CharacteristicTorqueEntry + public class TorqueConverterEntry { public double SpeedRatio; public NewtonMeter Torque; - } - - public class TorqueRatioCurveEntry - { - public double SpeedRatio; public double TorqueRatio; } } \ No newline at end of file diff --git a/VectoCore/VectoCoreTest/Models/SimulationComponentData/TorqueConverterDataTest.cs b/VectoCore/VectoCoreTest/Models/SimulationComponentData/TorqueConverterDataTest.cs index cc977dedb70dcfc04dbd9aba0a41eb736dece2ed..0c7394bf3eb4eb40a4e44c1f931af3be5591c5b0 100644 --- a/VectoCore/VectoCoreTest/Models/SimulationComponentData/TorqueConverterDataTest.cs +++ b/VectoCore/VectoCoreTest/Models/SimulationComponentData/TorqueConverterDataTest.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using NUnit.Framework; using TUGraz.VectoCommon.Utils; using TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox; @@ -9,8 +10,21 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponentData [TestFixture] public class TorqueConverterDataTest { - [Test] - public void TestTorqueConverterOperatingPoint() + [Test, + TestCase(30, 10, 1230.7, 842.8317), + TestCase(40, 10, 1081.028, 645.9384), + TestCase(50, 10, 981.7928, 528.8284), + TestCase(60, 10, 912.2327, 452.9006), + TestCase(70, 10, 860.6045, 399.6834), + TestCase(70, 30, 1433.893, 1129.279), + TestCase(90, 10, 789.4108, 330.28), + TestCase(90, 30, 1295.913, 912.1714), + TestCase(170, 30, 1055.424, 574.8998), + TestCase(170, 50, 1308.974, 900.0845), + TestCase(190, 30, 1029.455, 539.6072), + TestCase(190, 50, 1269.513, 837.2174), + TestCase(190, 70, 1465.33, 1128.088),] + public void TestTorqueConverterOperatingPoint(double nOut, double Pout, double nInExpected, double tqInExpected) { var tqInput = new[] { "0,3.935741,563.6598 ", @@ -22,7 +36,7 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponentData "0.6,1.249399,268.4255", "0.7,1.075149,114.9037", }; - ; + var tqData = TorqueConverterDataReader.ReadFromStream(InputDataHelper.InputDataAsStream("Speed Ratio, Torque Ratio,MP1000", tqInput)); @@ -30,10 +44,14 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponentData PerSecond inAngularSpeed; NewtonMeter inTorque; - tqData.GetInputTorqueAndAngularSpeed(400.SI<NewtonMeter>(), 10.RPMtoRad(), out inTorque, out inAngularSpeed); - Assert.AreEqual(0, inTorque.Value()); - Assert.AreEqual(0, inAngularSpeed.Value()); + var outAngularSpeed = nOut.RPMtoRad(); + var outTorque = (Pout * 1000).SI<Watt>() / outAngularSpeed; + tqData.GetInputTorqueAndAngularSpeed(outTorque, outAngularSpeed, out inTorque, out inAngularSpeed); + + + Assert.AreEqual(nInExpected.RPMtoRad().Value(), inAngularSpeed.Value(), 5); + Assert.AreEqual(tqInExpected, inTorque.Value(), 10); } } } \ No newline at end of file