diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Data/Gearbox/TorqueConverterData.cs b/VectoCore/VectoCore/Models/SimulationComponent/Data/Gearbox/TorqueConverterData.cs index 0d944e3b2fe71db3fc91806f4605db8294b758d6..485c9567d278de5a6f23bb16705a0f74573d45b6 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Data/Gearbox/TorqueConverterData.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Data/Gearbox/TorqueConverterData.cs @@ -62,12 +62,16 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox /// </summary> /// <param name="torqueOut">torque provided at the TC output</param> /// <param name="angularSpeedOut">angular speed at the TC output</param> + /// <param name="minSpeed"></param> /// <returns></returns> - public TorqueConverterOperatingPoint FindOperatingPoint(NewtonMeter torqueOut, PerSecond angularSpeedOut) + public IList<TorqueConverterOperatingPoint> FindOperatingPoint(NewtonMeter torqueOut, PerSecond angularSpeedOut, + PerSecond minSpeed) { var solutions = new List<double>(); var mpNorm = ReferenceSpeed.Value(); + var min = minSpeed == null ? 0 : minSpeed.Value(); + // 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) @@ -88,7 +92,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox torqueOut.Value(); var sol = VectoMath.QuadraticEquationSolver(a, b, c); - var selected = sol.Where(x => x > 0 + var selected = sol.Where(x => x > min && 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); @@ -98,15 +102,18 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox torqueOut); } - var retVal = new TorqueConverterOperatingPoint { - OutTorque = torqueOut, - OutAngularVelocity = angularSpeedOut, - InAngularVelocity = solutions.Min().SI<PerSecond>() - }; - retVal.SpeedRatio = angularSpeedOut / retVal.InAngularVelocity; - retVal.TorqueRatio = MuLookup(angularSpeedOut / retVal.InAngularVelocity); - retVal.InTorque = torqueOut / retVal.TorqueRatio; - + var retVal = new List<TorqueConverterOperatingPoint>(); + foreach (var sol in solutions) { + var tmp = new TorqueConverterOperatingPoint { + OutTorque = torqueOut, + OutAngularVelocity = angularSpeedOut, + InAngularVelocity = sol.SI<PerSecond>() + }; + tmp.SpeedRatio = angularSpeedOut / tmp.InAngularVelocity; + tmp.TorqueRatio = MuLookup(angularSpeedOut / tmp.InAngularVelocity); + tmp.InTorque = torqueOut / tmp.TorqueRatio; + retVal.Add(tmp); + } return retVal; } @@ -139,7 +146,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox retVal.OutTorque = retVal.InTorque * retVal.TorqueRatio; return retVal; } - throw new VectoException("No solution for output speed/input speed found! n_out: {0}, n_in: {1}, nu: {2}, nu_max: {3}", outAngularVelocity, + throw new VectoException( + "No solution for output speed/input speed found! n_out: {0}, n_in: {1}, nu: {2}, nu_max: {3}", outAngularVelocity, inAngularVelocity, outAngularVelocity / inAngularVelocity, TorqueConverterEntries.Last().SpeedRatio); } @@ -153,7 +161,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox /// <param name="inAngularVelocity"></param> /// <param name="outAngularSpeedEstimated"></param> /// <returns></returns> - public TorqueConverterOperatingPoint FindOperatingPoint(NewtonMeter inTorque, PerSecond inAngularVelocity, + public TorqueConverterOperatingPoint FindOperatingPointForward(NewtonMeter inTorque, PerSecond inAngularVelocity, PerSecond outAngularSpeedEstimated) { var referenceTorque = inTorque.Value() / inAngularVelocity.Value() / inAngularVelocity.Value() * diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/CycleGearbox.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/CycleGearbox.cs index 3d1f40e3348da9be7e9f87110699db2bcc623115..ebab9c27613051f27cc58d832643a1c7dca89edc 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/CycleGearbox.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/CycleGearbox.cs @@ -29,6 +29,8 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ +using System.Collections.Generic; +using System.Linq; using TUGraz.VectoCommon.Exceptions; using TUGraz.VectoCommon.Models; using TUGraz.VectoCommon.Utils; @@ -254,20 +256,21 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl (ResponseDryRun)NextComponent.Request(absTime, dt, dryOperatingPoint.InTorque, dryOperatingPoint.InAngularVelocity, true); - var deltaTorqueConverter = (outTorque - dryOperatingPoint.OutTorque) * - (PreviousState.OutAngularVelocity + dryOperatingPoint.OutAngularVelocity) / 2.0; + //var deltaTorqueConverter = (outTorque - dryOperatingPoint.OutTorque) * + // (PreviousState.OutAngularVelocity + dryOperatingPoint.OutAngularVelocity) / 2.0; - var deltaEngine = (engineResponse.DeltaFullLoad > 0 ? engineResponse.DeltaFullLoad : 0.SI<Watt>()) + - (engineResponse.DeltaDragLoad < 0 ? -engineResponse.DeltaDragLoad : 0.SI<Watt>()); + //var deltaEngine = (engineResponse.DeltaFullLoad > 0 ? engineResponse.DeltaFullLoad : 0.SI<Watt>()) + + // (engineResponse.DeltaDragLoad < 0 ? -engineResponse.DeltaDragLoad : 0.SI<Watt>()); dryOperatingPoint = outTorque.IsGreater(0) && DataBus.BrakePower.IsEqual(0) ? GetMaxPowerOperatingPoint(dt, outAngularVelocity, engineResponse) : GetDragPowerOperatingPoint(dt, outAngularVelocity, engineResponse); - engineResponse = (ResponseDryRun)NextComponent.Request(absTime, dt, dryOperatingPoint.InTorque, - dryOperatingPoint.InAngularVelocity, true); + //engineResponse = (ResponseDryRun)NextComponent.Request(absTime, dt, dryOperatingPoint.InTorque, + // dryOperatingPoint.InAngularVelocity, true); var delta = (outTorque - dryOperatingPoint.OutTorque) * (PreviousState.OutAngularVelocity + dryOperatingPoint.OutAngularVelocity) / 2.0; + //var tmp = FindOperatingPoint(dryOperatingPoint.OutTorque, dryOperatingPoint.OutAngularVelocity); //deltaTorqueConverter.Value() * (deltaEngine.IsEqual(0) ? 1 : deltaEngine.Value()); return new ResponseDryRun() { Source = this, @@ -331,11 +334,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl PerSecond outAngularVelocity) { try { - var operatingPoint = TorqueConverter.FindOperatingPoint(outTorque, outAngularVelocity); - if (operatingPoint.InAngularVelocity.IsSmaller(DataBus.EngineIdleSpeed)) { - throw new VectoException("Invalid operating point, inAngularVelocity below engine's idle speed: {0}", - operatingPoint.InAngularVelocity); - } + var operatingPointList = TorqueConverter.FindOperatingPoint(outTorque, outAngularVelocity, DataBus.EngineIdleSpeed); + var operatingPoint = SelectOperatingPoint(operatingPointList); if (operatingPoint.InAngularVelocity.IsGreater(DataBus.EngineRatedSpeed)) { operatingPoint = TorqueConverter.FindOperatingPoint(DataBus.EngineRatedSpeed, outAngularVelocity); } @@ -347,6 +347,24 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl } } + private TorqueConverterOperatingPoint SelectOperatingPoint(IList<TorqueConverterOperatingPoint> operatingPointList) + { + if (operatingPointList.Count == 1) { + return operatingPointList[0]; + } + + var filtered = operatingPointList.Where(x => + (x.InTorque * x.InAngularVelocity).IsSmallerOrEqual(DataBus.EngineStationaryFullPower(x.InAngularVelocity), + Constants.SimulationSettings.LineSearchTolerance.SI<Watt>()) && + (x.InTorque * x.InAngularVelocity).IsGreaterOrEqual(DataBus.EngineDragPower(x.InAngularVelocity), + Constants.SimulationSettings.LineSearchTolerance.SI<Watt>()) + ).ToArray(); + if (filtered.Count() == 1) { + return filtered.First(); + } + return operatingPointList[0]; + } + private TorqueConverterOperatingPoint GetDragPowerOperatingPoint(Second dt, PerSecond outAngularVelocity, ResponseDryRun engineResponse) { @@ -430,12 +448,12 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl container[ModalResultField.TC_angularSpeedOut] = CurrentState.TorqueConverterOperatingPoint.OutAngularVelocity; var avgOutVelocity = ((PreviousState.TorqueConverterOperatingPoint != null - ? PreviousState.TorqueConverterOperatingPoint.OutAngularVelocity - : PreviousState.InAngularVelocity) + + ? PreviousState.TorqueConverterOperatingPoint.OutAngularVelocity + : PreviousState.InAngularVelocity) + CurrentState.TorqueConverterOperatingPoint.OutAngularVelocity) / 2.0; var avgInVelocity = ((PreviousState.TorqueConverterOperatingPoint != null - ? PreviousState.TorqueConverterOperatingPoint.InAngularVelocity - : PreviousState.InAngularVelocity) + + ? PreviousState.TorqueConverterOperatingPoint.InAngularVelocity + : PreviousState.InAngularVelocity) + CurrentState.TorqueConverterOperatingPoint.InAngularVelocity) / 2.0; container[ModalResultField.P_TC_out] = CurrentState.OutTorque * avgOutVelocity; container[ModalResultField.P_TC_loss] = CurrentState.InTorque * avgInVelocity - diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/TorqueConverter.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/TorqueConverter.cs index 5840f0311cf7fa07bafb3a132b03ed78d6aaa114..35c37c67ab293fc6c683d01a91fc46964e769dc5 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/TorqueConverter.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/TorqueConverter.cs @@ -1,4 +1,6 @@ -using TUGraz.VectoCommon.Exceptions; +using System.Collections.Generic; +using System.Linq; +using TUGraz.VectoCommon.Exceptions; using TUGraz.VectoCommon.Models; using TUGraz.VectoCommon.Utils; using TUGraz.VectoCore.Configuration; @@ -41,14 +43,15 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl public IResponse Initialize(NewtonMeter outTorque, PerSecond outAngularVelocity) { - var operatingPoint = ModelData.FindOperatingPoint(outTorque, outAngularVelocity); - + var operatingPointList = ModelData.FindOperatingPoint(outTorque, outAngularVelocity, DataBus.EngineIdleSpeed); + var operatingPoint = SelectOperatingPoint(operatingPointList); var retVal = NextComponent.Initialize(operatingPoint.InTorque, operatingPoint.InAngularVelocity); PreviousState.SetState(operatingPoint.InTorque, operatingPoint.InAngularVelocity, operatingPoint.OutTorque, operatingPoint.OutAngularVelocity); return retVal; } + public IResponse Request(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, bool dryRun = false) { @@ -153,7 +156,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl PerSecond outAngularVelocity) { try { - var operatingPoint = ModelData.FindOperatingPoint(outTorque, outAngularVelocity); + var operatingPointList = ModelData.FindOperatingPoint(outTorque, outAngularVelocity, DataBus.EngineIdleSpeed); + var operatingPoint = SelectOperatingPoint(operatingPointList); if (operatingPoint.InAngularVelocity.IsSmaller(DataBus.EngineIdleSpeed)) { throw new VectoException("Invalid operating point, inAngularVelocity below engine's idle speed: {0}", operatingPoint.InAngularVelocity); @@ -169,6 +173,24 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl } } + + private TorqueConverterOperatingPoint SelectOperatingPoint(IList<TorqueConverterOperatingPoint> operatingPointList) + { + if (operatingPointList.Count == 1) { + return operatingPointList[0]; + } + var filtered = operatingPointList.Where(x => + (x.InTorque * x.InAngularVelocity).IsSmallerOrEqual(DataBus.EngineStationaryFullPower(x.InAngularVelocity), + Constants.SimulationSettings.LineSearchTolerance.SI<Watt>()) && + (x.InTorque * x.InAngularVelocity).IsGreaterOrEqual(DataBus.EngineDragPower(x.InAngularVelocity), + Constants.SimulationSettings.LineSearchTolerance.SI<Watt>()) + ).ToArray(); + if (filtered.Count() == 1) { + return filtered.First(); + } + return operatingPointList[0]; + } + protected override void DoWriteModalResults(IModalDataContainer container) { if (CurrentState.OperatingPoint == null) { diff --git a/VectoCore/VectoCoreTest/Models/SimulationComponentData/TorqueConverterDataTest.cs b/VectoCore/VectoCoreTest/Models/SimulationComponentData/TorqueConverterDataTest.cs index a395445c598cc95831ce57b059085ad263e9aa8d..6aae74a91a8c2dfc38b521c8afa59e4ec9a3df73 100644 --- a/VectoCore/VectoCoreTest/Models/SimulationComponentData/TorqueConverterDataTest.cs +++ b/VectoCore/VectoCoreTest/Models/SimulationComponentData/TorqueConverterDataTest.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; +using NLog.Targets; using NUnit.Framework; using TUGraz.VectoCommon.Utils; using TUGraz.VectoCore.Configuration; @@ -52,7 +54,9 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponentData var outAngularSpeed = nOut.RPMtoRad(); var outTorque = (Pout * 1000).SI<Watt>() / outAngularSpeed; - var result = tqData.FindOperatingPoint(outTorque, outAngularSpeed); + var resultList = tqData.FindOperatingPoint(outTorque, outAngularSpeed, 0.SI<PerSecond>()); + Assert.AreEqual(1, resultList.Count); + var result = resultList[0]; Assert.AreEqual(outAngularSpeed.Value(), result.OutAngularVelocity.Value(), 1e-3); Assert.AreEqual(outTorque.Value(), result.OutTorque.Value(), 1e-3); @@ -85,13 +89,16 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponentData tqInput), 1000.RPMtoRad(), tqLimit.RPMtoRad()); - var operatingPoint = tqData.FindOperatingPoint(tqIn.SI<NewtonMeter>(), nIn.RPMtoRad(), null); + var operatingPoint = tqData.FindOperatingPointForward(tqIn.SI<NewtonMeter>(), nIn.RPMtoRad(), null); Assert.AreEqual(operatingPoint.InTorque.Value(), tqIn, 1e-6); Assert.AreEqual(operatingPoint.InAngularVelocity.Value(), nIn.RPMtoRad().Value(), 1e-6); - var reverseOP = tqData.FindOperatingPoint(operatingPoint.OutTorque, operatingPoint.OutAngularVelocity); + var resultList = tqData.FindOperatingPoint(operatingPoint.OutTorque, operatingPoint.OutAngularVelocity, + 0.SI<PerSecond>()); + Assert.AreEqual(1, resultList.Count); + var reverseOP = resultList[0]; Assert.AreEqual(operatingPoint.InTorque.Value(), reverseOP.InTorque.Value(), 1e-6); Assert.AreEqual(operatingPoint.OutTorque.Value(), reverseOP.OutTorque.Value(), 1e-6); @@ -131,7 +138,7 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponentData foreach (var entry in testData) { var torqueTCOut = entry.Item1.SI<NewtonMeter>(); var angularSpeedOut = entry.Item2.RPMtoRad(); - var result = tqData.FindOperatingPoint(torqueTCOut, angularSpeedOut); + var result = tqData.FindOperatingPoint(torqueTCOut, angularSpeedOut, 0.SI<PerSecond>()).First(); Debug.WriteLine("n_out: {0}, tq_out: {1}, n_in: {2}, Tq_in: {3}", angularSpeedOut.Value() / Constants.RPMToRad, torqueTCOut.Value(), result.InAngularVelocity.Value() / Constants.RPMToRad, result.InTorque.Value()); } @@ -176,9 +183,80 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponentData var outAngularSpeed = nOut.RPMtoRad(); var outTorque = (Pout * 1000).SI<Watt>() / outAngularSpeed; - var result = tqData.FindOperatingPoint(outTorque, outAngularSpeed); + var resultList = tqData.FindOperatingPoint(outTorque, outAngularSpeed, 0.SI<PerSecond>()); + Assert.AreEqual(1, resultList.Count); + var result = resultList[0]; Assert.IsTrue(result.InAngularVelocity.Value() > tqLimit.Value()); } + + + [TestCase()] + public void TestForwardBackward() + { + var tqLimit = 1600.RPMtoRad(); + + var tqInput = new[] { + "0,4.6,708 ", + "0.1,3.7,641 ", + "0.2,2.9,560 ", + "0.3,2.4,465 ", + "0.4,1.8,356 ", + "0.5,1.4,251 ", + "0.6,0.9,166 ", + "0.735,0.9,1 ", + "0.738,1.361,0 ", + "0.808,1.351,-40 ", + "0.898,1.349,-80 ", + "1.01,1.338,-136 ", + "1.154,1.327,-217 ", + "1.347,1.316,-335 ", + "1.616,1.305,-529 ", + "3 ,1.294,-729 ", + }; + + var tqInput_1 = new[] { + "0.0,1.80,377.80 ", + "0.1,1.71,365.21 ", + "0.2,1.61,352.62 ", + "0.3,1.52,340.02 ", + "0.4,1.42,327.43 ", + "0.5,1.33,314.84 ", + "0.6,1.23,302.24 ", + "0.7,1.14,264.46 ", + "0.8,1.04,226.68 ", + "0.9,0.95,188.90 ", + "1.0,0.95,0.00 ", + "1.100,0.99,-40.34 ", + "1.222,0.98,-80.34 ", + "1.375,0.97,-136.11 ", + "1.571,0.96,-216.52 ", + "1.833,0.95,-335.19 ", + "2.200,0.94,-528.77 ", + "2.750,0.93,-883.40 ", + "4.400,0.92,-2462.17 ", + "11.000,0.91,-16540.98 ", + }; + var tqData = + TorqueConverterDataReader.ReadFromStream(InputDataHelper.InputDataAsStream("Speed Ratio, Torque Ratio,MP1000", + tqInput), 1000.RPMtoRad(), tqLimit); + + var operatingPoint = tqData.FindOperatingPointForPowerDemand(20000.SI<Watt>(), 113.5.SI<PerSecond>(), + 1200.RPMtoRad(), 4.SI<KilogramSquareMeter>(), 0.5.SI<Second>()); + + var tmp = tqData.FindOperatingPoint(operatingPoint.OutTorque, operatingPoint.OutAngularVelocity, 0.RPMtoRad()); + var backward = tmp.First(); + + Debug.WriteLine(operatingPoint); + Debug.WriteLine(operatingPoint.InAngularVelocity * operatingPoint.InTorque); + + Debug.WriteLine(backward); + Debug.WriteLine(backward.InAngularVelocity * backward.InTorque); + + Assert.AreEqual(backward.OutAngularVelocity.Value(), operatingPoint.OutAngularVelocity.Value(), 1e-9); + Assert.AreEqual(backward.OutTorque.Value(), operatingPoint.OutTorque.Value(), 1e-9); + Assert.AreEqual(backward.InAngularVelocity.Value(), operatingPoint.InAngularVelocity.Value(), 1e-9); + Assert.AreEqual(backward.InTorque.Value(), operatingPoint.InTorque.Value(), 1e-9); + } } } \ No newline at end of file