diff --git a/Testing/IntegrationTests/VECTO IntegrationTests/TestCases/Declaration/PowertrainBuilderTests/PowertrainBuilderComponentTests.cs b/Testing/IntegrationTests/VECTO IntegrationTests/TestCases/Declaration/PowertrainBuilderTests/PowertrainBuilderComponentTests.cs index 52c49f0b4933c2691faa702f437e615d16bb7974..1e7118d16b74f3150bbcfbede3f29806e4ec3ca4 100644 --- a/Testing/IntegrationTests/VECTO IntegrationTests/TestCases/Declaration/PowertrainBuilderTests/PowertrainBuilderComponentTests.cs +++ b/Testing/IntegrationTests/VECTO IntegrationTests/TestCases/Declaration/PowertrainBuilderTests/PowertrainBuilderComponentTests.cs @@ -105,9 +105,12 @@ namespace TUGraz.VectoCore.Tests.Models.Simulation var retVal = new Mock<ISimplePowertrainBuilder>(); //var ptBuilder = new SimplePowertrainBuilder(_kernel.Get<IPowertrainComponentFactory>(), _kernel.Get<IShiftStrategyFactory>()); retVal.Setup(b => b.CreateTestPowertrain(It.IsAny<IVehicleContainer>(), It.IsAny<bool>(), - It.IsAny<VectoSimulationJobType?>())) - .Returns((IVehicleContainer container, bool createDriver, VectoSimulationJobType? jobType) => + It.IsAny<VectoSimulationJobType>())) + .Returns((IVehicleContainer container, bool createDriver, VectoSimulationJobType jobType) => _simplePowertrainBuilder.CreateTestPowertrain(container, createDriver, jobType)); + retVal.Setup(b => b.CreateTestPowertrain(It.IsAny<IVehicleContainer>(), It.IsAny<bool>())) + .Returns((IVehicleContainer container, bool createDriver) => + _simplePowertrainBuilder.CreateTestPowertrain(container, createDriver)); return retVal.Object; } diff --git a/Testing/UnitTests/Vecto UnitTests/TestCases/Components/GearShiftStrategy/AMTShiftStrategyOptimizedTests.cs b/Testing/UnitTests/Vecto UnitTests/TestCases/Components/GearShiftStrategy/AMTShiftStrategyOptimizedTests.cs new file mode 100644 index 0000000000000000000000000000000000000000..45ca4700fb1b73e43a3e44765532a3baadefaf05 --- /dev/null +++ b/Testing/UnitTests/Vecto UnitTests/TestCases/Components/GearShiftStrategy/AMTShiftStrategyOptimizedTests.cs @@ -0,0 +1,1082 @@ +using System.ComponentModel.Design.Serialization; +using Moq; +using NUnit.Framework; +using TUGraz.VectoCommon.InputData; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Configuration; +using TUGraz.VectoCore.InputData.Reader.ComponentData; +using TUGraz.VectoCore.Models.Connector.Ports; +using TUGraz.VectoCore.Models.Connector.Ports.Impl; +using TUGraz.VectoCore.Models.Declaration; +using TUGraz.VectoCore.Models.Simulation; +using TUGraz.VectoCore.Models.Simulation.Data; +using TUGraz.VectoCore.Models.Simulation.DataBus; +using TUGraz.VectoCore.Models.Simulation.Impl; +using TUGraz.VectoCore.Models.SimulationComponent; +using TUGraz.VectoCore.Models.SimulationComponent.Data; +using TUGraz.VectoCore.Models.SimulationComponent.Data.Engine; +using TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox; +using TUGraz.VectoCore.Models.SimulationComponent.Impl; +using TUGraz.VectoCore.Models.SimulationComponent.Impl.Gearbox; +using TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies; +using TUGraz.VectoCore.Tests.Utils; +using Assert = NUnit.Framework.Assert; +using Range = System.Range; + +namespace TUGraz.Vecto.UnitTests.TestCases.Components.GearShiftStrategy; + +[TestFixture] +public class AMTShiftStrategyOptimizedTests +{ + [TestCase(8, 7, 1800, 750, true), +TestCase(7, 6, 1800, 750, true), +TestCase(6, 5, 1800, 750, true), +TestCase(5, 4, 1800, 750, true), +TestCase(4, 3, 1800, 750, true), +TestCase(3, 2, 1800, 750, true), +TestCase(2, 1, 1900, 750, true), +TestCase(1, 1, 1200, 700, false), +TestCase(8, 4, 15000, 200, true),] + public void Gearbox_ShiftDown_ACEA_Shiftlines(int gear, int newGear, double t, double n, bool shiftExpected) + { + // the first element 0.0 is just a placeholder for axlegear, not used in this test + var ratios = new[] { 0.0, 6.38, 4.63, 3.44, 2.59, 1.86, 1.35, 1, 0.76 }; + + //Get Containers and MockData + var vehicleContainer = GetMocks(ratios, out var runData, out var testPowertrain); + + + var shiftStrategy = GetShiftStrategyAndGearbox(vehicleContainer, out var gbx); + vehicleContainer.Setup(c => c.EngineInfo.EngineSpeed).Returns(() => n.RPMtoRad()); + vehicleContainer.Setup(c => c.EngineInfo.EngineN95hSpeed).Returns(() => 2000.RPMtoRad()); + + + var absTime = 0.SI<Second>(); + var dt = 2.SI<Second>(); + + var expectedN = n.RPMtoRad(); + var angularVelocity = expectedN / ratios[gear]; + + + var gearShiftPosition = shiftStrategy.InitGear(0.SI<Second>(), Constants.SimulationSettings.TargetTimeInterval, 1.SI<NewtonMeter>(), + angularVelocity); + + var expectedT = t.SI<NewtonMeter>(); + var torque = expectedT * ratios[gear]; + + var response = new ResponseSuccess(this); + response.Engine.TorqueOutDemand = expectedT; + response.Engine.EngineSpeed = expectedN; + + var shiftRequired = shiftStrategy.ShiftRequired(absTime, dt, torque, angularVelocity, expectedT, expectedN, + new GearshiftPosition((uint)gear), -double.MaxValue.SI<Second>(), response); + Assert.AreEqual(shiftExpected, shiftRequired); + Assert.AreEqual(newGear, shiftStrategy.NextGear.Gear); + } + + + [TestCase(7, 8, 1000, 1400, true), + TestCase(6, 8, 800, 1400, true), + TestCase(5, 6, 1000, 1400, true), + TestCase(4, 5, 1000, 1400, true), + TestCase(3, 4, 1000, 1400, true), + TestCase(2, 4, 800, 1400, true), + TestCase(1, 2, 1000, 1400, true), + TestCase(8, 8, 1000, 1400, false), + TestCase(1, 6, 200, 9000, true),] + public void Gearbox_ShiftUp(int gear, int newGear, double tq, double n, bool shiftExpected) + { + // the first element 0.0 is just a placeholder for axlegear, not used in this test + var ratios = new[] { 0.0, 6.38, 4.63, 3.44, 2.59, 1.86, 1.35, 1, 0.76 }; + + + var container = GetMocks(ratios, out var runData, out _); + var shiftStrategy = GetShiftStrategyAndGearbox(container, out var gbx); + + container.Setup(c => c.EngineInfo.EngineSpeed).Returns(() => n.RPMtoRad()); + container.Setup(c => c.EngineInfo.EngineN95hSpeed).Returns(2000.RPMtoRad()); + + + var absTime = 0.SI<Second>(); + var dt = 2.SI<Second>(); + + var expectedN = n.RPMtoRad(); + var angularVelocity = expectedN / ratios[gear]; + + var gearShiftPosition = shiftStrategy.InitGear(0.SI<Second>(), Constants.SimulationSettings.TargetTimeInterval, 1.SI<NewtonMeter>(), + angularVelocity); + + absTime += dt; + + var expectedT = tq.SI<NewtonMeter>(); + var torque = expectedT * ratios[gear]; + + var response = new ResponseSuccess(this); + //Setup Response + response.Engine.TorqueOutDemand = expectedT; + response.Engine.EngineSpeed = expectedN; + + + var shiftRequired = shiftStrategy.ShiftRequired(absTime, dt, torque, angularVelocity, expectedT, expectedN, + new GearshiftPosition((uint)gear), -double.MaxValue.SI<Second>(), response); + + + + Assert.AreEqual(shiftExpected, shiftRequired); + Assert.AreEqual(newGear, shiftStrategy.NextGear.Gear); + } + + + // [TestCase(2, 3, 800, 1400, 20_000, true, Description = "A gear would be skipped, but due to the uphill driving conditions, the next gear should be used")] + // [TestCase(3, 3, 1000, 1400, 30_000, false, Description = "No upshifting because acceleration would be to low")] + // public void Gearbox_ShiftUpUphill(int gear, int newGear, double tq, double n, double slopeResistance, bool shiftExpected) + // { + // // the first element 0.0 is just a placeholder for axlegear, not used in this test + // var ratios = new[] { 0.0, 6.38, 4.63, 3.44, 2.59, 1.86, 1.35, 1, 0.76 }; + // var container = GetMocks(ratios, out var runData, out _); + // + // var accEstimationLookAhead = Constants.SimulationSettings.GearboxLookaheadForAccelerationEstimation; + // + // container.Setup(c => c.VehicleInfo.SlopeResistance(It.IsAny<Radian>())).Returns(slopeResistance.SI<Newton>()); + // container.Setup(c => c.DrivingCycleInfo.CycleLookAhead(accEstimationLookAhead)) + // .Returns(new DrivingCycleData.DrivingCycleEntry() { + // Altitude = 100.SI<Meter>() + // }); + // container.Setup(c => c.DrivingCycleInfo.Altitude).Returns(0.SI<Meter>()); + // + // + // + // + // + // + // // var testPt = GetMockTestPowertrain(runData, out var simplePt); + // // + // // var ptBuilder = new Mock<ISimplePowertrainBuilder>(); + // // ptBuilder.Setup(p => p.CreateTestPowertrain<Gearbox>(It.IsAny<ISimpleVehicleContainer>(), It.IsAny<IDataBus>())) + // // .Returns(testPt.Object); + // // + // // ptBuilder.Setup(p => p.BuildSimplePowertrain(It.IsAny<VectoRunData>())).Returns(simplePt.Object); + // // container.Setup(c => c.SimplePowertrainBuilder).Returns(ptBuilder.Object); + // // + // // var gbx = GetMockGearbox(container); + // // Mock.Get(container.Object.EngineInfo).Setup(e => e.EngineSpeed).Returns(() => n.RPMtoRad()); + // // Mock.Get(container.Object.EngineInfo).Setup(e => e.EngineN95hSpeed).Returns(2000.RPMtoRad()); + // + // var shiftStrategy = GetShiftStrategyAndGearbox(container, out var gbx); + // // var shiftStrategy = new AMTShiftStrategyOptimized(container.Object); + // // shiftStrategy.Gearbox = gbx.Object; + // + // var absTime = 0.SI<Second>(); + // var dt = 2.SI<Second>(); + // + // var expectedN = n.RPMtoRad(); + // var angularVelocity = expectedN / ratios[gear]; + // + // var gearShiftPosition = shiftStrategy.InitGear(0.SI<Second>(), Constants.SimulationSettings.TargetTimeInterval, 1.SI<NewtonMeter>(), + // angularVelocity); + // + // absTime += dt; + // + // var expectedT = tq.SI<NewtonMeter>(); + // var torque = expectedT * ratios[gear]; + // + // + // var shiftRequired = shiftStrategy.ShiftRequired(absTime, dt, torque, angularVelocity, expectedT, expectedN, + // new GearshiftPosition((uint)gear), -double.MaxValue.SI<Second>(), new ResponseSuccess(this)); + // + // Assert.AreEqual(shiftExpected, shiftRequired); + // Assert.AreEqual(newGear, shiftStrategy.NextGear.Gear); + // } + // + // + // [TestCase] + // public void GetMocksTest() + // { + // // the first element 0.0 is just a placeholder for axlegear, not used in this test + // var ratios = new[] { 0.0, 6.38, 4.63, 3.84, 2.59, 1.86, 1.35, 1, 0.76 }; + // + // var mockContainer = GetMocks(ratios, + // out var runData, + // out var testPowertrain); + // + // var container = mockContainer.Object; + // var createdTestPowertrain = container.SimplePowertrainBuilder.CreateTestPowertrain(container, false); + // + // Assert.NotNull(createdTestPowertrain.Container.GearboxOutPort); + // Assert.NotNull(createdTestPowertrain); + // } + + + [TestCase(1, 2, 100, 900, true)] + [TestCase(4, 5, 100, 900, true)] + [TestCase(5, 6, 100, 900, true)] + + public void Gearbox_EarlyUpShift(int gear, int newGear, double tq, double n, bool shiftExpected) + { + // the first element 0.0 is just a placeholder for axlegear, not used in this test + var ratios = new[] { 0.0, 6.38, 4.63, 3.84, 2.59, 1.86, 1.35, 1, 0.76 }; + + var container = GetMocks(ratios, + out var runData, + out var testPowertrain); + + + + + runData.GearshiftParameters.RatioEarlyUpshiftFC = 10; + runData.GearshiftParameters.MinEngineSpeedPostUpshift = 1.RPMtoRad(); + runData.GearshiftParameters.TorqueReserve = 0.1; + runData.GearshiftParameters.RatingFactorCurrentGear = 0.97; + var shiftStrategy = GetShiftStrategyAndGearbox(container, out var gbx); + + + container.Setup(c => c.EngineInfo.EngineSpeed).Returns(() => n.RPMtoRad()); + container.Setup(c => c.EngineInfo.EngineN95hSpeed).Returns(() => 2000.RPMtoRad()); + + + var absTime = 0.SI<Second>(); + var dt = 2.SI<Second>(); + + var expectedN = n.RPMtoRad(); + var angularVelocity = expectedN / ratios[gear]; + + var gearShiftPosition = shiftStrategy.InitGear(0.SI<Second>(), Constants.SimulationSettings.TargetTimeInterval, 1.SI<NewtonMeter>(), + angularVelocity); + + + + absTime += dt; + + var expectedT = tq.SI<NewtonMeter>(); + var torque = expectedT * ratios[gear]; + + var response = new ResponseSuccess(this); + response.Engine.TorqueOutDemand = expectedT; + response.Engine.EngineSpeed = expectedN; + + + + var shiftRequired = shiftStrategy.ShiftRequired(absTime, dt, torque, angularVelocity, expectedT, expectedN, + new GearshiftPosition((uint)gear), -double.MaxValue.SI<Second>(), response); + + Assert.AreEqual(newGear, shiftStrategy.NextGear.Gear); + Assert.AreEqual(shiftExpected, shiftRequired); + } + + + + [TestCase(7, 1, 1000, 1400, true)] + [TestCase(7, 2, 400, 200, true)] + public void InitStartGear(int gear, int newGear, double tq, double n, bool shiftExpected) + { + // the first element 0.0 is just a placeholder for axlegear, not used in this test + var ratios = new[] { 0.0, 6.38, 5.2, 4.3, 3.2, 2.5, 1.8, 1, 0.76 }; + var container = GetMocks(ratios, out var runData, out var testPt); + + container.Setup(c => c.VehicleInfo.VehicleSpeed).Returns(0.KMPHtoMeterPerSecond()); + + var gbx = GetMockGearbox(); + Mock.Get(container.Object.EngineInfo).Setup(e => e.EngineSpeed).Returns(() => n.RPMtoRad()); + Mock.Get(container.Object.EngineInfo).Setup(e => e.EngineN95hSpeed).Returns(2000.RPMtoRad()); + + var shiftStrategy = new AMTShiftStrategyOptimized(container.Object); + shiftStrategy.Gearbox = gbx.Object; + + var absTime = 0.SI<Second>(); + var dt = 2.SI<Second>(); + + var expectedN = n.RPMtoRad(); + var angularVelocity = expectedN / ratios[gear]; + + + testPt.Setup(t => t.Gearbox.Request( + It.IsAny<Second>(), + It.IsAny<Second>(), + It.IsAny<NewtonMeter>(), + It.IsAny<PerSecond>(), + true)).Returns(new ResponseDryRun(null) + { + Engine = { + TotalTorqueDemand = 2.SI<NewtonMeter>(), + DynamicFullLoadTorque = 4.SI<NewtonMeter>(), + EngineSpeed = 600.RPMtoRad(), + } + }); + + var gearShiftPosition = shiftStrategy.InitGear(0.SI<Second>(), Constants.SimulationSettings.TargetTimeInterval, 1.SI<NewtonMeter>(), + angularVelocity); + + absTime += dt; + + var expectedT = tq.SI<NewtonMeter>(); + var torque = expectedT * ratios[gear]; + + + //var shiftRequired = shiftStrategy.ShiftRequired(absTime, dt, torque, angularVelocity, expectedT, expectedN, + // new GearshiftPosition((uint)gear), -double.MaxValue.SI<Second>(), new ResponseSuccess(this)); + + //Assert.AreEqual(shiftExpected, shiftRequired); + Assert.GreaterOrEqual(shiftStrategy.MaxStartGear.Gear, newGear); + Assert.AreEqual(newGear, shiftStrategy.NextGear.Gear); + } + + + [TestCase(2, 1, 2, 1000, 300)] + [TestCase(3, 2, 2, 1000, 1400)] + [TestCase(8, 7, 2, 1800, 750)] + [TestCase(7, 6, 2, 1800, 750)] + [TestCase(6, 5, 2, 1800, 750)] + [TestCase(5, 4, 2, 1800, 750)] + [TestCase(4, 3, 2, 1800, 750)] + [TestCase(3, 2, 2, 1800, 750)] + [TestCase(2, 2, 2, 1900, 750)] + [TestCase(1, 2, 2, 1200, 700)] + [TestCase(8, 4, 2, 15000, 200)] + [TestCase(2, 2, 2, 300, 1000)] + public void Gearbox_PTO(int gear, int newGear, int ptoGear, double tq, double n) + { + var shiftExpected = gear != newGear; + // the first element 0.0 is just a placeholder for axlegear, not used in this test + var ratios = new[] { 0.0, 6.38, 4.63, 3.44, 2.59, 1.86, 1.35, 1, 0.76 }; + + var container = GetMocks(ratios, out VectoRunData runData, out _); + + runData.DriverData = new DriverData() { + PTODriveRoadsweepingGear = new GearshiftPosition((uint)ptoGear) + }; + + container.Setup(c => c.DrivingCycleInfo.CycleData).Returns( + new CycleData() { + LeftSample = new DrivingCycleData.DrivingCycleEntry() { + PTOActive = PTOActivity.PTOActivityRoadSweeping, + RoadGradient = 0.SI<Radian>(), + } + } + ); + + var shiftStrategy = GetShiftStrategyAndGearbox(container, out var gbx); + + + + ////Mock.Get(container.Object.EngineInfo).Setup(e => e.EngineSpeed).Returns(() => n.RPMtoRad()); + ////Mock.Get(container.Object.EngineInfo).Setup(e => e.EngineN95hSpeed).Returns(2000.RPMtoRad()); + + + + var absTime = 0.SI<Second>(); + var dt = 2.SI<Second>(); + + var expectedN = n.RPMtoRad(); + var angularVelocity = expectedN / ratios[gear]; + + var gearShiftPosition = shiftStrategy.InitGear(0.SI<Second>(), Constants.SimulationSettings.TargetTimeInterval, 1.SI<NewtonMeter>(), + angularVelocity); + + absTime += dt; + + var expectedT = tq.SI<NewtonMeter>(); + var torque = expectedT * ratios[gear]; + + var response = new ResponseSuccess(this) { + + }; + var shiftRequired = shiftStrategy.ShiftRequired(absTime, dt, torque, angularVelocity, expectedT, expectedN, + new GearshiftPosition((uint)gear), -double.MaxValue.SI<Second>(), response); + + Assert.AreEqual(shiftExpected, shiftRequired); + Assert.AreEqual(newGear, shiftStrategy.NextGear.Gear); + } + + + private Mock<IVehicleContainer> GetMocks(double[] ratios, + out VectoRunData runData, + out Mock<ITestPowertrain> testPowertrain) + { + runData = GetRunData(ratios); + + var container = GetMockVehicleContainer(runData); + + + //Use simple powertrain to create testpowertrain + testPowertrain = GetMockTestPowertrain(runData, out var simpleContainer); + + + var ptBuilder = new Mock<ISimplePowertrainBuilder>(); + + //TestPowertrain + ptBuilder.Setup(p => p.CreateTestPowertrain( + It.IsAny<IVehicleContainer>(), + It.IsAny<bool>())) + .Returns(testPowertrain.Object); + + ptBuilder.Setup(p => p.CreateTestPowertrain( + It.IsAny<IVehicleContainer>(), + It.IsAny<bool>(), It.IsAny<VectoSimulationJobType>())).Throws(new NotImplementedException()); + + container.Setup(c => c.SimplePowertrainBuilder).Returns(ptBuilder.Object); + + + + return container; + } + + + + + private Mock<ITestPowertrain> GetMockTestPowertrain(VectoRunData runData, out Mock<ISimpleVehicleContainer> simpleContainer) + { + var testPt = new Mock<ITestPowertrain>(); + + simpleContainer = GetSimplePowertrain(runData, out var testGearbox); + testPt.Setup(t => t.Container).Returns(simpleContainer.Object); + + testPt.Setup(t => t.Gearbox).Returns(testGearbox.Object); + // tGbx.Setup(g => g.Initialize(It.IsAny<NewtonMeter>(), It.IsAny<PerSecond>())) + // .Returns((NewtonMeter t, PerSecond n) => new ResponseSuccess(this) { + // Engine = { PowerRequest = n * t, + // EngineSpeed = n }, + // Clutch = { PowerRequest = n * t } + // }); + // tGbx.Setup(g => g.Request(It.IsAny<Second>(), It.IsAny<Second>(), It.IsAny<NewtonMeter>(), It.IsAny<PerSecond>(), + // It.IsAny<bool>())) + // .Returns((Second absTime, Second dt, NewtonMeter t, PerSecond n, bool dryRun) => new ResponseSuccess(this) { + // Engine = { PowerRequest = n * t, EngineSpeed = n }, + // Clutch = { PowerRequest = n * t } + // }); + // tGbx.Setup(g => g.Request(It.IsAny<Second>(), It.IsAny<Second>(), It.IsAny<NewtonMeter>(), It.IsAny<PerSecond>(), + // It.IsAny<bool>())) + // .Returns((Second absTime, Second dt, NewtonMeter t, PerSecond n, bool dryRun) => dryRun ? + // new ResponseDryRun(this) { + // Engine = { + // PowerRequest = n * t, + // EngineSpeed = n, + // TotalTorqueDemand = t, + // }, + // Clutch = { PowerRequest = n * t }, + // DeltaFullLoad = n*t / 2 *(-1) + // }: new ResponseSuccess(this) { + // Engine = { PowerRequest = n * t, EngineSpeed = n }, + // Clutch = { PowerRequest = n * t } + // }); + var tEng = new Mock<ITestpowertrainCombustionEngine>(); + testPt.Setup(t => t.CombustionEngine).Returns(tEng.Object); + tEng.Setup(e => e.EngineStationaryFullPower(It.IsAny<PerSecond>())) + .Returns((PerSecond n) => runData.EngineData.FullLoadCurves[0].FullLoadStationaryPower(n)); + return testPt; + } + + private static Mock<IPowertainInfo> GetPowertrainInfo() + { + var tPi = new Mock<IPowertainInfo>(); + tPi.Setup(p => p.HasCombustionEngine).Returns(true); + return tPi; + } + + private static Mock<IVehicleContainer> GetMockVehicleContainer(VectoRunData runData) + { + var container = new Mock<IVehicleContainer>(); + container.Setup(c => c.RunData).Returns(runData); + var veh = new Mock<IVehicleInfo>(); + veh.Setup(v => v.VehicleSpeed).Returns(10.SI<MeterPerSecond>()); + container.Setup(c => c.VehicleInfo).Returns(veh.Object); + var eng = new Mock<IEngineInfo>(); + container.Setup(c => c.EngineInfo).Returns(eng.Object); + eng.Setup(e => e.EngineIdleSpeed).Returns(runData.EngineData.IdleSpeed); + eng.Setup(e => e.EngineRatedSpeed).Returns(runData.EngineData.FullLoadCurves.First().Value.RatedSpeed); + eng.Setup(e => e.EngineN95hSpeed).Returns(runData.EngineData.FullLoadCurves.First().Value.N95hSpeed); + eng.Setup(e => e.EngineStationaryFullPower(It.IsAny<PerSecond>())) + .Returns((PerSecond n) => runData.EngineData.FullLoadCurves[0].FullLoadStationaryPower(n)); + var ci = new Mock<IDrivingCycleInfo>(); + container.Setup(c => c.DrivingCycleInfo).Returns(ci.Object); + var di = new Mock<IDriverInfo>(); + di.Setup(d => d.DriverBehavior).Returns(DrivingBehavior.Accelerating); + di.Setup(d => d.DrivingAction).Returns(DrivingAction.Accelerate); + container.Setup(c => c.DriverInfo).Returns(di.Object); + ci.Setup(c => c.CycleData).Returns(new CycleData() { LeftSample = new DrivingCycleData.DrivingCycleEntry() { PTOActive = PTOActivity.Inactive } }); + ci.Setup(c => c.CycleLookAhead(It.IsAny<Meter>())).Returns(new DrivingCycleData.DrivingCycleEntry() { + Altitude = 0.SI<Meter>() + }); + ci.Setup(c => c.Altitude).Returns(0.SI<Meter>()); + var pi = new Mock<IPowertainInfo>(); + pi.Setup(p => p.HasCombustionEngine).Returns(true); + container.Setup(c => c.PowertrainInfo).Returns(pi.Object); + var vi = new Mock<IVehicleInfo>(); + vi.Setup(v => v.AirDragResistance(It.IsAny<MeterPerSecond>(), It.IsAny<MeterPerSecond>())) + .Returns(0.SI<Newton>()); + vi.Setup(v => v.RollingResistance(It.IsAny<Radian>())).Returns(0.SI<Newton>()); + vi.Setup(v => v.SlopeResistance(It.IsAny<Radian>())).Returns(0.SI<Newton>()); + vi.Setup(v => v.VehicleSpeed).Returns(30.KMPHtoMeterPerSecond()); + vi.Setup(v => v.TotalMass).Returns(12000.SI<Kilogram>()); + container.Setup(c => c.VehicleInfo).Returns(vi.Object); + var wi = new Mock<IWheelsInfo>(); + container.Setup(c => c.WheelsInfo).Returns(wi.Object); + wi.Setup(w => w.ReducedMassWheels).Returns(0.SI<Kilogram>()); + var axli = new Mock<IAxlegearInfo>(); + container.Setup(c => c.AxlegearInfo).Returns(axli.Object); + axli.Setup(a => a.AxlegearLoss()).Returns(0.SI<Watt>()); + return container; + } + + + private AMTShiftStrategyOptimized GetShiftStrategyAndGearbox(Mock<IVehicleContainer> vehicleContainer, out Mock<IGearbox> gbx) + { + var shiftStrategy = new AMTShiftStrategyOptimized(vehicleContainer.Object); + + gbx = GetMockGearbox(); + shiftStrategy.Gearbox = gbx.Object; + + SetVelocityDropLookupData(shiftStrategy); + return shiftStrategy; + } + + + + + private Mock<ISimpleVehicleContainer> GetSimplePowertrain(VectoRunData runData, out Mock<ITestPowertrainTransmission> testGearbox) + { + var simplePt = new Mock<ISimpleVehicleContainer>(); + simplePt.Setup(s => s.RunData).Returns(runData); + simplePt.Setup(s => s.AddComponent(It.IsAny<VectoSimulationComponent>())); + simplePt.Setup(s => s.PowertrainInfo).Returns(GetPowertrainInfo().Object); + simplePt.Setup(s => s.IsTestPowertrain).Returns(true); + + var gbx = GetMockTestGearbox(runData.GearboxData.Gears); + simplePt.Setup(s => s.GearboxInfo).Returns(gbx.Object); + simplePt.Setup(s => s.GearboxCtl).Returns(gbx.Object); + simplePt.Setup(s => s.GearboxOutPort).Returns(gbx.Object); + //Vehicle Info + var vehicleInfo = new Mock<IVehicleInfo>(); + simplePt.Setup(c => c.VehicleInfo).Returns(vehicleInfo.Object); + vehicleInfo.Setup(v => v.VehicleSpeed).Returns(1.KMPHtoMeterPerSecond()); + + //VehiclePort + var vehiclePort = new Mock<IDriverDemandOutPort>(); + vehiclePort.Setup(port => port.Initialize( + It.IsAny<MeterPerSecond>(), It.IsAny<Radian>())).Returns(new ResponseSuccess(this)); + + // simplePt.Setup(c => c).Returns(vehiclePort.Object); + + + //GearboxOutPort + + + // var mockPort = new Mock<ITnOutPort>(); + // mockPort.Name = "MockPort1"; + // mockPort.Setup(p => p.Initialize(It.IsAny<NewtonMeter>(), + // It.IsAny<PerSecond>())).Returns((NewtonMeter tq, PerSecond rpm) => { + // return new ResponseSuccess(this) + // { + // Engine = { + // EngineSpeed = rpm, + // PowerRequest = tq * rpm, + // }, + // }; + // }); + // mockPort.Setup(p => p.Request( + // It.IsAny<Second>(), + // It.IsAny<Second>(), + // It.IsAny<NewtonMeter>(), + // It.IsAny<PerSecond>(), + // true)).Returns(( + // Second absTime, + // Second dt, + // NewtonMeter t, + // PerSecond n, + // bool dryRun) => { + // + // var ratio = + // gbx.Object.Gear == null ? 1.0 : ratios[gbx.Object.Gear.Gear].Ratio; + // return dryRun + // + // ? new ResponseDryRun(this) + // { + // Engine = { + // PowerRequest = n * t, EngineSpeed = n * ratio, + // DynamicFullLoadPower = (t / ratio + 2300.SI<NewtonMeter>()) * n * ratio, + // TotalTorqueDemand = t, + // }, + // Clutch = { PowerRequest = n * t }, + // DeltaFullLoad = n*t / 2 * (-1) + // } + // : new ResponseSuccess(this) + // { + // Engine = { + // PowerRequest = n * t, + // EngineSpeed = n * ratio + // + // }, + // Clutch = { PowerRequest = n * t } + // }; + // }); + + // simplePt.Setup(c => c.GearboxOutPort).Returns(mockPort.Object); + + testGearbox = gbx; + return simplePt; + } + + private Mock<IGearbox> GetMockGearbox() + { + var amtGearbox = new Mock<IAMTGearbox>(MockBehavior.Strict); + amtGearbox.Name = "AMT_Gearbox"; + var gbx = amtGearbox.As<IGearbox>(); + gbx.Setup(g => g.LastUpshift).Returns(-double.MaxValue.SI<Second>()); + gbx.Setup(g => g.LastDownshift).Returns(-double.MaxValue.SI<Second>()); + return gbx; + } + + + private Mock<ITestPowertrainTransmission> GetMockTestGearbox(Dictionary<uint, GearData> ratios) + { + + Mock<IAMTGearbox> amtGearbox = new Mock<IAMTGearbox>(); + amtGearbox.Name = "AMT_TestGearbox"; + Mock<ITestPowertrainTransmission> gbx = amtGearbox.As<ITestPowertrainTransmission>(); + + + + gbx.Setup(g => g.LastUpshift).Returns(-double.MaxValue.SI<Second>()); + gbx.Setup(g => g.LastDownshift).Returns(-double.MaxValue.SI<Second>()); + + GearshiftPosition gear = null; + gbx.SetupGet(g => g.Gear).Returns(() => { + + return gear; + }); + gbx.SetupSet(g => g.SetGear = It.IsAny<GearshiftPosition>()) + .Callback<GearshiftPosition>(p => { + gear = p; + }); + + + GearshiftPosition nextGear = null; + gbx.SetupGet(g => g.NextGear).Returns(() => nextGear); + gbx.SetupSet(g => g.SetNextGear = It.IsAny<GearshiftPosition>()) + .Callback<GearshiftPosition>(p => nextGear = p); + + gbx.Setup(p => p.Initialize(It.IsAny<NewtonMeter>(), + It.IsAny<PerSecond>())).Returns((NewtonMeter tq, PerSecond rpm) => { + return new ResponseSuccess(this) + { + Engine = { + EngineSpeed = rpm, + PowerRequest = tq * rpm, + }, + }; + }); + gbx.Setup(p => p.Request( + It.IsAny<Second>(), + It.IsAny<Second>(), + It.IsAny<NewtonMeter>(), + It.IsAny<PerSecond>(), + true)).Returns(( + Second absTime, + Second dt, + NewtonMeter t, + PerSecond n, + bool dryRun) => { + + var ratio = + gbx.Object.Gear == null ? 1.0 : ratios[gbx.Object.Gear.Gear].Ratio; + return dryRun + ? new ResponseDryRun(this) { + Engine = { + PowerRequest = n * t, EngineSpeed = n * ratio, + DynamicFullLoadPower = (t / ratio + 2300.SI<NewtonMeter>()) * n * ratio, + TotalTorqueDemand = t, + }, + Clutch = { PowerRequest = n * t }, + DeltaFullLoad = n * t / 2 * (-1) + } + : new ResponseSuccess(this) { + Engine = { + PowerRequest = n * t, + EngineSpeed = n * ratio + + }, + Clutch = { PowerRequest = n * t } + }; + }); + return gbx; + } + + + private void SetVelocityDropLookupData(AMTShiftStrategyOptimized shiftStrategy) + { + //"StartVelocity [km/h], Gradient [-], EndVelocity [km/h]" + var data = new[] { + new[] { 5.0, -0.0997, 9.061522965237558 }, + new[] { 5.0, -0.0798, 7.76698080079411 }, + new[] { 5.0, -0.0599, 6.46583777913701 }, + new[] { 5.0, -0.0400, 5.1596021788785045 }, + new[] { 5.0, -0.0200, 3.8498121019126907 }, + new[] { 5.0, 0.0000, 2.5380265159468918 }, + new[] { 5.0, 0.0200, 1.2258160477557427 }, + new[] { 5.0, 0.0400, 0.0 }, + new[] { 5.0, 0.0599, 0.0 }, + new[] { 5.0, 0.0798, 0.0 }, + new[] { 5.0, 0.0997, 0.0 }, + new[] { 10.0, -0.0997, 14.807789640888302 }, + new[] { 10.0, -0.0798, 13.474253785811362 }, + new[] { 10.0, -0.0599, 12.133880027250777 }, + new[] { 10.0, -0.0400, 10.788221550084467 }, + new[] { 10.0, -0.0200, 9.438862432338068 }, + new[] { 10.0, 0.0000, 8.087408432114643 }, + new[] { 10.0, 0.0200, 6.735477499784416 }, + new[] { 10.0, 0.0400, 5.384690105076845 }, + new[] { 10.0, 0.0599, 4.036659549786269 }, + new[] { 10.0, 0.0798, 2.6929823705748137 }, + new[] { 10.0, 0.0997, 1.3552289800549435 }, + new[] { 20.0, -0.0997, 25.061542153872097 }, + new[] { 20.0, -0.0798, 23.72002987685605 }, + new[] { 20.0, -0.0599, 22.371630788642932 }, + new[] { 20.0, -0.0400, 21.017907257116025 }, + new[] { 20.0, -0.0200, 19.660452757813403 }, + new[] { 20.0, 0.0000, 18.30088261992287 }, + new[] { 20.0, 0.0200, 16.94082447048767 }, + new[] { 20.0, 0.0400, 15.581908518759507 }, + new[] { 20.0, 0.0599, 14.225757795590708 }, + new[] { 20.0, 0.0798, 12.873978508374211 }, + new[] { 20.0, 0.0997, 11.528150617530041 }, + new[] { 30.000000000000004, -0.0997, 35.091774208140095 }, + new[] { 30.000000000000004, -0.0798, 33.750904327320896 }, + new[] { 30.000000000000004, -0.0599, 32.40315158162777 }, + new[] { 30.000000000000004, -0.0400, 31.050077596965064 }, + new[] { 30.000000000000004, -0.0200, 29.69327509188113 }, + new[] { 30.000000000000004, 0.0000, 28.33435862498606 }, + new[] { 30.000000000000004, 0.0200, 26.974955046566407 }, + new[] { 30.000000000000004, 0.0400, 25.616693776603913 }, + new[] { 30.000000000000004, 0.0599, 24.261197065863925 }, + new[] { 30.000000000000004, 0.0798, 22.91007034016412 }, + new[] { 30.000000000000004, 0.0997, 21.56489279686667 }, + new[] { 40.0, -0.0997, 45.024018797189854 }, + new[] { 40.0, -0.0798, 43.68636622428101 }, + new[] { 40.0, -0.0599, 42.34185052441486 }, + new[] { 40.0, -0.0400, 40.99202962224952 }, + new[] { 40.0, -0.0200, 39.63849244500093 }, + new[] { 40.0, 0.0000, 38.282849690992855 }, + new[] { 40.0, 0.0200, 36.926724305651554 }, + new[] { 40.0, 0.0400, 35.57174178507285 }, + new[] { 40.0, 0.0599, 34.21952045137207 }, + new[] { 40.0, 0.0798, 32.87166183129923 }, + new[] { 40.0, 0.0997, 31.5297412694979 }, + new[] { 50.0, -0.0997, 54.652157586769704 }, + new[] { 50.0, -0.0798, 53.319266704395716 }, + new[] { 50.0, -0.0599, 51.97954186606304 }, + new[] { 50.0, -0.0400, 50.634535516787736 }, + new[] { 50.0, -0.0200, 49.28583097196263 }, + new[] { 50.0, 0.0000, 47.93503321632867 }, + new[] { 50.0, 0.0200, 46.583759417454765 }, + new[] { 50.0, 0.0400, 45.23362925944123 }, + new[] { 50.0, 0.0599, 43.88625525588574 }, + new[] { 50.0, 0.0798, 42.54323315977748 }, + new[] { 50.0, 0.0997, 41.20613261641401 }, + new[] { 60.00000000000001, -0.0997, 64.2503607025971 }, + new[] { 60.00000000000001, -0.0798, 62.91932863058169 }, + new[] { 60.00000000000001, -0.0599, 61.58156853535776 }, + new[] { 60.00000000000001, -0.0400, 60.23862904729555 }, + new[] { 60.00000000000001, -0.0200, 58.89369896300112 }, + new[] { 60.00000000000001, 0.0000, 57.547040626925885 }, + new[] { 60.00000000000001, 0.0200, 56.199911833784675 }, + new[] { 60.00000000000001, 0.0400, 54.85392730356455 }, + new[] { 60.00000000000001, 0.0599, 53.510694584916905 }, + new[] { 60.00000000000001, 0.0798, 52.17180450267632 }, + new[] { 60.00000000000001, 0.0997, 50.83882182989668 }, + new[] { 70.0, -0.0997, 73.78388063954164 }, + new[] { 70.0, -0.0798, 72.45700102808648 }, + new[] { 70.0, -0.0599, 71.12341092304165 }, + new[] { 70.0, -0.0400, 69.78459543842656 }, + new[] { 70.0, -0.0200, 68.44188526693415 }, + new[] { 70.0, 0.0000, 67.09719334997524 }, + new[] { 70.0, 0.0200, 65.75212749798493 }, + new[] { 70.0, 0.0400, 64.40829754257321 }, + new[] { 70.0, 0.0599, 63.06730571969745 }, + new[] { 70.0, 0.0798, 61.73073716025881 }, + new[] { 70.0, 0.0997, 60.40015062055851 }, + new[] { 80.0, -0.0997, 83.25457689135129 }, + new[] { 80.0, -0.0798, 81.93182852399568 }, + new[] { 80.0, -0.0599, 80.60238880559001 }, + new[] { 80.0, -0.0400, 79.2676325992058 }, + new[] { 80.0, -0.0200, 77.92916666616652 }, + new[] { 80.0, 0.0000, 76.58872134590663 }, + new[] { 80.0, 0.0200, 75.24790011046437 }, + new[] { 80.0, 0.0400, 73.90830846424944 }, + new[] { 80.0, 0.0599, 72.57154434889891 }, + new[] { 80.0, 0.0798, 71.23918865436896 }, + new[] { 80.0, 0.0997, 69.91277394305271 }, + }; + var entries = new List<VelocitySpeedGearshiftPreprocessor.Entry>(); + foreach (var d in data) + { + entries.Add(new VelocitySpeedGearshiftPreprocessor.Entry() + { + StartVelocity = d[0].KMPHtoMeterPerSecond(), + Gradient = d[1].SI<Radian>(), + EndVelocity = d[2].KMPHtoMeterPerSecond(), + }); + } + + shiftStrategy.VelocityDropData.Data = entries.ToArray(); + + } + + private static VectoRunData GetRunData(double[] ratios) + { + var gearboxData = new GearboxData { + Gears = new Dictionary<uint, GearData>() + }; + for (uint i = 1; i < ratios.Length; i++) { + gearboxData.Gears[i] = new GearData { + Ratio = ratios[i], + LossMap = TransmissionLossMapReader.Create(0.96, ratios[i], $"Gear {i}") + }; + } + + IEnumerable<(uint key, EngineFullLoadCurve fld)> fldCurves = + ratios.Select( + (_, i) => ((uint)i, + FullLoadCurveReader.Create(InputDataHelper.InputDataAsTableData(EngineFldHdr, EngineFldData)) + )); + + + List<CombustionEngineFuelData> fuels = new List<CombustionEngineFuelData>() { + new CombustionEngineFuelData() { + ColdHotCorrectionFactor = 1, + ConsumptionMap = FuelConsumptionMapReader.Create(InputDataHelper.InputDataAsTableData( + EngineFcMapHdr, + EngineFcMapData)), + FuelData = FuelData.Diesel, + } + }; + var engineData = new CombustionEngineData() { + IdleSpeed = 560.RPMtoRad(), + FullLoadCurves = fldCurves.ToDictionary((x) => x.key, (x) => x.fld), + Fuels = fuels, + }; + + var axlRatio = 3.240355; + var gearsInput = gearboxData.Gears.Select(x => { + var r = new Mock<ITransmissionInputData>(); + r.Setup(g => g.Ratio).Returns(x.Value.Ratio); + return r.Object; + }).ToList(); + foreach (var entry in gearboxData.Gears) { + entry.Value.ShiftPolygon = DeclarationData.Gearbox.ComputeManualTransmissionShiftPolygon( + (int)(entry.Key - 1), engineData.FullLoadCurves.First().Value, + gearsInput, engineData, axlRatio, 0.5.SI<Meter>()); + } + + + var mockCycle = new Mock<IDrivingCycleData>(); + mockCycle.Setup(cd => cd.Entries).Returns( + new List<DrivingCycleData.DrivingCycleEntry>() { + new DrivingCycleData.DrivingCycleEntry() { + RoadGradient = 0.SI<Radian>() + } + }); + + + + + + + + + + var runData = new VectoRunData() { + GearboxData = gearboxData, + GearshiftParameters = new ShiftStrategyParameters() { + StartSpeed = 2.SI<MeterPerSecond>(), + TimeBetweenGearshifts = 6.SI<Second>(), + DownshiftAfterUpshiftDelay = 2.SI<Second>(), + UpshiftAfterDownshiftDelay = 2.SI<Second>(), + UpshiftMinAcceleration = 0.1.SI<MeterPerSquareSecond>(), + StartTorqueReserve = 0.2, + }, + EngineData = engineData, + AxleGearData = new AxleGearData() { + AxleGear = new TransmissionData() { + Ratio = 3.240355 + } + }, + VehicleData = new VehicleData() { + DynamicTyreRadius = 0.492.SI<Meter>(), + }, + Cycle = mockCycle.Object, + }; + return runData; + } + + const string EngineFldHdr = "engine speed [1/min],full load torque [Nm],motoring torque [Nm],PT1 [s]"; + + static readonly string[] EngineFldData = new[] { + "560,1180,-149,0.6 ", + "600,1282,-148,0.6 ", + "799.9999999,1791,-149,0.6 ", + "1000,2300,-160,0.6 ", + "1200,2300,-179,0.6 ", + "1400,2300,-203,0.6 ", + "1599.999999,2079,-235,0.49", + "1800,1857,-264,0.25 ", + "2000.000001,1352,-301,0.25", + "2100,1100,-320,0.25 ", + }; + + + const string EngineFcMapHdr = "engine speed [rpm], torque [Nm], fuel consumption [g/h]"; + static readonly string[] EngineFcMapData = new[] { + "500,-235.5,0", +"500,-135.5,0", +"500,0,1355", +"500,213.4,3412.291", +"500,426.8,5830.1", +"500,640.2,8316.426", +"500,853.6,10439.87", +"500,1067,12823.69", +"500,1188,14228.79", +"500,1401.4,16628.66", +"600,-238,0", +"600,-138,0", +"600,0,1355", +"600,213.4,3412.291", +"600,426.8,5830.1", +"600,640.2,8316.426", +"600,853.6,10439.87", +"600,1067,12823.69", +"600,1188,14228.79", +"600,1401.4,16628.66", +"751,-241.775,0", +"751,-141.775,0", +"750.9,0,1649.255", +"750.9,213.4,4157.795", +"750.9,426.8,7149.494", +"750.9,640.2,10037.08", +"750.9,853.6,12957.07", +"750.9,1067,16055.22", +"750.9,1280.4,19231.36", +"750.9,1493.8,22400.17", +"750.9,1544.879,23213.92", +"751,1758.279,26392.93", +"902,-247.59,0", +"902,-147.59,0", +"901.8,0,2210.735", +"901.8,213.4,5204.867", +"901.8,426.8,8515.462", +"901.8,640.2,11804.75", +"901.8,853.6,15410.55", +"901.8,1067,19081.7", +"901.8,1280.4,22742.96", +"901.8,1493.8,26543.87", +"901.8,1707.2,30534.68", +"901.8,1901.757,34352.75", +"902,2115.157,38403.27", +"1053,-255.445,0", +"1053,-155.445,0", +"1052.7,0,2768.035", +"1052.7,213.4,6228.407", +"1052.7,426.8,9836.041", +"1052.7,640.2,13624.5", +"1052.7,853.6,17854.95", +"1052.7,1067,22072.71", +"1052.7,1280.4,26161.13", +"1052.7,1493.8,30525.55", +"1052.7,1707.2,35019.18", +"1052.7,1920.6,39913.3", +"1052.7,2134,45438.16", +"1053,2347.4,50542.53", +"1204,-265.44,0", +"1203.6,0,3086.704", +"1203.6,213.4,6943.027", +"1203.6,426.8,11040.37", +"1203.6,640.2,15504.65", +"1203.6,853.6,20335.89", +"1203.6,1067,25176.6", +"1203.6,1280.4,29782.22", +"1203.6,1493.8,34642.24", +"1203.6,1707.2,39786.14", +"1203.6,1920.6,45254.8", +"1203.6,2134,51129.03", +"1204,2347.4,56732.88", +"1367,-283.37,0", +"1367,-183.37,0", +"1367.1,0,3845.344", +"1367.1,213.4,7981.742", +"1367.1,426.8,12796.69", +"1367.1,640.2,17789.2", +"1367.1,853.6,22854.21", +"1367.1,1067,28302.84", +"1367.1,1280.4,33739.91", +"1367.1,1493.8,39393.87", +"1367.1,1707.2,45836.33", +"1367.1,1920.6,52078.71", +"1367.1,2134,58296.41", +"1367,2347.4,64530.56", +"1490,-300.5,0", +"1490,-200.5,0", +"1489.6,0,4373.424", +"1489.6,213.4,8861.484", +"1489.6,426.8,14090.86", +"1489.6,640.2,19518.29", +"1489.6,853.6,25092.8", +"1489.6,1067,30873.69", +"1489.6,1280.4,36865.42", +"1489.6,1493.8,43095.57", +"1489.6,1707.2,50249.81", +"1489.6,1920.6,57035.25", +"1489.6,2041.712,60609.5", +"1490,2255.112,67311.83", +"1612,-318.62,0", +"1612,-218.62,0", +"1612.2,0,4904.015", +"1612.2,213.4,9810.482", +"1612.2,426.8,15403.9", +"1612.2,640.2,21301.35", +"1612.2,853.6,27492.32", +"1612.2,1067,33580.96", +"1612.2,1280.4,40114.61", +"1612.2,1493.8,46914.77", +"1612.2,1707.2,54666.14", +"1612.2,1915.434,61862.91", +"1612,2128.834,69491.99", +"1735,-335.225,0", +"1735,-235.225,0", +"1734.7,0,5586.953", +"1734.7,213.4,11041.15", +"1734.7,426.8,16949.24", +"1734.7,640.2,23500.23", +"1734.7,853.6,30159.59", +"1734.7,1067,36741.18", +"1734.7,1280.4,43923.85", +"1734.7,1493.8,51295.21", +"1734.7,1707.2,59469.31", +"1734.7,1789.259,62731.31", +"1735,2002.659,70935.23", +"1857,-353.69,0", +"1857,-253.69,0", +"1857.3,0,6673.839", +"1857.3,213.4,12518.56", +"1857.3,426.8,18687.88", +"1857.3,640.2,25652.39", +"1857.3,853.6,33003.08", +"1857.3,1067,40438.09", +"1857.3,1280.4,48117.52", +"1857.3,1493.8,55848.59", +"1857.3,1587.631,59434.17", +"1857,1801.031,67215.39", +"1957,-370.69,0", +"1957,-270.69,0", +"1957.3,0,6673.839", +"1957.3,213.4,12518.56", +"1957.3,426.8,18687.88", +"1957.3,640.2,25652.39", +"1957.3,853.6,33003.08", +"1957.3,1067,40438.09", +"1957.3,1280.4,48117.52", +"1957.3,1493.8,55848.59", +"1957.3,1587.631,59434.17", +"1957,1801.031,67215.39", + }; + + +} \ No newline at end of file diff --git a/Testing/UnitTests/Vecto UnitTests/TestCases/Components/GearShiftStrategy/AMTShiftStrategyTests.cs b/Testing/UnitTests/Vecto UnitTests/TestCases/Components/GearShiftStrategy/AMTShiftStrategyTests.cs new file mode 100644 index 0000000000000000000000000000000000000000..fdf935902851d2368c1224a642d378a8ddab6360 --- /dev/null +++ b/Testing/UnitTests/Vecto UnitTests/TestCases/Components/GearShiftStrategy/AMTShiftStrategyTests.cs @@ -0,0 +1,613 @@ +using Microsoft.VisualStudio.TestPlatform.ObjectModel; +using Moq; +using NUnit.Framework; +using TUGraz.VectoCommon.InputData; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.InputData.Reader.ComponentData; +using TUGraz.VectoCore.Models.Connector.Ports.Impl; +using TUGraz.VectoCore.Models.Declaration; +using TUGraz.VectoCore.Models.Simulation; +using TUGraz.VectoCore.Models.Simulation.Data; +using TUGraz.VectoCore.Models.Simulation.DataBus; +using TUGraz.VectoCore.Models.SimulationComponent; +using TUGraz.VectoCore.Models.SimulationComponent.Data; +using TUGraz.VectoCore.Models.SimulationComponent.Data.Engine; +using TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox; +// using TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox; +using TUGraz.VectoCore.Models.SimulationComponent.Impl; +using TUGraz.VectoCore.Models.SimulationComponent.Impl.Gearbox; +using TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies; +using TUGraz.VectoCore.Tests.Utils; +using Assert = NUnit.Framework.Assert; +using Constants = TUGraz.VectoCore.Configuration.Constants; + +namespace TUGraz.Vecto.UnitTests.TestCases.Components.GearShiftStrategy; + +public class AMTShiftStrategyTests +{ + [TestCase(8, 7, 1800, 750, true), +TestCase(7, 6, 1800, 750, true), +TestCase(6, 5, 1800, 750, true), +TestCase(5, 4, 1800, 750, true), +TestCase(4, 3, 1800, 750, true), +TestCase(3, 2, 1800, 750, true), +TestCase(2, 1, 1900, 750, true), +TestCase(1, 1, 1200, 700, false), +TestCase(8, 4, 15000, 200, true),] + public void Gearbox_ShiftDown_ACEA_Shiftlines(int gear, int newGear, double t, double n, bool shiftExpected) + { + // the first element 0.0 is just a placeholder for axlegear, not used in this test + var ratios = new[] { 0.0, 6.38, 4.63, 3.44, 2.59, 1.86, 1.35, 1, 0.76 }; + var runData = GetRunData(ratios); + + var container = GetMockVehicleContainer(runData); + + var testPt = GetMockTestPowertrain(runData); + + var ptBuilder = new Mock<ISimplePowertrainBuilder>(); + ptBuilder.Setup(p => p.CreateTestPowertrain(It.IsAny<IVehicleContainer>(), It.IsAny<bool>())) + .Returns(testPt.Object); + container.Setup(c => c.SimplePowertrainBuilder).Returns(ptBuilder.Object); + + var gbx = GetMockGearbox(container); + + + var shiftStrategy = new AMTShiftStrategy(container.Object); + shiftStrategy.Gearbox = gbx.Object; + + var absTime = 0.SI<Second>(); + var dt = 2.SI<Second>(); + + var expectedN = n.RPMtoRad(); + var angularVelocity = expectedN / ratios[gear]; + + + shiftStrategy.InitGear(0.SI<Second>(), Constants.SimulationSettings.TargetTimeInterval, 1.SI<NewtonMeter>(), + angularVelocity); + + var expectedT = t.SI<NewtonMeter>(); + var torque = expectedT * ratios[gear]; + + var shiftRequired = shiftStrategy.ShiftRequired(absTime, dt, torque, angularVelocity, expectedT, expectedN, + new GearshiftPosition((uint)gear), -double.MaxValue.SI<Second>(), new ResponseSuccess(this)); + + Assert.AreEqual(shiftExpected, shiftRequired); + Assert.AreEqual(newGear, shiftStrategy.NextGear.Gear); + } + + [TestCase(7, 8, 1000, 1400, true), + TestCase(6, 8, 800, 1400, true), + TestCase(5, 6, 1000, 1400, true), + TestCase(4, 5, 1000, 1400, true), + TestCase(3, 4, 1000, 1400, true), + TestCase(2, 4, 800, 1400, true), + TestCase(1, 2, 1000, 1400, true), + TestCase(8, 8, 1000, 1400, false), + TestCase(1, 6, 200, 9000, true),] + public void Gearbox_ShiftUp(int gear, int newGear, double tq, double n, bool shiftExpected) + { + // the first element 0.0 is just a placeholder for axlegear, not used in this test + var ratios = new[] { 0.0, 6.38, 4.63, 3.44, 2.59, 1.86, 1.35, 1, 0.76 }; + var runData = GetRunData(ratios); + + var container = GetMockVehicleContainer(runData); + + var testPt = GetMockTestPowertrain(runData); + + var ptBuilder = new Mock<ISimplePowertrainBuilder>(); + ptBuilder.Setup(p => p.CreateTestPowertrain(It.IsAny<IVehicleContainer>(), + It.IsAny<bool>())) + .Returns(testPt.Object); + container.Setup(c => c.SimplePowertrainBuilder).Returns(ptBuilder.Object); + + var gbx = GetMockGearbox(container); + Mock.Get(container.Object.EngineInfo).Setup(e => e.EngineSpeed).Returns(() => n.RPMtoRad()); + Mock.Get(container.Object.EngineInfo).Setup(e => e.EngineN95hSpeed).Returns(2000.RPMtoRad()); + + var shiftStrategy = new AMTShiftStrategy(container.Object); + shiftStrategy.Gearbox = gbx.Object; + + var absTime = 0.SI<Second>(); + var dt = 2.SI<Second>(); + + var expectedN = n.RPMtoRad(); + var angularVelocity = expectedN / ratios[gear]; + + var gearShiftPosition = shiftStrategy.InitGear(0.SI<Second>(), Constants.SimulationSettings.TargetTimeInterval, 1.SI<NewtonMeter>(), + angularVelocity); + + absTime += dt; + + var expectedT = tq.SI<NewtonMeter>(); + var torque = expectedT * ratios[gear]; + + + var shiftRequired = shiftStrategy.ShiftRequired(absTime, dt, torque, angularVelocity, expectedT, expectedN, + new GearshiftPosition((uint)gear), -double.MaxValue.SI<Second>(), new ResponseSuccess(this)); + + Assert.AreEqual(shiftExpected, shiftRequired); + Assert.AreEqual(newGear, shiftStrategy.NextGear.Gear); + } + + + [TestCase(2, 3, 800, 1400, 20_000, true, Description = "A gear would be skipped, but due to the uphill driving conditions, the next gear should be used")] + [TestCase(3, 3, 1000, 1400, 30_000, false, Description = "No upshifting because acceleration would be to low")] + public void Gearbox_ShiftUpUphill(int gear, int newGear, double tq, double n, double slopeResistance, bool shiftExpected) + { + // the first element 0.0 is just a placeholder for axlegear, not used in this test + var ratios = new[] { 0.0, 6.38, 4.63, 3.44, 2.59, 1.86, 1.35, 1, 0.76 }; + var runData = GetRunData(ratios); + + var container = GetMockVehicleContainer(runData); + + var accEstimationLookAhead = Constants.SimulationSettings.GearboxLookaheadForAccelerationEstimation; + + container.Setup(c => c.VehicleInfo.SlopeResistance(It.IsAny<Radian>())).Returns(slopeResistance.SI<Newton>()); + + + //container.Setup(c => c.DrivingCycleInfo.CycleLookAhead(accEstimationLookAhead)) + // .Returns(new DrivingCycleData.DrivingCycleEntry() { + // Altitude = 100.SI<Meter>() + // }); + //container.Setup(c => c.DrivingCycleInfo.Altitude).Returns(0.SI<Meter>()); + + + + + + + var testPt = GetMockTestPowertrain(runData); + + var ptBuilder = new Mock<ISimplePowertrainBuilder>(); + ptBuilder.Setup(p => p.CreateTestPowertrain( + It.IsAny<IVehicleContainer>(), + It.IsAny<bool>())) + .Returns(testPt.Object); + container.Setup(c => c.SimplePowertrainBuilder).Returns(ptBuilder.Object); + + var gbx = GetMockGearbox(container); + Mock.Get(container.Object.EngineInfo).Setup(e => e.EngineSpeed).Returns(() => n.RPMtoRad()); + Mock.Get(container.Object.EngineInfo).Setup(e => e.EngineN95hSpeed).Returns(2000.RPMtoRad()); + + var shiftStrategy = new AMTShiftStrategy(container.Object); + shiftStrategy.Gearbox = gbx.Object; + + var absTime = 0.SI<Second>(); + var dt = 2.SI<Second>(); + + var expectedN = n.RPMtoRad(); + var angularVelocity = expectedN / ratios[gear]; + + var gearShiftPosition = shiftStrategy.InitGear(0.SI<Second>(), Constants.SimulationSettings.TargetTimeInterval, 1.SI<NewtonMeter>(), + angularVelocity); + + absTime += dt; + + var expectedT = tq.SI<NewtonMeter>(); + var torque = expectedT * ratios[gear]; + + + var shiftRequired = shiftStrategy.ShiftRequired(absTime, dt, torque, angularVelocity, expectedT, expectedN, + new GearshiftPosition((uint)gear), -double.MaxValue.SI<Second>(), new ResponseSuccess(this)); + + Assert.AreEqual(shiftExpected, shiftRequired); + Assert.AreEqual(newGear, shiftStrategy.NextGear.Gear); + } + + + + [TestCase(7, 1, 1000, 1400, true)] + [TestCase(7, 2, 400, 200, true)] + public void InitStartGear(int gear, int newGear, double tq, double n, bool shiftExpected) + { + // the first element 0.0 is just a placeholder for axlegear, not used in this test + var ratios = new[] { 0.0, 6.38, 5.2, 4.3, 3.2, 2.5, 1.8, 1, 0.76 }; + var runData = GetRunData(ratios); + + var container = GetMockVehicleContainer(runData); + container.Setup(c => c.VehicleInfo.VehicleSpeed).Returns(0.KMPHtoMeterPerSecond()); + var testPt = GetMockTestPowertrain(runData); + + var ptBuilder = new Mock<ISimplePowertrainBuilder>(); + ptBuilder.Setup(p => p.CreateTestPowertrain(It.IsAny<IVehicleContainer>(), It.IsAny<bool>())) + .Returns(testPt.Object); + container.Setup(c => c.SimplePowertrainBuilder).Returns(ptBuilder.Object); + + var gbx = GetMockGearbox(container); + Mock.Get(container.Object.EngineInfo).Setup(e => e.EngineSpeed).Returns(() => n.RPMtoRad()); + Mock.Get(container.Object.EngineInfo).Setup(e => e.EngineN95hSpeed).Returns(2000.RPMtoRad()); + + var shiftStrategy = new AMTShiftStrategy(container.Object); + shiftStrategy.Gearbox = gbx.Object; + + var absTime = 0.SI<Second>(); + var dt = 2.SI<Second>(); + + var expectedN = n.RPMtoRad(); + var angularVelocity = expectedN / ratios[gear]; + + + testPt.Setup(t => t.Gearbox.Request( + It.IsAny<Second>(), + It.IsAny<Second>(), + It.IsAny<NewtonMeter>(), + It.IsAny<PerSecond>(), + true)).Returns(new ResponseDryRun(null) + { + Engine = { + TotalTorqueDemand = 2.SI<NewtonMeter>(), + DynamicFullLoadTorque = 4.SI<NewtonMeter>(), + EngineSpeed = 600.RPMtoRad(), + } + }); + + var gearShiftPosition = shiftStrategy.InitGear(0.SI<Second>(), Constants.SimulationSettings.TargetTimeInterval, 1.SI<NewtonMeter>(), + angularVelocity); + + absTime += dt; + + var expectedT = tq.SI<NewtonMeter>(); + var torque = expectedT * ratios[gear]; + + + //var shiftRequired = shiftStrategy.ShiftRequired(absTime, dt, torque, angularVelocity, expectedT, expectedN, + // new GearshiftPosition((uint)gear), -double.MaxValue.SI<Second>(), new ResponseSuccess(this)); + + //Assert.AreEqual(shiftExpected, shiftRequired); + Assert.GreaterOrEqual(shiftStrategy.MaxStartGear.Gear, newGear); + Assert.AreEqual(newGear, shiftStrategy.NextGear.Gear); + } + + + [TestCase(2, 1, 2, 1000, 300)] + [TestCase(3, 2, 2, 1000, 1400)] + [TestCase(8, 7, 2, 1800, 750)] + [TestCase(7, 6, 2, 1800, 750)] + [TestCase(6, 5, 2, 1800, 750)] + [TestCase(5, 4, 2, 1800, 750)] + [TestCase(4, 3, 2, 1800, 750)] + [TestCase(3, 2, 2, 1800, 750)] + [TestCase(2, 2, 2, 1900, 750)] + [TestCase(1, 2, 2, 1200, 700)] + [TestCase(8, 4, 2, 15000, 200)] + [TestCase(2, 2, 2, 300, 1000)] + public void Gearbox_PTO(int gear, int newGear, int ptoGear, double tq, double n) + { + var shiftExpected = gear != newGear; + // the first element 0.0 is just a placeholder for axlegear, not used in this test + var ratios = new[] { 0.0, 6.38, 4.63, 3.44, 2.59, 1.86, 1.35, 1, 0.76 }; + var runData = GetRunData(ratios); + + runData.DriverData = new DriverData() { + PTODriveRoadsweepingGear = new GearshiftPosition((uint)ptoGear) + }; + + var container = GetMockVehicleContainer(runData); + + container.Setup(c => c.DrivingCycleInfo.CycleData).Returns( + new CycleData() { + LeftSample = new DrivingCycleData.DrivingCycleEntry() { + PTOActive = PTOActivity.PTOActivityRoadSweeping, + RoadGradient = 0.SI<Radian>(), + } + } + ); + + + var testPt = GetMockTestPowertrain(runData); + + var ptBuilder = new Mock<ISimplePowertrainBuilder>(); + ptBuilder.Setup(p => p.CreateTestPowertrain(It.IsAny<IVehicleContainer>(), It.IsAny<bool>())) + .Returns(testPt.Object); + container.Setup(c => c.SimplePowertrainBuilder).Returns(ptBuilder.Object); + + var gbx = GetMockGearbox(container); + Mock.Get(container.Object.EngineInfo).Setup(e => e.EngineSpeed).Returns(() => n.RPMtoRad()); + Mock.Get(container.Object.EngineInfo).Setup(e => e.EngineN95hSpeed).Returns(2000.RPMtoRad()); + + var shiftStrategy = new AMTShiftStrategy(container.Object); + shiftStrategy.Gearbox = gbx.Object; + + var absTime = 0.SI<Second>(); + var dt = 2.SI<Second>(); + + var expectedN = n.RPMtoRad(); + var angularVelocity = expectedN / ratios[gear]; + + shiftStrategy.InitGear(0.SI<Second>(), Constants.SimulationSettings.TargetTimeInterval, 1.SI<NewtonMeter>(), + angularVelocity); + + absTime += dt; + + var expectedT = tq.SI<NewtonMeter>(); + var torque = expectedT * ratios[gear]; + + + var shiftRequired = shiftStrategy.ShiftRequired(absTime, dt, torque, angularVelocity, expectedT, expectedN, + new GearshiftPosition((uint)gear), -double.MaxValue.SI<Second>(), new ResponseSuccess(this)); + + Assert.AreEqual(shiftExpected, shiftRequired); + Assert.AreEqual(newGear, shiftStrategy.NextGear.Gear); + } + + private Mock<ISimpleVehicleContainer> GetSimpleVehicleContainer(VectoRunData runData, out Mock<ITestPowertrainTransmission> gbx) + { + var simpleContainer = new Mock<ISimpleVehicleContainer>(); + + simpleContainer.Setup(c => c.RunData).Returns(runData); + simpleContainer.Setup(c => c.PowertrainInfo.HasCombustionEngine).Returns(true); + + gbx = GetTestGearbox(runData.GearboxData.Gears); + + simpleContainer.Setup(c => c.GearboxOutPort).Returns(gbx.Object); + + return simpleContainer; + } + + private Mock<ITestPowertrainTransmission> GetTestGearbox(Dictionary<uint, GearData> ratios) + { + var gbx = new Mock<ITestPowertrainTransmission>(); + + gbx.Setup(g => g.LastUpshift).Returns(-double.MaxValue.SI<Second>()); + gbx.Setup(g => g.LastDownshift).Returns(-double.MaxValue.SI<Second>()); + + GearshiftPosition gear = null; + gbx.SetupGet(g => g.Gear).Returns(() => { + + return gear; + }); + gbx.SetupSet(g => g.SetGear = It.IsAny<GearshiftPosition>()) + .Callback<GearshiftPosition>(p => { + gear = p; + }); + + + GearshiftPosition nextGear = null; + gbx.SetupGet(g => g.NextGear).Returns(() => nextGear); + gbx.SetupSet(g => g.SetNextGear = It.IsAny<GearshiftPosition>()) + .Callback<GearshiftPosition>(p => nextGear = p); + + gbx.Setup(p => p.Initialize(It.IsAny<NewtonMeter>(), + It.IsAny<PerSecond>())).Returns((NewtonMeter tq, PerSecond rpm) => { + return new ResponseSuccess(this) + { + Engine = { + EngineSpeed = rpm, + PowerRequest = tq * rpm, + }, + }; + }); + + + gbx.Setup(g => g.Request(It.IsAny<Second>(), It.IsAny<Second>(), It.IsAny<NewtonMeter>(), It.IsAny<PerSecond>(), + It.IsAny<bool>())) + .Returns((Second absTime, Second dt, NewtonMeter t, PerSecond n, bool dryRun) => { + var ratio = gbx.Object.Gear == null ? 1.0 : ratios[gbx.Object.Gear.Gear].Ratio; + return dryRun + ? new ResponseDryRun(this) { + Engine = { + PowerRequest = n * t, EngineSpeed = n * ratio, + DynamicFullLoadPower = (t / ratio + 2300.SI<NewtonMeter>()) * n * ratio, + }, + Clutch = { PowerRequest = n * t } + } + : new ResponseSuccess(this) { + Engine = { PowerRequest = n * t, EngineSpeed = n * ratio }, + Clutch = { PowerRequest = n * t } + }; + }); + return gbx; + } + private Mock<ITestPowertrain> GetMockTestPowertrain(VectoRunData runData) + { + var testPt = new Mock<ITestPowertrain>(); + + var simpleContainer = GetSimpleVehicleContainer(runData, out var gbx); + // var tCnt = new Mock<ISimpleVehicleContainer>(); + testPt.Setup(t => t.Container).Returns(simpleContainer.Object); + testPt.Setup(t => t.Gearbox).Returns(gbx.Object); + + var tEng = new Mock<ITestpowertrainCombustionEngine>(); + testPt.Setup(t => t.CombustionEngine).Returns(tEng.Object); + tEng.Setup(e => e.EngineStationaryFullPower(It.IsAny<PerSecond>())) + .Returns((PerSecond n) => runData.EngineData.FullLoadCurves[0].FullLoadStationaryPower(n)); + return testPt; + } + + private static Mock<IVehicleContainer> GetMockVehicleContainer(VectoRunData runData) + { + var container = new Mock<IVehicleContainer>(); + container.Setup(c => c.RunData).Returns(runData); + var veh = new Mock<IVehicleInfo>(); + veh.Setup(v => v.VehicleSpeed).Returns(10.SI<MeterPerSecond>()); + container.Setup(c => c.VehicleInfo).Returns(veh.Object); + + //EngineInfo + var eng = GetEngineInfo(runData); + container.Setup(c => c.EngineInfo).Returns(eng.Object); + + var ci = new Mock<IDrivingCycleInfo>(); + container.Setup(c => c.DrivingCycleInfo).Returns(ci.Object); + var di = new Mock<IDriverInfo>(); + di.Setup(d => d.DriverBehavior).Returns(DrivingBehavior.Accelerating); + di.Setup(d => d.DrivingAction).Returns(DrivingAction.Accelerate); + container.Setup(c => c.DriverInfo).Returns(di.Object); + ci.Setup(c => c.CycleData).Returns(new CycleData() { LeftSample = new DrivingCycleData.DrivingCycleEntry() { PTOActive = PTOActivity.Inactive } }); + ci.Setup(c => c.CycleLookAhead(It.IsAny<Meter>())).Returns(new DrivingCycleData.DrivingCycleEntry() { + Altitude = 0.SI<Meter>() + }); + ci.Setup(c => c.Altitude).Returns(0.SI<Meter>()); + var pi = new Mock<IPowertainInfo>(); + pi.Setup(p => p.HasCombustionEngine).Returns(true); + container.Setup(c => c.PowertrainInfo).Returns(pi.Object); + + var vi = GetVehicleInfo(); + container.Setup(c => c.VehicleInfo).Returns(vi.Object); + + + var wi = new Mock<IWheelsInfo>(); + container.Setup(c => c.WheelsInfo).Returns(wi.Object); + wi.Setup(w => w.ReducedMassWheels).Returns(0.SI<Kilogram>()); + var axli = new Mock<IAxlegearInfo>(); + container.Setup(c => c.AxlegearInfo).Returns(axli.Object); + axli.Setup(a => a.AxlegearLoss()).Returns(0.SI<Watt>()); + return container; + } + + private static Mock<IVehicleInfo> GetVehicleInfo() + { + var vi = new Mock<IVehicleInfo>(); + vi.Setup(v => v.AirDragResistance(It.IsAny<MeterPerSecond>(), It.IsAny<MeterPerSecond>())) + .Returns(0.SI<Newton>()); + vi.Setup(v => v.RollingResistance(It.IsAny<Radian>())).Returns(0.SI<Newton>()); + vi.Setup(v => v.SlopeResistance(It.IsAny<Radian>())).Returns(0.SI<Newton>()); + vi.Setup(v => v.VehicleSpeed).Returns(30.KMPHtoMeterPerSecond()); + vi.Setup(v => v.TotalMass).Returns(12000.SI<Kilogram>()); + return vi; + } + + private static Mock<IEngineInfo> GetEngineInfo(VectoRunData runData) + { + var eng = new Mock<IEngineInfo>(); + + eng.Setup(e => e.EngineIdleSpeed).Returns(runData.EngineData.IdleSpeed); + eng.Setup(e => e.EngineRatedSpeed).Returns(runData.EngineData.FullLoadCurves.First().Value.RatedSpeed); + eng.Setup(e => e.EngineN95hSpeed).Returns(runData.EngineData.FullLoadCurves.First().Value.N95hSpeed); + eng.Setup(e => e.EngineStationaryFullPower(It.IsAny<PerSecond>())) + .Returns((PerSecond n) => runData.EngineData.FullLoadCurves[0].FullLoadStationaryPower(n)); + return eng; + } + + private Mock<ITestPowertrainTransmission> GetMockTestGearbox(Dictionary<uint, GearData> ratios) + { + var gbx = new Mock<ITestPowertrainTransmission>(); + + gbx.Setup(g => g.LastUpshift).Returns(-double.MaxValue.SI<Second>()); + gbx.Setup(g => g.LastDownshift).Returns(-double.MaxValue.SI<Second>()); + + GearshiftPosition gear = null; + gbx.SetupGet(g => g.Gear).Returns(() => { + + return gear; + }); + gbx.SetupSet(g => g.SetGear = It.IsAny<GearshiftPosition>()) + .Callback<GearshiftPosition>(p => { + gear = p; + }); + + + GearshiftPosition nextGear = null; + gbx.SetupGet(g => g.NextGear).Returns(() => nextGear); + gbx.SetupSet(g => g.SetNextGear = It.IsAny<GearshiftPosition>()) + .Callback<GearshiftPosition>(p => nextGear = p); + + gbx.Setup(p => p.Initialize(It.IsAny<NewtonMeter>(), + It.IsAny<PerSecond>())).Returns((NewtonMeter tq, PerSecond rpm) => { + return new ResponseSuccess(this) + { + Engine = { + EngineSpeed = rpm, + PowerRequest = tq * rpm, + }, + }; + }); + + + gbx.Setup(g => g.Request(It.IsAny<Second>(), It.IsAny<Second>(), It.IsAny<NewtonMeter>(), It.IsAny<PerSecond>(), + It.IsAny<bool>())) + .Returns((Second absTime, Second dt, NewtonMeter t, PerSecond n, bool dryRun) => { + var ratio = gbx.Object.Gear == null ? 1.0 : ratios[gbx.Object.Gear.Gear].Ratio; + return dryRun + ? new ResponseDryRun(this) { + Engine = { + PowerRequest = n * t, EngineSpeed = n * ratio, + DynamicFullLoadPower = (t / ratio + 2300.SI<NewtonMeter>()) * n * ratio, + }, + Clutch = { PowerRequest = n * t } + } + : new ResponseSuccess(this) { + Engine = { PowerRequest = n * t, EngineSpeed = n * ratio }, + Clutch = { PowerRequest = n * t } + }; + }); + return gbx; + } + + + private Mock<IAMTGearbox> GetMockGearbox(Mock<IVehicleContainer> container) + { + //Make sure no method that is not explicitly mocked is called + var gbx = new Mock<IAMTGearbox>(MockBehavior.Strict); + gbx.Setup(g => g.LastUpshift).Returns(-double.MaxValue.SI<Second>()); + gbx.Setup(g => g.LastDownshift).Returns(-double.MaxValue.SI<Second>()); + return gbx; + } + + private static VectoRunData GetRunData(double[] ratios) + { + var gearboxData = new GearboxData { + Gears = new Dictionary<uint, GearData>() + }; + for (uint i = 1; i < ratios.Length; i++) { + gearboxData.Gears[i] = new GearData { + Ratio = ratios[i], + LossMap = TransmissionLossMapReader.Create(0.96, ratios[i], $"Gear {i}") + }; + } + + var engineData = new CombustionEngineData() { + IdleSpeed = 560.RPMtoRad(), + FullLoadCurves = new Dictionary<uint, EngineFullLoadCurve>() { + { 0u, FullLoadCurveReader.Create(InputDataHelper.InputDataAsTableData(EngineFldHdr, EngineFldData)) } + } + }; + var axlRatio = 3.240355; + var gearsInput = gearboxData.Gears.Select(x => { + var r = new Mock<ITransmissionInputData>(); + r.Setup(g => g.Ratio).Returns(x.Value.Ratio); + return r.Object; + }).ToList(); + foreach (var entry in gearboxData.Gears) { + entry.Value.ShiftPolygon = DeclarationData.Gearbox.ComputeManualTransmissionShiftPolygon( + (int)(entry.Key - 1), engineData.FullLoadCurves.First().Value, + gearsInput, engineData, axlRatio, 0.5.SI<Meter>()); + } + + var runData = new VectoRunData() { + GearboxData = gearboxData, + GearshiftParameters = new ShiftStrategyParameters() { + StartSpeed = 2.SI<MeterPerSecond>(), + TimeBetweenGearshifts = 6.SI<Second>(), + DownshiftAfterUpshiftDelay = 2.SI<Second>(), + UpshiftAfterDownshiftDelay = 2.SI<Second>(), + UpshiftMinAcceleration = 0.1.SI<MeterPerSquareSecond>() + }, + EngineData = engineData, + AxleGearData = new AxleGearData() { + AxleGear = new TransmissionData() { + Ratio = 3.240355 + } + }, + VehicleData = new VehicleData() { + DynamicTyreRadius = 0.492.SI<Meter>(), + } + }; + return runData; + } + + const string EngineFldHdr = "engine speed [1/min],full load torque [Nm],motoring torque [Nm],PT1 [s]"; + + static readonly string[] EngineFldData = new[] { + "560,1180,-149,0.6 ", + "600,1282,-148,0.6 ", + "799.9999999,1791,-149,0.6 ", + "1000,2300,-160,0.6 ", + "1200,2300,-179,0.6 ", + "1400,2300,-203,0.6 ", + "1599.999999,2079,-235,0.49", + "1800,1857,-264,0.25 ", + "2000.000001,1352,-301,0.25", + "2100,1100,-320,0.25 ", + }; +} \ No newline at end of file diff --git a/Testing/UnitTests/Vecto UnitTests/TestCases/Components/GearShiftStrategy/AMTShistStrategyTests.cs b/Testing/UnitTests/Vecto UnitTests/TestCases/Components/GearShiftStrategy/AMTShistStrategyTests.cs deleted file mode 100644 index 22101872842256a1809e0cc7b7b470c30e5c72ea..0000000000000000000000000000000000000000 --- a/Testing/UnitTests/Vecto UnitTests/TestCases/Components/GearShiftStrategy/AMTShistStrategyTests.cs +++ /dev/null @@ -1,306 +0,0 @@ -using Moq; -using NUnit.Framework; -using TUGraz.VectoCommon.InputData; -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.Configuration; -using TUGraz.VectoCore.InputData.Reader.ComponentData; -using TUGraz.VectoCore.Models.Connector.Ports.Impl; -using TUGraz.VectoCore.Models.Declaration; -using TUGraz.VectoCore.Models.Simulation; -using TUGraz.VectoCore.Models.Simulation.Data; -using TUGraz.VectoCore.Models.Simulation.DataBus; -using TUGraz.VectoCore.Models.SimulationComponent; -using TUGraz.VectoCore.Models.SimulationComponent.Data; -using TUGraz.VectoCore.Models.SimulationComponent.Data.Engine; -using TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox; -using TUGraz.VectoCore.Models.SimulationComponent.Impl; -using TUGraz.VectoCore.Models.SimulationComponent.Impl.Gearbox; -using TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies; -using TUGraz.VectoCore.Tests.Utils; -using Assert = NUnit.Framework.Assert; - -namespace TUGraz.Vecto.UnitTests.TestCases.Components.GearShiftStrategy; - -public class AMTShistStrategyTests -{ - [TestCase(8, 7, 1800, 750, true), -TestCase(7, 6, 1800, 750, true), -TestCase(6, 5, 1800, 750, true), -TestCase(5, 4, 1800, 750, true), -TestCase(4, 3, 1800, 750, true), -TestCase(3, 2, 1800, 750, true), -TestCase(2, 1, 1900, 750, true), -TestCase(1, 1, 1200, 700, false), -TestCase(8, 4, 15000, 200, true),] - public void Gearbox_ShiftDown_ACEA_Shiftlines(int gear, int newGear, double t, double n, bool shiftExpected) - { - // the first element 0.0 is just a placeholder for axlegear, not used in this test - var ratios = new[] { 0.0, 6.38, 4.63, 3.44, 2.59, 1.86, 1.35, 1, 0.76 }; - var runData = GetRunData(ratios); - - var container = GetMockVehicleContainer(runData); - - var testPt = GetMockTestPowertrain(runData); - - var ptBuilder = new Mock<ISimplePowertrainBuilder>(); - ptBuilder.Setup(p => p.CreateTestPowertrain(It.IsAny<IVehicleContainer>(), It.IsAny<bool>(), It.IsAny<VectoSimulationJobType?>())) - .Returns(testPt.Object); - container.Setup(c => c.SimplePowertrainBuilder).Returns(ptBuilder.Object); - - var gbx = GetMockGearbox(container); - - - var shiftStrategy = new AMTShiftStrategy(container.Object); - shiftStrategy.Gearbox = gbx.Object; - - var absTime = 0.SI<Second>(); - var dt = 2.SI<Second>(); - - var expectedN = n.RPMtoRad(); - var angularVelocity = expectedN / ratios[gear]; - - - shiftStrategy.InitGear(0.SI<Second>(), Constants.SimulationSettings.TargetTimeInterval, 1.SI<NewtonMeter>(), - angularVelocity); - - var expectedT = t.SI<NewtonMeter>(); - var torque = expectedT * ratios[gear]; - - var shiftRequired = shiftStrategy.ShiftRequired(absTime, dt, torque, angularVelocity, expectedT, expectedN, - new GearshiftPosition((uint)gear), -double.MaxValue.SI<Second>(), new ResponseSuccess(this)); - - Assert.AreEqual(shiftExpected, shiftRequired); - Assert.AreEqual(newGear, shiftStrategy.NextGear.Gear); - } - - [TestCase(7, 8, 1000, 1400, true), - TestCase(6, 8, 800, 1400, true), - TestCase(5, 6, 1000, 1400, true), - TestCase(4, 5, 1000, 1400, true), - TestCase(3, 4, 1000, 1400, true), - TestCase(2, 4, 800, 1400, true), - TestCase(1, 2, 1000, 1400, true), - TestCase(8, 8, 1000, 1400, false), - TestCase(1, 6, 200, 9000, true),] - public void Gearbox_ShiftUp(int gear, int newGear, double tq, double n, bool shiftExpected) - { - // the first element 0.0 is just a placeholder for axlegear, not used in this test - var ratios = new[] { 0.0, 6.38, 4.63, 3.44, 2.59, 1.86, 1.35, 1, 0.76 }; - var runData = GetRunData(ratios); - - var container = GetMockVehicleContainer(runData); - - var testPt = GetMockTestPowertrain(runData); - - var ptBuilder = new Mock<ISimplePowertrainBuilder>(); - ptBuilder.Setup(p => p.CreateTestPowertrain(It.IsAny<IVehicleContainer>(), It.IsAny<bool>(), It.IsAny<VectoSimulationJobType?>())) - .Returns(testPt.Object); - container.Setup(c => c.SimplePowertrainBuilder).Returns(ptBuilder.Object); - - var gbx = GetMockGearbox(container); - Mock.Get(container.Object.EngineInfo).Setup(e => e.EngineSpeed).Returns(() => n.RPMtoRad()); - Mock.Get(container.Object.EngineInfo).Setup(e => e.EngineN95hSpeed).Returns(2000.RPMtoRad()); - - var shiftStrategy = new AMTShiftStrategy(container.Object); - shiftStrategy.Gearbox = gbx.Object; - - var absTime = 0.SI<Second>(); - var dt = 2.SI<Second>(); - - var expectedN = n.RPMtoRad(); - var angularVelocity = expectedN / ratios[gear]; - - shiftStrategy.InitGear(0.SI<Second>(), Constants.SimulationSettings.TargetTimeInterval, 1.SI<NewtonMeter>(), - angularVelocity); - - absTime += dt; - - var expectedT = tq.SI<NewtonMeter>(); - var torque = expectedT * ratios[gear]; - - - var shiftRequired = shiftStrategy.ShiftRequired(absTime, dt, torque, angularVelocity, expectedT, expectedN, - new GearshiftPosition((uint)gear), -double.MaxValue.SI<Second>(), new ResponseSuccess(this)); - - Assert.AreEqual(shiftExpected, shiftRequired); - Assert.AreEqual(newGear, shiftStrategy.NextGear.Gear); - } - - private Mock<ITestPowertrain> GetMockTestPowertrain(VectoRunData runData) - { - var testPt = new Mock<ITestPowertrain>(); - var tCnt = new Mock<ISimpleVehicleContainer>(); - tCnt.Setup(c => c.RunData).Returns(runData); - var tPi = new Mock<IPowertainInfo>(); - tPi.Setup(p => p.HasCombustionEngine).Returns(true); - tCnt.Setup(c => c.PowertrainInfo).Returns(tPi.Object); - var tGbx = new Mock<ITestPowertrainTransmission>(); - testPt.Setup(t => t.Gearbox).Returns(tGbx.Object); - tGbx.Setup(g => g.Initialize(It.IsAny<NewtonMeter>(), It.IsAny<PerSecond>())) - .Returns((NewtonMeter t, PerSecond n) => new ResponseSuccess(this) { - Engine = { PowerRequest = n * t, EngineSpeed = n }, - Clutch = { PowerRequest = n * t } - }); - tGbx.Setup(g => g.Request(It.IsAny<Second>(), It.IsAny<Second>(), It.IsAny<NewtonMeter>(), It.IsAny<PerSecond>(), - It.IsAny<bool>())) - .Returns((Second absTime, Second dt, NewtonMeter t, PerSecond n, bool dryRun) => new ResponseSuccess(this) { - Engine = { PowerRequest = n * t, EngineSpeed = n }, - Clutch = { PowerRequest = n * t } - }); - tGbx.Setup(g => g.Request(It.IsAny<Second>(), It.IsAny<Second>(), It.IsAny<NewtonMeter>(), It.IsAny<PerSecond>(), - It.IsAny<bool>())) - .Returns((Second absTime, Second dt, NewtonMeter t, PerSecond n, bool dryRun) => dryRun ? - new ResponseDryRun(this) { - Engine = { PowerRequest = n * t, EngineSpeed = n }, - Clutch = { PowerRequest = n * t } - }: new ResponseSuccess(this) { - Engine = { PowerRequest = n * t, EngineSpeed = n }, - Clutch = { PowerRequest = n * t } - }); - var tEng = new Mock<ITestpowertrainCombustionEngine>(); - testPt.Setup(t => t.CombustionEngine).Returns(tEng.Object); - tEng.Setup(e => e.EngineStationaryFullPower(It.IsAny<PerSecond>())) - .Returns((PerSecond n) => runData.EngineData.FullLoadCurves[0].FullLoadStationaryPower(n)); - return testPt; - } - - private static Mock<IVehicleContainer> GetMockVehicleContainer(VectoRunData runData) - { - var container = new Mock<IVehicleContainer>(); - container.Setup(c => c.RunData).Returns(runData); - var veh = new Mock<IVehicleInfo>(); - veh.Setup(v => v.VehicleSpeed).Returns(10.SI<MeterPerSecond>()); - container.Setup(c => c.VehicleInfo).Returns(veh.Object); - var eng = new Mock<IEngineInfo>(); - container.Setup(c => c.EngineInfo).Returns(eng.Object); - eng.Setup(e => e.EngineIdleSpeed).Returns(runData.EngineData.IdleSpeed); - eng.Setup(e => e.EngineRatedSpeed).Returns(runData.EngineData.FullLoadCurves.First().Value.RatedSpeed); - eng.Setup(e => e.EngineN95hSpeed).Returns(runData.EngineData.FullLoadCurves.First().Value.N95hSpeed); - eng.Setup(e => e.EngineStationaryFullPower(It.IsAny<PerSecond>())) - .Returns((PerSecond n) => runData.EngineData.FullLoadCurves[0].FullLoadStationaryPower(n)); - var ci = new Mock<IDrivingCycleInfo>(); - container.Setup(c => c.DrivingCycleInfo).Returns(ci.Object); - var di = new Mock<IDriverInfo>(); - di.Setup(d => d.DriverBehavior).Returns(DrivingBehavior.Accelerating); - di.Setup(d => d.DrivingAction).Returns(DrivingAction.Accelerate); - container.Setup(c => c.DriverInfo).Returns(di.Object); - ci.Setup(c => c.CycleData).Returns(new CycleData() { LeftSample = new DrivingCycleData.DrivingCycleEntry() { PTOActive = PTOActivity.Inactive } }); - ci.Setup(c => c.CycleLookAhead(It.IsAny<Meter>())).Returns(new DrivingCycleData.DrivingCycleEntry() { - Altitude = 0.SI<Meter>() - }); - ci.Setup(c => c.Altitude).Returns(0.SI<Meter>()); - var pi = new Mock<IPowertainInfo>(); - pi.Setup(p => p.HasCombustionEngine).Returns(true); - container.Setup(c => c.PowertrainInfo).Returns(pi.Object); - var vi = new Mock<IVehicleInfo>(); - vi.Setup(v => v.AirDragResistance(It.IsAny<MeterPerSecond>(), It.IsAny<MeterPerSecond>())) - .Returns(0.SI<Newton>()); - vi.Setup(v => v.RollingResistance(It.IsAny<Radian>())).Returns(0.SI<Newton>()); - vi.Setup(v => v.SlopeResistance(It.IsAny<Radian>())).Returns(0.SI<Newton>()); - vi.Setup(v => v.VehicleSpeed).Returns(30.KMPHtoMeterPerSecond()); - vi.Setup(v => v.TotalMass).Returns(12000.SI<Kilogram>()); - container.Setup(c => c.VehicleInfo).Returns(vi.Object); - var wi = new Mock<IWheelsInfo>(); - container.Setup(c => c.WheelsInfo).Returns(wi.Object); - wi.Setup(w => w.ReducedMassWheels).Returns(0.SI<Kilogram>()); - var axli = new Mock<IAxlegearInfo>(); - container.Setup(c => c.AxlegearInfo).Returns(axli.Object); - axli.Setup(a => a.AxlegearLoss()).Returns(0.SI<Watt>()); - return container; - } - - private Mock<AMTGearbox> GetMockGearbox(Mock<IVehicleContainer> container) - { - var gbx = new Mock<AMTGearbox>(container.Object, null); - var ratios = container.Object.RunData.GearboxData.Gears; - gbx.Setup(g => g.LastUpshift).Returns(-double.MaxValue.SI<Second>()); - gbx.Setup(g => g.LastDownshift).Returns(-double.MaxValue.SI<Second>()); - gbx.SetupProperty(g => g.Gear); - gbx.Setup(g => g.Request(It.IsAny<Second>(), It.IsAny<Second>(), It.IsAny<NewtonMeter>(), It.IsAny<PerSecond>(), - It.IsAny<bool>())) - .Returns((Second absTime, Second dt, NewtonMeter t, PerSecond n, bool dryRun) => { - var ratio = gbx.Object.Gear == null ? 1.0 : ratios[gbx.Object.Gear.Gear].Ratio; - return dryRun - ? new ResponseDryRun(this) { - Engine = { - PowerRequest = n * t, EngineSpeed = n * ratio, - DynamicFullLoadPower = (t / ratio + 2300.SI<NewtonMeter>()) * n * ratio, - }, - Clutch = { PowerRequest = n * t } - } - : new ResponseSuccess(this) { - Engine = { PowerRequest = n * t, EngineSpeed = n * ratio }, - Clutch = { PowerRequest = n * t } - }; - }); - return gbx; - } - - private static VectoRunData GetRunData(double[] ratios) - { - var gearboxData = new GearboxData { - Gears = new Dictionary<uint, GearData>() - }; - for (uint i = 1; i < ratios.Length; i++) { - gearboxData.Gears[i] = new GearData { - Ratio = ratios[i], - LossMap = TransmissionLossMapReader.Create(0.96, ratios[i], $"Gear {i}") - }; - } - - var engineData = new CombustionEngineData() { - IdleSpeed = 560.RPMtoRad(), - FullLoadCurves = new Dictionary<uint, EngineFullLoadCurve>() { - { 0u, FullLoadCurveReader.Create(InputDataHelper.InputDataAsTableData(EngineFldHdr, EngineFldData)) } - } - }; - var axlRatio = 3.240355; - var gearsInput = gearboxData.Gears.Select(x => { - var r = new Mock<ITransmissionInputData>(); - r.Setup(g => g.Ratio).Returns(x.Value.Ratio); - return r.Object; - }).ToList(); - foreach (var entry in gearboxData.Gears) { - entry.Value.ShiftPolygon = DeclarationData.Gearbox.ComputeManualTransmissionShiftPolygon( - (int)(entry.Key - 1), engineData.FullLoadCurves.First().Value, - gearsInput, engineData, axlRatio, 0.5.SI<Meter>()); - } - - var runData = new VectoRunData() { - GearboxData = gearboxData, - GearshiftParameters = new ShiftStrategyParameters() { - StartSpeed = 2.SI<MeterPerSecond>(), - TimeBetweenGearshifts = 6.SI<Second>(), - DownshiftAfterUpshiftDelay = 2.SI<Second>(), - UpshiftAfterDownshiftDelay = 2.SI<Second>(), - UpshiftMinAcceleration = 0.1.SI<MeterPerSquareSecond>() - }, - EngineData = engineData, - AxleGearData = new AxleGearData() { - AxleGear = new TransmissionData() { - Ratio = 3.240355 - } - }, - VehicleData = new VehicleData() { - DynamicTyreRadius = 0.492.SI<Meter>(), - } - }; - return runData; - } - - const string EngineFldHdr = "engine speed [1/min],full load torque [Nm],motoring torque [Nm],PT1 [s]"; - - static readonly string[] EngineFldData = new[] { - "560,1180,-149,0.6 ", - "600,1282,-148,0.6 ", - "799.9999999,1791,-149,0.6 ", - "1000,2300,-160,0.6 ", - "1200,2300,-179,0.6 ", - "1400,2300,-203,0.6 ", - "1599.999999,2079,-235,0.49", - "1800,1857,-264,0.25 ", - "2000.000001,1352,-301,0.25", - "2100,1100,-320,0.25 ", - }; -} \ No newline at end of file diff --git a/Testing/UnitTests/Vecto UnitTests/TestCases/Components/GearShiftStrategy/APTNShiftStrategyTests.cs b/Testing/UnitTests/Vecto UnitTests/TestCases/Components/GearShiftStrategy/APTNShiftStrategyTests.cs new file mode 100644 index 0000000000000000000000000000000000000000..d3d72531ab56c5e1a78b64a7fbe9a8fbf647d93c --- /dev/null +++ b/Testing/UnitTests/Vecto UnitTests/TestCases/Components/GearShiftStrategy/APTNShiftStrategyTests.cs @@ -0,0 +1,1997 @@ +using Moq; +using NUnit.Framework; +using TUGraz.VectoCommon.InputData; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.InputData.Impl; +using TUGraz.VectoCore.InputData.Reader.ComponentData; +using TUGraz.VectoCore.InputData.Reader.DataObjectAdapter.SimulationComponents; +using TUGraz.VectoCore.Models.Connector.Ports.Impl; +using TUGraz.VectoCore.Models.Declaration; +using TUGraz.VectoCore.Models.Simulation; +using TUGraz.VectoCore.Models.Simulation.Data; +using TUGraz.VectoCore.Models.Simulation.DataBus; +using TUGraz.VectoCore.Models.Simulation.Impl; +using TUGraz.VectoCore.Models.SimulationComponent; +using TUGraz.VectoCore.Models.SimulationComponent.Data; +using TUGraz.VectoCore.Models.SimulationComponent.Data.ElectricMotor; +using TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox; +using TUGraz.VectoCore.Models.SimulationComponent.Impl; +using TUGraz.VectoCore.Models.SimulationComponent.Impl.Gearbox; +using TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies; +using TUGraz.VectoCore.Models.SimulationComponent.Strategies; +using TUGraz.VectoCore.Tests.Utils; +using TUGraz.VectoCore.Utils; +using Range = System.Range; + +namespace TUGraz.Vecto.UnitTests.TestCases.Components.GearShiftStrategy +{ + [TestFixture] + public class APTNShiftStrategyTests + { + [TestCase(500, 80, 1)] + [TestCase(5, 500, 2)] + public void InitGear(double torque_Nm, double speed_rpm, int expectedGear) + { + // the first element 0.0 is just a placeholder for axlegear, not used in this test + var ratios = new[] { 0.0, 3.86, 1.93 }; + + var container = GetMocks(ratios); + + var shiftStrategy = GetShiftStrategyAndGearbox(container, out var gearbox); + + var absTime = 0.SI<Second>(); + var dt = 0.5.SI<Second>(); + + var torque = torque_Nm.SI<NewtonMeter>(); + var speed = speed_rpm.RPMtoRad(); + + var result = shiftStrategy.InitGear(absTime, dt, torque, speed); + + var newGear = result.Gear; + Assert.AreEqual(expectedGear, newGear); + + + + } + + [TestCase(5000, 80, 1)] + [TestCase(5, 500, 2)] + public void InitStartGear(double torque_Nm, double speed_rpm, int expectedGear) + { + // the first element 0.0 is just a placeholder for axlegear, not used in this test + var ratios = new[] { 0.0, 3.86, 1.93 }; + + var container = GetMocks(ratios); + container.Setup(c => c.VehicleInfo.VehicleSpeed).Returns(0.KMPHtoMeterPerSecond()); + + var shiftStrategy = GetShiftStrategyAndGearbox(container, out var gearbox); + + var absTime = 0.SI<Second>(); + var dt = 0.5.SI<Second>(); + + var torque = torque_Nm.SI<NewtonMeter>(); + var speed = speed_rpm.RPMtoRad(); + + var result = shiftStrategy.InitGear(absTime, dt, torque, speed); + + var newGear = result.Gear; + Assert.AreEqual(expectedGear, newGear); + + + + } + + [TestCase( + 500, + 80, + 500, + 10000, + 1, + 2, TestName = "Emergency UpShift")] + + [TestCase( + 500, + 80, + 1000, + 1800, + 1, + 2, TestName = "UpShift")] + [TestCase( + 500, + 80, + 1000, + 800, + 1, + 1, TestName = "No Upshift")] + public void Upshift(double init_outTorque_Nm, double init_outSpeed_rpm, double outTorque_Nm, + double outSpeed_rpm, int currentGear, int expectedGear) + { + CheckUpshift(init_outTorque_Nm, init_outSpeed_rpm, outTorque_Nm, outSpeed_rpm, currentGear, expectedGear, false); + } + + + public void CheckUpshift(double init_outTorque_Nm, double init_outSpeed_rpm, double outTorque_Nm, + double outSpeed_rpm, int currentGear, int expectedGear, bool effShift) + { + // the first element 0.0 is just a placeholder for axlegear, not used in this test + var ratios = new[] { 0.0, 3.86, 1.93 }; + var ratio = ratios[currentGear]; + var container = GetMocks(ratios); + + if (!effShift) { + DisableEffshift(container.Object.RunData); + } + + + var shiftRequired = currentGear != expectedGear; + + var shiftStrategy = GetShiftStrategyAndGearbox(container, out var gearbox); + // var gear = new GearshiftPosition((uint)currentGear); + // gearbox.Gear = gear; + + var absTime = 0.SI<Second>(); + var dt = 0.5.SI<Second>(); + + var init_outTorque = init_outTorque_Nm.SI<NewtonMeter>(); + var init_outAngularVelocity = init_outSpeed_rpm.RPMtoRad(); + + + var outTorque = outTorque_Nm.SI<NewtonMeter>(); + var outAngularVelocity = outSpeed_rpm.RPMtoRad(); + + var inTorque = outTorque / ratio; + var inAngularVelocity = outAngularVelocity * ratio; + + var lastShiftTime = float.MinValue.SI<Second>(); + + var response = new ResponseSuccess(this); + + Console.WriteLine( + $"OutTorque: {outTorque}\n" + + $"InTorque: {inTorque} \n" + + $"OutSpeed: {outAngularVelocity.AsRPM} [rpm]\n" + + $"InSpeed: {inAngularVelocity.AsRPM} [rpm]\n"); + + + //Init gear + var initResult = shiftStrategy.InitGear(absTime, dt, init_outTorque, init_outAngularVelocity); + Assert.That(shiftStrategy.NextGear.Gear, Is.EqualTo(currentGear)); + + //Check shift required + var result = shiftStrategy.ShiftRequired(absTime, dt, + outTorque: outTorque, + outAngularVelocity: outAngularVelocity, + inTorque: inTorque, + inAngularVelocity: inAngularVelocity, + gear: shiftStrategy.NextGear, + lastShiftTime: lastShiftTime, + response: response); + + Assert.AreEqual(shiftRequired, result); + Assert.AreEqual(expectedGear, shiftStrategy.NextGear.Gear); + + + + } + + [TestCase( + 500, + 80, + -10, + 1000, + 1, + 2, TestName = "UpShift")] + public void EarlyUpshift(double init_outTorque_Nm, double init_outSpeed_rpm, double outTorque_Nm, + double outSpeed_rpm, int currentGear, int expectedGear) + { + // the first element 0.0 is just a placeholder for axlegear, not used in this test + var ratios = new[] { 0.0, 3.86, 1.93 }; + var ratio = ratios[currentGear]; + var container = GetMocks(ratios); + container.Setup(c => c.VehicleInfo.VehicleSpeed).Returns(20.KMPHtoMeterPerSecond()); + + + var shiftRequired = currentGear != expectedGear; + + var shiftStrategy = GetShiftStrategyAndGearbox(container, out var gearbox); + var gear = new GearshiftPosition((uint)currentGear); + // gearbox.Gear = gear; + + var absTime = 0.SI<Second>(); + var dt = 0.5.SI<Second>(); + + var init_outTorque = init_outTorque_Nm.SI<NewtonMeter>(); + var init_outAngularVelocity = init_outSpeed_rpm.RPMtoRad(); + + + var outTorque = outTorque_Nm.SI<NewtonMeter>(); + var outAngularVelocity = outSpeed_rpm.RPMtoRad(); + + var inTorque = outTorque / ratio; + var inAngularVelocity = outAngularVelocity * ratio; + + var lastShiftTime = float.MinValue.SI<Second>(); + + var response = new ResponseSuccess(this); + + Console.WriteLine( + $"OutTorque: {outTorque}\n" + + $"InTorque: {inTorque} \n" + + $"OutSpeed: {outAngularVelocity.AsRPM} [rpm]\n" + + $"InSpeed: {inAngularVelocity.AsRPM} [rpm]\n"); + + + //Init gear + var initResult = shiftStrategy.InitGear(absTime, dt, init_outTorque, init_outAngularVelocity); + Assert.That(shiftStrategy.NextGear.Gear, Is.EqualTo(currentGear)); + + //Check shift required + var result = shiftStrategy.ShiftRequired(absTime, dt, + outTorque: outTorque, + outAngularVelocity: outAngularVelocity, + inTorque: inTorque, + inAngularVelocity: inAngularVelocity, + gear: shiftStrategy.NextGear, + lastShiftTime: lastShiftTime, + response: response); + + Assert.AreEqual(shiftRequired, result); + Assert.AreEqual(expectedGear, shiftStrategy.NextGear.Gear); + + + } + + [TestCase( + 5, + 200, + 2000, + 200, + 2, + 1, TestName = "Downshift")] + public void Downshift(double init_outTorque_Nm, double init_outSpeed_rpm, double outTorque_Nm, + double outSpeed_rpm, int currentGear, int expectedGear, int speedKmh=1) + { + var ratios = new[] { 0.0, 3.86, 1.93 }; + CheckDownshift(init_outTorque_Nm, init_outSpeed_rpm, outTorque_Nm, outSpeed_rpm, currentGear, expectedGear, ratios, false, speedKmh); + } + + [TestCase( + 5, + 200, + -500, + 200, + 4, + 2, + 40, TestName = "EarlyDownshift")] + public void EarlyDownshift(double init_outTorque_Nm, double init_outSpeed_rpm, double outTorque_Nm, + double outSpeed_rpm, int currentGear, int expectedGear, int speedKmh=1) + { + var ratios = new[] { 0.0, 3.86, 3, 2.5, 1.93 }; + CheckDownshift(init_outTorque_Nm, init_outSpeed_rpm, outTorque_Nm, outSpeed_rpm, currentGear, expectedGear, ratios, true, speedKmh); + } + + [TestCase( + 5, + 200, + 2000, + 40, + 4, + 2, TestName = "Downshift_SkipGear")] + public void DownshiftSkipGears(double init_outTorque_Nm, double init_outSpeed_rpm, double outTorque_Nm, + double outSpeed_rpm, int currentGear, int expectedGear) + { + var ratios = new[] { 0.0, 3.86, 3, 2.5, 1.93 }; + CheckDownshift(init_outTorque_Nm, init_outSpeed_rpm, outTorque_Nm, outSpeed_rpm, currentGear, expectedGear, ratios, false); + } + + private void DisableEffshift(VectoRunData runData) + { + TestContext.WriteLine("EffShift Disabled"); + runData.GearshiftParameters.AllowedGearRangeFC = 0; + } + + private void DisableEffshift(Mock<IVehicleContainer> vehicleContainer) + { + DisableEffshift(vehicleContainer.Object.RunData); + } + + public void CheckDownshift( + double init_outTorque_Nm, + double init_outSpeed_rpm, + double outTorque_Nm, + double outSpeed_rpm, + int currentGear, + int expectedGear, + double[] ratios, + bool effShift = true, + int vehicleSpeed_kmH = 1) + { + // the first element 0.0 is just a placeholder for axlegear, not used in this test + var ratio = ratios[currentGear]; + var container = GetMocks(ratios); + container.Setup(c => c.VehicleInfo.VehicleSpeed).Returns(vehicleSpeed_kmH.KMPHtoMeterPerSecond()); + + + if (!effShift) { + DisableEffshift(container.Object.RunData); + } + + var shiftRequired = currentGear != expectedGear; + + var shiftStrategy = GetShiftStrategyAndGearbox(container, out var gearbox); + var gear = new GearshiftPosition((uint)currentGear); + // gearbox.Gear = gear; + + var absTime = 0.SI<Second>(); + var dt = 0.5.SI<Second>(); + + var init_outTorque = init_outTorque_Nm.SI<NewtonMeter>(); + var init_outAngularVelocity = init_outSpeed_rpm.RPMtoRad(); + + var outTorque = outTorque_Nm.SI<NewtonMeter>(); + var outAngularVelocity = outSpeed_rpm.RPMtoRad(); + + var inTorque = outTorque / ratio; + var inAngularVelocity = outAngularVelocity * ratio; + + var lastShiftTime = float.MinValue.SI<Second>(); + + + + Console.WriteLine( + $"OutTorque: {outTorque}\n" + + $"InTorque: {inTorque} \n" + + $"OutSpeed: {outAngularVelocity}\n" + + $"InSpeed: {inAngularVelocity}\n"); + + + //Init gear + var initResult = shiftStrategy.InitGear(absTime, dt, init_outTorque, init_outAngularVelocity); + Assert.That(shiftStrategy.NextGear.Gear, Is.EqualTo(currentGear)); + + var response = new ResponseSuccess(this) { }; + response.ElectricMotor.AngularVelocity = inAngularVelocity; + response.ElectricMotor.TorqueRequestEmMap = inTorque; + response.ElectricMotor.DeRatingActive = false; + // response.ElectricMotor; + + //Check shift required + var result = shiftStrategy.ShiftRequired(absTime, dt, + outTorque: outTorque, + outAngularVelocity: outAngularVelocity, + inTorque: inTorque, + inAngularVelocity: inAngularVelocity, + gear: shiftStrategy.NextGear, + lastShiftTime: lastShiftTime, + response: response); + + Assert.AreEqual(shiftRequired, result, "Expected Shift"); + Assert.AreEqual(expectedGear, shiftStrategy.NextGear.Gear); + + + + } + + + + + + private APTNShiftStrategy GetShiftStrategyAndGearbox(Mock<IVehicleContainer> container, out Mock<IIEPCGearbox> gearbox) + { + var shiftStrategy = new APTNShiftStrategy(container.Object); + + var gbx = new Mock<IIEPCGearbox>(MockBehavior.Strict); + gbx.Name = "MockGearbox"; + gbx.Setup(g => g.LastUpshift).Returns(-double.MaxValue.SI<Second>()); + gbx.Setup(g => g.LastDownshift).Returns(-double.MaxValue.SI<Second>()); + + shiftStrategy.Gearbox = gbx.Object; + SetVelocityDropLookupData(shiftStrategy); + container.Setup(c => c.GearboxInfo).Returns(gbx.Object); + + gearbox = gbx; + return shiftStrategy; + } + + private Mock<IVehicleContainer> GetMocks(double[] ratios) + { + var container = new Mock<IVehicleContainer>(); + + //RunData + var runData = GetRunData(ratios); + container.Setup(r => r.RunData).Returns(runData); + + //EmInfo + var em = GetElectricMotor(container.Object, runData.ElectricMachinesData.Single().Item2); + container.Setup(c => c.ElectricMotorInfo(PowertrainPosition.BatteryElectricE2)) + .Returns(em); + container.Setup(c => c.PowertrainInfo.ElectricMotorPositions).Returns(new[] { + PowertrainPosition.BatteryElectricE2 + }); + + // container.Setup(r => r.GetElectricMotors()).Returns(new List<IElectricMotorInfo>(){em}); + + container.Setup(c => c.PowertrainInfo.HasCombustionEngine).Returns(false); + + //BatteryInfo + container.Setup(c => c.BatteryInfo.InternalVoltage).Returns(700.SI<Volt>()); + + //VehicleInfo + container.Setup(c => c.VehicleInfo.VehicleSpeed).Returns(1.KMPHtoMeterPerSecond()); + container.Setup(c => c.VehicleInfo.VehicleStopped).Returns(false); + + //DriverInfo + container.Setup(c => c.DriverInfo.DriverBehavior).Returns(DrivingBehavior.Accelerating); + container.Setup(c => c.DriverInfo.DrivingAction).Returns(DrivingAction.Accelerate); + // container.Set + + //PowertrainBuilder, SimplePowertrain + var testPt = GetTestPowertrain(ratios, container, out _); + var ptBuilder = new Mock<ISimplePowertrainBuilder>(); + ptBuilder.Setup(c => c.CreateTestPowertrain( + It.IsAny<IVehicleContainer>(), It.IsAny<bool>())) + .Returns(testPt.Object); + ptBuilder.Setup(c => c.CreateTestPowertrain( + It.IsAny<IVehicleContainer>(), It.IsAny<bool>(), It.IsAny<VectoSimulationJobType>())) + .Returns(testPt.Object); + container.Setup(c => c.SimplePowertrainBuilder).Returns(ptBuilder.Object); + + //DrivingCycleInfo + container.Setup(c => c.DrivingCycleInfo.RoadGradient).Returns(0.SI<Radian>()); + + return container; + } + + private ElectricMotor GetElectricMotor(IVehicleContainer container, ElectricMotorData emData) + { + var emControl = new SimpleElectricMotorControl(); + + var electricMotor = new ElectricMotor(container: container, emData, emControl, + PowertrainPosition.BatteryElectricE2); + + //Connect Electric System + var es = GetMockElectricSystem(); + electricMotor.Connect(es.Object); + return electricMotor; + } + + private TestPowertrainElectricMotor GetTestPowertrainElectricMotor(ISimpleVehicleContainer container, + ElectricMotorData emData) + { + var emControl = new SimpleElectricMotorControl(); + + var electricMotor = new TestPowertrainElectricMotor(container: container, emData, emControl, + PowertrainPosition.BatteryElectricE2); + + //Connect Electric System + var es = GetMockElectricSystem(); + electricMotor.Connect(es.Object); + return electricMotor; + } + + private Mock<ITestPowertrain> GetTestPowertrain(double[] ratios, + Mock<IVehicleContainer> container, + out Mock<ISimpleVehicleContainer> simplePt) + { + var testPt = new Mock<ITestPowertrain>(); + simplePt = GetSimplePowertrain(ratios, container, out var gbx); + var simplePtObj = simplePt.Object; + testPt.Setup(t => t.ElectricMotors).Returns(() => { + var dict = new Dictionary<PowertrainPosition, ITestpowertrainElectricMotor>(); + foreach (var (k, v) in simplePtObj.ElectricMotors) { + if (v is ITestpowertrainElectricMotor testEm) { + dict[k] = testEm; + } else { + throw new Exception("Expected TestElectricMotor in simple powertrain"); + } + } + return dict; + }); + + testPt.Setup(t => t.Container).Returns(simplePt.Object); + + testPt.Setup(t => t.Gearbox).Returns(gbx.Object); + return testPt; + } + + private Mock<IElectricSystem> GetMockElectricSystem() + { + var electricSystem = new Mock<IElectricSystem>(); + + + electricSystem + .Setup(es => es.Request(It.IsAny<Second>(), It.IsAny<Second>(), It.IsAny<Watt>(), true)) + .Returns((Second t, Second dt, Watt powerDemand, bool dryrun) => { + + var response = new Mock<IElectricSystemResponse>(); + response + .Setup(mr => mr.MaxPowerDrive) + .Returns(-100E3.SI<Watt>()); + response + .Setup(mr => mr.MaxPowerDrag) + .Returns(100E3.SI<Watt>()); + response + .Setup(mr => mr.RESSPowerDemand).Returns(powerDemand); + + + + + return response.Object; + }); + + + return electricSystem; + } + + private ElectricMotor GetMockElectricMotor(IVehicleContainer container, ElectricMotorData emData) + { + var emControl = new SimpleElectricMotorControl(); + + var electricMotor = new ElectricMotor(container: container, emData, emControl, + PowertrainPosition.BatteryElectricE2); + + //Connect Electric System + var es = GetMockElectricSystem(); + electricMotor.Connect(es.Object); + return electricMotor; + } + + private Mock<ISimpleVehicleContainer> GetSimplePowertrain( + double[] ratios, + Mock<IVehicleContainer> container, + out Mock<ITestPowertrainTransmission> testGbx) + { + var simplePt = new Mock<ISimpleVehicleContainer>(); + simplePt.Setup(s => s.IsTestPowertrain).Returns(true); + + + var components = new List<VectoSimulationComponent>(); + + var runData = container.Object.RunData; + var em = GetTestPowertrainElectricMotor(simplePt.Object, runData.ElectricMachinesData.Single().Item2); + var emDict = new Dictionary<PowertrainPosition, IElectricMotorInfo>() { + { PowertrainPosition.BatteryElectricE2, em }, + }; + simplePt.Setup(r => r.ElectricMotorInfo(PowertrainPosition.BatteryElectricE2)) + .Returns(em); + + //BatteryInfo + simplePt.Setup(s => s.BatteryInfo.InternalVoltage).Returns(700.SI<Volt>()); + + simplePt.Setup(s => s.ElectricMotors).Returns(emDict); + + simplePt.Setup(s => s.PowertrainInfo.HasCombustionEngine).Returns(false); + + simplePt.Setup(s => s.RunData).Returns(runData); + + testGbx = GetTestGearbox(simplePt.Object, em, runData.GearboxData.Gears); + + simplePt.Setup(s => s.GearboxCtl).Returns(testGbx.Object); + simplePt.Setup(s => s.GearboxInfo).Returns(testGbx.Object); + simplePt.Setup(s => s.GearboxOutPort).Returns(testGbx.Object); + + simplePt.Setup(s => s.SimulationComponents()).Returns(components); + simplePt.Setup(s => s.Brakes).Returns(new Mock<IBrakes>().Object); + + //Take from real powertrain + simplePt.Setup(s => s.VehicleInfo).Returns(container.Object.VehicleInfo); + simplePt.Setup(s => s.DriverInfo).Returns(container.Object.DriverInfo); + + return simplePt; + } + + Mock<ITestPowertrainTransmission> GetTestGearbox( + ISimpleVehicleContainer simpleContainer, + TestPowertrainElectricMotor em, + Dictionary<uint, GearData> ratios) + { + Mock<IAMTGearbox> amtGearbox = new Mock<IAMTGearbox>(); + amtGearbox.Name = "PEVAMT_TestGearbox"; + Mock<ITestPowertrainTransmission> gbx = amtGearbox.As<ITestPowertrainTransmission>(); + + gbx.Setup(g => g.LastUpshift).Returns(-double.MaxValue.SI<Second>()); + gbx.Setup(g => g.LastDownshift).Returns(-double.MaxValue.SI<Second>()); + + GearshiftPosition gear = null; + gbx.SetupGet(g => g.Gear).Returns(() => gear); + gbx.SetupSet(g => g.SetGear = It.IsAny<GearshiftPosition>()) + .Callback<GearshiftPosition>(p => { + gear = p; + }); + + + GearshiftPosition nextGear = null; + gbx.SetupGet(g => g.NextGear).Returns(() => nextGear); + gbx.SetupSet(g => g.SetNextGear = It.IsAny<GearshiftPosition>()) + .Callback<GearshiftPosition>(p => nextGear = p); + + + gbx.Setup(p => p.Initialize(It.IsAny<NewtonMeter>(), + It.IsAny<PerSecond>())).Returns((NewtonMeter outTorque, PerSecond outSpeed) => { + var ratio = + gbx.Object.Gear == null ? 1.0 : ratios[gbx.Object.Gear.Gear].Ratio; + + var inSpeed = outSpeed * ratio; + var inTorque = outTorque / ratio; + + em.Initialize(inTorque, inSpeed); + return new ResponseSuccess(this) + { + + }; + }); + gbx.Setup(p => p.Request( + It.IsAny<Second>(), + It.IsAny<Second>(), + It.IsAny<NewtonMeter>(), + It.IsAny<PerSecond>(), + true)).Returns(( + Second absTime, + Second dt, + NewtonMeter outTorque, + PerSecond outSpeed, + bool dryRun) => { + + var ratio = + gbx.Object.Gear == null ? 1.0 : ratios[gbx.Object.Gear.Gear].Ratio; + + var inSpeed = outSpeed * ratio; + var inTorque = outTorque / ratio; + + var emResponse = em.Request(absTime, dt, inTorque, inSpeed, dryRun); + return dryRun + ? new ResponseDryRun(this, emResponse) { + // Engine = { + // PowerRequest = n * t, EngineSpeed = n * ratio, + // DynamicFullLoadPower = (t / ratio + 2300.SI<NewtonMeter>()) * n * ratio, + // TotalTorqueDemand = t, + // }, + // ElectricMotor = emResponse.ElectricMotor, + Gearbox = { + Gear = gbx.Object.Gear, + InputSpeed = inSpeed, + InputTorque = inTorque, + OutputSpeed = outSpeed, + OutputTorque = outTorque, + PowerRequest = outSpeed * outTorque, + }, + Clutch = { PowerRequest = outSpeed * outTorque }, + DeltaFullLoad = outSpeed * outTorque / 2 * (-1) + } + : new ResponseSuccess(this) { + Gearbox = { + Gear = gbx.Object.Gear, + InputSpeed = inSpeed, + InputTorque = inTorque, + }, + Clutch = { PowerRequest = outSpeed * outTorque } + }; + }); + return gbx; + } + + + private VectoRunData GetRunData(double[] ratios) + { + var runData = new VectoRunData(); + + //GearShiftParameters + var gearshiftParameters = new ShiftStrategyParameters() { + TorqueReserve = 0.0, + TimeBetweenGearshifts = 2.SI<Second>(), + DownshiftAfterUpshiftDelay = 2.SI<Second>(), + UpshiftAfterDownshiftDelay = 2.SI<Second>(), + UpshiftMinAcceleration = 0.1.SI<MeterPerSquareSecond>(), + StartSpeed = 0.KMPHtoMeterPerSecond(), + RatingFactorCurrentGear = 1, + AllowedGearRangeFC = 2, + MinEngineSpeedPostUpshift = 0.RPMtoRad(), + }; + runData.GearshiftParameters = gearshiftParameters; + + runData.ElectricMachinesData = GetElectricMachinesData(); + var emData = runData.ElectricMachinesData.Single(i => i.Item1 == PowertrainPosition.BatteryElectricE2) + .Item2; + //VehicleData + var vehicleData = new VehicleData() { + DynamicTyreRadius = 0.492.SI<Meter>(), + }; + runData.VehicleData = vehicleData; + + //CycleData + var mockCycle = new Mock<IDrivingCycleData>(); + mockCycle.Setup(cd => cd.Entries).Returns( + new List<DrivingCycleData.DrivingCycleEntry>() { + new DrivingCycleData.DrivingCycleEntry() { + RoadGradient = 0.SI<Radian>() + } + }); + runData.Cycle = mockCycle.Object; + + + //Gearboxdata + var gearboxInputData = new Mock<IGearboxDeclarationInputData>(); + + var gearsInputData = new List<Mock<ITransmissionInputData>>(); + + gearboxInputData.Setup( + d => d.Gears) + .Returns(gearsInputData.Select(m => m.Object) + .ToList()); + + + var gearboxData = new GearboxData() { + Gears = new Dictionary<uint, GearData>(ratios.Length), + InputData = gearboxInputData.Object, + Type = GearboxType.AMT, + TractionInterruption = 1.SI<Second>(), + Inertia = 0.SI<KilogramSquareMeter>(), + }; + + + + + + runData.GearboxData = gearboxData; + for (uint i = 1; i < ratios.Length; i++) { + gearboxData.Gears[i] = new GearData + { + Ratio = ratios[i], + LossMap = TransmissionLossMapReader.Create(0.96, ratios[i], $"Gear {i}"), + + }; + } + var axlRatio = 3.240355; + var gearsInput = gearboxData.Gears.Select(x => { + var r = new Mock<ITransmissionInputData>(); + r.Setup(g => g.Ratio).Returns(x.Value.Ratio); + r.Setup(g => g.MaxTorque).Returns(x.Value.MaxTorque); + r.Setup(g => g.MaxInputSpeed).Returns(x.Value.MaxSpeed); + + return r.Object; + }).ToList(); + foreach (var entry in gearboxData.Gears) { + var gearIdx = (int)entry.Key - 1; + var dynamicTyreRadius = 0.5.SI<Meter>(); + + var shiftPolygon = DeclarationData.Gearbox.ComputeElectricMotorShiftPolygon( + gearIdx, + emData, + gearsInput); + + entry.Value.ShiftPolygon = shiftPolygon; + + } + + + return runData; + } + + private IList<Tuple<PowertrainPosition, ElectricMotorData>> GetElectricMachinesData() + { + //Nr of electric machines + const int emCount = 2; + //ElectricMachines + // var electricMotorData = new ElectricMotorData() { + // + // }; + var emDataAdapter = new ElectricMachinesDataAdapter(); + var emInputData = new Mock<IElectricMotorDeclarationInputData>(); + + var powerMapMock = new Mock<IElectricMotorPowerMap>(); + powerMapMock.Setup(pm => pm.Gear).Returns(0); + powerMapMock.Setup(pm => pm.PowerMap).Returns(GetEfficiencyMapData()); + + var voltageLevels = new List<IElectricMotorVoltageLevel>() { + new ElectricMotorVoltageLevel(){ + VoltageLevel = 100.SI<Volt>(), + ContinuousTorque = 450.SI<NewtonMeter>(), + ContinuousTorqueSpeed = 2460.RPMtoRad(), + OverloadTorque = 485.SI<NewtonMeter>(), + OverloadTestSpeed = 2460.RPMtoRad(), + OverloadTime = 120.SI<Second>(), + FullLoadCurve = GetFullLoadCurveData(), + PowerMap = new List<IElectricMotorPowerMap>(){powerMapMock.Object} + }, + new ElectricMotorVoltageLevel(){ + VoltageLevel = 1000.SI<Volt>(), + ContinuousTorque = 450.SI<NewtonMeter>(), + ContinuousTorqueSpeed = 2460.RPMtoRad(), + OverloadTorque = 485.SI<NewtonMeter>(), + OverloadTestSpeed = 2460.RPMtoRad(), + OverloadTime = 120.SI<Second>(), + FullLoadCurve = GetFullLoadCurveData(), + PowerMap = new List<IElectricMotorPowerMap>(){powerMapMock.Object} + } + }; + + emInputData.Setup(em => em.CertificationMethod).Returns(CertificationMethod.Measured); + emInputData.Setup(em => em.Inertia).Returns(0.225.SI<KilogramSquareMeter>()); + emInputData.Setup(em => em.R85RatedPower).Returns(250E3.SI<Watt>()); + emInputData.Setup(em => em.ElectricMachineType).Returns(ElectricMachineType.ASM); + emInputData.Setup(em => em.VoltageLevels).Returns(voltageLevels); + emInputData.Setup(em => em.DragCurve).Returns(GetDragCurveData); + + var adcInputData = new Mock<IADCDeclarationInputData>(); + adcInputData.Setup(adc => adc.Ratio).Returns(1.0f); + + var emsInputData = new Mock<IElectricMachinesDeclarationInputData>(); + emsInputData.Setup(em => em.Entries).Returns( + new List<ElectricMachineEntry<IElectricMotorDeclarationInputData>>() { + new ElectricMachineEntry<IElectricMotorDeclarationInputData>() { + Count = emCount, + Position = PowertrainPosition.BatteryElectricE2, + ElectricMachine = emInputData.Object, + ADC = adcInputData.Object, + RatioADC = 2.0, + MechanicalTransmissionEfficiency = 0.97, + } + }); + + var avgVoltage = 200.SI<Volt>(); + IDictionary<PowertrainPosition, IList<Tuple<Volt, TableData>>> torqueLimits = new Dictionary<PowertrainPosition, IList<Tuple<Volt, TableData>>>(); + + var electricMachinesData = emDataAdapter.CreateElectricMachines(emsInputData.Object, torqueLimits:torqueLimits, + avgVoltage, null); + + + + + + return electricMachinesData; + + } + + private TableData GetDragCurveData() + { + return InputDataHelper.InputDataAsTableData( + "n [rpm] , T_drag [Nm]", + "0 , -6.06", + "7363.77 , -30.31"); + } + + + private TableData GetFullLoadCurveData() + { + return InputDataHelper.InputDataAsTableData("n [rpm] , T_drive [Nm] , T_drag [Nm]", + #region data + "0,485,-485", +"2461.158914,485,-485", +"2452.135493,485,-485", +"2466.863034,483.8845,-483.8845", +"2481.590574,481.010875,-481.010875", +"2496.318115,478.173625,-478.173625", +"2503.681885,476.767125,-476.767125", +"2577.319588,463.138625,-463.138625", +"2650.95729,450.274,-450.274", +"2724.594993,438.1005,-438.1005", +"2798.232695,426.58175,-426.58175", +"2871.870398,415.645,-415.645", +"2945.5081,405.253875,-405.253875", +"3019.145803,395.359875,-395.359875", +"3092.783505,385.950875,-385.950875", +"3166.421208,376.978375,-376.978375", +"3240.05891,368.406,-368.406", +"3313.696613,360.221625,-360.221625", +"3387.334315,352.388875,-352.388875", +"3460.972018,344.895625,-344.895625", +"3534.60972,337.7055,-337.7055", +"3608.247423,330.8185,-330.8185", +"3681.885125,324.19825,-324.19825", +"3755.522828,317.84475,-317.84475", +"3829.16053,311.73375,-311.73375", +"3902.798233,305.853125,-305.853125", +"3976.435935,300.178625,-300.178625", +"4050.073638,294.722375,-294.722375", +"4123.71134,289.460125,-289.460125", +"4197.349043,284.37975,-284.37975", +"4270.986745,279.48125,-279.48125", +"4344.624448,274.740375,-274.740375", +"4418.26215,270.16925,-270.16925", +"4491.899853,265.7315,-265.7315", +"4565.537555,261.451375,-261.451375", +"4639.175258,257.304625,-257.304625", +"4712.81296,253.279125,-253.279125", +"4786.450663,249.387,-249.387", +"4860.088365,245.604,-245.604", +"4933.726068,241.94225,-241.94225", +"5007.36377,238.3775,-238.3775", +"5081.001473,234.921875,-234.921875", +"5154.639175,231.575375,-231.575375", +"5228.276878,228.31375,-228.31375", +"5301.91458,225.137,-225.137", +"5375.552283,222.05725,-222.05725", +"5449.189985,219.05025,-219.05025", +"5522.827688,216.128125,-216.128125", +"5596.46539,213.290875,-213.290875", +"5670.103093,210.51425,-210.51425", +"5743.740795,207.8225,-207.8225", +"5817.378498,205.191375,-205.191375", +"5891.0162,202.620875,-202.620875", +"5964.653903,200.123125,-200.123125", +"6038.291605,197.686,-197.686", +"6111.929308,195.297375,-195.297375", +"6185.56701,192.969375,-192.969375", +"6259.204713,190.702,-190.702", +"6332.842415,188.483125,-188.483125", +"6406.480118,186.324875,-186.324875", +"6480.11782,184.203,-184.203", +"6553.755523,182.129625,-182.129625", +"6627.393225,180.10475,-180.10475", +"6701.030928,178.128375,-178.128375", +"6774.66863,176.2005,-176.2005", +"6848.306333,174.296875,-174.296875", +"6921.944035,172.44175,-172.44175", +"6995.581738,170.635125,-170.635125", +"7069.21944,168.85275,-168.85275", +"7142.857143,167.10675,-167.10675", +"7216.494845,165.40925,-165.40925", +"7290.132548,163.736,-163.736", +"7363.77025,162.099125,-162.099125" + #endregion data + ); + } + private ElectricMotorFullLoadCurve GetFullLoadCurve(int count) + { + var inputData = GetFullLoadCurveData(); + return ElectricFullLoadCurveReader.Create(inputData, count); + } + private TableData GetEfficiencyMapData() + { + return InputDataHelper.InputDataAsTableData( + "n [rpm] , T [Nm] , P_el [kW]", + #region entries + "0, -485, 0.000", +"0, -461, 0.000", +"0, -437, 0.000", +"0, -412, 0.000", +"0, -388, 0.000", +"0, -364, 0.000", +"0, -340, 0.000", +"0, -315, 0.000", +"0, -291, 0.000", +"0, -267, 0.000", +"0, -243, 0.000", +"0, -218, 0.000", +"0, -194, 0.000", +"0, -170, 0.000", +"0, -146, 0.000", +"0, -121, 0.000", +"0, -97, 0.000", +"0, -73, 0.000", +"0, -48, 0.000", +"0, -24, 0.000", +"0, -5, 0.000", +"0, 5, 0.000", +"0, 24, 0.000", +"0, 48, 0.000", +"0, 73, 0.000", +"0, 97, 0.000", +"0, 121, 0.000", +"0, 146, 0.000", +"0, 170, 0.000", +"0, 194, 0.000", +"0, 218, 0.000", +"0, 243, 0.000", +"0, 267, 0.000", +"0, 291, 0.000", +"0, 315, 0.000", +"0, 340, 0.000", +"0, 364, 0.000", +"0, 388, 0.000", +"0, 412, 0.000", +"0, 437, 0.000", +"0, 461, 0.000", +"0, 485, 0.000", +"49, -485, 0.000", +"49, -461, 0.000", +"49, -437, 0.000", +"49, -412, 0.000", +"49, -388, 0.000", +"49, -364, 0.000", +"49, -340, -0.045", +"49, -315, -0.111", +"49, -291, -0.166", +"49, -267, -0.211", +"49, -243, -0.245", +"49, -218, -0.268", +"49, -194, -0.280", +"49, -170, -0.281", +"49, -146, -0.272", +"49, -121, -0.252", +"49, -97, -0.221", +"49, -73, -0.179", +"49, -48, -0.126", +"49, -24, -0.062", +"49, -5, -0.004", +"49, 5, 0.048", +"49, 24, 0.193", +"49, 48, 0.384", +"49, 73, 0.587", +"49, 97, 0.802", +"49, 121, 1.029", +"49, 146, 1.267", +"49, 170, 1.518", +"49, 194, 1.779", +"49, 218, 2.053", +"49, 243, 2.338", +"49, 267, 2.636", +"49, 291, 2.944", +"49, 315, 3.265", +"49, 340, 3.597", +"49, 364, 3.941", +"49, 388, 4.297", +"49, 412, 4.665", +"49, 437, 5.044", +"49, 461, 5.435", +"49, 485, 5.838", +"492, -485, -20.733", +"492, -461, -19.800", +"492, -437, -18.856", +"492, -412, -17.900", +"492, -388, -16.932", +"492, -364, -15.953", +"492, -340, -14.962", +"492, -315, -13.959", +"492, -291, -12.945", +"492, -267, -11.919", +"492, -243, -10.881", +"492, -218, -9.832", +"492, -194, -8.771", +"492, -170, -7.699", +"492, -146, -6.614", +"492, -121, -5.519", +"492, -97, -4.411", +"492, -73, -3.292", +"492, -48, -2.161", +"492, -24, -1.019", +"492, -5, -0.097", +"492, 5, 0.416", +"492, 24, 1.498", +"492, 48, 2.863", +"492, 73, 4.240", +"492, 97, 5.630", +"492, 121, 7.033", +"492, 146, 8.448", +"492, 170, 9.876", +"492, 194, 11.316", +"492, 218, 12.769", +"492, 243, 14.235", +"492, 267, 15.713", +"492, 291, 17.204", +"492, 315, 18.708", +"492, 340, 20.224", +"492, 364, 21.753", +"492, 388, 23.294", +"492, 412, 24.848", +"492, 437, 26.415", +"492, 461, 27.994", +"492, 485, 29.586", +"984, -485, -44.101", +"984, -461, -42.013", +"984, -437, -39.910", +"984, -412, -37.794", +"984, -388, -35.664", +"984, -364, -33.520", +"984, -340, -31.362", +"984, -315, -29.190", +"984, -291, -27.004", +"984, -267, -24.805", +"984, -243, -22.591", +"984, -218, -20.363", +"984, -194, -18.122", +"984, -170, -15.867", +"984, -146, -13.597", +"984, -121, -11.314", +"984, -97, -9.017", +"984, -73, -6.706", +"984, -48, -4.381", +"984, -24, -2.042", +"984, -5, -0.161", +"984, 5, 0.867", +"984, 24, 2.993", +"984, 48, 5.663", +"984, 73, 8.349", +"984, 97, 11.049", +"984, 121, 13.765", +"984, 146, 16.496", +"984, 170, 19.242", +"984, 194, 22.003", +"984, 218, 24.779", +"984, 243, 27.571", +"984, 267, 30.377", +"984, 291, 33.198", +"984, 315, 36.035", +"984, 340, 38.887", +"984, 364, 41.754", +"984, 388, 44.635", +"984, 412, 47.532", +"984, 437, 50.445", +"984, 461, 53.372", +"984, 485, 56.314", +"1477, -485, -67.122", +"1477, -461, -63.906", +"1477, -437, -60.673", +"1477, -412, -57.422", +"1477, -388, -54.153", +"1477, -364, -50.867", +"1477, -340, -47.563", +"1477, -315, -44.241", +"1477, -291, -40.902", +"1477, -267, -37.545", +"1477, -243, -34.170", +"1477, -218, -30.778", +"1477, -194, -27.368", +"1477, -170, -23.941", +"1477, -146, -20.496", +"1477, -121, -17.033", +"1477, -97, -13.552", +"1477, -73, -10.054", +"1477, -48, -6.539", +"1477, -24, -3.005", +"1477, -5, -0.166", +"1477, 5, 1.383", +"1477, 24, 4.552", +"1477, 48, 8.530", +"1477, 73, 12.528", +"1477, 97, 16.545", +"1477, 121, 20.581", +"1477, 146, 24.636", +"1477, 170, 28.710", +"1477, 194, 32.804", +"1477, 218, 36.916", +"1477, 243, 41.048", +"1477, 267, 45.199", +"1477, 291, 49.369", +"1477, 315, 53.558", +"1477, 340, 57.766", +"1477, 364, 61.994", +"1477, 388, 66.240", +"1477, 412, 70.506", +"1477, 437, 74.791", +"1477, 461, 79.095", +"1477, 485, 83.418", +"1969, -485, -89.780", +"1969, -461, -85.464", +"1969, -437, -81.126", +"1969, -412, -76.766", +"1969, -388, -72.382", +"1969, -364, -67.976", +"1969, -340, -63.546", +"1969, -315, -59.094", +"1969, -291, -54.620", +"1969, -267, -50.122", +"1969, -243, -45.602", +"1969, -218, -41.058", +"1969, -194, -36.492", +"1969, -170, -31.904", +"1969, -146, -27.292", +"1969, -121, -22.658", +"1969, -97, -18.000", +"1969, -73, -13.320", +"1969, -48, -8.618", +"1969, -24, -3.892", +"1969, -5, -0.095", +"1969, 5, 1.980", +"1969, 24, 6.193", +"1969, 48, 11.483", +"1969, 73, 16.796", +"1969, 97, 22.135", +"1969, 121, 27.498", +"1969, 146, 32.886", +"1969, 170, 38.299", +"1969, 194, 43.736", +"1969, 218, 49.199", +"1969, 243, 54.686", +"1969, 267, 60.197", +"1969, 291, 65.734", +"1969, 315, 71.295", +"1969, 340, 76.881", +"1969, 364, 82.492", +"1969, 388, 88.127", +"1969, 412, 93.787", +"1969, 437, 99.472", +"1969, 461, 105.182", +"1969, 485, 110.916", +"2461, -485, -112.056", +"2461, -461, -106.670", +"2461, -437, -101.254", +"2461, -412, -95.808", +"2461, -388, -90.334", +"2461, -364, -84.830", +"2461, -340, -79.296", +"2461, -315, -73.733", +"2461, -291, -68.141", +"2461, -267, -62.519", +"2461, -243, -56.868", +"2461, -218, -51.188", +"2461, -194, -45.478", +"2461, -170, -39.738", +"2461, -146, -33.970", +"2461, -121, -28.172", +"2461, -97, -22.344", +"2461, -73, -16.487", +"2461, -48, -10.601", +"2461, -24, -4.685", +"2461, -5, 0.000", +"2461, 5, 2.679", +"2461, 24, 7.937", +"2461, 48, 14.539", +"2461, 73, 21.173", +"2461, 97, 27.839", +"2461, 121, 34.536", +"2461, 146, 41.266", +"2461, 170, 48.027", +"2461, 194, 54.820", +"2461, 218, 61.646", +"2461, 243, 68.503", +"2461, 267, 75.392", +"2461, 291, 82.313", +"2461, 315, 89.265", +"2461, 340, 96.250", +"2461, 364, 103.267", +"2461, 388, 110.315", +"2461, 412, 117.396", +"2461, 437, 124.508", +"2461, 461, 131.652", +"2461, 485, 138.828", +"2953, -485, -133.934", +"2953, -461, -127.504", +"2953, -437, -121.037", +"2953, -412, -114.532", +"2953, -388, -107.990", +"2953, -364, -101.411", +"2953, -340, -94.794", +"2953, -315, -88.140", +"2953, -291, -81.448", +"2953, -267, -74.719", +"2953, -243, -67.952", +"2953, -218, -61.148", +"2953, -194, -54.306", +"2953, -170, -47.427", +"2953, -146, -40.511", +"2953, -121, -33.557", +"2953, -97, -26.566", +"2953, -73, -19.537", +"2953, -48, -12.471", +"2953, -24, -5.367", +"2953, -5, 0.000", +"2953, 5, 3.497", +"2953, 24, 9.801", +"2953, 48, 17.718", +"2953, 73, 25.676", +"2953, 97, 33.674", +"2953, 121, 41.713", +"2953, 146, 49.793", +"2953, 170, 57.913", +"2953, 194, 66.074", +"2953, 218, 74.275", +"2953, 243, 82.517", +"2953, 267, 90.800", +"2953, 291, 99.123", +"2953, 315, 107.487", +"2953, 340, 115.892", +"2953, 364, 124.337", +"2953, 388, 132.823", +"2953, 412, 141.349", +"2953, 437, 149.916", +"2953, 461, 158.524", +"2953, 485, 167.172", +"3446, -485, -155.396", +"3446, -461, -147.951", +"3446, -437, -140.460", +"3446, -412, -132.921", +"3446, -388, -125.335", +"3446, -364, -117.703", +"3446, -340, -110.023", +"3446, -315, -102.297", +"3446, -291, -94.524", +"3446, -267, -86.703", +"3446, -243, -78.836", +"3446, -218, -70.922", +"3446, -194, -62.961", +"3446, -170, -54.953", +"3446, -146, -46.898", +"3446, -121, -38.797", +"3446, -97, -30.648", +"3446, -73, -22.452", +"3446, -48, -14.210", +"3446, -24, -5.921", +"3446, -5, 0.000", +"3446, 5, 4.454", +"3446, 24, 11.805", +"3446, 48, 21.040", +"3446, 73, 30.325", +"3446, 97, 39.661", +"3446, 121, 49.049", +"3446, 146, 58.487", +"3446, 170, 67.976", +"3446, 194, 77.516", +"3446, 218, 87.107", +"3446, 243, 96.749", +"3446, 267, 106.442", +"3446, 291, 116.185", +"3446, 315, 125.980", +"3446, 340, 135.826", +"3446, 364, 145.722", +"3446, 388, 155.669", +"3446, 412, 165.668", +"3446, 437, 175.717", +"3446, 461, 185.817", +"3446, 485, 195.968", +"3938, -485, -176.425", +"3938, -461, -167.994", +"3938, -437, -159.504", +"3938, -412, -150.956", +"3938, -388, -142.351", +"3938, -364, -133.687", +"3938, -340, -124.966", +"3938, -315, -116.187", +"3938, -291, -107.351", +"3938, -267, -98.456", +"3938, -243, -89.503", +"3938, -218, -80.493", +"3938, -194, -71.425", +"3938, -170, -62.299", +"3938, -146, -53.115", +"3938, -121, -43.873", +"3938, -97, -34.574", +"3938, -73, -25.217", +"3938, -48, -15.801", +"3938, -24, -6.328", +"3938, -5, 0.000", +"3938, 5, 5.568", +"3938, 24, 13.967", +"3938, 48, 24.521", +"3938, 73, 35.138", +"3938, 97, 45.818", +"3938, 121, 56.561", +"3938, 146, 67.366", +"3938, 170, 78.235", +"3938, 194, 89.166", +"3938, 218, 100.159", +"3938, 243, 111.216", +"3938, 267, 122.335", +"3938, 291, 133.517", +"3938, 315, 144.762", +"3938, 340, 156.070", +"3938, 364, 167.440", +"3938, 388, 178.873", +"3938, 412, 190.369", +"3938, 437, 201.927", +"3938, 461, 213.549", +"3938, 485, 225.233", +"4430, -485, -197.004", +"4430, -461, -187.614", +"4430, -437, -178.152", +"4430, -412, -168.621", +"4430, -388, -159.020", +"4430, -364, -149.348", +"4430, -340, -139.606", +"4430, -315, -129.794", +"4430, -291, -119.912", +"4430, -267, -109.959", +"4430, -243, -99.936", +"4430, -218, -89.844", +"4430, -194, -79.680", +"4430, -170, -69.447", +"4430, -146, -59.144", +"4430, -121, -48.770", +"4430, -97, -38.326", +"4430, -73, -27.812", +"4430, -48, -17.228", +"4430, -24, -6.573", +"4430, -5, 0.000", +"4430, 5, 6.859", +"4430, 24, 16.305", +"4430, 48, 28.182", +"4430, 73, 40.135", +"4430, 97, 52.164", +"4430, 121, 64.269", +"4430, 146, 76.450", +"4430, 170, 88.707", +"4430, 194, 101.041", +"4430, 218, 113.451", +"4430, 243, 125.937", +"4430, 267, 138.499", +"4430, 291, 151.138", +"4430, 315, 163.852", +"4430, 340, 176.643", +"4430, 364, 189.510", +"4430, 388, 202.453", +"4430, 412, 215.472", +"4430, 437, 228.567", +"4430, 461, 241.739", +"4430, 485, 254.986", +"4922, -485, -217.116", +"4922, -461, -206.794", +"4922, -437, -196.388", +"4922, -412, -185.899", +"4922, -388, -175.325", +"4922, -364, -164.667", +"4922, -340, -153.925", +"4922, -315, -143.099", +"4922, -291, -132.190", +"4922, -267, -121.196", +"4922, -243, -110.118", +"4922, -218, -98.956", +"4922, -194, -87.710", +"4922, -170, -76.381", +"4922, -146, -64.967", +"4922, -121, -53.469", +"4922, -97, -41.887", +"4922, -73, -30.221", +"4922, -48, -18.472", +"4922, -24, -6.638", +"4922, -5, 0.000", +"4922, 5, 8.344", +"4922, 24, 18.839", +"4922, 48, 32.040", +"4922, 73, 45.333", +"4922, 97, 58.716", +"4922, 121, 72.191", +"4922, 146, 85.757", +"4922, 170, 99.413", +"4922, 194, 113.161", +"4922, 218, 127.001", +"4922, 243, 140.931", +"4922, 267, 154.952", +"4922, 291, 169.065", +"4922, 315, 183.269", +"4922, 340, 197.564", +"4922, 364, 211.950", +"4922, 388, 226.427", +"4922, 412, 240.995", +"4922, 437, 255.655", +"4922, 461, 270.406", +"4922, 485, 285.247", +"5415, -485, -236.743", +"5415, -461, -225.518", +"5415, -437, -214.194", +"5415, -412, -202.771", +"5415, -388, -191.249", +"5415, -364, -179.627", +"5415, -340, -167.906", +"5415, -315, -156.086", +"5415, -291, -144.167", +"5415, -267, -132.149", +"5415, -243, -120.031", +"5415, -218, -107.814", +"5415, -194, -95.497", +"5415, -170, -83.082", +"5415, -146, -70.567", +"5415, -121, -57.953", +"5415, -97, -45.240", +"5415, -73, -32.428", +"5415, -48, -19.516", +"5415, -24, -6.505", +"5415, -5, 0.000", +"5415, 5, 10.043", +"5415, 24, 21.588", +"5415, 48, 36.116", +"5415, 73, 50.751", +"5415, 97, 65.495", +"5415, 121, 80.346", +"5415, 146, 95.305", +"5415, 170, 110.371", +"5415, 194, 125.545", +"5415, 218, 140.827", +"5415, 243, 156.217", +"5415, 267, 171.714", +"5415, 291, 187.319", +"5415, 315, 203.031", +"5415, 340, 218.852", +"5415, 364, 234.779", +"5415, 388, 250.815", +"5415, 412, 266.958", +"5415, 437, 283.209", +"5415, 461, 299.568", +"5415, 485, 316.034", +"5907, -485, -255.867", +"5907, -461, -243.768", +"5907, -437, -231.553", +"5907, -412, -219.222", +"5907, -388, -206.774", +"5907, -364, -194.211", +"5907, -340, -181.532", +"5907, -315, -168.738", +"5907, -291, -155.827", +"5907, -267, -142.800", +"5907, -243, -129.657", +"5907, -218, -116.399", +"5907, -194, -103.024", +"5907, -170, -89.534", +"5907, -146, -75.928", +"5907, -121, -62.205", +"5907, -97, -48.367", +"5907, -73, -34.413", +"5907, -48, -20.343", +"5907, -24, -6.157", +"5907, -5, 0.000", +"5907, 5, 11.974", +"5907, 24, 24.569", +"5907, 48, 40.426", +"5907, 73, 56.409", +"5907, 97, 72.518", +"5907, 121, 88.753", +"5907, 146, 105.113", +"5907, 170, 121.599", +"5907, 194, 138.211", +"5907, 218, 154.949", +"5907, 243, 171.813", +"5907, 267, 188.802", +"5907, 291, 205.917", +"5907, 315, 223.158", +"5907, 340, 240.525", +"5907, 364, 258.017", +"5907, 388, 275.635", +"5907, 412, 293.379", +"5907, 437, 311.249", +"5907, 461, 329.245", +"5907, 485, 347.366", +"6399, -485, -274.473", +"6399, -461, -261.527", +"6399, -437, -248.447", +"6399, -412, -235.232", +"6399, -388, -221.884", +"6399, -364, -208.402", +"6399, -340, -194.786", +"6399, -315, -181.036", +"6399, -291, -167.151", +"6399, -267, -153.133", +"6399, -243, -138.981", +"6399, -218, -124.694", +"6399, -194, -110.274", +"6399, -170, -95.719", +"6399, -146, -81.031", +"6399, -121, -66.208", +"6399, -97, -51.252", +"6399, -73, -36.161", +"6399, -48, -20.936", +"6399, -24, -5.577", +"6399, -5, 0.000", +"6399, 5, 14.156", +"6399, 24, 27.802", +"6399, 48, 44.991", +"6399, 73, 62.325", +"6399, 97, 79.805", +"6399, 121, 97.430", +"6399, 146, 115.201", +"6399, 170, 133.117", +"6399, 194, 151.179", +"6399, 218, 169.386", +"6399, 243, 187.738", +"6399, 267, 206.236", +"6399, 291, 224.879", +"6399, 315, 243.668", +"6399, 340, 262.602", +"6399, 364, 281.682", +"6399, 388, 300.907", +"6399, 412, 320.277", +"6399, 437, 339.793", +"6399, 461, 359.455", +"6399, 485, 379.261", +"6891, -485, -292.541", +"6891, -461, -278.777", +"6891, -437, -264.858", +"6891, -412, -250.787", +"6891, -388, -236.561", +"6891, -364, -222.182", +"6891, -340, -207.650", +"6891, -315, -192.963", +"6891, -291, -178.124", +"6891, -267, -163.130", +"6891, -243, -147.983", +"6891, -218, -132.683", +"6891, -194, -117.228", +"6891, -170, -101.621", +"6891, -146, -85.859", +"6891, -121, -69.944", +"6891, -97, -53.876", +"6891, -73, -37.653", +"6891, -48, -21.278", +"6891, -24, -4.748", +"6891, -5, 0.000", +"6891, 5, 16.608", +"6891, 24, 31.306", +"6891, 48, 49.829", +"6891, 73, 68.518", +"6891, 97, 87.374", +"6891, 121, 106.397", +"6891, 146, 125.587", +"6891, 170, 144.943", +"6891, 194, 164.466", +"6891, 218, 184.155", +"6891, 243, 204.011", +"6891, 267, 224.034", +"6891, 291, 244.223", +"6891, 315, 264.580", +"6891, 340, 285.102", +"6891, 364, 305.792", +"6891, 388, 326.648", +"6891, 412, 347.671", +"6891, 437, 368.860", +"6891, 461, 390.216", +"6891, 485, 411.739", +"7383, -485, -310.056", +"7383, -461, -295.501", +"7383, -437, -280.771", +"7383, -412, -265.867", +"7383, -388, -250.788", +"7383, -364, -235.535", +"7383, -340, -220.106", +"7383, -315, -204.504", +"7383, -291, -188.726", +"7383, -267, -172.775", +"7383, -243, -156.648", +"7383, -218, -140.347", +"7383, -194, -123.871", +"7383, -170, -107.221", +"7383, -146, -90.396", +"7383, -121, -73.397", +"7383, -97, -56.222", +"7383, -73, -38.874", +"7383, -48, -21.350", +"7383, -24, -3.653", +"7383, -5, 0.000", +"7383, 5, 19.348", +"7383, 24, 35.099", +"7383, 48, 54.958", +"7383, 73, 75.007", +"7383, 97, 95.245", +"7383, 121, 115.672", +"7383, 146, 136.289", +"7383, 170, 157.095", +"7383, 194, 178.091", +"7383, 218, 199.276", +"7383, 243, 220.651", +"7383, 267, 242.215", +"7383, 291, 263.969", +"7383, 315, 285.912", +"7383, 340, 308.044", +"7383, 364, 330.366", +"7383, 388, 352.878", +"7383, 412, 375.578", +"7383, 437, 398.469", +"7383, 461, 421.549", +"7383, 485, 444.818", +"7876, -485, -327.000", +"7876, -461, -311.682", +"7876, -437, -296.167", +"7876, -412, -280.456", +"7876, -388, -264.547", +"7876, -364, -248.442", +"7876, -340, -232.139", +"7876, -315, -215.639", +"7876, -291, -198.942", +"7876, -267, -182.048", +"7876, -243, -164.958", +"7876, -218, -147.670", +"7876, -194, -130.185", +"7876, -170, -112.503", +"7876, -146, -94.624", +"7876, -121, -76.548", +"7876, -97, -58.274", +"7876, -73, -39.804", +"7876, -48, -21.137", +"7876, -24, -2.273", +"7876, -5, 0.000", +"7876, 5, 22.396", +"7876, 24, 39.201", +"7876, 48, 60.398", +"7876, 73, 81.810", +"7876, 97, 103.435", +"7876, 121, 125.274", +"7876, 146, 147.327", +"7876, 170, 169.593", +"7876, 194, 192.074", +"7876, 218, 214.768", +"7876, 243, 237.676", +"7876, 267, 260.798", +"7876, 291, 284.134", +"7876, 315, 307.683", +"7876, 340, 331.447", +"7876, 364, 355.424", +"7876, 388, 379.615", +"7876, 412, 404.019", +"7876, 437, 428.638", +"7876, 461, 453.470", +"7876, 485, 478.516", +"8368, -485, -343.355", +"8368, -461, -327.303", +"8368, -437, -311.030", +"8368, -412, -294.536", +"8368, -388, -277.822", +"8368, -364, -260.886", +"8368, -340, -243.730", +"8368, -315, -226.352", +"8368, -291, -208.754", +"8368, -267, -190.935", +"8368, -243, -172.895", +"8368, -218, -154.634", +"8368, -194, -136.152", +"8368, -170, -117.449", +"8368, -146, -98.525", +"8368, -121, -79.380", +"8368, -97, -60.014", +"8368, -73, -40.428", +"8368, -48, -20.620", +"8368, -24, -0.592", +"8368, -5, 0.000", +"8368, 5, 25.770", +"8368, 24, 43.629", +"8368, 48, 66.167", +"8368, 73, 88.946", +"8368, 97, 111.964", +"8368, 121, 135.221", +"8368, 146, 158.719", +"8368, 170, 182.456", +"8368, 194, 206.433", +"8368, 218, 230.649", +"8368, 243, 255.106", +"8368, 267, 279.802", +"8368, 291, 304.738", +"8368, 315, 329.913", +"8368, 340, 355.328", +"8368, 364, 380.983", +"8368, 388, 406.878", +"8368, 412, 433.012", +"8368, 437, 459.386", +"8368, 461, 486.000", +"8368, 485, 512.853", +"8860, -485, -359.104", +"8860, -461, -342.346", +"8860, -437, -325.341", +"8860, -412, -308.091", +"8860, -388, -290.594", +"8860, -364, -272.851", +"8860, -340, -254.862", +"8860, -315, -236.626", +"8860, -291, -218.144", +"8860, -267, -199.416", +"8860, -243, -180.442", +"8860, -218, -161.221", +"8860, -194, -141.755", +"8860, -170, -122.042", +"8860, -146, -102.082", +"8860, -121, -81.877", +"8860, -97, -61.425", +"8860, -73, -40.727", +"8860, -48, -19.783", +"8860, -24, 0.000", +"8860, -5, 0.000", +"8860, 5, 29.489", +"8860, 24, 48.402", +"8860, 48, 72.284", +"8860, 73, 96.433", +"8860, 97, 120.849", +"8860, 121, 145.533", +"8860, 146, 170.484", +"8860, 170, 195.701", +"8860, 194, 221.186", +"8860, 218, 246.939", +"8860, 243, 272.958", +"8860, 267, 299.245", +"8860, 291, 325.798", +"8860, 315, 352.619", +"8860, 340, 379.708", +"8860, 364, 407.063", +"8860, 388, 434.685", +"8860, 412, 462.575", +"8860, 437, 490.732", +"8860, 461, 519.156", +"8860, 485, 547.847", +"9352, -485, -374.230", +"9352, -461, -356.794", +"9352, -437, -339.084", +"9352, -412, -321.102", +"9352, -388, -302.847", +"9352, -364, -284.319", +"9352, -340, -265.517", +"9352, -315, -246.443", +"9352, -291, -227.096", +"9352, -267, -207.475", +"9352, -243, -187.582", +"9352, -218, -167.416", +"9352, -194, -146.976", +"9352, -170, -126.264", +"9352, -146, -105.279", +"9352, -121, -84.021", +"9352, -97, -62.489", +"9352, -73, -40.685", +"9352, -48, -18.608", +"9352, -24, 0.000", +"9352, -5, 0.000", +"9352, 5, 33.571", +"9352, 24, 53.540", +"9352, 48, 78.768", +"9352, 73, 104.291", +"9352, 97, 130.111", +"9352, 121, 156.228", +"9352, 146, 182.640", +"9352, 170, 209.349", +"9352, 194, 236.354", +"9352, 218, 263.655", +"9352, 243, 291.252", +"9352, 267, 319.146", +"9352, 291, 347.335", +"9352, 315, 375.821", +"9352, 340, 404.604", +"9352, 364, 433.682", +"9352, 388, 463.057", +"9352, 412, 492.728", +"9352, 437, 522.695", +"9352, 461, 552.958", +"9352, 485, 583.518", +"9845, -485, -388.716", +"9845, -461, -370.630", +"9845, -437, -352.242", +"9845, -412, -333.553", +"9845, -388, -314.563", +"9845, -364, -295.272", +"9845, -340, -275.680", +"9845, -315, -255.786", +"9845, -291, -235.591", +"9845, -267, -215.095", +"9845, -243, -194.298", +"9845, -218, -173.200", +"9845, -194, -151.800", +"9845, -170, -130.099", +"9845, -146, -108.097", +"9845, -121, -85.794", +"9845, -97, -63.190", +"9845, -73, -40.284", +"9845, -48, -17.077", +"9845, -24, 0.000", +"9845, -5, 0.000", +"9845, 5, 38.036", +"9845, 24, 59.061", +"9845, 48, 85.637", +"9845, 73, 112.539", +"9845, 97, 139.768", +"9845, 121, 167.324", +"9845, 146, 195.207", +"9845, 170, 223.417", +"9845, 194, 251.953", +"9845, 218, 280.816", +"9845, 243, 310.007", +"9845, 267, 339.523", +"9845, 291, 369.367", +"9845, 315, 399.538", +"9845, 340, 430.035", +"9845, 364, 460.859", +"9845, 388, 492.010", +"9845, 412, 523.488", +"9845, 437, 555.293", +"9845, 461, 587.424", +"9845, 485, 619.883" + #endregion data + ).ApplyFactor(ElectricMotorMapReader.Fields.PowerElectrical, 1E3); //Convert from kW to W + } + + private EfficiencyMap GetEfficiencyMap(int count) + { + return ElectricMotorMapReader.Create(GetEfficiencyMapData(), count, ExecutionMode.Declaration); + } + private void SetVelocityDropLookupData(PEVAMTShiftStrategy shiftStrategy) + { + //"StartVelocity [km/h], Gradient [-], EndVelocity [km/h]" + var data = new[] { + new[] { 5.0, -0.0997, 9.061522965237558 }, + new[] { 5.0, -0.0798, 7.76698080079411 }, + new[] { 5.0, -0.0599, 6.46583777913701 }, + new[] { 5.0, -0.0400, 5.1596021788785045 }, + new[] { 5.0, -0.0200, 3.8498121019126907 }, + new[] { 5.0, 0.0000, 2.5380265159468918 }, + new[] { 5.0, 0.0200, 1.2258160477557427 }, + new[] { 5.0, 0.0400, 0.0 }, + new[] { 5.0, 0.0599, 0.0 }, + new[] { 5.0, 0.0798, 0.0 }, + new[] { 5.0, 0.0997, 0.0 }, + new[] { 10.0, -0.0997, 14.807789640888302 }, + new[] { 10.0, -0.0798, 13.474253785811362 }, + new[] { 10.0, -0.0599, 12.133880027250777 }, + new[] { 10.0, -0.0400, 10.788221550084467 }, + new[] { 10.0, -0.0200, 9.438862432338068 }, + new[] { 10.0, 0.0000, 8.087408432114643 }, + new[] { 10.0, 0.0200, 6.735477499784416 }, + new[] { 10.0, 0.0400, 5.384690105076845 }, + new[] { 10.0, 0.0599, 4.036659549786269 }, + new[] { 10.0, 0.0798, 2.6929823705748137 }, + new[] { 10.0, 0.0997, 1.3552289800549435 }, + new[] { 20.0, -0.0997, 25.061542153872097 }, + new[] { 20.0, -0.0798, 23.72002987685605 }, + new[] { 20.0, -0.0599, 22.371630788642932 }, + new[] { 20.0, -0.0400, 21.017907257116025 }, + new[] { 20.0, -0.0200, 19.660452757813403 }, + new[] { 20.0, 0.0000, 18.30088261992287 }, + new[] { 20.0, 0.0200, 16.94082447048767 }, + new[] { 20.0, 0.0400, 15.581908518759507 }, + new[] { 20.0, 0.0599, 14.225757795590708 }, + new[] { 20.0, 0.0798, 12.873978508374211 }, + new[] { 20.0, 0.0997, 11.528150617530041 }, + new[] { 30.000000000000004, -0.0997, 35.091774208140095 }, + new[] { 30.000000000000004, -0.0798, 33.750904327320896 }, + new[] { 30.000000000000004, -0.0599, 32.40315158162777 }, + new[] { 30.000000000000004, -0.0400, 31.050077596965064 }, + new[] { 30.000000000000004, -0.0200, 29.69327509188113 }, + new[] { 30.000000000000004, 0.0000, 28.33435862498606 }, + new[] { 30.000000000000004, 0.0200, 26.974955046566407 }, + new[] { 30.000000000000004, 0.0400, 25.616693776603913 }, + new[] { 30.000000000000004, 0.0599, 24.261197065863925 }, + new[] { 30.000000000000004, 0.0798, 22.91007034016412 }, + new[] { 30.000000000000004, 0.0997, 21.56489279686667 }, + new[] { 40.0, -0.0997, 45.024018797189854 }, + new[] { 40.0, -0.0798, 43.68636622428101 }, + new[] { 40.0, -0.0599, 42.34185052441486 }, + new[] { 40.0, -0.0400, 40.99202962224952 }, + new[] { 40.0, -0.0200, 39.63849244500093 }, + new[] { 40.0, 0.0000, 38.282849690992855 }, + new[] { 40.0, 0.0200, 36.926724305651554 }, + new[] { 40.0, 0.0400, 35.57174178507285 }, + new[] { 40.0, 0.0599, 34.21952045137207 }, + new[] { 40.0, 0.0798, 32.87166183129923 }, + new[] { 40.0, 0.0997, 31.5297412694979 }, + new[] { 50.0, -0.0997, 54.652157586769704 }, + new[] { 50.0, -0.0798, 53.319266704395716 }, + new[] { 50.0, -0.0599, 51.97954186606304 }, + new[] { 50.0, -0.0400, 50.634535516787736 }, + new[] { 50.0, -0.0200, 49.28583097196263 }, + new[] { 50.0, 0.0000, 47.93503321632867 }, + new[] { 50.0, 0.0200, 46.583759417454765 }, + new[] { 50.0, 0.0400, 45.23362925944123 }, + new[] { 50.0, 0.0599, 43.88625525588574 }, + new[] { 50.0, 0.0798, 42.54323315977748 }, + new[] { 50.0, 0.0997, 41.20613261641401 }, + new[] { 60.00000000000001, -0.0997, 64.2503607025971 }, + new[] { 60.00000000000001, -0.0798, 62.91932863058169 }, + new[] { 60.00000000000001, -0.0599, 61.58156853535776 }, + new[] { 60.00000000000001, -0.0400, 60.23862904729555 }, + new[] { 60.00000000000001, -0.0200, 58.89369896300112 }, + new[] { 60.00000000000001, 0.0000, 57.547040626925885 }, + new[] { 60.00000000000001, 0.0200, 56.199911833784675 }, + new[] { 60.00000000000001, 0.0400, 54.85392730356455 }, + new[] { 60.00000000000001, 0.0599, 53.510694584916905 }, + new[] { 60.00000000000001, 0.0798, 52.17180450267632 }, + new[] { 60.00000000000001, 0.0997, 50.83882182989668 }, + new[] { 70.0, -0.0997, 73.78388063954164 }, + new[] { 70.0, -0.0798, 72.45700102808648 }, + new[] { 70.0, -0.0599, 71.12341092304165 }, + new[] { 70.0, -0.0400, 69.78459543842656 }, + new[] { 70.0, -0.0200, 68.44188526693415 }, + new[] { 70.0, 0.0000, 67.09719334997524 }, + new[] { 70.0, 0.0200, 65.75212749798493 }, + new[] { 70.0, 0.0400, 64.40829754257321 }, + new[] { 70.0, 0.0599, 63.06730571969745 }, + new[] { 70.0, 0.0798, 61.73073716025881 }, + new[] { 70.0, 0.0997, 60.40015062055851 }, + new[] { 80.0, -0.0997, 83.25457689135129 }, + new[] { 80.0, -0.0798, 81.93182852399568 }, + new[] { 80.0, -0.0599, 80.60238880559001 }, + new[] { 80.0, -0.0400, 79.2676325992058 }, + new[] { 80.0, -0.0200, 77.92916666616652 }, + new[] { 80.0, 0.0000, 76.58872134590663 }, + new[] { 80.0, 0.0200, 75.24790011046437 }, + new[] { 80.0, 0.0400, 73.90830846424944 }, + new[] { 80.0, 0.0599, 72.57154434889891 }, + new[] { 80.0, 0.0798, 71.23918865436896 }, + new[] { 80.0, 0.0997, 69.91277394305271 }, + }; + var entries = new List<VelocitySpeedGearshiftPreprocessor.Entry>(); + foreach (var d in data) { + entries.Add(new VelocitySpeedGearshiftPreprocessor.Entry() { + StartVelocity = d[0].KMPHtoMeterPerSecond(), + Gradient = d[1].SI<Radian>(), + EndVelocity = d[2].KMPHtoMeterPerSecond(), + }); + } + + shiftStrategy.VelocityDropData.Data = entries.ToArray(); + + } + + } +} + + \ No newline at end of file diff --git a/Testing/UnitTests/Vecto UnitTests/TestCases/Components/GearShiftStrategy/ATShiftStrategyOptimizedTests.cs b/Testing/UnitTests/Vecto UnitTests/TestCases/Components/GearShiftStrategy/ATShiftStrategyOptimizedTests.cs new file mode 100644 index 0000000000000000000000000000000000000000..5ce9fd15e72267a0b797467f3a9cb577992fe81f --- /dev/null +++ b/Testing/UnitTests/Vecto UnitTests/TestCases/Components/GearShiftStrategy/ATShiftStrategyOptimizedTests.cs @@ -0,0 +1,1062 @@ +using System.ComponentModel; +using System.Globalization; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; +using System.Runtime.CompilerServices; +using System.Security.Cryptography; +using Moq; +using NUnit.Framework; +using NUnit.Framework.Internal; +using TUGraz.Vecto.UnitTests.Utils.MockComponents; +using TUGraz.VectoCommon.BusAuxiliaries; +using TUGraz.VectoCommon.InputData; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Configuration; +using TUGraz.VectoCore.InputData.Reader.ComponentData; +using TUGraz.VectoCore.InputData.Reader.DataObjectAdapter.SimulationComponents; +using TUGraz.VectoCore.Models.Connector.Ports; +using TUGraz.VectoCore.Models.Connector.Ports.Impl; +using TUGraz.VectoCore.Models.Declaration; +using TUGraz.VectoCore.Models.Simulation; +using TUGraz.VectoCore.Models.Simulation.Data; +using TUGraz.VectoCore.Models.Simulation.DataBus; +using TUGraz.VectoCore.Models.Simulation.Impl; +using TUGraz.VectoCore.Models.SimulationComponent; +using TUGraz.VectoCore.Models.SimulationComponent.Data; +using TUGraz.VectoCore.Models.SimulationComponent.Data.Engine; +using TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox; +using TUGraz.VectoCore.Models.SimulationComponent.Impl; +using TUGraz.VectoCore.Models.SimulationComponent.Impl.Gearbox; +using TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies; +using TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies.ShiftPolygonCalc; +using TUGraz.VectoCore.OutputData.XML.DeclarationReports.ManufacturerReport.ManufacturerReport_0_9.ManufacturerReportGroupWriter; +using TUGraz.VectoCore.Tests.Utils; +using Assert = NUnit.Framework.Assert; + +namespace TUGraz.Vecto.UnitTests.TestCases.Components.GearShiftStrategy; + +[TestFixture] +public class ATShiftStrategyOptimizedTests +{ + [TestCase(0, 100, 1)] + [TestCase(0, 200, 1)] + [TestCase(5, 100, 1)] + [TestCase(5, 300, 1)] + [TestCase(5, 600, 1)] + [TestCase(15, 100, 3)] + [TestCase(15, 300, 3)] + [TestCase(15, 600, 3)] + [TestCase(40, 100, 6)] + [TestCase(40, 300, 6)] + [TestCase(40, 600, 6)] + [TestCase(70, 100, 6)] + [TestCase(70, 300, 6)] + [TestCase(70, 600, 6)] + public void TestATGearInitialize(double vehicleSpeed, double torque, int expectedGear) + { + var gearRatios = new[] { 3.4, 1.9, 1.42, 1.0, 0.7, 0.62 }; + var vehicleContainer = GetMockVehicleContainer( + speedKmh: vehicleSpeed, + driverBehavior: DrivingBehavior.Accelerating, + gearRatios: gearRatios, + inputData: out _, + runData: out var runData, + simplePt: out _); + + var shiftStrategy = GetShiftStrategyAndGearbox(vehicleContainer, out var gbx, out _); + var angularVelocity = GetAngularVelocityBySpeed(vehicleSpeed, runData); + var response = shiftStrategy.InitGear( + 0.SI<Second>(), + 1.SI<Second>(), + torque.SI<NewtonMeter>(), + angularVelocity); + + Assert.AreEqual(expectedGear, response.Gear); + } + + + + + [TestCase(1, 1, 1000, 1500, 0, Description = "Engage 0-> 1C")] + public void Gearbox_Engage(int gear, int newGear, double tqNm, double nRPM, double speedKmh) + { + var gearRatios = new[] { 6.38, 4.63, 3.44, 2.59, 1.86, 1.35, 1, 0.76 }; + + var vehicleContainer = GetMockVehicleContainer(speedKmh, DrivingBehavior.Accelerating, gearRatios, + inputData: out _, + runData: out var runData, simplePt: out _); + + var shiftStrategy = GetShiftStrategyAndGearbox(vehicleContainer, out var gbx); + var angularVelocity = GetAngularVelocityBySpeed(speedKmh, runData: runData); + + + + var absTime = 0.SI<Second>(); + var dt = 2.SI<Second>(); + + + var expectedN = nRPM.RPMtoRad(); + angularVelocity = expectedN / gearRatios[gear]; + + var initGear = shiftStrategy.InitGear(absTime, dt, 0.SI<NewtonMeter>(), angularVelocity); + SetCurrentGear(gbx, initGear); + + var expectedT = tqNm.SI<NewtonMeter>(); + var torque = expectedT * gearRatios[gear]; + + var shiftRequired = shiftStrategy.ShiftRequired(absTime, dt, torque, angularVelocity, expectedT, expectedN, + new GearshiftPosition((uint)gear), -double.MaxValue.SI<Second>(), new ResponseSuccess(this)); + + Assert.AreEqual(newGear, shiftStrategy.NextGear.Gear); + + var shiftExpected = gear != newGear; //Different Gear + var disengaged = gbx.Object.Disengaged; + shiftExpected = shiftRequired || disengaged; //Gearbox was disengaged + + Assert.AreEqual(shiftExpected, shiftRequired); + } + + [TestCase(2, 1, -1000, 1500, 4, DrivingBehavior.Braking, Description = "_ -> 0: disengage before halting")] + public void Gearbox_Disengange(int gear, int newGear, double tqNm, double nRPM, double speedKmh, + DrivingBehavior driverBehavior) + { + // Assert.Ignore("Work in Progress"); + var gearRatios = new[] { 6.38, 4.63, 3.44, 2.59, 1.86, 1.35, 1, 0.76 }; + + var vehicleContainer = GetMockVehicleContainer(speedKmh, driverBehavior, gearRatios, + inputData: out _, + runData: out var runData, simplePt: out _); + + var shiftStrategy = GetShiftStrategyAndGearbox(vehicleContainer, out var gbx); + var angularVelocity = GetAngularVelocityBySpeed(speedKmh, runData); + + var absTime = 0.SI<Second>(); + var dt = 2.SI<Second>(); + + var initGear = shiftStrategy.InitGear(absTime, dt, 0.SI<NewtonMeter>(), angularVelocity); + SetCurrentGear(gbx, initGear); + + var expectedN = nRPM.RPMtoRad(); + angularVelocity = expectedN / gearRatios[gear]; + + //Called in gbx initialize + //var gearShiftPosition = shiftStrategy.InitGear(absTime, Constants.SimulationSettings.TargetTimeInterval, 1.SI<NewtonMeter>(), + // angularVelocity); + var engagedPosition = shiftStrategy.Engage(absTime, dt, null, null); + Assert.IsTrue(engagedPosition.Engaged); + + // gbx.CurrentState = new ATGearboxState() + // { + // Disengaged = gbx.Disengaged, + // Gear = gbx.Gear, + // }; + + var expectedT = tqNm.SI<NewtonMeter>(); + var torque = expectedT * gearRatios[gear]; + + + var shiftRequired = shiftStrategy.ShiftRequired(absTime, dt, torque, angularVelocity, expectedT, expectedN, + new GearshiftPosition((uint)gear), -double.MaxValue.SI<Second>(), new ResponseSuccess(this)); + + Assert.AreEqual(newGear, shiftStrategy.NextGear.Gear); + + var shiftExpected = gear != newGear; //Different Gear + var disengaged = false; + shiftExpected = shiftRequired || disengaged; //Gearbox was disengaged + + Assert.AreEqual(shiftExpected, shiftRequired); + } + + [TestCase(2, true, 3, true, 100, 1800, 13, Description = "Upshift-TCLocked", TestName="Upshift-TCLocked")] + [TestCase(1, false, 1, true, 100, 1000, 1, Description = "Upshift-TC", TestName = "Upshift-TC")] + [TestCase(2, true, 3, true, 100, 800, 13, Description = "Upshift-TCLocked", TestName = "EarlyUpshift")] + [TestCase(1, false, 1, true, 100, 500, 1, Description = "EarlyUpshift-TC", TestName="EarlyUpshift-TC")] + public void Gearbox_Upshift(int gear, bool tcLocked, int newGear, bool newTcLocked, double tqNm, double nRPM, double speedKmh) + { + // Assert.Ignore("Work in Progress"); + var gearRatios = new[] { 3.4, 1.9, 1.42, 1.0, 0.7, 0.62 }; + + var vehicleContainer = GetMockVehicleContainer( + speedKmh, + DrivingBehavior.Accelerating, + gearRatios, + out var inputData, out var runData, out var simplePt); + + + + var shiftStrategy = GetShiftStrategyAndGearbox(vehicleContainer, out var gbx); + var angularVelocity = GetAngularVelocityBySpeed(speedKmh, runData); + + var absTime = 0.SI<Second>(); + var dt = 2.SI<Second>(); + + var gbxObj = gbx.Object; + // var gbxResponse = gbx.Object.Initialize(0.SI<NewtonMeter>(), angularVelocity); + + var initGear = shiftStrategy.InitGear(absTime, dt, 0.SI<NewtonMeter>(), angularVelocity); + + + Assert.AreEqual((uint)gear, initGear.Gear); + Assert.That(initGear.TorqueConverterLocked, Is.EqualTo(tcLocked)); + + SetCurrentGear(gbx, initGear); + + + // gbx.CurrentState = new ATGearboxState() + // { + // Disengaged = gbx.Disengaged, + // Gear = gbx.Gear, + // }; + + + var inAngularVelocity = nRPM.RPMtoRad(); + var outAngularVelocity = inAngularVelocity / gearRatios[gear]; + + var inTorque = tqNm.SI<NewtonMeter>(); + var outTortque = inTorque * gearRatios[gear]; + + var response = new ResponseSuccess(this); + response.Engine.DynamicFullLoadTorque = 50.SI<NewtonMeter>(); + response.Engine.EngineSpeed = inAngularVelocity; + response.Engine.TorqueOutDemand = inTorque; + + + runData.GearshiftParameters.RatingFactorCurrentGear = 1.1; + + + var shiftRequired = shiftStrategy.ShiftRequired(absTime, dt, outTortque, outAngularVelocity, inTorque, inAngularVelocity, initGear, -double.MaxValue.SI<Second>(), response); + + + Assert.That(shiftStrategy.NextGear.Gear, Is.EqualTo(newGear)); + Assert.That(shiftStrategy.NextGear.TorqueConverterLocked ?? true, Is.EqualTo(newTcLocked)); + + var shiftExpected = gear != newGear; //Different Gear + + shiftExpected = shiftRequired || gbx.Object.Disengaged; //Gearbox was disengaged + + Assert.AreEqual(shiftExpected, shiftRequired); + } + + private void SetCurrentGear(Mock<IAPTGearbox> gbx, GearshiftPosition initGear) + { + gbx.Setup(g => g.Gear).Returns(initGear); + gbx.SetupGet(g => g.TorqueConverterLocked).Returns(initGear.TorqueConverterLocked ?? false); + } + + [TestCase(2, true, 3, true, 100, 1800, 13, Description = "Upshift-TCLocked")] + [TestCase(1, false, 1, true, 100, 1000, 1, Description = "Upshift-TC")] + public void Gearbox_EarlyUpshift(int gear, bool tcLocked, int newGear, bool newTcLocked, double tqNm, double nRPM, double speedKmh) + { + var gearRatios = new[] { 3.4, 1.9, 1.42, 1.0, 0.7, 0.62 }; + + var vehicleContainer = GetMockVehicleContainer( + speedKmh, + DrivingBehavior.Accelerating, + gearRatios, + out var inputData, out var runData, out _); + + + var shiftStrategy = GetShiftStrategyAndGearbox(vehicleContainer, out var gbx); + var angularVelocity = GetAngularVelocityBySpeed(speedKmh, runData); + + var absTime = 0.SI<Second>(); + var dt = 2.SI<Second>(); + var initGear = shiftStrategy.InitGear(absTime, dt, 0.SI<NewtonMeter>(), angularVelocity); + SetCurrentGear(gbx, initGear); + + Assert.AreEqual((uint)gear, initGear.Gear); + Assert.That(initGear.TorqueConverterLocked, Is.EqualTo(tcLocked)); + + + + + var inAngularVelocity = nRPM.RPMtoRad(); + var outAngularVelocity = inAngularVelocity / gearRatios[gear]; + + var inTorque = tqNm.SI<NewtonMeter>(); + var outTortque = inTorque * gearRatios[gear]; + + var shiftRequired = shiftStrategy.ShiftRequired(absTime, dt, outTortque, outAngularVelocity, inTorque, inAngularVelocity, initGear, -double.MaxValue.SI<Second>(), new ResponseSuccess(this)); + + + Assert.That(shiftStrategy.NextGear.Gear, Is.EqualTo(newGear)); + Assert.That(shiftStrategy.NextGear.TorqueConverterLocked ?? true, Is.EqualTo(newTcLocked)); + + var shiftExpected = gear != newGear; //Different Gear + shiftExpected = shiftRequired || gbx.Object.Disengaged; //Gearbox was disengaged + + Assert.AreEqual(shiftExpected, shiftRequired); + } + +// + [TestCase(1, false, 2, false, 100, 1000, 1, Description = "Upshift-TC")] + public void Gearbox_Upshift_TC_TC(int gear, bool tcLocked, int newGear, bool newTcLocked, double tqNm, double nRPM, double speedKmh) + { + var gearRatios = new[] { 3.4, 1.3, 1.1, 1.0, 0.7, 0.62 }; + + var vehicleContainer = GetMockVehicleContainer( + speedKmh, + DrivingBehavior.Accelerating, + gearRatios, + out var inputData, out var runData, out _); + + + var shiftStrategy = GetShiftStrategyAndGearbox(vehicleContainer, out var gbx); + var angularVelocity = GetAngularVelocityBySpeed(speedKmh, runData); + + + var absTime = 0.SI<Second>(); + var dt = 2.SI<Second>(); + + Assert.That(runData.GearboxData.GearList.First(p => p.Gear == 2).TorqueConverterLocked, Is.False, "Expected 2nd gear with TC"); + var initGear = shiftStrategy.InitGear(absTime, dt, 0.SI<NewtonMeter>(), angularVelocity); + SetCurrentGear(gbx, initGear); + + + + var inAngularVelocity = nRPM.RPMtoRad(); + var outAngularVelocity = inAngularVelocity / gearRatios[gear]; + + var inTorque = tqNm.SI<NewtonMeter>(); + var outTortque = inTorque * gearRatios[gear]; + + var response = new ResponseSuccess(this); + response.Engine.EngineSpeed = inAngularVelocity; + response.Engine.TorqueOutDemand = inTorque; + + + var shiftRequired = shiftStrategy.ShiftRequired(absTime, dt, outTortque, outAngularVelocity, inTorque, inAngularVelocity, initGear, -double.MaxValue.SI<Second>(), response); + + + Assert.That(shiftStrategy.NextGear.Gear, Is.EqualTo(newGear)); + Assert.That(shiftStrategy.NextGear.TorqueConverterLocked ?? true, Is.EqualTo(newTcLocked)); + + var shiftExpected = gear != newGear; //Different Gear + shiftExpected = shiftRequired || gbx.Object.Disengaged; //Gearbox was disengaged + + Assert.AreEqual(shiftExpected, shiftRequired); + } +// +// +// +// + [TestCase(3, true, 2, true, 900, 600, 15, Description = "Downshift", TestName="Gearbox_DownShift_1")] + public void Gearbox_Downshift(int gear, bool tcLocked, int newGear, bool newTcLocked, double tqNm, double nRPM, double speedKmh) + { + // Assert.Ignore("Work in Progress"); + + var gearRatios = new[] { 3.4, 1.9, 1.42, 1.0, 0.7, 0.62 }; + + var vehicleContainer = GetMockVehicleContainer( + speedKmh, + DrivingBehavior.Accelerating, + gearRatios, + out var inputData, + out var runData, + out var simplePt); + + vehicleContainer.Setup(v => v.DriverInfo.DrivingAction).Returns(DrivingAction.Accelerate); + + var shiftStrategy = GetShiftStrategyAndGearbox(vehicleContainer, out var gbx); + var angularVelocity = GetAngularVelocityBySpeed(speedKmh, runData); + + + var absTime = 0.SI<Second>(); + var dt = 2.SI<Second>(); + + var initGear = shiftStrategy.InitGear(absTime, dt, 0.SI<NewtonMeter>(), angularVelocity); + + Assert.AreEqual((uint)gear, initGear.Gear); + Assert.That(initGear.TorqueConverterLocked, Is.EqualTo(tcLocked)); + + + + + var inAngularVelocity = nRPM.RPMtoRad(); + var outAngularVelocity = inAngularVelocity / gearRatios[gear]; + + var inTorque = tqNm.SI<NewtonMeter>(); + var outTortque = inTorque * gearRatios[gear]; + + var response = new ResponseSuccess(this); + response.Engine.EngineSpeed = inAngularVelocity; + response.Engine.TorqueOutDemand = inTorque; + + + var mockPort = new Mock<ITnOutPort>(); + + simplePt.Setup(s => s.GearboxOutPort).Returns(mockPort.Object); + mockPort.Setup(p => p.Request( + It.IsAny<Second>(), + It.IsAny<Second>(), + It.IsAny<NewtonMeter>(), + It.IsAny<PerSecond>(), + true + )).Returns((Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, bool dryRun) => { + var response = new ResponseDryRun(this); + response.Engine.PowerRequest = outTorque * outAngularVelocity; + return response; + }); + // + // + // + // + // var shiftRequired = shiftStrategy.ShiftRequired(absTime, dt, outTortque, outAngularVelocity, inTorque, inAngularVelocity, gbx.Gear, -double.MaxValue.SI<Second>(), response); + // + // + // Assert.That(shiftStrategy.NextGear.Gear, Is.EqualTo(newGear)); + // Assert.That(shiftStrategy.NextGear.TorqueConverterLocked ?? true, Is.EqualTo(newTcLocked)); + // + // var shiftExpected = gear != newGear; //Different Gear + // var disengaged = false; //gbx.Disengaged; + // shiftExpected = shiftRequired || disengaged; //Gearbox was disengaged + // + // Assert.AreEqual(shiftExpected, shiftRequired); + } +// + [TestCase(3, true, 2, true, 200, 700, 15, Description = "Downshift_3", TestName = "Gearbox_DownShift_3")] + public void Gearbox_Downshift_2(int gear, bool tcLocked, int newGear, bool newTcLocked, double tqNm, double nRPM, + double speedKmh) + { + var gearRatios = new[] { 3.4, 1.9, 1.42, 1.0, 0.7, 0.62 }; + + var vehicleContainer = GetMockVehicleContainer( + speedKmh, + DrivingBehavior.Accelerating, + gearRatios, + out var inputData, + out var runData, + out var simplePt); + + vehicleContainer.Setup(v => v.DriverInfo.DrivingAction).Returns(DrivingAction.Accelerate); + + // Condition from ATShiftStrategy + //if (DataBus.VehicleInfo.VehicleSpeed < DataBus.DrivingCycleInfo.CycleData.LeftSample.VehicleTargetSpeed - 10.KMPHtoMeterPerSecond() && + // DataBus.DriverInfo.DriverAcceleration < 0.SI<MeterPerSquareSecond>()) + vehicleContainer.Setup(v => v.DrivingCycleInfo.CycleData).Returns(new CycleData() { + LeftSample = new DrivingCycleData.DrivingCycleEntry() { + VehicleTargetSpeed = 30.KMPHtoMeterPerSecond() + } + }); + + vehicleContainer.Setup(v => v.DriverInfo.DriverAcceleration).Returns(-0.1.SI<MeterPerSquareSecond>()); + + + runData.EngineData.Inertia = 1.SI<KilogramSquareMeter>(); + var shiftStrategy = GetShiftStrategyAndGearbox(vehicleContainer, out var gbx, out var gbxNextComponent); + + var angularVelocity = GetAngularVelocityBySpeed(speedKmh, runData); + + + + var absTime = 0.SI<Second>(); + var dt = 2.SI<Second>(); + var initGear = shiftStrategy.InitGear(absTime, dt, 0.SI<NewtonMeter>(), angularVelocity); + SetCurrentGear(gbx, initGear); + + + Assert.AreEqual((uint)gear, initGear.Gear); + Assert.That(initGear.TorqueConverterLocked, Is.EqualTo(tcLocked)); + + + var dryRunResponse = new ResponseDryRun(this); + dryRunResponse.Engine.EngineSpeed = + vehicleContainer.Object.EngineInfo.EngineN95hSpeed - 1.SI<PerSecond>(); + dryRunResponse.DeltaFullLoad = 40_000.SI<Watt>(); + + // gbx.Setup(g => g) + var testPt = + vehicleContainer.Object.SimplePowertrainBuilder.CreateTestPowertrain(vehicleContainer.Object, false); + + var mockGb = Mock.Get(testPt.Gearbox); + mockGb.Setup(g => g.Request(It.IsAny<Second>(), It.IsAny<Second>(), It.IsAny<NewtonMeter>(), + It.IsAny<PerSecond>(), true)).Returns(dryRunResponse); + + + var inAngularVelocity = nRPM.RPMtoRad(); + var outAngularVelocity = inAngularVelocity / gearRatios[gear]; + + var inTorque = tqNm.SI<NewtonMeter>(); + var outTortque = inTorque * gearRatios[gear]; + + var shiftRequired = shiftStrategy.ShiftRequired(absTime, + dt, + outTortque, outAngularVelocity, inTorque, inAngularVelocity, initGear, -double.MaxValue.SI<Second>(), new ResponseSuccess(this)); + + + Assert.That(shiftStrategy.NextGear.Gear, Is.EqualTo(newGear)); + Assert.That(shiftStrategy.NextGear.TorqueConverterLocked ?? true, Is.EqualTo(newTcLocked)); + + var shiftExpected = gear != newGear; //Different Gear + shiftExpected = shiftRequired || gbx.Object.Disengaged; //Gearbox was disengaged + + Assert.AreEqual(shiftExpected, shiftRequired); + } + + // [TestCase(3, true, 2, true, 1700, 700, 15, Description = "Downshift", TestName = "Gearbox_Early_DownShift_1")] + [TestCase(6, true, 5, true, -100, 700, 45, Description = "Downshift", TestName = "Gearbox_Early_DownShift_1")] + public void Gearbox_Early_Downshift(int gear, bool tcLocked, int newGear, bool newTcLocked, double tqNm, double nRPM, double speedKmh) + { + var gearRatios = new[] { 3.4, 1.9, 1.42, 1.0, 0.7, 0.62 }; + + var vehicleContainer = GetMockVehicleContainer( + speedKmh, + DrivingBehavior.Accelerating, + gearRatios, + out var inputData, out var runData, out var simplePt); + + vehicleContainer.Setup(v => v.DriverInfo.DrivingAction).Returns(DrivingAction.Accelerate); + + var shiftStrategy = GetShiftStrategyAndGearbox(vehicleContainer, out var gbx); + var angularVelocity = GetAngularVelocityBySpeed(speedKmh, runData); + + + + var absTime = 0.SI<Second>(); + var dt = 2.SI<Second>(); + var initGear = shiftStrategy.InitGear(absTime, dt, 0.SI<NewtonMeter>(), angularVelocity); + SetCurrentGear(gbx, initGear); + + Assert.AreEqual((uint)gear, initGear.Gear); + Assert.That(initGear.TorqueConverterLocked, Is.EqualTo(tcLocked)); + + var gearIdx = gear - 1; + var inAngularVelocity = nRPM.RPMtoRad(); + var outAngularVelocity = inAngularVelocity / gearRatios[gearIdx]; + + var inTorque = tqNm.SI<NewtonMeter>(); + var outTortque = inTorque * gearRatios[gearIdx]; + + var response = new ResponseSuccess(this); + response.Engine.EngineSpeed = inAngularVelocity; + response.Engine.TorqueOutDemand = inTorque; + + + var mockPort = new Mock<ITnOutPort>(); + + // simplePt.Setup(s => s.GearboxOutPort).Returns(mockPort.Object); + // mockPort.Setup(p => p.Request( + // It.IsAny<Second>(), + // It.IsAny<Second>(), + // It.IsAny<NewtonMeter>(), + // It.IsAny<PerSecond>(), + // true + // )).Returns((Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, bool dryRun) => { + // var response = new ResponseDryRun(this); + // response.Engine.PowerRequest = outTorque * outAngularVelocity; + // return response; + // }); + + + runData.GearshiftParameters.RatingFactorCurrentGear = 2; + + var shiftRequired = shiftStrategy.ShiftRequired(absTime, + dt, + outTortque, + outAngularVelocity, + inTorque, + inAngularVelocity, + initGear, -double.MaxValue.SI<Second>(), response); + + + Assert.That(shiftStrategy.NextGear.Gear, Is.EqualTo(newGear)); + Assert.That(shiftStrategy.NextGear.TorqueConverterLocked ?? true, Is.EqualTo(newTcLocked)); + + var shiftExpected = gear != newGear; //Different Gear + shiftRequired = shiftRequired || gbx.Object.Disengaged; //Gearbox was disengaged + + Assert.AreEqual(shiftExpected, shiftRequired); + } + + private Mock<IVehicleContainer> GetMockVehicleContainer(double speedKmh, DrivingBehavior driverBehavior, + double[] gearRatios, + out Mock<IVehicleDeclarationInputData> inputData, out VectoRunData runData, + out Mock<ISimpleVehicleContainer> simplePt) + { + var vehicleContainer = new Mock<IVehicleContainer>(); + + inputData = GetMockInputData(gearRatios); + runData = GetDummyVectoRunData(inputData.Object); + + vehicleContainer.Setup(c => c.RunData).Returns(runData); + + + //Testpowertrain + var testPowertrain = GetMockTestPowertrain( + runData, + out simplePt); + + vehicleContainer.Setup(c => c.SimplePowertrainBuilder.CreateTestPowertrain(It.IsAny<IVehicleContainer>(), + It.IsAny<bool>())).Returns(testPowertrain.Object); + + //VehicleInfo + vehicleContainer.Setup(c => c.VehicleInfo) + .Returns(GetVehicleInfo(speedKmh.KMPHtoMeterPerSecond()).Object); + + //EngineInfo + vehicleContainer.Setup(c => c.EngineInfo).Returns(GetEngineInfo(vehicleContainer, runData)); + + //AxleGearInfo + var axleGearInfo = new Mock<IAxlegearInfo>(); + vehicleContainer.Setup(c => c.AxlegearInfo).Returns(axleGearInfo.Object); + axleGearInfo.Setup(a => a.AxlegearLoss()).Returns(0.SI<Watt>()); + + //WheelsInfo + var wi = new Mock<IWheelsInfo>(); + vehicleContainer.Setup(c => c.WheelsInfo).Returns(wi.Object); + wi.Setup(w => w.ReducedMassWheels).Returns(0.SI<Kilogram>()); + + //Cycle Info + var cycleInfo = new Mock<IDrivingCycleInfo>(); + vehicleContainer.Setup(c => c.DrivingCycleInfo).Returns(cycleInfo.Object); + cycleInfo.Setup(c => c.CycleData).Returns( + GetCycleData()); + cycleInfo.Setup(c => c.RoadGradient).Returns(0.SI<Radian>()); + + + cycleInfo.Setup(c => c.CycleLookAhead(It.IsAny<Meter>())).Returns(new DrivingCycleData.DrivingCycleEntry() { + Altitude = 0.SI<Meter>() + }); + cycleInfo.Setup(c => c.Altitude).Returns(0.SI<Meter>()); + + //DriverINfo + vehicleContainer.Setup(v => v.DriverInfo.DriverBehavior).Returns(driverBehavior); + var acc = 0.SI<MeterPerSquareSecond>(); + switch (driverBehavior) { + case DrivingBehavior.Accelerating: + acc = 1.SI<MeterPerSquareSecond>(); + break; + case DrivingBehavior.Braking: + acc = -1.SI<MeterPerSquareSecond>(); + break; + case DrivingBehavior.Halted: + acc = 0.SI<MeterPerSquareSecond>(); + break; + default: + throw new ArgumentOutOfRangeException(); + } + + + + + + vehicleContainer.Setup(v => v.DriverInfo.DriverAcceleration).Returns(acc); + return vehicleContainer; + } + + private IEngineInfo GetEngineInfo(Mock<IVehicleContainer> vehicleContainer, VectoRunData runData) + { + //EngineInfo + var engineInfo = new Mock<IEngineInfo>(); + vehicleContainer.Setup(c => c.EngineInfo).Returns(engineInfo.Object); + engineInfo.Setup(e => e.EngineIdleSpeed).Returns(runData.EngineData.IdleSpeed); + engineInfo.Setup(e => e.EngineRatedSpeed).Returns(runData.EngineData.FullLoadCurves.First().Value.RatedSpeed); + + engineInfo.Setup(e => e.EngineSpeed).Returns(1400.RPMtoRad()); + engineInfo.Setup(e => e.EngineN95hSpeed).Returns + (runData.EngineData.FullLoadCurves.First().Value.N95hSpeed); + engineInfo.Setup(e => e.EngineN80hSpeed).Returns( + runData.EngineData.FullLoadCurves.First().Value.N80hSpeed); + engineInfo.Setup(e => e.EngineStationaryFullPower(It.IsAny<PerSecond>())).Returns((PerSecond n) => + runData.EngineData.FullLoadCurves[0].FullLoadStationaryPower(n)); + return engineInfo.Object; + } + + private CycleData GetCycleData() + { + return new CycleData() { + LeftSample = new DrivingCycleData.DrivingCycleEntry() { + PTOActive = PTOActivity.Inactive, + VehicleTargetSpeed = 10.KMPHtoMeterPerSecond() + } + }; + } + + private Mock<IVehicleInfo> GetVehicleInfo(MeterPerSecond speed) + { + var vehicleInfo = new Mock<IVehicleInfo>(); + vehicleInfo.Setup(v => v.VehicleSpeed).Returns(speed); + vehicleInfo.Setup(v => v.AirDragResistance(It.IsAny<MeterPerSecond>(), It.IsAny<MeterPerSecond>())) + .Returns(0.SI<Newton>()); + vehicleInfo.Setup(v => v.RollingResistance(It.IsAny<Radian>())).Returns(0.SI<Newton>()); + vehicleInfo.Setup(v => v.SlopeResistance(It.IsAny<Radian>())).Returns(0.SI<Newton>()); + vehicleInfo.Setup(v => v.TotalMass).Returns(12000.SI<Kilogram>()); + return vehicleInfo; + } + + private Mock<ITestPowertrain> GetMockTestPowertrain(VectoRunData runData, + out Mock<ISimpleVehicleContainer> simpleContainer) + { + var testPt = new Mock<ITestPowertrain>(); + simpleContainer = GetSimplePowertrain(runData, + out var testGearbox); + + + + testPt.Setup(t => t.Container).Returns(simpleContainer.Object); + testPt.Setup(t => t.Gearbox).Returns(testGearbox.Object); + + //Vehicle + var vehicle = new Mock<ITestPowertrainVehicle>(); + vehicle.Setup(v => v.Initialize( + It.IsAny<MeterPerSecond>(), + It.IsAny<Radian>())).Returns(new ResponseSuccess(this)); + testPt.Setup(t => t.Vehicle).Returns(vehicle.Object); + + + return testPt; + } + + private Mock<IVehicleDeclarationInputData> GetMockInputData(double[]? gearRatios) + { + var input = new Mock<IVehicleDeclarationInputData>(); + var components = new Mock<IVehicleComponentsDeclaration>(); + input.Setup(i => i.Components).Returns(components.Object); + var gbx = new Mock<IGearboxDeclarationInputData>(); + var tc = new Mock<ITorqueConverterDeclarationInputData>(); + + components.Setup(c => c.GearboxInputData).Returns(gbx.Object); + components.Setup(c => c.TorqueConverterInputData).Returns(tc.Object); + gearRatios = gearRatios ?? new double[] { }; + var header = "Input Speed [rpm],Input Torque [Nm],Torque Loss [Nm]"; + var efficiency = 0.98; + var data = new List<string>(); + + foreach (var speed in new[] { 0, 10000 }) { + foreach (var tq in new[] { 1e5, -1e5, 0 }) { + data.Add(FormattableString.Invariant($"{speed:f2}, {tq:f2}, {(1 - efficiency) * Math.Abs(tq)}")); + } + } + + var lossmap = InputDataHelper.InputDataAsTableData(header, data.ToArray()); + //lossmap.Columns + var gears = gearRatios.Select((x, idx) => { + var gear = new Mock<ITransmissionInputData>(); + gear.Setup(g => g.Ratio).Returns(x); + gear.Setup(g => g.Gear).Returns(idx + 1); + //gear.Setup(g => g.Efficiency).Returns(0.98); + gear.Setup(g => g.LossMap).Returns(lossmap); + gear.Setup(g => g.MaxInputSpeed).Returns(2000.RPMtoRad()); + return gear.Object; + }).ToList(); + gbx.Setup(g => g.Type).Returns(GearboxType.ATSerial); + gbx.Setup(g => g.Gears).Returns(gears); + + var tcData = InputDataHelper.InputDataAsTableData(TcHeader, TcData); + tc.Setup(t => t.TCData).Returns(tcData); + return input; + } + + private static VectoRunData GetDummyVectoRunData(IVehicleDeclarationInputData inputData) + { + var nrOfGears = inputData.Components.GearboxInputData.Gears.Count; + var fldData = InputDataHelper.InputDataAsTableData(EngineFldHeader, EngineFldData); + var fld = FullLoadCurveReader.Create(fldData); + + // create gearbox data + var tcDataAdapter = new TorqueConverterDataAdapter(); + + // fuel data + var fuelData = new CombustionEngineFuelData() { + ConsumptionMap = FuelConsumptionMapReader.Create( + InputDataHelper.InputDataAsTableData( + "engine speed [rpm] ,torque [Nm] ,fuel consumption [g/h] ,whr power electrical [W]", + "500,-131,0,0", + "500,95.6,1814.959,0", + "500,573.6,9771.095,0", + "2453,-209.12,0,0", + "2453,764.8,39097.94,0" + )), + FuelData = DeclarationData.FuelData.Lookup(FuelType.DieselCI), + }; + + var runData = new VectoRunData() { + VehicleData = new VehicleData() { + DynamicTyreRadius = 0.465.SI<Meter>(), + GrossVehicleMass = 12_000.SI<Kilogram>(), + CurbMass = 10_000.SI<Kilogram>(), + }, + EngineData = new CombustionEngineData() { + Inertia = 0.SI<KilogramSquareMeter>(), + FullLoadCurves = new Dictionary<uint, EngineFullLoadCurve>(), + IdleSpeed = 600.RPMtoRad(), + RatedSpeedDeclared = 2000.RPMtoRad(), + Fuels = new List<CombustionEngineFuelData>() { + fuelData, + } + }, + Cycle = new DrivingCycleData() { + CycleType = CycleType.DistanceBased + } + }; + for (uint i = 0; i <= nrOfGears; i++) { + runData.EngineData.FullLoadCurves[i] = fld; + } + + var gbxDataAdapter = new GearboxDataAdapter(tcDataAdapter); + var gbxTypes = new[] { + GearboxType.ATSerial, GearboxType.ATPowerSplit + }; + + var gearboxData = gbxDataAdapter.CreateGearboxData(inputData, runData, + new ATShiftStrategyOptimizedPolygonCalculator(), new GearboxType[] { + GearboxType.ATSerial, + GearboxType.ATPowerSplit + }); + + var gearShiftParams = + gbxDataAdapter.CreateGearshiftData(1.0, runData.EngineData.IdleSpeed, GearboxType.ATSerial, nrOfGears); + + runData.GearboxData = gearboxData; + runData.GearshiftParameters = gearShiftParams; + return runData; + } + + private Mock<ISimpleVehicleContainer> GetSimplePowertrain(VectoRunData runData, + out Mock<ITestPowertrainTransmission> testGearbox) + { + var simplePt = new Mock<ISimpleVehicleContainer>(); + + testGearbox = GetMockTestGearbox(runData.GearboxData.Gears); + + + simplePt.Setup(s => s.GearboxInfo).Returns(testGearbox.Object); + simplePt.Setup(s => s.GearboxOutPort).Returns(testGearbox.Object); + + + + + //VehiclePort + return simplePt; + } + + private Mock<ITestPowertrainTransmission> GetMockTestGearbox(Dictionary<uint, GearData> ratios) + { + Mock<IAPTGearbox> amtGearbox = new Mock<IAPTGearbox>(); + amtGearbox.Name = "APT_TestGearbox"; + TestContext.WriteLine(amtGearbox.Name); + Mock<ITestPowertrainTransmission> gbx = amtGearbox.As<ITestPowertrainTransmission>(); + + + + gbx.Setup(g => g.LastUpshift).Returns(-double.MaxValue.SI<Second>()); + gbx.Setup(g => g.LastDownshift).Returns(-double.MaxValue.SI<Second>()); + + GearshiftPosition gear = null; + gbx.SetupGet(g => g.Gear).Returns(() => { return gear; }); + gbx.SetupSet(g => g.SetGear = It.IsAny<GearshiftPosition>()) + .Callback<GearshiftPosition>(p => { gear = p; }); + + + GearshiftPosition nextGear = null; + gbx.SetupGet(g => g.NextGear).Returns(() => nextGear); + gbx.SetupSet(g => g.SetNextGear = It.IsAny<GearshiftPosition>()) + .Callback<GearshiftPosition>(p => nextGear = p); + + gbx.Setup(p => p.Initialize(It.IsAny<NewtonMeter>(), + It.IsAny<PerSecond>())).Returns((NewtonMeter tq, PerSecond rpm) => { + return new ResponseSuccess(this) { + Engine = { + EngineSpeed = rpm, + PowerRequest = tq * rpm, + }, + }; + }); + gbx.Setup(p => p.Request( + It.IsAny<Second>(), + It.IsAny<Second>(), + It.IsAny<NewtonMeter>(), + It.IsAny<PerSecond>(), + true)).Returns(( + Second absTime, + Second dt, + NewtonMeter t, + PerSecond n, + bool dryRun) => { + + var gear = gbx.Object.Gear.Gear; + var ratio = (gbx.Object.Gear.TorqueConverterLocked ?? false) + ? ratios[gear].Ratio + : ratios[gear].TorqueConverterRatio; + + + + // var ratio = + // gbx.Object.Gear == null ? 1.0 : ratios[gbx.Object.Gear.Gear].Ratio; + return dryRun + ? new ResponseDryRun(this) { + Engine = { + PowerRequest = n * t, EngineSpeed = n * ratio, + DynamicFullLoadPower = (t / ratio + 2300.SI<NewtonMeter>()) * n * ratio, + TotalTorqueDemand = t, + TorqueOutDemand = t, + }, + Clutch = { PowerRequest = n * t }, + DeltaFullLoad = n * t / 2 * (-1) + } + : new ResponseSuccess(this) { + Engine = { + PowerRequest = n * t, + EngineSpeed = n * ratio + + }, + Clutch = { PowerRequest = n * t } + }; + }); + return gbx; + } + + private static PerSecond GetAngularVelocityBySpeed(double speedKmh, VectoRunData runData) + { + // r_dyn = 0.465m, i_axle = 6.2 + var angularVelocity = + speedKmh.KMPHtoMeterPerSecond() + / runData.VehicleData.DynamicTyreRadius * 6.2; + return angularVelocity; + } + + + + + + + public const string TcHeader = "Speed Ratio, Torque Ratio,MP1000"; + + public static readonly string[] TcData = 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,1.02,188.90", + "1.0,1.0,0.00", + "1.100,0.999,-40.34", + "1.222,0.998,-80.34", + "1.375,0.997,-136.11", + "1.571,0.996,-216.52", + "1.833,0.995,-335.19", + "2.200,0.994,-528.77", + "2.750,0.993,-883.40", + "4.400,0.992,-2462.17", + "11.000,0.991,-16540.98", + }; + + public const string EngineFldHeader = "engine speed [1/min],full load torque [Nm],motoring torque [Nm],PT1 [s]"; + + public static readonly string[] EngineFldData = new[] { + "560,1180,-149,0.6", + "600,1282,-148,0.6", + "799.9999999,1791,-149,0.6", + "1000,2300,-160,0.6", + "1200,2300,-179,0.6", + "1400,2300,-203,0.6", + "1599.999999,2079,-235,0.49", + "1800,1857,-264,0.25", + "2000.000001,1352,-301,0.25", + "2100,1100,-320,0.25", + }; + + private ATShiftStrategyOptimized GetShiftStrategyAndGearbox(Mock<IVehicleContainer> vehicleContainer, + out Mock<IAPTGearbox> gbx) + { + return GetShiftStrategyAndGearbox(vehicleContainer, out gbx, out _); + } + + private ATShiftStrategyOptimized GetShiftStrategyAndGearbox(Mock<IVehicleContainer> vehicleContainer, + out Mock<IAPTGearbox> gbx, + out Mock<ITnOutPort> gbxNextComponent) + { + var shiftStrategy = new ATShiftStrategyOptimized(vehicleContainer.Object); + + gbx = GetGearbox(vehicleContainer.Object.RunData); + + + gbxNextComponent = null; + + + shiftStrategy.Gearbox = gbx.Object; + return shiftStrategy; + + // var gbxMock = new Mock<APTGearbox>(vehicleContainer.Object, shiftStrategy) { + // CallBase = true + // }; + // + // gbx = gbxMock.Object; + // shiftStrategy.Gearbox = gbx; + // + // var mockPort = new Mock<ITnOutPort>(); + // NewtonMeter tqRequest = null; + // PerSecond rpmRequest = null; + // + // mockPort.Setup(p => p.Initialize(It.IsAny<NewtonMeter>(), + // It.IsAny<PerSecond>())).Returns((NewtonMeter tq, PerSecond rpm) => { + // tqRequest = tq; + // rpmRequest = rpm; + // return new ResponseSuccess(this) { + // Engine = { + // EngineSpeed = rpm, + // PowerRequest = tq * rpm, + // }, + // }; + // }); + // + // mockPort.Setup(p => p.Request(It.IsAny<Second>(), It.IsAny<Second>(), It.IsAny<NewtonMeter>(), + // It.IsAny<PerSecond>(), true)).Returns(new ResponseDryRun(this)); + // + // var idleController = new Mock<IIdleController>(); + // + // + // gbx.IdleController = idleController.Object; + // gbx.Connect(mockPort.Object); + // + // gbxNextComponent = mockPort; + // return shiftStrategy; + } + + private static Mock<IAPTGearbox> GetGearbox(VectoRunData objectRunData) + { + Mock<IAPTGearbox> gbx; + gbx = new Mock<IAPTGearbox>(MockBehavior.Strict); + gbx.Name = "MockGearbox"; + TestContext.WriteLine(gbx.Name); + bool disengaged = false; + gbx.SetupGet(g => g.Disengaged).Returns(() => disengaged); + gbx.SetupSet(g => g.Disengaged = It.IsAny<bool>()).Callback((bool value) => disengaged = value); + + gbx.Setup(g => g.ComputeShiftLosses( + It.IsAny<NewtonMeter>(), + It.IsAny<PerSecond>(), + It.IsAny<GearshiftPosition>())).Returns((NewtonMeter outT, PerSecond outN, GearshiftPosition gear) => + { + return 0.SI<WattSecond>(); + }); + gbx.Setup(g => g.EngineInertia).Returns(objectRunData.EngineData.Inertia); + + //TorqueConverter + var tq = new Mock<ITorqueConverter>(MockBehavior.Strict); + gbx.Setup(g => g.TorqueConverter).Returns(tq.Object); + tq.Setup(tq => tq.FindOperatingPoint( + It.IsAny<Second>(), + It.IsAny<Second>(), + It.IsAny<NewtonMeter>(), + It.IsAny<PerSecond>())).Returns((Second t, Second dt, NewtonMeter outTorque, PerSecond outSpeed) => { + var speedRatio = 1.0; + var torqueRatio = 1.0; + return new TorqueConverterOperatingPoint() { + Creeping = false, + InAngularVelocity = speedRatio * outSpeed, + OutAngularVelocity = outSpeed, + InTorque = torqueRatio * outTorque, + OutTorque = outTorque, + SpeedRatio = speedRatio, + TorqueRatio = torqueRatio + }; + }); + return gbx; + } +} \ No newline at end of file diff --git a/Testing/UnitTests/Vecto UnitTests/TestCases/Components/GearShiftStrategy/ATShiftStrategyTests.cs b/Testing/UnitTests/Vecto UnitTests/TestCases/Components/GearShiftStrategy/ATShiftStrategyTests.cs deleted file mode 100644 index fa6040c0ccf318168be226977520942b2d4f1c84..0000000000000000000000000000000000000000 --- a/Testing/UnitTests/Vecto UnitTests/TestCases/Components/GearShiftStrategy/ATShiftStrategyTests.cs +++ /dev/null @@ -1,240 +0,0 @@ -using Moq; -using NUnit.Framework; -using NUnit.Framework.Interfaces; -using TUGraz.VectoCommon.InputData; -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.InputData.Reader.ComponentData; -using TUGraz.VectoCore.InputData.Reader.DataObjectAdapter.SimulationComponents; -using TUGraz.VectoCore.Models.Connector.Ports; -using TUGraz.VectoCore.Models.Connector.Ports.Impl; -using TUGraz.VectoCore.Models.Declaration; -using TUGraz.VectoCore.Models.Simulation; -using TUGraz.VectoCore.Models.Simulation.Data; -using TUGraz.VectoCore.Models.Simulation.DataBus; -using TUGraz.VectoCore.Models.SimulationComponent; -using TUGraz.VectoCore.Models.SimulationComponent.Data; -using TUGraz.VectoCore.Models.SimulationComponent.Data.Engine; -using TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox; -using TUGraz.VectoCore.Models.SimulationComponent.Impl; -using TUGraz.VectoCore.Models.SimulationComponent.Impl.Gearbox; -using TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies; -using TUGraz.VectoCore.Tests.Utils; -using Assert = NUnit.Framework.Assert; - -namespace TUGraz.Vecto.UnitTests.TestCases.Components.GearShiftStrategy; - -public class ATShiftStrategyTests -{ - [Test, - TestCase(0, 100, 1), - TestCase(0, 200, 1), - TestCase(5, 100, 1), - TestCase(5, 300, 1), - TestCase(5, 600, 1), - TestCase(15, 100, 3), - TestCase(15, 300, 3), - TestCase(15, 600, 3), - TestCase(40, 100, 6), - TestCase(40, 300, 6), - TestCase(40, 600, 6), - TestCase(70, 100, 6), - TestCase(70, 300, 6), - TestCase(70, 600, 6), - ] - public void TestATGearInitialize(double vehicleSpeed, double torque, int expectedGear) - { - var inputData = GetMockInputData(); - var gbxTypes = new[] { - GearboxType.ATSerial - }; - var runData = GetDummyVectoRunData(inputData.Components.GearboxInputData.Gears.Count); - var shiftPolygonCalc = GetMockShiftPolygonCalc(); - - // create gearbox data - var tcDataAdapter = new TorqueConverterDataAdapter(); - var gearboxData = new GearboxDataAdapter(tcDataAdapter).CreateGearboxData(inputData, runData, shiftPolygonCalc, gbxTypes); - runData.GearboxData = gearboxData; - - var vehicleContainer = GetMockVehicleContainer(runData, out var vehicleInfo); - vehicleInfo.Setup(v => v.VehicleSpeed).Returns(vehicleSpeed.KMPHtoMeterPerSecond()); - var shiftStrategy = new ATShiftStrategyOptimized(vehicleContainer); - - var gearbox = new APTGearbox(vehicleContainer, shiftStrategy); - - var mockPort = new Mock<ITnOutPort>(); - NewtonMeter tqRequest = null; - PerSecond rpmRequest = null; - mockPort.Setup(p => p.Initialize(It.IsAny<NewtonMeter>(), - It.IsAny<PerSecond>())).Returns((NewtonMeter tq, PerSecond rpm) => { - tqRequest = tq; - rpmRequest = rpm; - return new ResponseSuccess(this) { - Engine = { - EngineSpeed = rpm, - PowerRequest = tq * rpm, - } - }; - }); - gearbox.Connect(mockPort.Object); - - // r_dyn = 0.465m, i_axle = 6.2 - var angularVelocity = vehicleSpeed.KMPHtoMeterPerSecond() / runData.VehicleData.DynamicTyreRadius * 6.2; - - var response = gearbox.Initialize(torque.SI<NewtonMeter>(), angularVelocity); - - Assert.IsInstanceOf(typeof(ResponseSuccess), response); - Assert.AreEqual(expectedGear, gearbox.Gear.Gear); - Assert.AreEqual(vehicleSpeed.IsEqual(0), gearbox.Disengaged); - } - - private static VectoRunData GetDummyVectoRunData(int inputData) - { - var fldData = InputDataHelper.InputDataAsTableData(EngineFldHeader, EngineFldData); - var fld = FullLoadCurveReader.Create(fldData); - var engineIdlingSpeed = 600.RPMtoRad(); - var runData = new VectoRunData() { - Cycle = new DrivingCycleData() { - CycleType = CycleType.DistanceBased, - }, - VehicleData = new VehicleData() { - DynamicTyreRadius = 0.465.SI<Meter>(), - }, - EngineData = new CombustionEngineData() { - Inertia = 0.SI<KilogramSquareMeter>(), - FullLoadCurves = new Dictionary<uint, EngineFullLoadCurve>() - }, - GearshiftParameters = new ShiftStrategyParameters() { - LoadStageThresoldsUp = DeclarationData.GearboxTCU.LoadStageThresholdsUp, - LoadStageThresoldsDown = DeclarationData.GearboxTCU.LoadStageThresoldsDown, - ShiftSpeedsTCToLocked = engineIdlingSpeed == null ? null : DeclarationData.GearboxTCU.ShiftSpeedsTCToLocked - .Select(x => x.Select(y => y + engineIdlingSpeed.AsRPM).ToArray()).ToArray(), - } - }; - for(uint i = 0; i <= inputData; i++) - runData.EngineData.FullLoadCurves[i] = fld; - return runData; - } - - private static IShiftPolygonCalculator GetMockShiftPolygonCalc() - { - var shiftPolygonCalc = new Mock<IShiftPolygonCalculator>(); - var downshift = new List<ShiftPolygon.ShiftPolygonEntry>() { }; - var upshift = new List<ShiftPolygon.ShiftPolygonEntry>() { }; - var shiftpolygon = new ShiftPolygon(downshift, upshift); - shiftPolygonCalc.Setup(s => s.ComputeDeclarationShiftPolygon(It.IsIn(GearboxType.ATSerial), It.IsAny<int>(), - It.IsAny<EngineFullLoadCurve>(), It.IsAny<IList<ITransmissionInputData>>(), - It.IsAny<CombustionEngineData>(), It.IsAny<double>(), It.IsAny<Meter>(), It.IsAny<ElectricMotorData>())) - .Returns(shiftpolygon); - return shiftPolygonCalc.Object; - } - - private static IVehicleContainer GetMockVehicleContainer(VectoRunData runData, out Mock<IVehicleInfo> vehicleInfo) - { - var vehicleContainer = new Mock<IVehicleContainer>(); - vehicleInfo = new Mock<IVehicleInfo>(); - var engineInfo = new Mock<IEngineInfo>(); - var ptBuilder = new Mock<ISimplePowertrainBuilder>(); - var testPt = new Mock<ITestPowertrain>(); - var testContainer = new Mock<ISimpleVehicleContainer>(); - var vehiclePort = new Mock<ITestPowertrainVehicle>(); - var testGbx = new Mock<ITestPowertrainTransmission>(); - - vehicleContainer.Setup(c => c.RunData).Returns(runData); - vehicleContainer.Setup(c => c.VehicleInfo).Returns(vehicleInfo.Object); - vehicleContainer.Setup(c => c.EngineInfo).Returns(engineInfo.Object); - vehicleContainer.Setup(c => c.SimplePowertrainBuilder).Returns(ptBuilder.Object); - - engineInfo.Setup(e => e.EngineIdleSpeed).Returns(600.RPMtoRad()); - engineInfo.Setup(e => e.EngineRatedSpeed).Returns(2000.RPMtoRad()); - - ptBuilder.Setup(b => b.CreateTestPowertrain(It.IsAny<IVehicleContainer>(), It.IsAny<bool>(), It.IsAny<VectoSimulationJobType?>())).Returns(testPt.Object); - - testPt.Setup(t => t.Gearbox).Returns(testGbx.Object); - testPt.Setup(t => t.Container).Returns(testContainer.Object); - testPt.Setup(t => t.Vehicle).Returns(vehiclePort.Object); - - testContainer.Setup(c => c.RunData).Returns(runData); - testContainer.Setup(c => c.GearboxCtl).Returns(new APTGearbox(testContainer.Object, null)); - - return vehicleContainer.Object; - } - - private IVehicleDeclarationInputData GetMockInputData() - { - var input = new Mock<IVehicleDeclarationInputData>(); - var components = new Mock<IVehicleComponentsDeclaration>(); - input.Setup(i => i.Components).Returns(components.Object); - var gbx = new Mock<IGearboxDeclarationInputData>(); - var tc = new Mock<ITorqueConverterDeclarationInputData>(); - - components.Setup(c => c.GearboxInputData).Returns(gbx.Object); - components.Setup(c => c.TorqueConverterInputData).Returns(tc.Object); - var gearRatios = new double[] { - 3.4, 1.9, 1.42, 1.0, 0.7, 0.62 - }; - var header = "Input Speed [rpm],Input Torque [Nm],Torque Loss [Nm]"; - var efficiency = 0.98; - var data = new List<string>(); - foreach (var speed in new[] {0, 10000}) { - foreach (var tq in new[] {1e5, -1e5, 0}) { - data.Add($"{speed:f2}, {tq:f2}, {(1 - efficiency) * Math.Abs(tq)}"); - } - } - var lossmap = InputDataHelper.InputDataAsTableData(header, data.ToArray()); - var gears = gearRatios.Select((x, idx) => { - var gear = new Mock<ITransmissionInputData>(); - gear.Setup(g => g.Ratio).Returns(x); - gear.Setup(g => g.Gear).Returns(idx + 1); - //gear.Setup(g => g.Efficiency).Returns(0.98); - gear.Setup(g => g.LossMap).Returns(lossmap); - return gear.Object; - }).ToList(); - gbx.Setup(g => g.Type).Returns(GearboxType.ATSerial); - gbx.Setup(g => g.Gears).Returns(gears); - - var tcData = InputDataHelper.InputDataAsTableData(TcHeader, TcData); - tc.Setup(t => t.TCData).Returns(tcData); - return input.Object; - } - - public const string TcHeader = "Speed Ratio, Torque Ratio,MP1000"; - - public static readonly string[] TcData = 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,1.02,188.90", - "1.0,1.0,0.00", - "1.100,0.999,-40.34", - "1.222,0.998,-80.34", - "1.375,0.997,-136.11", - "1.571,0.996,-216.52", - "1.833,0.995,-335.19", - "2.200,0.994,-528.77", - "2.750,0.993,-883.40", - "4.400,0.992,-2462.17", - "11.000,0.991,-16540.98", - }; - - public const string EngineFldHeader = "engine speed [1/min],full load torque [Nm],motoring torque [Nm],PT1 [s]"; - - public static readonly string[] EngineFldData = new[] { - "560,1180,-149,0.6", - "600,1282,-148,0.6", - "799.9999999,1791,-149,0.6", - "1000,2300,-160,0.6", - "1200,2300,-179,0.6", - "1400,2300,-203,0.6", - "1599.999999,2079,-235,0.49", - "1800,1857,-264,0.25", - "2000.000001,1352,-301,0.25", - "2100,1100,-320,0.25", - }; -} \ No newline at end of file diff --git a/Testing/UnitTests/Vecto UnitTests/TestCases/Components/GearShiftStrategy/MTShiftStrategyTests.cs b/Testing/UnitTests/Vecto UnitTests/TestCases/Components/GearShiftStrategy/MTShiftStrategyTests.cs new file mode 100644 index 0000000000000000000000000000000000000000..ea2e1b95049e1e67e8b2bf9845c74cc538e2b67a --- /dev/null +++ b/Testing/UnitTests/Vecto UnitTests/TestCases/Components/GearShiftStrategy/MTShiftStrategyTests.cs @@ -0,0 +1,665 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Moq; +using NUnit.Framework; +using TUGraz.VectoCommon.InputData; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Configuration; +using TUGraz.VectoCore.InputData.Reader.ComponentData; +using TUGraz.VectoCore.Models.Connector.Ports.Impl; +using TUGraz.VectoCore.Models.Declaration; +using TUGraz.VectoCore.Models.Simulation; +using TUGraz.VectoCore.Models.Simulation.Data; +using TUGraz.VectoCore.Models.Simulation.DataBus; +using TUGraz.VectoCore.Models.SimulationComponent; +using TUGraz.VectoCore.Models.SimulationComponent.Data; +using TUGraz.VectoCore.Models.SimulationComponent.Data.Engine; +using TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox; +using TUGraz.VectoCore.Models.SimulationComponent.Impl; +using TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies; +using TUGraz.VectoCore.Tests.Utils; + +namespace TUGraz.Vecto.UnitTests.TestCases.Components.GearShiftStrategy; + +public class MTShiftStrategyTests +{ + [TestCase(1, 2, 1000, 1500)] + [TestCase(1, 6, 200, 8000)] + [TestCase(2, 4, 800, 1400)] + [TestCase(7, 8, 1000, 1400)] + [TestCase(6, 8, 800, 1400)] + [TestCase(5, 6, 1000, 1300)] + [TestCase(4, 5, 1000, 1400)] + [TestCase(3, 4, 1000, 1400)] + [TestCase(8, 8, 1000, 1400)] + public void Gearbox_ShiftUp(int gear, int newGear, double tq_Nm, double n_RPM) + { + var shiftExpected = gear != newGear; + + var gearRatios = new[] { 0.0, 6.38, 4.63, 3.44, 2.59, 1.86, 1.35, 1, 0.76 }; + + + var container = GetMocks(n_RPM, gearRatios, + out var runData, + out var info, + out var testPt, + out var ptBuilder); + + + var shiftStrategy = GetShiftStrategyAndGearbox(container, out _); + + + + var absTime = 0.SI<Second>(); + var dt = 2.SI<Second>(); + + + var expectedN = n_RPM.RPMtoRad(); + var angularVelocity = expectedN / gearRatios[gear]; + + var gearShiftPosition = shiftStrategy.InitGear(0.SI<Second>(), Constants.SimulationSettings.TargetTimeInterval, 1.SI<NewtonMeter>(), + angularVelocity); + + var expectedT = tq_Nm.SI<NewtonMeter>(); + var torque = expectedT * gearRatios[gear]; + var shiftRequired = shiftStrategy.ShiftRequired(absTime, dt, torque, angularVelocity, expectedT, expectedN, + new GearshiftPosition((uint)gear), -double.MaxValue.SI<Second>(), new ResponseSuccess(this)); + Assert.AreEqual(newGear, shiftStrategy.NextGear.Gear); + Assert.AreEqual(shiftExpected, shiftRequired); + } + + + [TestCase(2, 1, 1000, 300)] + [TestCase(3, 4, 1000, 1400)] + [TestCase(8, 7, 1800, 750)] + [TestCase(7, 6, 1800, 750)] + [TestCase(6, 5, 1800, 750)] + [TestCase(5, 4, 1800, 750)] + [TestCase(4, 3, 1800, 750)] + [TestCase(3, 2, 1800, 750)] + [TestCase(2, 1, 1900, 750)] + [TestCase(1, 1, 1200, 700)] + [TestCase(8, 4, 15000, 200)] + public void Gearbox_ShiftDown(int gear, int newGear, double tq_Nm, double n_RPM) + { + var shiftExpected = gear != newGear; + + var gearRatios = new[] { 0.0, 6.38, 4.63, 3.44, 2.59, 1.86, 1.35, 1, 0.76 }; + + var container = GetMocks(n_RPM, gearRatios, + out var runData, + out var info, + out var testPt, + out var ptBuilder); + + + var shiftStrategy = GetShiftStrategyAndGearbox(container, out _); + + var absTime = 0.SI<Second>(); + var dt = 2.SI<Second>(); + + + var expectedN = n_RPM.RPMtoRad(); + var angularVelocity = expectedN / gearRatios[gear]; + + var gearShiftPosition = shiftStrategy.InitGear(0.SI<Second>(), Constants.SimulationSettings.TargetTimeInterval, 1.SI<NewtonMeter>(), + angularVelocity); + + var expectedT = tq_Nm.SI<NewtonMeter>(); + var torque = expectedT * gearRatios[gear]; + var shiftRequired = shiftStrategy.ShiftRequired(absTime, dt, torque, angularVelocity, expectedT, expectedN, + new GearshiftPosition((uint)gear), -double.MaxValue.SI<Second>(), new ResponseSuccess(this)); + Assert.AreEqual(newGear, shiftStrategy.NextGear.Gear); + Assert.AreEqual(shiftExpected, shiftRequired); + } + + [TestCase(2, 1,2, 1000, 300)] + [TestCase(3, 2,2, 1000, 1400)] + [TestCase(8, 7,2, 1800, 750)] + [TestCase(7, 6,2, 1800, 750)] + [TestCase(6, 5,2, 1800, 750)] + [TestCase(5, 4,2, 1800, 750)] + [TestCase(4, 3,2, 1800, 750)] + [TestCase(3, 2,2, 1800, 750)] + [TestCase(2, 2,2, 1900, 750)] + [TestCase(1, 2,2, 1200, 700)] + [TestCase(8, 4,2, 15000, 200)] + [TestCase(2, 2, 2, 300, 1000)] + public void Gearbox_PTO(int gear, int newGear, int ptoGear, double tq_Nm, double n_RPM) + { + var shiftExpected = gear != newGear; + + var gearRatios = new[] { 0.0, 6.38, 4.63, 3.44, 2.59, 1.86, 1.35, 1, 0.76 }; + var container = GetMocks( + n_RPM: n_RPM, + gearRatios: gearRatios, + runData: out var runData, + info: out _, + testPt: out _, + ptBuilder: out _); + + //Cycle Info + var cycleInfo = new Mock<IDrivingCycleInfo>(); + container.Setup(c => c.DrivingCycleInfo).Returns(cycleInfo.Object); + cycleInfo.Setup(c => c.CycleData).Returns( + GetPTOCycleData()); + + runData.DriverData = new DriverData() { + PTODriveRoadsweepingGear = new GearshiftPosition((uint)ptoGear) + }; + //Recreate Shiftstrategy with updated rundata + + var shiftStrategy = GetShiftStrategyAndGearbox(container, out _); + + + var absTime = 0.SI<Second>(); + var dt = 2.SI<Second>(); + + + var expectedN = n_RPM.RPMtoRad(); + var angularVelocity = expectedN / gearRatios[gear]; + + + + + var gearShiftPosition = shiftStrategy.InitGear(0.SI<Second>(), Constants.SimulationSettings.TargetTimeInterval, 1.SI<NewtonMeter>(), + angularVelocity); + + + + var expectedT = tq_Nm.SI<NewtonMeter>(); + var torque = expectedT * gearRatios[gear]; + var shiftRequired = shiftStrategy.ShiftRequired(absTime, dt, torque, angularVelocity, expectedT, expectedN, + new GearshiftPosition((uint)gear), -double.MaxValue.SI<Second>(), new ResponseSuccess(this)); + Assert.AreEqual(newGear, shiftStrategy.NextGear.Gear); + Assert.AreEqual(shiftExpected, shiftRequired); + } + + + private MTShiftStrategy GetShiftStrategyAndGearbox(Mock<IVehicleContainer> container, + out Mock<IGearbox> gearbox) + { + gearbox = GetMockGearbox(); + + var shiftStrategy = new MTShiftStrategy(container.Object) { + Gearbox = gearbox.Object + }; + + SetVelocityDropLookupData(shiftStrategy); + return shiftStrategy; + } + + + + private Mock<IVehicleContainer> GetMocks( + double n_RPM, + double[] gearRatios, + out VectoRunData runData, + out Mock<IVehicleInfo> info, + out Mock<ITestPowertrain> testPt, + out Mock<ISimplePowertrainBuilder> ptBuilder) + { + runData = GetRunData(gearRatios); + var container = GetMockVehicleContainer(runData, n_RPM.RPMtoRad(), out info); + + testPt = GetMockTestPowertrain(runData); + + ptBuilder = new Mock<ISimplePowertrainBuilder>(MockBehavior.Strict); + + ptBuilder.Setup(p => p.CreateTestPowertrain(It.IsAny<IVehicleContainer>(),It.IsAny<bool>())) + .Returns(testPt.Object); + + + container.Setup(c => c.SimplePowertrainBuilder).Returns(ptBuilder.Object); + + // gbx = GetMockGearbox(container.Object); + // + // var shiftStrategy = new MTShiftStrategy(container.Object) + // { + // Gearbox = gbx.Object + // }; + // SetVelocityDropLookupData(shiftStrategy); + return container; + } + + + + + private VectoRunData GetRunData(double[] gearRatios) + { + var gearboxData = new GearboxData() { + Gears = new Dictionary<uint, GearData>() + }; + + for (uint i = 1; i < gearRatios.Length; i++) { + var gearRatio = gearRatios[i]; + gearboxData.Gears[i] = new GearData() { + Ratio = gearRatio, + LossMap = TransmissionLossMapReader.Create(0.96, gearRatio, $"Gear {i}") + }; + } + + var gearShiftParameters = new ShiftStrategyParameters() { + StartSpeed = 2.SI<MeterPerSecond>(), + TimeBetweenGearshifts = 6.SI<Second>(), + DownshiftAfterUpshiftDelay = 2.SI<Second>(), + UpshiftAfterDownshiftDelay = 2.SI<Second>(), + UpshiftMinAcceleration = 0.1.SI<MeterPerSquareSecond>() + }; + + + string engineFldHdr = "engine speed [1/min],full load torque [Nm],motoring torque [Nm],PT1 [s]"; + + string[] engineFldData = new[] { + "560,1180,-149,0.6 ", + "600,1282,-148,0.6 ", + "799.9999999,1791,-149,0.6 ", + "1000,2300,-160,0.6 ", + "1200,2300,-179,0.6 ", + "1400,2300,-203,0.6 ", + "1599.999999,2079,-235,0.49", + "1800,1857,-264,0.25 ", + "2000.000001,1352,-301,0.25", + "2100,1100,-320,0.25 ", + }; + + + var fullLoadCurve = + FullLoadCurveReader.Create(InputDataHelper.InputDataAsTableData(engineFldHdr, engineFldData)); + var engineData = new CombustionEngineData() { + IdleSpeed = 560.RPMtoRad(), + FullLoadCurves = new Dictionary<uint, EngineFullLoadCurve>() { + { + 0u, fullLoadCurve + } + } + }; + + + var axlRatio = 3.240355; + var gearsInput = gearboxData.Gears.Select(x => { + var r = new Mock<ITransmissionInputData>(); + r.Setup(g => g.Ratio).Returns(x.Value.Ratio); + return r.Object; + }).ToList(); + foreach (var entry in gearboxData.Gears) { + var gearIdx = (int)entry.Key - 1; + var dynamicTyreRadius = 0.5.SI<Meter>(); + + entry.Value.ShiftPolygon = + DeclarationData.Gearbox.ComputeManualTransmissionShiftPolygon( + gearIdx, engineData.FullLoadCurves.First().Value, + gearsInput, engineData, axlRatio, 0.5.SI<Meter>()); + + entry.Value.ExtendedShiftPolygon = DeclarationData.Gearbox.ComputeManualTransmissionShiftPolygonExtended( + gearIdx, engineData.FullLoadCurves.First().Value, gearsInput, engineData, axlRatio, dynamicTyreRadius); + } + + + var axleGearData = new AxleGearData() { + AxleGear = new TransmissionData() { + Ratio = 3.240355, + } + }; + + + var vehicleData = new VehicleData() { + DynamicTyreRadius = 0.492.SI<Meter>(), + }; + + + var mockCycle = new Mock<IDrivingCycleData>(); + mockCycle.Setup(cd => cd.Entries).Returns( + new List<DrivingCycleData.DrivingCycleEntry>() { + new DrivingCycleData.DrivingCycleEntry() { + RoadGradient = 0.SI<Radian>() + } + }); + + + + return new VectoRunData() { + GearboxData = gearboxData, + GearshiftParameters = gearShiftParameters, + EngineData = engineData, + AxleGearData = axleGearData, + VehicleData = vehicleData, + Cycle = mockCycle.Object, + }; + } + + + private Mock<IGearbox> GetMockGearbox() + { + var mtGbx = new Mock<IMTGearbox>(MockBehavior.Strict); + var gbx = mtGbx.As<IGearbox>(); + + gbx.Setup(g => g.LastUpshift).Returns(-double.MaxValue.SI<Second>()); + gbx.Setup(g => g.LastDownshift).Returns(-double.MaxValue.SI<Second>()); + + return gbx; + } + + + private Mock<ITestPowertrainTransmission> GetMockTestGearbox(Dictionary<uint, GearData> ratios) + { + var gbx = new Mock<ITestPowertrainTransmission>(); + + gbx.Setup(g => g.LastUpshift).Returns(-double.MaxValue.SI<Second>()); + gbx.Setup(g => g.LastDownshift).Returns(-double.MaxValue.SI<Second>()); + + GearshiftPosition gear = null; + gbx.SetupGet(g => g.Gear).Returns(() => { + + return gear; + }); + gbx.SetupSet(g => g.SetGear = It.IsAny<GearshiftPosition>()) + .Callback<GearshiftPosition>(p => { + gear = p; + }); + + + GearshiftPosition nextGear = null; + gbx.SetupGet(g => g.NextGear).Returns(() => nextGear); + gbx.SetupSet(g => g.SetNextGear = It.IsAny<GearshiftPosition>()) + .Callback<GearshiftPosition>(p => nextGear = p); + + gbx.Setup(p => p.Initialize(It.IsAny<NewtonMeter>(), + It.IsAny<PerSecond>())).Returns((NewtonMeter tq, PerSecond rpm) => { + return new ResponseSuccess(this) + { + Engine = { + EngineSpeed = rpm, + PowerRequest = tq * rpm, + }, + }; + }); + + + gbx.Setup(g => g.Request(It.IsAny<Second>(), It.IsAny<Second>(), It.IsAny<NewtonMeter>(), It.IsAny<PerSecond>(), + It.IsAny<bool>())) + .Returns((Second absTime, Second dt, NewtonMeter t, PerSecond n, bool dryRun) => { + var ratio = gbx.Object.Gear == null ? 1.0 : ratios[gbx.Object.Gear.Gear].Ratio; + return dryRun + ? new ResponseDryRun(this) { + Engine = { + PowerRequest = n * t, EngineSpeed = n * ratio, + DynamicFullLoadPower = (t / ratio + 2300.SI<NewtonMeter>()) * n * ratio, + }, + Clutch = { PowerRequest = n * t } + } + : new ResponseSuccess(this) { + Engine = { PowerRequest = n * t, EngineSpeed = n * ratio }, + Clutch = { PowerRequest = n * t } + }; + }); + return gbx; + } + private Mock<IPowertainInfo> GetPowertrainInfo() + { + var powerTrainInfo = new Mock<IPowertainInfo>(); + powerTrainInfo.Setup(p => p.HasCombustionEngine).Returns(true); + return powerTrainInfo; + } + + private CycleData GetCycleData() + { + return new CycleData() { + LeftSample = new DrivingCycleData.DrivingCycleEntry() { + PTOActive = PTOActivity.Inactive + } + }; + } + + private CycleData GetPTOCycleData() + { + return new CycleData() { + LeftSample = new DrivingCycleData.DrivingCycleEntry() { + PTOActive = PTOActivity.PTOActivityRoadSweeping + } + }; + } + + private Mock<IVehicleContainer> GetMockVehicleContainer(VectoRunData runData, PerSecond engineSpeed, out Mock<IVehicleInfo> vehicleInfo) + { + var vehicleContainer = new Mock<IVehicleContainer>(); + + var preProcessingRuns = new List<ISimulationPreprocessor>(); + + vehicleContainer.Setup(c => c.RunData).Returns(runData); + vehicleContainer.Setup(c => c.AddComponent(It.IsAny<VectoSimulationComponent>())); + + vehicleContainer.Setup(c => c.AddPreprocessor(It.IsAny<ISimulationPreprocessor>())) + .Callback((ISimulationPreprocessor pre) => preProcessingRuns.Add(pre)); + + //Vehicle Info + vehicleInfo = new Mock<IVehicleInfo>(); + vehicleContainer.Setup(c => c.VehicleInfo).Returns(vehicleInfo.Object); + vehicleInfo.Setup(v => v.VehicleSpeed).Returns(1.KMPHtoMeterPerSecond()); + + vehicleInfo.Setup(v => v.AirDragResistance(It.IsAny<MeterPerSecond>(), It.IsAny<MeterPerSecond>())) + .Returns(0.SI<Newton>()); + vehicleInfo.Setup(v => v.RollingResistance(It.IsAny<Radian>())).Returns(0.SI<Newton>()); + vehicleInfo.Setup(v => v.SlopeResistance(It.IsAny<Radian>())).Returns(0.SI<Newton>()); + vehicleInfo.Setup(v => v.VehicleSpeed).Returns(30.KMPHtoMeterPerSecond()); + vehicleInfo.Setup(v => v.TotalMass).Returns(12000.SI<Kilogram>()); + + //WheelsInfo + vehicleContainer.Setup(c => c.WheelsInfo.ReducedMassWheels).Returns(0.SI<Kilogram>()); + + //AxlegearInfo + var axleGearInfo = new Mock<IAxlegearInfo>(); + vehicleContainer.Setup(c => c.AxlegearInfo).Returns(axleGearInfo.Object); + axleGearInfo.Setup(a => a.AxlegearLoss()).Returns(0.SI<Watt>()); + + //Powertrain Info + vehicleContainer.Setup(c => c.PowertrainInfo).Returns(GetPowertrainInfo().Object); + + //Engine Info + var engineInfo = new Mock<IEngineInfo>(); + vehicleContainer.Setup(c => c.EngineInfo).Returns(engineInfo.Object); + engineInfo.Setup(e => e.EngineIdleSpeed).Returns(runData.EngineData.IdleSpeed); + engineInfo.Setup(e => e.EngineRatedSpeed).Returns(runData.EngineData.FullLoadCurves.First().Value.RatedSpeed); + engineInfo.Setup(e => e.EngineSpeed).Returns(engineSpeed); + engineInfo.Setup(e => e.EngineN95hSpeed).Returns + (runData.EngineData.FullLoadCurves.First().Value.N95hSpeed); + engineInfo.Setup(e => e.EngineStationaryFullPower(It.IsAny<PerSecond>())).Returns((PerSecond n) => + runData.EngineData.FullLoadCurves[0].FullLoadStationaryPower(n)); + + //Cycle Info + var cycleInfo = new Mock<IDrivingCycleInfo>(); + vehicleContainer.Setup(c => c.DrivingCycleInfo).Returns(cycleInfo.Object); + cycleInfo.Setup(c => c.CycleData).Returns( + GetCycleData()); + + cycleInfo.Setup(c => c.CycleLookAhead(It.IsAny<Meter>())).Returns(new DrivingCycleData.DrivingCycleEntry() { + Altitude = 0.SI<Meter>() + }); + cycleInfo.Setup(c => c.Altitude).Returns(0.SI<Meter>()); + + var pi = new Mock<IPowertainInfo>(); + + + + //Driver Info + var driverInfo = new Mock<IDriverInfo>(); + vehicleContainer.Setup(c => c.DriverInfo).Returns(driverInfo.Object); + + driverInfo.Setup(d => d.DriverBehavior).Returns(DrivingBehavior.Accelerating); + driverInfo.Setup(d => d.DrivingAction).Returns(DrivingAction.Accelerate); + + return vehicleContainer; + } + + private Mock<ITestPowertrain> GetMockTestPowertrain(VectoRunData runData) + { + var testPt = new Mock<ITestPowertrain>(MockBehavior.Strict); + var simplePt = GetSimplePowertrain(runData, out var gbx); + + testPt.Setup(c => c.Container).Returns(simplePt.Object); + testPt.Setup(c => c.Gearbox).Returns(gbx.Object); + testPt.Setup(c => c.UpdateComponents()); + + + // var simplePt = GetSimplePowertrain(gearRatios); + // + // + // testContainer.Setup(c => c.RunData).Returns(runData); + // testContainer.Setup(c => c.PowertrainInfo).Returns(GetPowertrainInfo().Object); + // + // testPowertrain.Setup(t => t.Gearbox).Returns(GetMockGearbox(testContainer.Object).Object); + + var tEng = new Mock<ITestpowertrainCombustionEngine>(); + testPt.Setup(t => t.CombustionEngine).Returns(tEng.Object); + tEng.Setup(e => e.EngineStationaryFullPower(It.IsAny<PerSecond>())) + .Returns((PerSecond n) => runData.EngineData.FullLoadCurves[0].FullLoadStationaryPower(n)); + + return testPt; + } + + private Mock<ISimpleVehicleContainer> GetSimplePowertrain(VectoRunData runData, out Mock<ITestPowertrainTransmission> testGearbox) + { + var simplePt = new Mock<ISimpleVehicleContainer>(); + + simplePt.Setup(s => s.RunData).Returns(runData); + simplePt.Setup(s => s.AddComponent(It.IsAny<VectoSimulationComponent>())); + simplePt.Setup(s => s.PowertrainInfo).Returns(GetPowertrainInfo().Object); + + testGearbox = GetMockTestGearbox(runData.GearboxData.Gears); + simplePt.Setup(s => s.GearboxCtl).Returns(testGearbox.Object); + + + //Vehicle Info + var vehicleInfo = new Mock<IVehicleInfo>(); + simplePt.Setup(c => c.VehicleInfo).Returns(vehicleInfo.Object); + vehicleInfo.Setup(v => v.VehicleSpeed).Returns(1.KMPHtoMeterPerSecond()); + + + + + //simplePt.Setup(s => s.AddPreprocessor(It.IsAny<ISimulationPreprocessor>())) + // .Callback((ISimulationPreprocessor p) => p.RunPreprocessing()); + return simplePt; + } + + private void SetVelocityDropLookupData(MTShiftStrategy shiftStrategy) + { + //"StartVelocity [km/h], Gradient [-], EndVelocity [km/h]" + var data = new[] { + new[] { 5.0, -0.0997, 9.061522965237558 }, + new[] { 5.0, -0.0798, 7.76698080079411 }, + new[] { 5.0, -0.0599, 6.46583777913701 }, + new[] { 5.0, -0.0400, 5.1596021788785045 }, + new[] { 5.0, -0.0200, 3.8498121019126907 }, + new[] { 5.0, 0.0000, 2.5380265159468918 }, + new[] { 5.0, 0.0200, 1.2258160477557427 }, + new[] { 5.0, 0.0400, 0.0 }, + new[] { 5.0, 0.0599, 0.0 }, + new[] { 5.0, 0.0798, 0.0 }, + new[] { 5.0, 0.0997, 0.0 }, + new[] { 10.0, -0.0997, 14.807789640888302 }, + new[] { 10.0, -0.0798, 13.474253785811362 }, + new[] { 10.0, -0.0599, 12.133880027250777 }, + new[] { 10.0, -0.0400, 10.788221550084467 }, + new[] { 10.0, -0.0200, 9.438862432338068 }, + new[] { 10.0, 0.0000, 8.087408432114643 }, + new[] { 10.0, 0.0200, 6.735477499784416 }, + new[] { 10.0, 0.0400, 5.384690105076845 }, + new[] { 10.0, 0.0599, 4.036659549786269 }, + new[] { 10.0, 0.0798, 2.6929823705748137 }, + new[] { 10.0, 0.0997, 1.3552289800549435 }, + new[] { 20.0, -0.0997, 25.061542153872097 }, + new[] { 20.0, -0.0798, 23.72002987685605 }, + new[] { 20.0, -0.0599, 22.371630788642932 }, + new[] { 20.0, -0.0400, 21.017907257116025 }, + new[] { 20.0, -0.0200, 19.660452757813403 }, + new[] { 20.0, 0.0000, 18.30088261992287 }, + new[] { 20.0, 0.0200, 16.94082447048767 }, + new[] { 20.0, 0.0400, 15.581908518759507 }, + new[] { 20.0, 0.0599, 14.225757795590708 }, + new[] { 20.0, 0.0798, 12.873978508374211 }, + new[] { 20.0, 0.0997, 11.528150617530041 }, + new[] { 30.000000000000004, -0.0997, 35.091774208140095 }, + new[] { 30.000000000000004, -0.0798, 33.750904327320896 }, + new[] { 30.000000000000004, -0.0599, 32.40315158162777 }, + new[] { 30.000000000000004, -0.0400, 31.050077596965064 }, + new[] { 30.000000000000004, -0.0200, 29.69327509188113 }, + new[] { 30.000000000000004, 0.0000, 28.33435862498606 }, + new[] { 30.000000000000004, 0.0200, 26.974955046566407 }, + new[] { 30.000000000000004, 0.0400, 25.616693776603913 }, + new[] { 30.000000000000004, 0.0599, 24.261197065863925 }, + new[] { 30.000000000000004, 0.0798, 22.91007034016412 }, + new[] { 30.000000000000004, 0.0997, 21.56489279686667 }, + new[] { 40.0, -0.0997, 45.024018797189854 }, + new[] { 40.0, -0.0798, 43.68636622428101 }, + new[] { 40.0, -0.0599, 42.34185052441486 }, + new[] { 40.0, -0.0400, 40.99202962224952 }, + new[] { 40.0, -0.0200, 39.63849244500093 }, + new[] { 40.0, 0.0000, 38.282849690992855 }, + new[] { 40.0, 0.0200, 36.926724305651554 }, + new[] { 40.0, 0.0400, 35.57174178507285 }, + new[] { 40.0, 0.0599, 34.21952045137207 }, + new[] { 40.0, 0.0798, 32.87166183129923 }, + new[] { 40.0, 0.0997, 31.5297412694979 }, + new[] { 50.0, -0.0997, 54.652157586769704 }, + new[] { 50.0, -0.0798, 53.319266704395716 }, + new[] { 50.0, -0.0599, 51.97954186606304 }, + new[] { 50.0, -0.0400, 50.634535516787736 }, + new[] { 50.0, -0.0200, 49.28583097196263 }, + new[] { 50.0, 0.0000, 47.93503321632867 }, + new[] { 50.0, 0.0200, 46.583759417454765 }, + new[] { 50.0, 0.0400, 45.23362925944123 }, + new[] { 50.0, 0.0599, 43.88625525588574 }, + new[] { 50.0, 0.0798, 42.54323315977748 }, + new[] { 50.0, 0.0997, 41.20613261641401 }, + new[] { 60.00000000000001, -0.0997, 64.2503607025971 }, + new[] { 60.00000000000001, -0.0798, 62.91932863058169 }, + new[] { 60.00000000000001, -0.0599, 61.58156853535776 }, + new[] { 60.00000000000001, -0.0400, 60.23862904729555 }, + new[] { 60.00000000000001, -0.0200, 58.89369896300112 }, + new[] { 60.00000000000001, 0.0000, 57.547040626925885 }, + new[] { 60.00000000000001, 0.0200, 56.199911833784675 }, + new[] { 60.00000000000001, 0.0400, 54.85392730356455 }, + new[] { 60.00000000000001, 0.0599, 53.510694584916905 }, + new[] { 60.00000000000001, 0.0798, 52.17180450267632 }, + new[] { 60.00000000000001, 0.0997, 50.83882182989668 }, + new[] { 70.0, -0.0997, 73.78388063954164 }, + new[] { 70.0, -0.0798, 72.45700102808648 }, + new[] { 70.0, -0.0599, 71.12341092304165 }, + new[] { 70.0, -0.0400, 69.78459543842656 }, + new[] { 70.0, -0.0200, 68.44188526693415 }, + new[] { 70.0, 0.0000, 67.09719334997524 }, + new[] { 70.0, 0.0200, 65.75212749798493 }, + new[] { 70.0, 0.0400, 64.40829754257321 }, + new[] { 70.0, 0.0599, 63.06730571969745 }, + new[] { 70.0, 0.0798, 61.73073716025881 }, + new[] { 70.0, 0.0997, 60.40015062055851 }, + new[] { 80.0, -0.0997, 83.25457689135129 }, + new[] { 80.0, -0.0798, 81.93182852399568 }, + new[] { 80.0, -0.0599, 80.60238880559001 }, + new[] { 80.0, -0.0400, 79.2676325992058 }, + new[] { 80.0, -0.0200, 77.92916666616652 }, + new[] { 80.0, 0.0000, 76.58872134590663 }, + new[] { 80.0, 0.0200, 75.24790011046437 }, + new[] { 80.0, 0.0400, 73.90830846424944 }, + new[] { 80.0, 0.0599, 72.57154434889891 }, + new[] { 80.0, 0.0798, 71.23918865436896 }, + new[] { 80.0, 0.0997, 69.91277394305271 }, + }; + var entries = new List<VelocitySpeedGearshiftPreprocessor.Entry>(); + foreach (var d in data) { + entries.Add(new VelocitySpeedGearshiftPreprocessor.Entry() { + StartVelocity = d[0].KMPHtoMeterPerSecond(), + Gradient = d[1].SI<Radian>(), + EndVelocity = d[2].KMPHtoMeterPerSecond(), + }); + } + + shiftStrategy.VelocityDropData.Data = entries.ToArray(); + + } +} \ No newline at end of file diff --git a/Testing/UnitTests/Vecto UnitTests/TestCases/Components/GearShiftStrategy/PEVAMTShiftStrategyTests.cs b/Testing/UnitTests/Vecto UnitTests/TestCases/Components/GearShiftStrategy/PEVAMTShiftStrategyTests.cs new file mode 100644 index 0000000000000000000000000000000000000000..e6c72605482562f11f604357af9561894384076f --- /dev/null +++ b/Testing/UnitTests/Vecto UnitTests/TestCases/Components/GearShiftStrategy/PEVAMTShiftStrategyTests.cs @@ -0,0 +1,2099 @@ +using Moq; +using NUnit.Framework; +using TUGraz.VectoCommon.InputData; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.InputData.Impl; +using TUGraz.VectoCore.InputData.Reader.ComponentData; +using TUGraz.VectoCore.InputData.Reader.DataObjectAdapter.SimulationComponents; +using TUGraz.VectoCore.Models.Connector.Ports.Impl; +using TUGraz.VectoCore.Models.Declaration; +using TUGraz.VectoCore.Models.Simulation; +using TUGraz.VectoCore.Models.Simulation.Data; +using TUGraz.VectoCore.Models.Simulation.DataBus; +using TUGraz.VectoCore.Models.Simulation.Impl; +using TUGraz.VectoCore.Models.SimulationComponent; +using TUGraz.VectoCore.Models.SimulationComponent.Data; +using TUGraz.VectoCore.Models.SimulationComponent.Data.ElectricMotor; +using TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox; +using TUGraz.VectoCore.Models.SimulationComponent.Impl; +using TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies; +using TUGraz.VectoCore.Models.SimulationComponent.Strategies; +using TUGraz.VectoCore.Tests.Utils; +using TUGraz.VectoCore.Utils; +using Range = System.Range; + +// ReSharper disable InconsistentNaming + +namespace TUGraz.Vecto.UnitTests.TestCases.Components.GearShiftStrategy +{ + [TestFixture] + public class PEVAMTShiftStrategyTests + { + [TestCase(500, 80, 1)] + [TestCase(5, 500, 2)] + public void InitGear(double torque_Nm, double speed_rpm, int expectedGear) + { + // the first element 0.0 is just a placeholder for axlegear, not used in this test + var ratios = new[] { 0.0, 3.86, 1.93 }; + + var container = GetMocks(ratios); + + var shiftStrategy = GetShiftStrategyAndGearbox(container, out var gearbox); + + var absTime = 0.SI<Second>(); + var dt = 0.5.SI<Second>(); + + var torque = torque_Nm.SI<NewtonMeter>(); + var speed = speed_rpm.RPMtoRad(); + + var result = shiftStrategy.InitGear(absTime, dt, torque, speed); + + var newGear = result.Gear; + Assert.AreEqual(expectedGear, newGear); + + + + } + + [TestCase(5000, 80, 1)] + [TestCase(5, 500, 2)] + public void InitStartGear(double torque_Nm, double speed_rpm, int expectedGear) + { + // the first element 0.0 is just a placeholder for axlegear, not used in this test + var ratios = new[] { 0.0, 3.86, 1.93 }; + + var container = GetMocks(ratios); + container.Setup(c => c.VehicleInfo.VehicleSpeed).Returns(0.KMPHtoMeterPerSecond()); + + var shiftStrategy = GetShiftStrategyAndGearbox(container, out var gearbox); + + var absTime = 0.SI<Second>(); + var dt = 0.5.SI<Second>(); + + var torque = torque_Nm.SI<NewtonMeter>(); + var speed = speed_rpm.RPMtoRad(); + + var result = shiftStrategy.InitGear(absTime, dt, torque, speed); + + var newGear = result.Gear; + Assert.AreEqual(expectedGear, newGear); + + + + } + + [TestCase( + 500, + 80, + 500, + 10000, + 1, + 2, TestName = "Emergency UpShift")] + + [TestCase( + 500, + 80, + 1000, + 1800, + 1, + 2, TestName = "UpShift")] + [TestCase( + 500, + 80, + 1000, + 800, + 1, + 1, TestName = "No Upshift")] + public void Upshift(double init_outTorque_Nm, double init_outSpeed_rpm, double outTorque_Nm, + double outSpeed_rpm, int currentGear, int expectedGear) + { + CheckUpshift(init_outTorque_Nm, init_outSpeed_rpm, outTorque_Nm, outSpeed_rpm, currentGear, expectedGear, false); + } + + [TestCase( + 500, + 80, + 100, + 1800, + 1, + 3, TestName = "UpShiftSkipGear")] + public void UpshiftSkipGear(double init_outTorque_Nm, double init_outSpeed_rpm, double outTorque_Nm, + double outSpeed_rpm, int currentGear, int expectedGear) + { + CheckUpshift(init_outTorque_Nm, init_outSpeed_rpm, outTorque_Nm, outSpeed_rpm, currentGear, expectedGear, false, new[] { 0.0, 3.86, 1.93, 1.92 }); + } + + + public void CheckUpshift(double init_outTorque_Nm, double init_outSpeed_rpm, double outTorque_Nm, + double outSpeed_rpm, int currentGear, int expectedGear, bool effShift, double[]? ratios = null) + { + // the first element 0.0 is just a placeholder for axlegear, not used in this test + ratios = ratios ?? new[] { 0.0, 3.86, 1.93 }; + var ratio = ratios[currentGear]; + var container = GetMocks(ratios); + + if (!effShift) { + DisableEffshift(container.Object.RunData); + } + + + var shiftRequired = currentGear != expectedGear; + + var shiftStrategy = GetShiftStrategyAndGearbox(container, out var gearbox); + // var gear = new GearshiftPosition((uint)currentGear); + // gearbox.Gear = gear; + + var absTime = 0.SI<Second>(); + var dt = 0.5.SI<Second>(); + + var init_outTorque = init_outTorque_Nm.SI<NewtonMeter>(); + var init_outAngularVelocity = init_outSpeed_rpm.RPMtoRad(); + + + var outTorque = outTorque_Nm.SI<NewtonMeter>(); + var outAngularVelocity = outSpeed_rpm.RPMtoRad(); + + var inTorque = outTorque / ratio; + var inAngularVelocity = outAngularVelocity * ratio; + + var lastShiftTime = float.MinValue.SI<Second>(); + + var response = new ResponseSuccess(this); + + Console.WriteLine( + $"OutTorque: {outTorque}\n" + + $"InTorque: {inTorque} \n" + + $"OutSpeed: {outAngularVelocity.AsRPM} [rpm]\n" + + $"InSpeed: {inAngularVelocity.AsRPM} [rpm]\n"); + + + //Init gear + var initResult = shiftStrategy.InitGear(absTime, dt, init_outTorque, init_outAngularVelocity); + Assert.That(shiftStrategy.NextGear.Gear, Is.EqualTo(currentGear)); + + //Check shift required + var result = shiftStrategy.ShiftRequired(absTime, dt, + outTorque: outTorque, + outAngularVelocity: outAngularVelocity, + inTorque: inTorque, + inAngularVelocity: inAngularVelocity, + gear: shiftStrategy.NextGear, + lastShiftTime: lastShiftTime, + response: response); + + Assert.AreEqual(shiftRequired, result); + Assert.AreEqual(expectedGear, shiftStrategy.NextGear.Gear); + + + + } + + [TestCase( + 500, + 80, + -10, + 1000, + 1, + 2, TestName = "UpShift")] + public void EarlyUpshift(double init_outTorque_Nm, double init_outSpeed_rpm, double outTorque_Nm, + double outSpeed_rpm, int currentGear, int expectedGear) + { + // the first element 0.0 is just a placeholder for axlegear, not used in this test + var ratios = new[] { 0.0, 3.86, 1.93 }; + var ratio = ratios[currentGear]; + var container = GetMocks(ratios); + container.Setup(c => c.VehicleInfo.VehicleSpeed).Returns(20.KMPHtoMeterPerSecond()); + + + var shiftRequired = currentGear != expectedGear; + + var shiftStrategy = GetShiftStrategyAndGearbox(container, out var gearbox); + // var gear = new GearshiftPosition((uint)currentGear); + // gearbox.Gear = gear; + + var absTime = 0.SI<Second>(); + var dt = 0.5.SI<Second>(); + + var init_outTorque = init_outTorque_Nm.SI<NewtonMeter>(); + var init_outAngularVelocity = init_outSpeed_rpm.RPMtoRad(); + + + var outTorque = outTorque_Nm.SI<NewtonMeter>(); + var outAngularVelocity = outSpeed_rpm.RPMtoRad(); + + var inTorque = outTorque / ratio; + var inAngularVelocity = outAngularVelocity * ratio; + + var lastShiftTime = float.MinValue.SI<Second>(); + + var response = new ResponseSuccess(this); + + Console.WriteLine( + $"OutTorque: {outTorque}\n" + + $"InTorque: {inTorque} \n" + + $"OutSpeed: {outAngularVelocity.AsRPM} [rpm]\n" + + $"InSpeed: {inAngularVelocity.AsRPM} [rpm]\n"); + + + //Init gear + var initResult = shiftStrategy.InitGear(absTime, dt, init_outTorque, init_outAngularVelocity); + Assert.That(shiftStrategy.NextGear.Gear, Is.EqualTo(currentGear)); + + //Check shift required + var result = shiftStrategy.ShiftRequired(absTime, dt, + outTorque: outTorque, + outAngularVelocity: outAngularVelocity, + inTorque: inTorque, + inAngularVelocity: inAngularVelocity, + gear: shiftStrategy.NextGear, + lastShiftTime: lastShiftTime, + response: response); + + Assert.AreEqual(shiftRequired, result); + Assert.AreEqual(expectedGear, shiftStrategy.NextGear.Gear); + + + } + + + [TestCase( + 5, + 200, + 2000, + 200, + 2, + 1, TestName = "Downshift")] + public void Downshift(double init_outTorque_Nm, double init_outSpeed_rpm, double outTorque_Nm, + double outSpeed_rpm, int currentGear, int expectedGear, int speedKmh=1) + { + var ratios = new[] { 0.0, 3.86, 1.93 }; + CheckDownshift(init_outTorque_Nm, init_outSpeed_rpm, outTorque_Nm, outSpeed_rpm, currentGear, expectedGear, ratios, false, speedKmh); + } + + [TestCase( + 5, + 200, + -500, + 200, + 4, + 2, + 40, TestName = "EarlyDownshift")] + public void EarlyDownshift(double init_outTorque_Nm, double init_outSpeed_rpm, double outTorque_Nm, + double outSpeed_rpm, int currentGear, int expectedGear, int speedKmh=1) + { + var ratios = new[] { 0.0, 3.86, 3, 2.5, 1.93 }; + CheckDownshift(init_outTorque_Nm, init_outSpeed_rpm, outTorque_Nm, outSpeed_rpm, currentGear, expectedGear, ratios, true, speedKmh); + } + + [TestCase( + 5, + 200, + 2000, + 40, + 4, + 2, TestName = "Downshift_SkipGear")] + public void DownshiftSkipGears(double init_outTorque_Nm, double init_outSpeed_rpm, double outTorque_Nm, + double outSpeed_rpm, int currentGear, int expectedGear) + { + var ratios = new[] { 0.0, 3.86, 3, 2.5, 1.93 }; + CheckDownshift(init_outTorque_Nm, init_outSpeed_rpm, outTorque_Nm, outSpeed_rpm, currentGear, expectedGear, ratios, false); + } + + private void DisableEffshift(VectoRunData runData) + { + TestContext.WriteLine("EffShift Disabled"); + runData.GearshiftParameters.AllowedGearRangeFC = 0; + } + + private void DisableEffshift(Mock<IVehicleContainer> vehicleContainer) + { + DisableEffshift(vehicleContainer.Object.RunData); + } + + + [TestCase( + 5, + 200, + 2000, + 200, + 2, + 1, TestName = "BrakingGear")] + public void BrakingGear( + double init_outTorque_Nm, + double init_outSpeed_rpm, + double outTorque_Nm, + double outSpeed_rpm, + int currentGear, + int expectedGear, + int vehicleSpeed_kmH = 1) + { + // the first element 0.0 is just a placeholder for axlegear, not used in this test + var ratios = new[] { 0.0, 3.86, 1.93 }; + var ratio = ratios[currentGear]; + var container = GetMocks(ratios); + + + container.Setup(c => c.VehicleInfo.VehicleSpeed).Returns(vehicleSpeed_kmH.KMPHtoMeterPerSecond()); + container.Setup(c => c.DriverInfo.DriverBehavior).Returns(DrivingBehavior.Braking); + + + DisableEffshift(container.Object.RunData); + + + var shiftRequired = currentGear != expectedGear; + + var shiftStrategy = GetShiftStrategyAndGearbox(container, out var gearbox); + // var gear = new GearshiftPosition((uint)currentGear); + // gearbox.Gear = gear; + + var absTime = 0.SI<Second>(); + var dt = 0.5.SI<Second>(); + + var init_outTorque = init_outTorque_Nm.SI<NewtonMeter>(); + var init_outAngularVelocity = init_outSpeed_rpm.RPMtoRad(); + + var outTorque = outTorque_Nm.SI<NewtonMeter>(); + var outAngularVelocity = outSpeed_rpm.RPMtoRad(); + + var inTorque = outTorque / ratio; + var inAngularVelocity = outAngularVelocity * ratio; + + var lastShiftTime = float.MinValue.SI<Second>(); + + + + Console.WriteLine( + $"OutTorque: {outTorque}\n" + + $"InTorque: {inTorque} \n" + + $"OutSpeed: {outAngularVelocity}\n" + + $"InSpeed: {inAngularVelocity}\n"); + + + //Init gear + var initResult = shiftStrategy.InitGear(absTime, dt, init_outTorque, init_outAngularVelocity); + Assert.That(shiftStrategy.NextGear.Gear, Is.EqualTo(currentGear)); + + var response = new ResponseSuccess(this) { }; + response.ElectricMotor.AngularVelocity = inAngularVelocity; + response.ElectricMotor.TorqueRequestEmMap = inTorque; + response.ElectricMotor.DeRatingActive = false; + response.Gearbox.InputSpeed = inAngularVelocity; + // response.ElectricMotor; + + //Check shift required + var result = shiftStrategy.ShiftRequired(absTime, dt, + outTorque: outTorque, + outAngularVelocity: outAngularVelocity, + inTorque: inTorque, + inAngularVelocity: inAngularVelocity, + gear: shiftStrategy.NextGear, + lastShiftTime: lastShiftTime, + response: response); + + Assert.AreEqual(shiftRequired, result, "Expected Shift"); + Assert.AreEqual(expectedGear, shiftStrategy.NextGear.Gear); + + + + } + + + public void CheckDownshift( + double init_outTorque_Nm, + double init_outSpeed_rpm, + double outTorque_Nm, + double outSpeed_rpm, + int currentGear, + int expectedGear, + double[] ratios, + bool effShift = true, + int vehicleSpeed_kmH = 1) + { + // the first element 0.0 is just a placeholder for axlegear, not used in this test + var ratio = ratios[currentGear]; + var container = GetMocks(ratios); + container.Setup(c => c.VehicleInfo.VehicleSpeed).Returns(vehicleSpeed_kmH.KMPHtoMeterPerSecond()); + + + if (!effShift) { + DisableEffshift(container.Object.RunData); + } + + var shiftRequired = currentGear != expectedGear; + + var shiftStrategy = GetShiftStrategyAndGearbox(container, out var gearbox); + // var gear = new GearshiftPosition((uint)currentGear); + // gearbox.Gear = gear; + + var absTime = 0.SI<Second>(); + var dt = 0.5.SI<Second>(); + + var init_outTorque = init_outTorque_Nm.SI<NewtonMeter>(); + var init_outAngularVelocity = init_outSpeed_rpm.RPMtoRad(); + + var outTorque = outTorque_Nm.SI<NewtonMeter>(); + var outAngularVelocity = outSpeed_rpm.RPMtoRad(); + + var inTorque = outTorque / ratio; + var inAngularVelocity = outAngularVelocity * ratio; + + var lastShiftTime = float.MinValue.SI<Second>(); + + + + Console.WriteLine( + $"OutTorque: {outTorque}\n" + + $"InTorque: {inTorque} \n" + + $"OutSpeed: {outAngularVelocity}\n" + + $"InSpeed: {inAngularVelocity}\n"); + + + //Init gear + var initResult = shiftStrategy.InitGear(absTime, dt, init_outTorque, init_outAngularVelocity); + Assert.That(shiftStrategy.NextGear.Gear, Is.EqualTo(currentGear)); + + var response = new ResponseSuccess(this) { }; + response.ElectricMotor.AngularVelocity = inAngularVelocity; + response.ElectricMotor.TorqueRequestEmMap = inTorque; + response.ElectricMotor.DeRatingActive = false; + // response.ElectricMotor; + + //Check shift required + var result = shiftStrategy.ShiftRequired(absTime, dt, + outTorque: outTorque, + outAngularVelocity: outAngularVelocity, + inTorque: inTorque, + inAngularVelocity: inAngularVelocity, + gear: shiftStrategy.NextGear, + lastShiftTime: lastShiftTime, + response: response); + + Assert.AreEqual(shiftRequired, result, "Expected Shift"); + Assert.AreEqual(expectedGear, shiftStrategy.NextGear.Gear); + + + + } + + + + + + private PEVAMTShiftStrategy GetShiftStrategyAndGearbox(Mock<IVehicleContainer> container, + out Mock<IPEVGearbox> gearbox) + { + var shiftStrategy = new PEVAMTShiftStrategy(container.Object); + + // gearbox = new PEVGearbox(container.Object, shiftStrategy); + + SetVelocityDropLookupData(shiftStrategy); + + var gbx = GetGearbox(); + // gearbox.Gear = new GearshiftPosition(0); + // container.Setup(c => c.GearboxInfo).Returns(gearbox); + + gearbox = gbx; + + shiftStrategy.Gearbox = gbx.Object; + return shiftStrategy; + } + + private Mock<IPEVGearbox> GetGearbox() + { + var gbx = new Mock<IPEVGearbox>(MockBehavior.Strict); + gbx.Setup(g => g.LastUpshift).Returns(-double.MaxValue.SI<Second>()); + gbx.Setup(g => g.LastDownshift).Returns(-double.MaxValue.SI<Second>()); + + + + return gbx; + } + + private Mock<IVehicleContainer> GetMocks(double[] ratios) + { + var container = new Mock<IVehicleContainer>(); + + //RunData + var runData = GetRunData(ratios); + container.Setup(r => r.RunData).Returns(runData); + + //EmInfo + var em = GetElectricMotor(container.Object, runData.ElectricMachinesData.Single().Item2); + container.Setup(c => c.ElectricMotorInfo(PowertrainPosition.BatteryElectricE2)) + .Returns(em); + container.Setup(c => c.PowertrainInfo.ElectricMotorPositions).Returns(new[] { + PowertrainPosition.BatteryElectricE2 + }); + + // container.Setup(r => r.GetElectricMotors()).Returns(new List<IElectricMotorInfo>(){em}); + + container.Setup(c => c.PowertrainInfo.HasCombustionEngine).Returns(false); + + //BatteryInfo + container.Setup(c => c.BatteryInfo.InternalVoltage).Returns(700.SI<Volt>()); + + //VehicleInfo + container.Setup(c => c.VehicleInfo.VehicleSpeed).Returns(1.KMPHtoMeterPerSecond()); + container.Setup(c => c.VehicleInfo.VehicleStopped).Returns(false); + + //DriverInfo + container.Setup(c => c.DriverInfo.DriverBehavior).Returns(DrivingBehavior.Accelerating); + container.Setup(c => c.DriverInfo.DrivingAction).Returns(DrivingAction.Accelerate); + // container.Set + + //PowertrainBuilder, SimplePowertrain + var testPt = GetTestPowertrain(ratios, container, out _); + var ptBuilder = new Mock<ISimplePowertrainBuilder>(); + ptBuilder.Setup(c => c.CreateTestPowertrain( + It.IsAny<IVehicleContainer>(), It.IsAny<bool>())) + .Returns(testPt.Object); + ptBuilder.Setup(c => c.CreateTestPowertrain( + It.IsAny<IVehicleContainer>(), It.IsAny<bool>(), It.IsAny<VectoSimulationJobType>())) + .Returns(testPt.Object); + container.Setup(c => c.SimplePowertrainBuilder).Returns(ptBuilder.Object); + + //DrivingCycleInfo + container.Setup(c => c.DrivingCycleInfo.RoadGradient).Returns(0.SI<Radian>()); + + return container; + } + + private Mock<ITestPowertrain> GetTestPowertrain(double[] ratios, + Mock<IVehicleContainer> container, + out Mock<ISimpleVehicleContainer> simplePt) + { + var testPt = new Mock<ITestPowertrain>(); + simplePt = GetSimplePowertrain(ratios, container, out var gbx); + var simplePtObj = simplePt.Object; + testPt.Setup(t => t.ElectricMotors).Returns(() => { + var dict = new Dictionary<PowertrainPosition, ITestpowertrainElectricMotor>(); + foreach (var (k, v) in simplePtObj.ElectricMotors) { + if (v is ITestpowertrainElectricMotor testEm) { + dict[k] = testEm; + } else { + throw new Exception("Expected TestElectricMotor in simple powertrain"); + } + } + return dict; + }); + + testPt.Setup(t => t.Container).Returns(simplePt.Object); + + testPt.Setup(t => t.Gearbox).Returns(gbx.Object); + return testPt; + } + + private Mock<IElectricSystem> GetMockElectricSystem() + { + var electricSystem = new Mock<IElectricSystem>(); + + + electricSystem + .Setup(es => es.Request(It.IsAny<Second>(), It.IsAny<Second>(), It.IsAny<Watt>(), true)) + .Returns((Second t, Second dt, Watt powerDemand, bool dryrun) => { + + var response = new Mock<IElectricSystemResponse>(); + response + .Setup(mr => mr.MaxPowerDrive) + .Returns(-100E3.SI<Watt>()); + response + .Setup(mr => mr.MaxPowerDrag) + .Returns(100E3.SI<Watt>()); + response + .Setup(mr => mr.RESSPowerDemand).Returns(powerDemand); + + + + + return response.Object; + }); + + + return electricSystem; + } + + private ElectricMotor GetElectricMotor(IVehicleContainer container, ElectricMotorData emData) + { + var emControl = new SimpleElectricMotorControl(); + + var electricMotor = new ElectricMotor(container: container, emData, emControl, + PowertrainPosition.BatteryElectricE2); + + //Connect Electric System + var es = GetMockElectricSystem(); + electricMotor.Connect(es.Object); + return electricMotor; + } + + private TestPowertrainElectricMotor GetTestPowertrainElectricMotor(ISimpleVehicleContainer container, + ElectricMotorData emData) + { + var emControl = new SimpleElectricMotorControl(); + + var electricMotor = new TestPowertrainElectricMotor(container: container, emData, emControl, + PowertrainPosition.BatteryElectricE2); + + //Connect Electric System + var es = GetMockElectricSystem(); + electricMotor.Connect(es.Object); + return electricMotor; + } + + private Mock<ISimpleVehicleContainer> GetSimplePowertrain( + double[] ratios, + Mock<IVehicleContainer> container, + out Mock<ITestPowertrainTransmission> testGbx) + { + var simplePt = new Mock<ISimpleVehicleContainer>(); + simplePt.Setup(s => s.IsTestPowertrain).Returns(true); + + + var components = new List<VectoSimulationComponent>(); + + var runData = container.Object.RunData; + var em = GetTestPowertrainElectricMotor(simplePt.Object, runData.ElectricMachinesData.Single().Item2); + var emDict = new Dictionary<PowertrainPosition, IElectricMotorInfo>() { + { PowertrainPosition.BatteryElectricE2, em }, + }; + simplePt.Setup(r => r.ElectricMotorInfo(PowertrainPosition.BatteryElectricE2)) + .Returns(em); + + //BatteryInfo + simplePt.Setup(s => s.BatteryInfo.InternalVoltage).Returns(700.SI<Volt>()); + + simplePt.Setup(s => s.ElectricMotors).Returns(emDict); + + simplePt.Setup(s => s.PowertrainInfo.HasCombustionEngine).Returns(false); + + simplePt.Setup(s => s.RunData).Returns(runData); + + testGbx = GetTestGearbox(simplePt.Object, em, runData.GearboxData.Gears); + + simplePt.Setup(s => s.GearboxCtl).Returns(testGbx.Object); + simplePt.Setup(s => s.GearboxInfo).Returns(testGbx.Object); + simplePt.Setup(s => s.GearboxOutPort).Returns(testGbx.Object); + + simplePt.Setup(s => s.SimulationComponents()).Returns(components); + simplePt.Setup(s => s.Brakes).Returns(new Mock<IBrakes>().Object); + + //Take from real powertrain + simplePt.Setup(s => s.VehicleInfo).Returns(container.Object.VehicleInfo); + simplePt.Setup(s => s.DriverInfo).Returns(container.Object.DriverInfo); + + return simplePt; + } + + Mock<ITestPowertrainTransmission> GetTestGearbox( + ISimpleVehicleContainer simpleContainer, + TestPowertrainElectricMotor em, + Dictionary<uint, GearData> ratios) + { + Mock<IAMTGearbox> amtGearbox = new Mock<IAMTGearbox>(); + amtGearbox.Name = "PEVAMT_TestGearbox"; + Mock<ITestPowertrainTransmission> gbx = amtGearbox.As<ITestPowertrainTransmission>(); + + gbx.Setup(g => g.LastUpshift).Returns(-double.MaxValue.SI<Second>()); + gbx.Setup(g => g.LastDownshift).Returns(-double.MaxValue.SI<Second>()); + + GearshiftPosition gear = null; + gbx.SetupGet(g => g.Gear).Returns(() => gear); + gbx.SetupSet(g => g.SetGear = It.IsAny<GearshiftPosition>()) + .Callback<GearshiftPosition>(p => { + gear = p; + }); + + + GearshiftPosition nextGear = null; + gbx.SetupGet(g => g.NextGear).Returns(() => nextGear); + gbx.SetupSet(g => g.SetNextGear = It.IsAny<GearshiftPosition>()) + .Callback<GearshiftPosition>(p => nextGear = p); + + + gbx.Setup(p => p.Initialize(It.IsAny<NewtonMeter>(), + It.IsAny<PerSecond>())).Returns((NewtonMeter outTorque, PerSecond outSpeed) => { + var ratio = + gbx.Object.Gear == null ? 1.0 : ratios[gbx.Object.Gear.Gear].Ratio; + + var inSpeed = outSpeed * ratio; + var inTorque = outTorque / ratio; + + em.Initialize(inTorque, inSpeed); + return new ResponseSuccess(this) + { + + }; + }); + gbx.Setup(p => p.Request( + It.IsAny<Second>(), + It.IsAny<Second>(), + It.IsAny<NewtonMeter>(), + It.IsAny<PerSecond>(), + true)).Returns(( + Second absTime, + Second dt, + NewtonMeter outTorque, + PerSecond outSpeed, + bool dryRun) => { + + var ratio = + gbx.Object.Gear == null ? 1.0 : ratios[gbx.Object.Gear.Gear].Ratio; + + var inSpeed = outSpeed * ratio; + var inTorque = outTorque / ratio; + + var emResponse = em.Request(absTime, dt, inTorque, inSpeed, dryRun); + return dryRun + ? new ResponseDryRun(this, emResponse) { + // Engine = { + // PowerRequest = n * t, EngineSpeed = n * ratio, + // DynamicFullLoadPower = (t / ratio + 2300.SI<NewtonMeter>()) * n * ratio, + // TotalTorqueDemand = t, + // }, + // ElectricMotor = emResponse.ElectricMotor, + Gearbox = { + Gear = gbx.Object.Gear, + InputSpeed = inSpeed, + InputTorque = inTorque, + OutputSpeed = outSpeed, + OutputTorque = outTorque, + PowerRequest = outSpeed * outTorque, + }, + Clutch = { PowerRequest = outSpeed * outTorque }, + DeltaFullLoad = outSpeed * outTorque / 2 * (-1) + } + : new ResponseSuccess(this) { + Gearbox = { + Gear = gbx.Object.Gear, + InputSpeed = inSpeed, + InputTorque = inTorque, + }, + Clutch = { PowerRequest = outSpeed * outTorque } + }; + }); + return gbx; + } + + + private VectoRunData GetRunData(double[] ratios) + { + var runData = new VectoRunData(); + + //GearShiftParameters + var gearshiftParameters = new ShiftStrategyParameters() { + TorqueReserve = 0.0, + TimeBetweenGearshifts = 2.SI<Second>(), + DownshiftAfterUpshiftDelay = 2.SI<Second>(), + UpshiftAfterDownshiftDelay = 2.SI<Second>(), + UpshiftMinAcceleration = 0.1.SI<MeterPerSquareSecond>(), + StartSpeed = 0.KMPHtoMeterPerSecond(), + RatingFactorCurrentGear = 1, + AllowedGearRangeFC = 2, + MinEngineSpeedPostUpshift = 0.RPMtoRad(), + }; + runData.GearshiftParameters = gearshiftParameters; + + runData.ElectricMachinesData = GetElectricMachinesData(); + var emData = runData.ElectricMachinesData.Single(i => i.Item1 == PowertrainPosition.BatteryElectricE2) + .Item2; + //VehicleData + var vehicleData = new VehicleData() { + DynamicTyreRadius = 0.492.SI<Meter>(), + }; + runData.VehicleData = vehicleData; + + //CycleData + var mockCycle = new Mock<IDrivingCycleData>(); + mockCycle.Setup(cd => cd.Entries).Returns( + new List<DrivingCycleData.DrivingCycleEntry>() { + new DrivingCycleData.DrivingCycleEntry() { + RoadGradient = 0.SI<Radian>() + } + }); + runData.Cycle = mockCycle.Object; + + + //Gearboxdata + var gearboxInputData = new Mock<IGearboxDeclarationInputData>(); + + var gearsInputData = new List<Mock<ITransmissionInputData>>(); + + gearboxInputData.Setup( + d => d.Gears) + .Returns(gearsInputData.Select(m => m.Object) + .ToList()); + + + var gearboxData = new GearboxData() { + Gears = new Dictionary<uint, GearData>(ratios.Length), + InputData = gearboxInputData.Object, + Type = GearboxType.AMT, + TractionInterruption = 1.SI<Second>(), + Inertia = 0.SI<KilogramSquareMeter>(), + }; + + + + + + runData.GearboxData = gearboxData; + for (uint i = 1; i < ratios.Length; i++) { + gearboxData.Gears[i] = new GearData + { + Ratio = ratios[i], + LossMap = TransmissionLossMapReader.Create(0.96, ratios[i], $"Gear {i}"), + + }; + } + var axlRatio = 3.240355; + var gearsInput = gearboxData.Gears.Select(x => { + var r = new Mock<ITransmissionInputData>(); + r.Setup(g => g.Ratio).Returns(x.Value.Ratio); + r.Setup(g => g.MaxTorque).Returns(x.Value.MaxTorque); + r.Setup(g => g.MaxInputSpeed).Returns(x.Value.MaxSpeed); + + return r.Object; + }).ToList(); + foreach (var entry in gearboxData.Gears) { + var gearIdx = (int)entry.Key - 1; + var dynamicTyreRadius = 0.5.SI<Meter>(); + + var shiftPolygon = DeclarationData.Gearbox.ComputeElectricMotorShiftPolygon( + gearIdx, + emData, + gearsInput); + + entry.Value.ShiftPolygon = shiftPolygon; + + } + + + return runData; + } + + private IList<Tuple<PowertrainPosition, ElectricMotorData>> GetElectricMachinesData() + { + //Nr of electric machines + const int emCount = 2; + //ElectricMachines + // var electricMotorData = new ElectricMotorData() { + // + // }; + var emDataAdapter = new ElectricMachinesDataAdapter(); + var emInputData = new Mock<IElectricMotorDeclarationInputData>(); + + var powerMapMock = new Mock<IElectricMotorPowerMap>(); + powerMapMock.Setup(pm => pm.Gear).Returns(0); + powerMapMock.Setup(pm => pm.PowerMap).Returns(GetEfficiencyMapData()); + + var voltageLevels = new List<IElectricMotorVoltageLevel>() { + new ElectricMotorVoltageLevel(){ + VoltageLevel = 100.SI<Volt>(), + ContinuousTorque = 450.SI<NewtonMeter>(), + ContinuousTorqueSpeed = 2460.RPMtoRad(), + OverloadTorque = 485.SI<NewtonMeter>(), + OverloadTestSpeed = 2460.RPMtoRad(), + OverloadTime = 120.SI<Second>(), + FullLoadCurve = GetFullLoadCurveData(), + PowerMap = new List<IElectricMotorPowerMap>(){powerMapMock.Object} + }, + new ElectricMotorVoltageLevel(){ + VoltageLevel = 1000.SI<Volt>(), + ContinuousTorque = 450.SI<NewtonMeter>(), + ContinuousTorqueSpeed = 2460.RPMtoRad(), + OverloadTorque = 485.SI<NewtonMeter>(), + OverloadTestSpeed = 2460.RPMtoRad(), + OverloadTime = 120.SI<Second>(), + FullLoadCurve = GetFullLoadCurveData(), + PowerMap = new List<IElectricMotorPowerMap>(){powerMapMock.Object} + } + }; + + emInputData.Setup(em => em.CertificationMethod).Returns(CertificationMethod.Measured); + emInputData.Setup(em => em.Inertia).Returns(0.225.SI<KilogramSquareMeter>()); + emInputData.Setup(em => em.R85RatedPower).Returns(250E3.SI<Watt>()); + emInputData.Setup(em => em.ElectricMachineType).Returns(ElectricMachineType.ASM); + emInputData.Setup(em => em.VoltageLevels).Returns(voltageLevels); + emInputData.Setup(em => em.DragCurve).Returns(GetDragCurveData); + + var adcInputData = new Mock<IADCDeclarationInputData>(); + adcInputData.Setup(adc => adc.Ratio).Returns(1.0f); + + var emsInputData = new Mock<IElectricMachinesDeclarationInputData>(); + emsInputData.Setup(em => em.Entries).Returns( + new List<ElectricMachineEntry<IElectricMotorDeclarationInputData>>() { + new ElectricMachineEntry<IElectricMotorDeclarationInputData>() { + Count = emCount, + Position = PowertrainPosition.BatteryElectricE2, + ElectricMachine = emInputData.Object, + ADC = adcInputData.Object, + RatioADC = 2.0, + MechanicalTransmissionEfficiency = 0.97, + } + }); + + var avgVoltage = 200.SI<Volt>(); + IDictionary<PowertrainPosition, IList<Tuple<Volt, TableData>>> torqueLimits = new Dictionary<PowertrainPosition, IList<Tuple<Volt, TableData>>>(); + + var electricMachinesData = emDataAdapter.CreateElectricMachines(emsInputData.Object, torqueLimits:torqueLimits, + avgVoltage, null); + + + + + + return electricMachinesData; + + } + + private TableData GetDragCurveData() + { + return InputDataHelper.InputDataAsTableData( + "n [rpm] , T_drag [Nm]", + "0 , -6.06", + "7363.77 , -30.31"); + } + + + private TableData GetFullLoadCurveData() + { + return InputDataHelper.InputDataAsTableData("n [rpm] , T_drive [Nm] , T_drag [Nm]", + #region data + "0,485,-485", +"2461.158914,485,-485", +"2452.135493,485,-485", +"2466.863034,483.8845,-483.8845", +"2481.590574,481.010875,-481.010875", +"2496.318115,478.173625,-478.173625", +"2503.681885,476.767125,-476.767125", +"2577.319588,463.138625,-463.138625", +"2650.95729,450.274,-450.274", +"2724.594993,438.1005,-438.1005", +"2798.232695,426.58175,-426.58175", +"2871.870398,415.645,-415.645", +"2945.5081,405.253875,-405.253875", +"3019.145803,395.359875,-395.359875", +"3092.783505,385.950875,-385.950875", +"3166.421208,376.978375,-376.978375", +"3240.05891,368.406,-368.406", +"3313.696613,360.221625,-360.221625", +"3387.334315,352.388875,-352.388875", +"3460.972018,344.895625,-344.895625", +"3534.60972,337.7055,-337.7055", +"3608.247423,330.8185,-330.8185", +"3681.885125,324.19825,-324.19825", +"3755.522828,317.84475,-317.84475", +"3829.16053,311.73375,-311.73375", +"3902.798233,305.853125,-305.853125", +"3976.435935,300.178625,-300.178625", +"4050.073638,294.722375,-294.722375", +"4123.71134,289.460125,-289.460125", +"4197.349043,284.37975,-284.37975", +"4270.986745,279.48125,-279.48125", +"4344.624448,274.740375,-274.740375", +"4418.26215,270.16925,-270.16925", +"4491.899853,265.7315,-265.7315", +"4565.537555,261.451375,-261.451375", +"4639.175258,257.304625,-257.304625", +"4712.81296,253.279125,-253.279125", +"4786.450663,249.387,-249.387", +"4860.088365,245.604,-245.604", +"4933.726068,241.94225,-241.94225", +"5007.36377,238.3775,-238.3775", +"5081.001473,234.921875,-234.921875", +"5154.639175,231.575375,-231.575375", +"5228.276878,228.31375,-228.31375", +"5301.91458,225.137,-225.137", +"5375.552283,222.05725,-222.05725", +"5449.189985,219.05025,-219.05025", +"5522.827688,216.128125,-216.128125", +"5596.46539,213.290875,-213.290875", +"5670.103093,210.51425,-210.51425", +"5743.740795,207.8225,-207.8225", +"5817.378498,205.191375,-205.191375", +"5891.0162,202.620875,-202.620875", +"5964.653903,200.123125,-200.123125", +"6038.291605,197.686,-197.686", +"6111.929308,195.297375,-195.297375", +"6185.56701,192.969375,-192.969375", +"6259.204713,190.702,-190.702", +"6332.842415,188.483125,-188.483125", +"6406.480118,186.324875,-186.324875", +"6480.11782,184.203,-184.203", +"6553.755523,182.129625,-182.129625", +"6627.393225,180.10475,-180.10475", +"6701.030928,178.128375,-178.128375", +"6774.66863,176.2005,-176.2005", +"6848.306333,174.296875,-174.296875", +"6921.944035,172.44175,-172.44175", +"6995.581738,170.635125,-170.635125", +"7069.21944,168.85275,-168.85275", +"7142.857143,167.10675,-167.10675", +"7216.494845,165.40925,-165.40925", +"7290.132548,163.736,-163.736", +"7363.77025,162.099125,-162.099125" + #endregion data + ); + } + private ElectricMotorFullLoadCurve GetFullLoadCurve(int count) + { + var inputData = GetFullLoadCurveData(); + return ElectricFullLoadCurveReader.Create(inputData, count); + } + private TableData GetEfficiencyMapData() + { + return InputDataHelper.InputDataAsTableData( + "n [rpm] , T [Nm] , P_el [kW]", + #region entries + "0, -485, 0.000", +"0, -461, 0.000", +"0, -437, 0.000", +"0, -412, 0.000", +"0, -388, 0.000", +"0, -364, 0.000", +"0, -340, 0.000", +"0, -315, 0.000", +"0, -291, 0.000", +"0, -267, 0.000", +"0, -243, 0.000", +"0, -218, 0.000", +"0, -194, 0.000", +"0, -170, 0.000", +"0, -146, 0.000", +"0, -121, 0.000", +"0, -97, 0.000", +"0, -73, 0.000", +"0, -48, 0.000", +"0, -24, 0.000", +"0, -5, 0.000", +"0, 5, 0.000", +"0, 24, 0.000", +"0, 48, 0.000", +"0, 73, 0.000", +"0, 97, 0.000", +"0, 121, 0.000", +"0, 146, 0.000", +"0, 170, 0.000", +"0, 194, 0.000", +"0, 218, 0.000", +"0, 243, 0.000", +"0, 267, 0.000", +"0, 291, 0.000", +"0, 315, 0.000", +"0, 340, 0.000", +"0, 364, 0.000", +"0, 388, 0.000", +"0, 412, 0.000", +"0, 437, 0.000", +"0, 461, 0.000", +"0, 485, 0.000", +"49, -485, 0.000", +"49, -461, 0.000", +"49, -437, 0.000", +"49, -412, 0.000", +"49, -388, 0.000", +"49, -364, 0.000", +"49, -340, -0.045", +"49, -315, -0.111", +"49, -291, -0.166", +"49, -267, -0.211", +"49, -243, -0.245", +"49, -218, -0.268", +"49, -194, -0.280", +"49, -170, -0.281", +"49, -146, -0.272", +"49, -121, -0.252", +"49, -97, -0.221", +"49, -73, -0.179", +"49, -48, -0.126", +"49, -24, -0.062", +"49, -5, -0.004", +"49, 5, 0.048", +"49, 24, 0.193", +"49, 48, 0.384", +"49, 73, 0.587", +"49, 97, 0.802", +"49, 121, 1.029", +"49, 146, 1.267", +"49, 170, 1.518", +"49, 194, 1.779", +"49, 218, 2.053", +"49, 243, 2.338", +"49, 267, 2.636", +"49, 291, 2.944", +"49, 315, 3.265", +"49, 340, 3.597", +"49, 364, 3.941", +"49, 388, 4.297", +"49, 412, 4.665", +"49, 437, 5.044", +"49, 461, 5.435", +"49, 485, 5.838", +"492, -485, -20.733", +"492, -461, -19.800", +"492, -437, -18.856", +"492, -412, -17.900", +"492, -388, -16.932", +"492, -364, -15.953", +"492, -340, -14.962", +"492, -315, -13.959", +"492, -291, -12.945", +"492, -267, -11.919", +"492, -243, -10.881", +"492, -218, -9.832", +"492, -194, -8.771", +"492, -170, -7.699", +"492, -146, -6.614", +"492, -121, -5.519", +"492, -97, -4.411", +"492, -73, -3.292", +"492, -48, -2.161", +"492, -24, -1.019", +"492, -5, -0.097", +"492, 5, 0.416", +"492, 24, 1.498", +"492, 48, 2.863", +"492, 73, 4.240", +"492, 97, 5.630", +"492, 121, 7.033", +"492, 146, 8.448", +"492, 170, 9.876", +"492, 194, 11.316", +"492, 218, 12.769", +"492, 243, 14.235", +"492, 267, 15.713", +"492, 291, 17.204", +"492, 315, 18.708", +"492, 340, 20.224", +"492, 364, 21.753", +"492, 388, 23.294", +"492, 412, 24.848", +"492, 437, 26.415", +"492, 461, 27.994", +"492, 485, 29.586", +"984, -485, -44.101", +"984, -461, -42.013", +"984, -437, -39.910", +"984, -412, -37.794", +"984, -388, -35.664", +"984, -364, -33.520", +"984, -340, -31.362", +"984, -315, -29.190", +"984, -291, -27.004", +"984, -267, -24.805", +"984, -243, -22.591", +"984, -218, -20.363", +"984, -194, -18.122", +"984, -170, -15.867", +"984, -146, -13.597", +"984, -121, -11.314", +"984, -97, -9.017", +"984, -73, -6.706", +"984, -48, -4.381", +"984, -24, -2.042", +"984, -5, -0.161", +"984, 5, 0.867", +"984, 24, 2.993", +"984, 48, 5.663", +"984, 73, 8.349", +"984, 97, 11.049", +"984, 121, 13.765", +"984, 146, 16.496", +"984, 170, 19.242", +"984, 194, 22.003", +"984, 218, 24.779", +"984, 243, 27.571", +"984, 267, 30.377", +"984, 291, 33.198", +"984, 315, 36.035", +"984, 340, 38.887", +"984, 364, 41.754", +"984, 388, 44.635", +"984, 412, 47.532", +"984, 437, 50.445", +"984, 461, 53.372", +"984, 485, 56.314", +"1477, -485, -67.122", +"1477, -461, -63.906", +"1477, -437, -60.673", +"1477, -412, -57.422", +"1477, -388, -54.153", +"1477, -364, -50.867", +"1477, -340, -47.563", +"1477, -315, -44.241", +"1477, -291, -40.902", +"1477, -267, -37.545", +"1477, -243, -34.170", +"1477, -218, -30.778", +"1477, -194, -27.368", +"1477, -170, -23.941", +"1477, -146, -20.496", +"1477, -121, -17.033", +"1477, -97, -13.552", +"1477, -73, -10.054", +"1477, -48, -6.539", +"1477, -24, -3.005", +"1477, -5, -0.166", +"1477, 5, 1.383", +"1477, 24, 4.552", +"1477, 48, 8.530", +"1477, 73, 12.528", +"1477, 97, 16.545", +"1477, 121, 20.581", +"1477, 146, 24.636", +"1477, 170, 28.710", +"1477, 194, 32.804", +"1477, 218, 36.916", +"1477, 243, 41.048", +"1477, 267, 45.199", +"1477, 291, 49.369", +"1477, 315, 53.558", +"1477, 340, 57.766", +"1477, 364, 61.994", +"1477, 388, 66.240", +"1477, 412, 70.506", +"1477, 437, 74.791", +"1477, 461, 79.095", +"1477, 485, 83.418", +"1969, -485, -89.780", +"1969, -461, -85.464", +"1969, -437, -81.126", +"1969, -412, -76.766", +"1969, -388, -72.382", +"1969, -364, -67.976", +"1969, -340, -63.546", +"1969, -315, -59.094", +"1969, -291, -54.620", +"1969, -267, -50.122", +"1969, -243, -45.602", +"1969, -218, -41.058", +"1969, -194, -36.492", +"1969, -170, -31.904", +"1969, -146, -27.292", +"1969, -121, -22.658", +"1969, -97, -18.000", +"1969, -73, -13.320", +"1969, -48, -8.618", +"1969, -24, -3.892", +"1969, -5, -0.095", +"1969, 5, 1.980", +"1969, 24, 6.193", +"1969, 48, 11.483", +"1969, 73, 16.796", +"1969, 97, 22.135", +"1969, 121, 27.498", +"1969, 146, 32.886", +"1969, 170, 38.299", +"1969, 194, 43.736", +"1969, 218, 49.199", +"1969, 243, 54.686", +"1969, 267, 60.197", +"1969, 291, 65.734", +"1969, 315, 71.295", +"1969, 340, 76.881", +"1969, 364, 82.492", +"1969, 388, 88.127", +"1969, 412, 93.787", +"1969, 437, 99.472", +"1969, 461, 105.182", +"1969, 485, 110.916", +"2461, -485, -112.056", +"2461, -461, -106.670", +"2461, -437, -101.254", +"2461, -412, -95.808", +"2461, -388, -90.334", +"2461, -364, -84.830", +"2461, -340, -79.296", +"2461, -315, -73.733", +"2461, -291, -68.141", +"2461, -267, -62.519", +"2461, -243, -56.868", +"2461, -218, -51.188", +"2461, -194, -45.478", +"2461, -170, -39.738", +"2461, -146, -33.970", +"2461, -121, -28.172", +"2461, -97, -22.344", +"2461, -73, -16.487", +"2461, -48, -10.601", +"2461, -24, -4.685", +"2461, -5, 0.000", +"2461, 5, 2.679", +"2461, 24, 7.937", +"2461, 48, 14.539", +"2461, 73, 21.173", +"2461, 97, 27.839", +"2461, 121, 34.536", +"2461, 146, 41.266", +"2461, 170, 48.027", +"2461, 194, 54.820", +"2461, 218, 61.646", +"2461, 243, 68.503", +"2461, 267, 75.392", +"2461, 291, 82.313", +"2461, 315, 89.265", +"2461, 340, 96.250", +"2461, 364, 103.267", +"2461, 388, 110.315", +"2461, 412, 117.396", +"2461, 437, 124.508", +"2461, 461, 131.652", +"2461, 485, 138.828", +"2953, -485, -133.934", +"2953, -461, -127.504", +"2953, -437, -121.037", +"2953, -412, -114.532", +"2953, -388, -107.990", +"2953, -364, -101.411", +"2953, -340, -94.794", +"2953, -315, -88.140", +"2953, -291, -81.448", +"2953, -267, -74.719", +"2953, -243, -67.952", +"2953, -218, -61.148", +"2953, -194, -54.306", +"2953, -170, -47.427", +"2953, -146, -40.511", +"2953, -121, -33.557", +"2953, -97, -26.566", +"2953, -73, -19.537", +"2953, -48, -12.471", +"2953, -24, -5.367", +"2953, -5, 0.000", +"2953, 5, 3.497", +"2953, 24, 9.801", +"2953, 48, 17.718", +"2953, 73, 25.676", +"2953, 97, 33.674", +"2953, 121, 41.713", +"2953, 146, 49.793", +"2953, 170, 57.913", +"2953, 194, 66.074", +"2953, 218, 74.275", +"2953, 243, 82.517", +"2953, 267, 90.800", +"2953, 291, 99.123", +"2953, 315, 107.487", +"2953, 340, 115.892", +"2953, 364, 124.337", +"2953, 388, 132.823", +"2953, 412, 141.349", +"2953, 437, 149.916", +"2953, 461, 158.524", +"2953, 485, 167.172", +"3446, -485, -155.396", +"3446, -461, -147.951", +"3446, -437, -140.460", +"3446, -412, -132.921", +"3446, -388, -125.335", +"3446, -364, -117.703", +"3446, -340, -110.023", +"3446, -315, -102.297", +"3446, -291, -94.524", +"3446, -267, -86.703", +"3446, -243, -78.836", +"3446, -218, -70.922", +"3446, -194, -62.961", +"3446, -170, -54.953", +"3446, -146, -46.898", +"3446, -121, -38.797", +"3446, -97, -30.648", +"3446, -73, -22.452", +"3446, -48, -14.210", +"3446, -24, -5.921", +"3446, -5, 0.000", +"3446, 5, 4.454", +"3446, 24, 11.805", +"3446, 48, 21.040", +"3446, 73, 30.325", +"3446, 97, 39.661", +"3446, 121, 49.049", +"3446, 146, 58.487", +"3446, 170, 67.976", +"3446, 194, 77.516", +"3446, 218, 87.107", +"3446, 243, 96.749", +"3446, 267, 106.442", +"3446, 291, 116.185", +"3446, 315, 125.980", +"3446, 340, 135.826", +"3446, 364, 145.722", +"3446, 388, 155.669", +"3446, 412, 165.668", +"3446, 437, 175.717", +"3446, 461, 185.817", +"3446, 485, 195.968", +"3938, -485, -176.425", +"3938, -461, -167.994", +"3938, -437, -159.504", +"3938, -412, -150.956", +"3938, -388, -142.351", +"3938, -364, -133.687", +"3938, -340, -124.966", +"3938, -315, -116.187", +"3938, -291, -107.351", +"3938, -267, -98.456", +"3938, -243, -89.503", +"3938, -218, -80.493", +"3938, -194, -71.425", +"3938, -170, -62.299", +"3938, -146, -53.115", +"3938, -121, -43.873", +"3938, -97, -34.574", +"3938, -73, -25.217", +"3938, -48, -15.801", +"3938, -24, -6.328", +"3938, -5, 0.000", +"3938, 5, 5.568", +"3938, 24, 13.967", +"3938, 48, 24.521", +"3938, 73, 35.138", +"3938, 97, 45.818", +"3938, 121, 56.561", +"3938, 146, 67.366", +"3938, 170, 78.235", +"3938, 194, 89.166", +"3938, 218, 100.159", +"3938, 243, 111.216", +"3938, 267, 122.335", +"3938, 291, 133.517", +"3938, 315, 144.762", +"3938, 340, 156.070", +"3938, 364, 167.440", +"3938, 388, 178.873", +"3938, 412, 190.369", +"3938, 437, 201.927", +"3938, 461, 213.549", +"3938, 485, 225.233", +"4430, -485, -197.004", +"4430, -461, -187.614", +"4430, -437, -178.152", +"4430, -412, -168.621", +"4430, -388, -159.020", +"4430, -364, -149.348", +"4430, -340, -139.606", +"4430, -315, -129.794", +"4430, -291, -119.912", +"4430, -267, -109.959", +"4430, -243, -99.936", +"4430, -218, -89.844", +"4430, -194, -79.680", +"4430, -170, -69.447", +"4430, -146, -59.144", +"4430, -121, -48.770", +"4430, -97, -38.326", +"4430, -73, -27.812", +"4430, -48, -17.228", +"4430, -24, -6.573", +"4430, -5, 0.000", +"4430, 5, 6.859", +"4430, 24, 16.305", +"4430, 48, 28.182", +"4430, 73, 40.135", +"4430, 97, 52.164", +"4430, 121, 64.269", +"4430, 146, 76.450", +"4430, 170, 88.707", +"4430, 194, 101.041", +"4430, 218, 113.451", +"4430, 243, 125.937", +"4430, 267, 138.499", +"4430, 291, 151.138", +"4430, 315, 163.852", +"4430, 340, 176.643", +"4430, 364, 189.510", +"4430, 388, 202.453", +"4430, 412, 215.472", +"4430, 437, 228.567", +"4430, 461, 241.739", +"4430, 485, 254.986", +"4922, -485, -217.116", +"4922, -461, -206.794", +"4922, -437, -196.388", +"4922, -412, -185.899", +"4922, -388, -175.325", +"4922, -364, -164.667", +"4922, -340, -153.925", +"4922, -315, -143.099", +"4922, -291, -132.190", +"4922, -267, -121.196", +"4922, -243, -110.118", +"4922, -218, -98.956", +"4922, -194, -87.710", +"4922, -170, -76.381", +"4922, -146, -64.967", +"4922, -121, -53.469", +"4922, -97, -41.887", +"4922, -73, -30.221", +"4922, -48, -18.472", +"4922, -24, -6.638", +"4922, -5, 0.000", +"4922, 5, 8.344", +"4922, 24, 18.839", +"4922, 48, 32.040", +"4922, 73, 45.333", +"4922, 97, 58.716", +"4922, 121, 72.191", +"4922, 146, 85.757", +"4922, 170, 99.413", +"4922, 194, 113.161", +"4922, 218, 127.001", +"4922, 243, 140.931", +"4922, 267, 154.952", +"4922, 291, 169.065", +"4922, 315, 183.269", +"4922, 340, 197.564", +"4922, 364, 211.950", +"4922, 388, 226.427", +"4922, 412, 240.995", +"4922, 437, 255.655", +"4922, 461, 270.406", +"4922, 485, 285.247", +"5415, -485, -236.743", +"5415, -461, -225.518", +"5415, -437, -214.194", +"5415, -412, -202.771", +"5415, -388, -191.249", +"5415, -364, -179.627", +"5415, -340, -167.906", +"5415, -315, -156.086", +"5415, -291, -144.167", +"5415, -267, -132.149", +"5415, -243, -120.031", +"5415, -218, -107.814", +"5415, -194, -95.497", +"5415, -170, -83.082", +"5415, -146, -70.567", +"5415, -121, -57.953", +"5415, -97, -45.240", +"5415, -73, -32.428", +"5415, -48, -19.516", +"5415, -24, -6.505", +"5415, -5, 0.000", +"5415, 5, 10.043", +"5415, 24, 21.588", +"5415, 48, 36.116", +"5415, 73, 50.751", +"5415, 97, 65.495", +"5415, 121, 80.346", +"5415, 146, 95.305", +"5415, 170, 110.371", +"5415, 194, 125.545", +"5415, 218, 140.827", +"5415, 243, 156.217", +"5415, 267, 171.714", +"5415, 291, 187.319", +"5415, 315, 203.031", +"5415, 340, 218.852", +"5415, 364, 234.779", +"5415, 388, 250.815", +"5415, 412, 266.958", +"5415, 437, 283.209", +"5415, 461, 299.568", +"5415, 485, 316.034", +"5907, -485, -255.867", +"5907, -461, -243.768", +"5907, -437, -231.553", +"5907, -412, -219.222", +"5907, -388, -206.774", +"5907, -364, -194.211", +"5907, -340, -181.532", +"5907, -315, -168.738", +"5907, -291, -155.827", +"5907, -267, -142.800", +"5907, -243, -129.657", +"5907, -218, -116.399", +"5907, -194, -103.024", +"5907, -170, -89.534", +"5907, -146, -75.928", +"5907, -121, -62.205", +"5907, -97, -48.367", +"5907, -73, -34.413", +"5907, -48, -20.343", +"5907, -24, -6.157", +"5907, -5, 0.000", +"5907, 5, 11.974", +"5907, 24, 24.569", +"5907, 48, 40.426", +"5907, 73, 56.409", +"5907, 97, 72.518", +"5907, 121, 88.753", +"5907, 146, 105.113", +"5907, 170, 121.599", +"5907, 194, 138.211", +"5907, 218, 154.949", +"5907, 243, 171.813", +"5907, 267, 188.802", +"5907, 291, 205.917", +"5907, 315, 223.158", +"5907, 340, 240.525", +"5907, 364, 258.017", +"5907, 388, 275.635", +"5907, 412, 293.379", +"5907, 437, 311.249", +"5907, 461, 329.245", +"5907, 485, 347.366", +"6399, -485, -274.473", +"6399, -461, -261.527", +"6399, -437, -248.447", +"6399, -412, -235.232", +"6399, -388, -221.884", +"6399, -364, -208.402", +"6399, -340, -194.786", +"6399, -315, -181.036", +"6399, -291, -167.151", +"6399, -267, -153.133", +"6399, -243, -138.981", +"6399, -218, -124.694", +"6399, -194, -110.274", +"6399, -170, -95.719", +"6399, -146, -81.031", +"6399, -121, -66.208", +"6399, -97, -51.252", +"6399, -73, -36.161", +"6399, -48, -20.936", +"6399, -24, -5.577", +"6399, -5, 0.000", +"6399, 5, 14.156", +"6399, 24, 27.802", +"6399, 48, 44.991", +"6399, 73, 62.325", +"6399, 97, 79.805", +"6399, 121, 97.430", +"6399, 146, 115.201", +"6399, 170, 133.117", +"6399, 194, 151.179", +"6399, 218, 169.386", +"6399, 243, 187.738", +"6399, 267, 206.236", +"6399, 291, 224.879", +"6399, 315, 243.668", +"6399, 340, 262.602", +"6399, 364, 281.682", +"6399, 388, 300.907", +"6399, 412, 320.277", +"6399, 437, 339.793", +"6399, 461, 359.455", +"6399, 485, 379.261", +"6891, -485, -292.541", +"6891, -461, -278.777", +"6891, -437, -264.858", +"6891, -412, -250.787", +"6891, -388, -236.561", +"6891, -364, -222.182", +"6891, -340, -207.650", +"6891, -315, -192.963", +"6891, -291, -178.124", +"6891, -267, -163.130", +"6891, -243, -147.983", +"6891, -218, -132.683", +"6891, -194, -117.228", +"6891, -170, -101.621", +"6891, -146, -85.859", +"6891, -121, -69.944", +"6891, -97, -53.876", +"6891, -73, -37.653", +"6891, -48, -21.278", +"6891, -24, -4.748", +"6891, -5, 0.000", +"6891, 5, 16.608", +"6891, 24, 31.306", +"6891, 48, 49.829", +"6891, 73, 68.518", +"6891, 97, 87.374", +"6891, 121, 106.397", +"6891, 146, 125.587", +"6891, 170, 144.943", +"6891, 194, 164.466", +"6891, 218, 184.155", +"6891, 243, 204.011", +"6891, 267, 224.034", +"6891, 291, 244.223", +"6891, 315, 264.580", +"6891, 340, 285.102", +"6891, 364, 305.792", +"6891, 388, 326.648", +"6891, 412, 347.671", +"6891, 437, 368.860", +"6891, 461, 390.216", +"6891, 485, 411.739", +"7383, -485, -310.056", +"7383, -461, -295.501", +"7383, -437, -280.771", +"7383, -412, -265.867", +"7383, -388, -250.788", +"7383, -364, -235.535", +"7383, -340, -220.106", +"7383, -315, -204.504", +"7383, -291, -188.726", +"7383, -267, -172.775", +"7383, -243, -156.648", +"7383, -218, -140.347", +"7383, -194, -123.871", +"7383, -170, -107.221", +"7383, -146, -90.396", +"7383, -121, -73.397", +"7383, -97, -56.222", +"7383, -73, -38.874", +"7383, -48, -21.350", +"7383, -24, -3.653", +"7383, -5, 0.000", +"7383, 5, 19.348", +"7383, 24, 35.099", +"7383, 48, 54.958", +"7383, 73, 75.007", +"7383, 97, 95.245", +"7383, 121, 115.672", +"7383, 146, 136.289", +"7383, 170, 157.095", +"7383, 194, 178.091", +"7383, 218, 199.276", +"7383, 243, 220.651", +"7383, 267, 242.215", +"7383, 291, 263.969", +"7383, 315, 285.912", +"7383, 340, 308.044", +"7383, 364, 330.366", +"7383, 388, 352.878", +"7383, 412, 375.578", +"7383, 437, 398.469", +"7383, 461, 421.549", +"7383, 485, 444.818", +"7876, -485, -327.000", +"7876, -461, -311.682", +"7876, -437, -296.167", +"7876, -412, -280.456", +"7876, -388, -264.547", +"7876, -364, -248.442", +"7876, -340, -232.139", +"7876, -315, -215.639", +"7876, -291, -198.942", +"7876, -267, -182.048", +"7876, -243, -164.958", +"7876, -218, -147.670", +"7876, -194, -130.185", +"7876, -170, -112.503", +"7876, -146, -94.624", +"7876, -121, -76.548", +"7876, -97, -58.274", +"7876, -73, -39.804", +"7876, -48, -21.137", +"7876, -24, -2.273", +"7876, -5, 0.000", +"7876, 5, 22.396", +"7876, 24, 39.201", +"7876, 48, 60.398", +"7876, 73, 81.810", +"7876, 97, 103.435", +"7876, 121, 125.274", +"7876, 146, 147.327", +"7876, 170, 169.593", +"7876, 194, 192.074", +"7876, 218, 214.768", +"7876, 243, 237.676", +"7876, 267, 260.798", +"7876, 291, 284.134", +"7876, 315, 307.683", +"7876, 340, 331.447", +"7876, 364, 355.424", +"7876, 388, 379.615", +"7876, 412, 404.019", +"7876, 437, 428.638", +"7876, 461, 453.470", +"7876, 485, 478.516", +"8368, -485, -343.355", +"8368, -461, -327.303", +"8368, -437, -311.030", +"8368, -412, -294.536", +"8368, -388, -277.822", +"8368, -364, -260.886", +"8368, -340, -243.730", +"8368, -315, -226.352", +"8368, -291, -208.754", +"8368, -267, -190.935", +"8368, -243, -172.895", +"8368, -218, -154.634", +"8368, -194, -136.152", +"8368, -170, -117.449", +"8368, -146, -98.525", +"8368, -121, -79.380", +"8368, -97, -60.014", +"8368, -73, -40.428", +"8368, -48, -20.620", +"8368, -24, -0.592", +"8368, -5, 0.000", +"8368, 5, 25.770", +"8368, 24, 43.629", +"8368, 48, 66.167", +"8368, 73, 88.946", +"8368, 97, 111.964", +"8368, 121, 135.221", +"8368, 146, 158.719", +"8368, 170, 182.456", +"8368, 194, 206.433", +"8368, 218, 230.649", +"8368, 243, 255.106", +"8368, 267, 279.802", +"8368, 291, 304.738", +"8368, 315, 329.913", +"8368, 340, 355.328", +"8368, 364, 380.983", +"8368, 388, 406.878", +"8368, 412, 433.012", +"8368, 437, 459.386", +"8368, 461, 486.000", +"8368, 485, 512.853", +"8860, -485, -359.104", +"8860, -461, -342.346", +"8860, -437, -325.341", +"8860, -412, -308.091", +"8860, -388, -290.594", +"8860, -364, -272.851", +"8860, -340, -254.862", +"8860, -315, -236.626", +"8860, -291, -218.144", +"8860, -267, -199.416", +"8860, -243, -180.442", +"8860, -218, -161.221", +"8860, -194, -141.755", +"8860, -170, -122.042", +"8860, -146, -102.082", +"8860, -121, -81.877", +"8860, -97, -61.425", +"8860, -73, -40.727", +"8860, -48, -19.783", +"8860, -24, 0.000", +"8860, -5, 0.000", +"8860, 5, 29.489", +"8860, 24, 48.402", +"8860, 48, 72.284", +"8860, 73, 96.433", +"8860, 97, 120.849", +"8860, 121, 145.533", +"8860, 146, 170.484", +"8860, 170, 195.701", +"8860, 194, 221.186", +"8860, 218, 246.939", +"8860, 243, 272.958", +"8860, 267, 299.245", +"8860, 291, 325.798", +"8860, 315, 352.619", +"8860, 340, 379.708", +"8860, 364, 407.063", +"8860, 388, 434.685", +"8860, 412, 462.575", +"8860, 437, 490.732", +"8860, 461, 519.156", +"8860, 485, 547.847", +"9352, -485, -374.230", +"9352, -461, -356.794", +"9352, -437, -339.084", +"9352, -412, -321.102", +"9352, -388, -302.847", +"9352, -364, -284.319", +"9352, -340, -265.517", +"9352, -315, -246.443", +"9352, -291, -227.096", +"9352, -267, -207.475", +"9352, -243, -187.582", +"9352, -218, -167.416", +"9352, -194, -146.976", +"9352, -170, -126.264", +"9352, -146, -105.279", +"9352, -121, -84.021", +"9352, -97, -62.489", +"9352, -73, -40.685", +"9352, -48, -18.608", +"9352, -24, 0.000", +"9352, -5, 0.000", +"9352, 5, 33.571", +"9352, 24, 53.540", +"9352, 48, 78.768", +"9352, 73, 104.291", +"9352, 97, 130.111", +"9352, 121, 156.228", +"9352, 146, 182.640", +"9352, 170, 209.349", +"9352, 194, 236.354", +"9352, 218, 263.655", +"9352, 243, 291.252", +"9352, 267, 319.146", +"9352, 291, 347.335", +"9352, 315, 375.821", +"9352, 340, 404.604", +"9352, 364, 433.682", +"9352, 388, 463.057", +"9352, 412, 492.728", +"9352, 437, 522.695", +"9352, 461, 552.958", +"9352, 485, 583.518", +"9845, -485, -388.716", +"9845, -461, -370.630", +"9845, -437, -352.242", +"9845, -412, -333.553", +"9845, -388, -314.563", +"9845, -364, -295.272", +"9845, -340, -275.680", +"9845, -315, -255.786", +"9845, -291, -235.591", +"9845, -267, -215.095", +"9845, -243, -194.298", +"9845, -218, -173.200", +"9845, -194, -151.800", +"9845, -170, -130.099", +"9845, -146, -108.097", +"9845, -121, -85.794", +"9845, -97, -63.190", +"9845, -73, -40.284", +"9845, -48, -17.077", +"9845, -24, 0.000", +"9845, -5, 0.000", +"9845, 5, 38.036", +"9845, 24, 59.061", +"9845, 48, 85.637", +"9845, 73, 112.539", +"9845, 97, 139.768", +"9845, 121, 167.324", +"9845, 146, 195.207", +"9845, 170, 223.417", +"9845, 194, 251.953", +"9845, 218, 280.816", +"9845, 243, 310.007", +"9845, 267, 339.523", +"9845, 291, 369.367", +"9845, 315, 399.538", +"9845, 340, 430.035", +"9845, 364, 460.859", +"9845, 388, 492.010", +"9845, 412, 523.488", +"9845, 437, 555.293", +"9845, 461, 587.424", +"9845, 485, 619.883" + #endregion data + ).ApplyFactor(ElectricMotorMapReader.Fields.PowerElectrical, 1E3); //Convert from kW to W + } + + private EfficiencyMap GetEfficiencyMap(int count) + { + return ElectricMotorMapReader.Create(GetEfficiencyMapData(), count, ExecutionMode.Declaration); + } + private void SetVelocityDropLookupData(PEVAMTShiftStrategy shiftStrategy) + { + //"StartVelocity [km/h], Gradient [-], EndVelocity [km/h]" + var data = new[] { + new[] { 5.0, -0.0997, 9.061522965237558 }, + new[] { 5.0, -0.0798, 7.76698080079411 }, + new[] { 5.0, -0.0599, 6.46583777913701 }, + new[] { 5.0, -0.0400, 5.1596021788785045 }, + new[] { 5.0, -0.0200, 3.8498121019126907 }, + new[] { 5.0, 0.0000, 2.5380265159468918 }, + new[] { 5.0, 0.0200, 1.2258160477557427 }, + new[] { 5.0, 0.0400, 0.0 }, + new[] { 5.0, 0.0599, 0.0 }, + new[] { 5.0, 0.0798, 0.0 }, + new[] { 5.0, 0.0997, 0.0 }, + new[] { 10.0, -0.0997, 14.807789640888302 }, + new[] { 10.0, -0.0798, 13.474253785811362 }, + new[] { 10.0, -0.0599, 12.133880027250777 }, + new[] { 10.0, -0.0400, 10.788221550084467 }, + new[] { 10.0, -0.0200, 9.438862432338068 }, + new[] { 10.0, 0.0000, 8.087408432114643 }, + new[] { 10.0, 0.0200, 6.735477499784416 }, + new[] { 10.0, 0.0400, 5.384690105076845 }, + new[] { 10.0, 0.0599, 4.036659549786269 }, + new[] { 10.0, 0.0798, 2.6929823705748137 }, + new[] { 10.0, 0.0997, 1.3552289800549435 }, + new[] { 20.0, -0.0997, 25.061542153872097 }, + new[] { 20.0, -0.0798, 23.72002987685605 }, + new[] { 20.0, -0.0599, 22.371630788642932 }, + new[] { 20.0, -0.0400, 21.017907257116025 }, + new[] { 20.0, -0.0200, 19.660452757813403 }, + new[] { 20.0, 0.0000, 18.30088261992287 }, + new[] { 20.0, 0.0200, 16.94082447048767 }, + new[] { 20.0, 0.0400, 15.581908518759507 }, + new[] { 20.0, 0.0599, 14.225757795590708 }, + new[] { 20.0, 0.0798, 12.873978508374211 }, + new[] { 20.0, 0.0997, 11.528150617530041 }, + new[] { 30.000000000000004, -0.0997, 35.091774208140095 }, + new[] { 30.000000000000004, -0.0798, 33.750904327320896 }, + new[] { 30.000000000000004, -0.0599, 32.40315158162777 }, + new[] { 30.000000000000004, -0.0400, 31.050077596965064 }, + new[] { 30.000000000000004, -0.0200, 29.69327509188113 }, + new[] { 30.000000000000004, 0.0000, 28.33435862498606 }, + new[] { 30.000000000000004, 0.0200, 26.974955046566407 }, + new[] { 30.000000000000004, 0.0400, 25.616693776603913 }, + new[] { 30.000000000000004, 0.0599, 24.261197065863925 }, + new[] { 30.000000000000004, 0.0798, 22.91007034016412 }, + new[] { 30.000000000000004, 0.0997, 21.56489279686667 }, + new[] { 40.0, -0.0997, 45.024018797189854 }, + new[] { 40.0, -0.0798, 43.68636622428101 }, + new[] { 40.0, -0.0599, 42.34185052441486 }, + new[] { 40.0, -0.0400, 40.99202962224952 }, + new[] { 40.0, -0.0200, 39.63849244500093 }, + new[] { 40.0, 0.0000, 38.282849690992855 }, + new[] { 40.0, 0.0200, 36.926724305651554 }, + new[] { 40.0, 0.0400, 35.57174178507285 }, + new[] { 40.0, 0.0599, 34.21952045137207 }, + new[] { 40.0, 0.0798, 32.87166183129923 }, + new[] { 40.0, 0.0997, 31.5297412694979 }, + new[] { 50.0, -0.0997, 54.652157586769704 }, + new[] { 50.0, -0.0798, 53.319266704395716 }, + new[] { 50.0, -0.0599, 51.97954186606304 }, + new[] { 50.0, -0.0400, 50.634535516787736 }, + new[] { 50.0, -0.0200, 49.28583097196263 }, + new[] { 50.0, 0.0000, 47.93503321632867 }, + new[] { 50.0, 0.0200, 46.583759417454765 }, + new[] { 50.0, 0.0400, 45.23362925944123 }, + new[] { 50.0, 0.0599, 43.88625525588574 }, + new[] { 50.0, 0.0798, 42.54323315977748 }, + new[] { 50.0, 0.0997, 41.20613261641401 }, + new[] { 60.00000000000001, -0.0997, 64.2503607025971 }, + new[] { 60.00000000000001, -0.0798, 62.91932863058169 }, + new[] { 60.00000000000001, -0.0599, 61.58156853535776 }, + new[] { 60.00000000000001, -0.0400, 60.23862904729555 }, + new[] { 60.00000000000001, -0.0200, 58.89369896300112 }, + new[] { 60.00000000000001, 0.0000, 57.547040626925885 }, + new[] { 60.00000000000001, 0.0200, 56.199911833784675 }, + new[] { 60.00000000000001, 0.0400, 54.85392730356455 }, + new[] { 60.00000000000001, 0.0599, 53.510694584916905 }, + new[] { 60.00000000000001, 0.0798, 52.17180450267632 }, + new[] { 60.00000000000001, 0.0997, 50.83882182989668 }, + new[] { 70.0, -0.0997, 73.78388063954164 }, + new[] { 70.0, -0.0798, 72.45700102808648 }, + new[] { 70.0, -0.0599, 71.12341092304165 }, + new[] { 70.0, -0.0400, 69.78459543842656 }, + new[] { 70.0, -0.0200, 68.44188526693415 }, + new[] { 70.0, 0.0000, 67.09719334997524 }, + new[] { 70.0, 0.0200, 65.75212749798493 }, + new[] { 70.0, 0.0400, 64.40829754257321 }, + new[] { 70.0, 0.0599, 63.06730571969745 }, + new[] { 70.0, 0.0798, 61.73073716025881 }, + new[] { 70.0, 0.0997, 60.40015062055851 }, + new[] { 80.0, -0.0997, 83.25457689135129 }, + new[] { 80.0, -0.0798, 81.93182852399568 }, + new[] { 80.0, -0.0599, 80.60238880559001 }, + new[] { 80.0, -0.0400, 79.2676325992058 }, + new[] { 80.0, -0.0200, 77.92916666616652 }, + new[] { 80.0, 0.0000, 76.58872134590663 }, + new[] { 80.0, 0.0200, 75.24790011046437 }, + new[] { 80.0, 0.0400, 73.90830846424944 }, + new[] { 80.0, 0.0599, 72.57154434889891 }, + new[] { 80.0, 0.0798, 71.23918865436896 }, + new[] { 80.0, 0.0997, 69.91277394305271 }, + }; + var entries = new List<VelocitySpeedGearshiftPreprocessor.Entry>(); + foreach (var d in data) { + entries.Add(new VelocitySpeedGearshiftPreprocessor.Entry() { + StartVelocity = d[0].KMPHtoMeterPerSecond(), + Gradient = d[1].SI<Radian>(), + EndVelocity = d[2].KMPHtoMeterPerSecond(), + }); + } + + shiftStrategy.VelocityDropData.Data = entries.ToArray(); + + } + + } + +} diff --git a/Testing/UnitTests/Vecto UnitTests/TestCases/DeclarationDataTests/GenericModelParams/GearShiftStrategy/PEV_ShiftLineTests.cs b/Testing/UnitTests/Vecto UnitTests/TestCases/DeclarationDataTests/GenericModelParams/GearShiftStrategy/PEV_ShiftLineTests.cs index a742c2ba91c61da0b77a49b2ed41fad5338de89b..d5a1e87e47ad699d66e39b5a97cb1389a15f8eb7 100644 --- a/Testing/UnitTests/Vecto UnitTests/TestCases/DeclarationDataTests/GenericModelParams/GearShiftStrategy/PEV_ShiftLineTests.cs +++ b/Testing/UnitTests/Vecto UnitTests/TestCases/DeclarationDataTests/GenericModelParams/GearShiftStrategy/PEV_ShiftLineTests.cs @@ -3,14 +3,18 @@ using NUnit.Framework; using TUGraz.VectoCommon.InputData; using TUGraz.VectoCommon.Models; using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.InputData.Reader.ComponentData; using TUGraz.VectoCore.Models.Declaration; using TUGraz.VectoCore.Models.Simulation; using TUGraz.VectoCore.Models.Simulation.Data; using TUGraz.VectoCore.Models.SimulationComponent.Data; using TUGraz.VectoCore.Models.SimulationComponent.Data.ElectricMotor; using TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox; +using TUGraz.VectoCore.Models.SimulationComponent.Impl; using TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies; using TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies.ShiftPolygonCalc; +using TUGraz.VectoCore.Tests.Utils; +using TUGraz.VectoCore.Utils; using Assert = NUnit.Framework.Assert; namespace TUGraz.Vecto.UnitTests.TestCases.DeclarationDataTests.GenericModelParams.GearShiftStrategy; @@ -18,6 +22,156 @@ namespace TUGraz.Vecto.UnitTests.TestCases.DeclarationDataTests.GenericModelPara public class PEV_ShiftLineTests { [TestCase] + public void ComputePEVShiftLinesADC() + { + var axlegearRatio = 2.64; + var r_dyn = 0.421.SI<Meter>(); + + var expectedDownshiftNoADC = new[] { + // Gear 1 + new Point[] { + + }, + // Gear 2 + new[] { + new Point(1969.345479169557, -1067), + new Point(1969.345479169557, -950.6), + new Point(253.98783622789142, -950.6), + new Point(253.98783622789142, 950.6), + new Point(2452.135493, 950.6), + new Point(2461.1589140000006, 950.6), + new Point(2466.8630340000004, 948.41362), + new Point(2481.590574, 942.781315), + new Point(2496.3181150000005, 937.220305), + new Point(2503.681885, 934.463565), + new Point(2539.878362278914, 921.3333994166501), + new Point(2539.878362278914, 1067), + }, + // Gear 3 + new[] { + new Point(1969.345479169557, -1067), + new Point(1969.345479169557, -950.6), + new Point(253.98783622789142, -950.6), + new Point(253.98783622789142, 950.6), + new Point(2452.135493, 950.6), + new Point(2461.1589140000006, 950.6), + new Point(2466.8630340000004, 948.41362), + new Point(2481.590574, 942.781315), + new Point(2496.3181150000005, 937.220305), + new Point(2503.681885, 934.463565), + new Point(2539.878362278914, 921.3333994166501), + new Point(2539.878362278914, 1067), + }, + }; + var expectedUpshiftNoADC = new[] { + // Gear 1 + new[] { + new Point(6627.393225000001, 1067), + new Point(6627.393225000001, -1067), + }, + // Gear 2 + new[] { + new Point(6627.393225000001, 1067), + new Point(6627.393225000001, -1067), + }, + // Gear 3 + new[] { + new Point(6627.393225000001, 1067), + new Point(6627.393225000001, -1067), + }, + }; + var countEm = 2; + var emRatio = 2.0; + + var expectedUpshift = + expectedUpshiftNoADC.Select(ps => ps.Select(p => new Point(p.X / emRatio, p.Y * emRatio)).ToArray()).ToArray(); + var expectedDownshift = + expectedDownshiftNoADC.Select(ps => ps.Select(p => new Point(p.X / emRatio, p.Y * emRatio)).ToArray()).ToArray(); + + + + var emFld = new ElectricMotorFullLoadCurve(EM_FullLoad_125kW_485Nm.Select(x => + new ElectricMotorFullLoadCurve.FullLoadEntry() { + // invert motor full load curve here as would be done in respective reader class + MotorSpeed = x[0].RPMtoRad(), + FullDriveTorque = -x[1].SI<NewtonMeter>() * countEm, + FullGenerationTorque = -x[2].SI<NewtonMeter>() * countEm, + }).ToList()); + + var emEffMap = GetEffMap(emFld, countEm); + + + + + var emData = new ElectricMotorData() { + EfficiencyData = new VoltageLevelData() { + VoltageLevels = new List<ElectricMotorVoltageLevelData>() { + new ElectricMotorVoltageLevelData() { + FullLoadCurve = emFld, + EfficiencyMap = emEffMap, + } + } + }, + TransmissionLossMap = TransmissionLossMapReader.CreateEmADCLossMap(1, emRatio, "ADC"), + RatioADC = emRatio + }; + var gearboxData = new Mock<IGearboxEngineeringInputData>().Object; + var gear = new Mock<ITransmissionInputData>().Object; + Mock.Get(gearboxData).Setup(g => g.Gears).Returns(new List<ITransmissionInputData>() { + gear, gear, gear, gear, gear, gear, gear, gear, gear, gear, gear, gear, + }); + + var shiftPolygons = new List<ShiftPolygon>(); + + var shiftStrategyParams = new ShiftStrategyParameters(); // use default (declaration) shift strategy params + // var downshiftMaxSpeed = emFld.RatedSpeed * shiftStrategyParams.PEV_DownshiftSpeedFactor.LimitTo(0, 1); + // var downshiftMinSpeed = emFld.RatedSpeed * shiftStrategyParams.PEV_DownshiftMinSpeedFactor; + + + + for (var i = 0; i < gearboxData.Gears.Count; i++) { + var shiftPolygon = DeclarationData.Gearbox.ComputeElectricMotorShiftPolygon( + i, + emData, + gearboxData.Gears, + shiftStrategyParams.PEV_DownshiftSpeedFactor.LimitTo(0,1), + shiftStrategyParams.PEV_DownshiftMinSpeedFactor + ); + + // var shiftpolygon = DeclarationData.Gearbox.ComputeElectricMotorShiftPolygon(i, + // emFld, emRatio, + // gearboxData.Gears, + // axlegearRatio, + // r_dyn, + // downshiftMaxSpeed, + // downshiftMinSpeed); + shiftPolygons.Add(shiftPolygon); + } + + + CommonSanityChecks(shiftPolygons, emData.EfficiencyData.MaxSpeed / emRatio); + + + for (var i = 0; i < Math.Min(gearboxData.Gears.Count, Math.Min(expectedDownshift.Length, expectedUpshift.Length)); i++) { + foreach (var tuple in expectedDownshift[i].Zip(shiftPolygons[i].Downshift, Tuple.Create)) { + Assert.AreEqual(tuple.Item1.X, tuple.Item2.AngularSpeed.AsRPM, 1e-3, "gear: {0} entry: {1}", i + 1, tuple); + Assert.AreEqual(tuple.Item1.Y, tuple.Item2.Torque.Value(), 1e-3, "gear: {0} entry: {1}", i + 1, tuple); + } + + foreach (var tuple in expectedUpshift[i].Zip(shiftPolygons[i].Upshift, Tuple.Create)) { + Assert.AreEqual(tuple.Item1.X, tuple.Item2.AngularSpeed.AsRPM, 1e-3, "gear: {0} entry: {1}", i + 1, tuple); + Assert.AreEqual(tuple.Item1.Y, tuple.Item2.Torque.Value(), 1e-3, "gear: {0} entry: {1}", i + 1, tuple); + } + } + + Assert.AreEqual(0, shiftPolygons.First().Downshift.Count); + Assert.AreEqual(0, shiftPolygons.Last().Upshift.Count); + + //var suffix = factorDownshiftSpeed.HasValue ? $"_{factorDownshiftSpeed.Value}" : ""; + + } + + [TestCase] public void ComputePEVShiftLines() { var axlegearRatio = 2.64; @@ -78,7 +232,7 @@ public class PEV_ShiftLineTests }; var countEm = 2; - var emRatio = 2.0; + var emRatio = 1.0; var emFld = new ElectricMotorFullLoadCurve(EM_FullLoad_125kW_485Nm.Select(x => new ElectricMotorFullLoadCurve.FullLoadEntry() { @@ -88,6 +242,23 @@ public class PEV_ShiftLineTests FullGenerationTorque = -x[2].SI<NewtonMeter>() * countEm, }).ToList()); + var emEffMap = GetEffMap(emFld, countEm); + + + + + var emData = new ElectricMotorData() { + EfficiencyData = new VoltageLevelData() { + VoltageLevels = new List<ElectricMotorVoltageLevelData>() { + new ElectricMotorVoltageLevelData() { + FullLoadCurve = emFld, + EfficiencyMap = emEffMap, + } + } + }, + TransmissionLossMap = TransmissionLossMapReader.CreateEmADCLossMap(1, emRatio, "ADC"), + RatioADC = emRatio + }; var gearboxData = new Mock<IGearboxEngineeringInputData>().Object; var gear = new Mock<ITransmissionInputData>().Object; Mock.Get(gearboxData).Setup(g => g.Gears).Returns(new List<ITransmissionInputData>() { @@ -97,14 +268,33 @@ public class PEV_ShiftLineTests var shiftPolygons = new List<ShiftPolygon>(); var shiftStrategyParams = new ShiftStrategyParameters(); // use default (declaration) shift strategy params - var downshiftMaxSpeed = emFld.RatedSpeed * shiftStrategyParams.PEV_DownshiftSpeedFactor.LimitTo(0, 1); - var downshiftMinSpeed = emFld.RatedSpeed * shiftStrategyParams.PEV_DownshiftMinSpeedFactor; + // var downshiftMaxSpeed = emFld.RatedSpeed * shiftStrategyParams.PEV_DownshiftSpeedFactor.LimitTo(0, 1); + // var downshiftMinSpeed = emFld.RatedSpeed * shiftStrategyParams.PEV_DownshiftMinSpeedFactor; + + for (var i = 0; i < gearboxData.Gears.Count; i++) { - var shiftpolygon = DeclarationData.Gearbox.ComputeElectricMotorShiftPolygon(i, emFld, emRatio, gearboxData.Gears, axlegearRatio, r_dyn, downshiftMaxSpeed, downshiftMinSpeed); - shiftPolygons.Add(shiftpolygon); + var shiftPolygon = DeclarationData.Gearbox.ComputeElectricMotorShiftPolygon( + i, + emData, + gearboxData.Gears, + shiftStrategyParams.PEV_DownshiftSpeedFactor.LimitTo(0,1), + shiftStrategyParams.PEV_DownshiftMinSpeedFactor + ); + + // var shiftpolygon = DeclarationData.Gearbox.ComputeElectricMotorShiftPolygon(i, + // emFld, emRatio, + // gearboxData.Gears, + // axlegearRatio, + // r_dyn, + // downshiftMaxSpeed, + // downshiftMinSpeed); + shiftPolygons.Add(shiftPolygon); } + + CommonSanityChecks(shiftPolygons, emData.EfficiencyData.MaxSpeed / emRatio); + for (var i = 0; i < Math.Min(gearboxData.Gears.Count, Math.Min(expectedDownshift.Length, expectedUpshift.Length)); i++) { foreach (var tuple in expectedDownshift[i].Zip(shiftPolygons[i].Downshift, Tuple.Create)) { Assert.AreEqual(tuple.Item1.X, tuple.Item2.AngularSpeed.AsRPM, 1e-3, "gear: {0} entry: {1}", i + 1, tuple); @@ -124,7 +314,339 @@ public class PEV_ShiftLineTests } - [TestCase] + + + [TestCase] + public void ComputePEVShiftLinesDeratedSanity() + { + var axlegearRatio = 2.64; + var r_dyn = 0.421.SI<Meter>(); + + var expectedDownshift = new[] { + // Gear 1 + new Point[] { + + }, + // Gear 2 + new[] { + new Point(1969.345479169557, -1067), + new Point(1969.345479169557, -950.6), + new Point(253.98783622789142, -950.6), + new Point(253.98783622789142, 950.6), + new Point(2452.135493, 950.6), + new Point(2461.1589140000006, 950.6), + new Point(2466.8630340000004, 948.41362), + new Point(2481.590574, 942.781315), + new Point(2496.3181150000005, 937.220305), + new Point(2503.681885, 934.463565), + new Point(2539.878362278914, 921.3333994166501), + new Point(2539.878362278914, 1067), + }, + // Gear 3 + new[] { + new Point(1969.345479169557, -1067), + new Point(1969.345479169557, -950.6), + new Point(253.98783622789142, -950.6), + new Point(253.98783622789142, 950.6), + new Point(2452.135493, 950.6), + new Point(2461.1589140000006, 950.6), + new Point(2466.8630340000004, 948.41362), + new Point(2481.590574, 942.781315), + new Point(2496.3181150000005, 937.220305), + new Point(2503.681885, 934.463565), + new Point(2539.878362278914, 921.3333994166501), + new Point(2539.878362278914, 1067), + }, + }; + var expectedUpshift = new[] { + // Gear 1 + new[] { + new Point(6627.393225000001, 1067), + new Point(6627.393225000001, -1067), + }, + // Gear 2 + new[] { + new Point(6627.393225000001, 1067), + new Point(6627.393225000001, -1067), + }, + // Gear 3 + new[] { + new Point(6627.393225000001, 1067), + new Point(6627.393225000001, -1067), + }, + }; + + var countEm = 2; + var emRatio = 1.0; + + var emFld = new ElectricMotorFullLoadCurve(EM_FullLoad_125kW_485Nm.Select(x => + new ElectricMotorFullLoadCurve.FullLoadEntry() { + // invert motor full load curve here as would be done in respective reader class + MotorSpeed = x[0].RPMtoRad(), + FullDriveTorque = -x[1].SI<NewtonMeter>() * countEm, + FullGenerationTorque = -x[2].SI<NewtonMeter>() * countEm, + }).ToList()); + + var emEffMap = GetEffMap(emFld, countEm); + + + + var continuousTorque = emFld.MaxGenerationTorque; + var emData = new ElectricMotorData() { + Overload = new OverloadData() { + ContinuousTorque = continuousTorque, + }, + EfficiencyData = new VoltageLevelData() { + VoltageLevels = new List<ElectricMotorVoltageLevelData>() { + new ElectricMotorVoltageLevelData() { + FullLoadCurve = emFld, + EfficiencyMap = emEffMap, + } + } + }, + TransmissionLossMap = TransmissionLossMapReader.CreateEmADCLossMap(1, emRatio, "ADC"), + RatioADC = emRatio + }; + var gearboxData = new Mock<IGearboxEngineeringInputData>().Object; + var gear = new Mock<ITransmissionInputData>().Object; + Mock.Get(gearboxData).Setup(g => g.Gears).Returns(new List<ITransmissionInputData>() { + gear, gear, gear, gear, gear, gear, gear, gear, gear, gear, gear, gear, + }); + + var shiftPolygons = new List<ShiftPolygon>(); + var runData = new VectoRunData() { GearshiftParameters = new ShiftStrategyParameters() }; + var container = new Mock<IVehicleContainer>(); + container.Setup(c => c.RunData).Returns(runData); + // var shiftStrategy = new PEVAMTShiftStrategy(container.Object); + // var deRatedShiftLines = shiftStrategy.CalculateDeratedShiftLines(emData, gearboxData.Gears, + // r_dyn, axlegearRatio, GearboxType.AMT); + + var shiftStrategy = new PEVAMTShiftStrategyPolygonCreator(runData.GearshiftParameters); + //var deRatedShiftLines = shiftStrategy.CalculateDeratedShiftLines(emData, gearboxData.Gears, + // r_dyn, axlegearRatio, GearboxType.AMT); + + for (var i = 0; i < gearboxData.Gears.Count; i++) { + //var emFld = emData.EfficiencyData.VoltageLevels.First().FullLoadCurve; + var contTq = emData.Overload.ContinuousTorque; + var limitedFld = DeclarationData.Gearbox.LimitElectricMotorFullLoadCurve(emFld, contTq); + var limitedEm = new ElectricMotorData() { + EfficiencyData = new VoltageLevelData() { + VoltageLevels = new List<ElectricMotorVoltageLevelData>() { + new DeratedVoltageLevelData(emFld.MaxSpeed) { + FullLoadCurve = limitedFld + } + } + }, + RatioADC = emData.RatioADC, + }; + + var deratedShiftLine = shiftStrategy.ComputeElectricMotorDeclarationShiftPolygon(GearboxType.APTN, i, + gearboxData.Gears, axlegearRatio, r_dyn, emData, limitedEm); + shiftPolygons.Add(deratedShiftLine); + } + + + CommonSanityChecks(shiftPolygons, emData.EfficiencyData.MaxSpeed / emRatio); + + for (var i = 0; i < Math.Min(gearboxData.Gears.Count, Math.Min(expectedDownshift.Length, expectedUpshift.Length)); i++) { + foreach (var tuple in expectedDownshift[i].Zip(shiftPolygons[i].Downshift, Tuple.Create)) { + Assert.AreEqual(tuple.Item1.X, tuple.Item2.AngularSpeed.AsRPM, 1e-3, "gear: {0} entry: {1}", i + 1, tuple); + Assert.AreEqual(tuple.Item1.Y, tuple.Item2.Torque.Value(), 1e-3, "gear: {0} entry: {1}", i + 1, tuple); + } + + foreach (var tuple in expectedUpshift[i].Zip(shiftPolygons[i].Upshift, Tuple.Create)) { + Assert.AreEqual(tuple.Item1.X, tuple.Item2.AngularSpeed.AsRPM, 1e-3, "gear: {0} entry: {1}", i + 1, tuple); + Assert.AreEqual(tuple.Item1.Y, tuple.Item2.Torque.Value(), 1e-3, "gear: {0} entry: {1}", i + 1, tuple); + } + } + + Assert.AreEqual(0, shiftPolygons.First().Downshift.Count); + Assert.AreEqual(0, shiftPolygons.Last().Upshift.Count); + + //var suffix = factorDownshiftSpeed.HasValue ? $"_{factorDownshiftSpeed.Value}" : ""; + + } + + + + [TestCase] + public void ComputePEVShiftLinesDeratedSanityADC() + { + var axlegearRatio = 2.64; + var r_dyn = 0.421.SI<Meter>(); + + var expectedDownshiftNoADC = new[] { + // Gear 1 + new Point[] { + + }, + // Gear 2 + new[] { + new Point(1969.345479169557, -1067), + new Point(1969.345479169557, -950.6), + new Point(253.98783622789142, -950.6), + new Point(253.98783622789142, 950.6), + new Point(2452.135493, 950.6), + new Point(2461.1589140000006, 950.6), + new Point(2466.8630340000004, 948.41362), + new Point(2481.590574, 942.781315), + new Point(2496.3181150000005, 937.220305), + new Point(2503.681885, 934.463565), + new Point(2539.878362278914, 921.3333994166501), + new Point(2539.878362278914, 1067), + }, + // Gear 3 + new[] { + new Point(1969.345479169557, -1067), + new Point(1969.345479169557, -950.6), + new Point(253.98783622789142, -950.6), + new Point(253.98783622789142, 950.6), + new Point(2452.135493, 950.6), + new Point(2461.1589140000006, 950.6), + new Point(2466.8630340000004, 948.41362), + new Point(2481.590574, 942.781315), + new Point(2496.3181150000005, 937.220305), + new Point(2503.681885, 934.463565), + new Point(2539.878362278914, 921.3333994166501), + new Point(2539.878362278914, 1067), + }, + }; + var expectedUpshiftNoADC = new[] { + // Gear 1 + new[] { + new Point(6627.393225000001, 1067), + new Point(6627.393225000001, -1067), + }, + // Gear 2 + new[] { + new Point(6627.393225000001, 1067), + new Point(6627.393225000001, -1067), + }, + // Gear 3 + new[] { + new Point(6627.393225000001, 1067), + new Point(6627.393225000001, -1067), + }, + }; + + var countEm = 2; + var emRatio = 2.0; + + var expectedUpshift = + expectedUpshiftNoADC.Select(ps => ps.Select(p => new Point(p.X / emRatio, p.Y * emRatio)).ToArray()).ToArray(); + var expectedDownshift = + expectedDownshiftNoADC.Select(ps => ps.Select(p => new Point(p.X / emRatio, p.Y * emRatio)).ToArray()).ToArray(); + + + var emFld = new ElectricMotorFullLoadCurve(EM_FullLoad_125kW_485Nm.Select(x => + new ElectricMotorFullLoadCurve.FullLoadEntry() { + // invert motor full load curve here as would be done in respective reader class + MotorSpeed = x[0].RPMtoRad(), + FullDriveTorque = -x[1].SI<NewtonMeter>() * countEm, + FullGenerationTorque = -x[2].SI<NewtonMeter>() * countEm, + }).ToList()); + + var emEffMap = GetEffMap(emFld, countEm); + + + + var continuousTorque = emFld.MaxGenerationTorque; + var emData = new ElectricMotorData() { + Overload = new OverloadData() { + ContinuousTorque = continuousTorque, + }, + EfficiencyData = new VoltageLevelData() { + VoltageLevels = new List<ElectricMotorVoltageLevelData>() { + new ElectricMotorVoltageLevelData() { + FullLoadCurve = emFld, + EfficiencyMap = emEffMap, + } + } + }, + TransmissionLossMap = TransmissionLossMapReader.CreateEmADCLossMap(1, emRatio, "ADC"), + RatioADC = emRatio + }; + var gearboxData = new Mock<IGearboxEngineeringInputData>().Object; + var gear = new Mock<ITransmissionInputData>().Object; + Mock.Get(gearboxData).Setup(g => g.Gears).Returns(new List<ITransmissionInputData>() { + gear, gear, gear, gear, gear, gear, gear, gear, gear, gear, gear, gear, + }); + + var shiftPolygons = new List<ShiftPolygon>(); + var runData = new VectoRunData() { GearshiftParameters = new ShiftStrategyParameters() }; + var container = new Mock<IVehicleContainer>(); + container.Setup(c => c.RunData).Returns(runData); + + var polygonCreator = new PEVAMTShiftStrategyPolygonCreator(runData.GearshiftParameters); + //var deRatedShiftLines = shiftStrategy.CalculateDeratedShiftLines(emData, gearboxData.Gears, + // r_dyn, axlegearRatio, GearboxType.AMT); + + for (var i = 0; i < gearboxData.Gears.Count; i++) { + //var emFld = emData.EfficiencyData.VoltageLevels.First().FullLoadCurve; + var contTq = emData.Overload.ContinuousTorque; + var limitedFld = DeclarationData.Gearbox.LimitElectricMotorFullLoadCurve(emFld, contTq); + var limitedEm = new ElectricMotorData() { + EfficiencyData = new VoltageLevelData() { + VoltageLevels = new List<ElectricMotorVoltageLevelData>() { + new DeratedVoltageLevelData(emFld.MaxSpeed) { + FullLoadCurve = limitedFld + } + } + }, + RatioADC = emData.RatioADC, + }; + + var deratedShiftLine = polygonCreator.ComputeElectricMotorDeclarationShiftPolygon(GearboxType.APTN, i, + gearboxData.Gears, axlegearRatio, r_dyn, emData, limitedEm); + shiftPolygons.Add(deratedShiftLine); + } + + + CommonSanityChecks(shiftPolygons, emData.EfficiencyData.MaxSpeed / emRatio); + + for (var i = 0; i < Math.Min(gearboxData.Gears.Count, Math.Min(expectedDownshift.Length, expectedUpshift.Length)); i++) { + foreach (var tuple in expectedDownshift[i].Zip(shiftPolygons[i].Downshift, Tuple.Create)) { + Assert.AreEqual(tuple.Item1.X, tuple.Item2.AngularSpeed.AsRPM, 1e-3, "gear: {0} entry: {1}", i + 1, tuple); + Assert.AreEqual(tuple.Item1.Y, tuple.Item2.Torque.Value(), 1e-3, "gear: {0} entry: {1}", i + 1, tuple); + } + + foreach (var tuple in expectedUpshift[i].Zip(shiftPolygons[i].Upshift, Tuple.Create)) { + Assert.AreEqual(tuple.Item1.X, tuple.Item2.AngularSpeed.AsRPM, 1e-3, "gear: {0} entry: {1}", i + 1, tuple); + Assert.AreEqual(tuple.Item1.Y, tuple.Item2.Torque.Value(), 1e-3, "gear: {0} entry: {1}", i + 1, tuple); + } + } + + Assert.AreEqual(0, shiftPolygons.First().Downshift.Count); + Assert.AreEqual(0, shiftPolygons.Last().Upshift.Count); + + //var suffix = factorDownshiftSpeed.HasValue ? $"_{factorDownshiftSpeed.Value}" : ""; + + } + + + + private static EfficiencyMap GetEffMap(ElectricMotorFullLoadCurve emFld, int countEm) + { + var emEffMap = ElectricMotorMapReader.Create( + InputDataHelper.InputDataAsTableData( + "n [rpm] , T [Nm] , P_el [kW]", + $"0, {emFld.MaxDriveTorque.Value()}, 0", + $"0, {emFld.MaxGenerationTorque.Value()}, 0", + $"0, 0, 0", + $"{emFld.MaxSpeed.AsRPM / 3}, {emFld.MaxDriveTorque.Value()}, -300", + $"{emFld.MaxSpeed.AsRPM / 3}, {emFld.MaxGenerationTorque.Value()}, 750", + $"{emFld.MaxSpeed.AsRPM / 3}, 0, 100", + $"{emFld.MaxSpeed.AsRPM / 2}, {emFld.MaxDriveTorque.Value()}, -300", + $"{emFld.MaxSpeed.AsRPM / 2}, {emFld.MaxGenerationTorque.Value()}, 750", + $"{emFld.MaxSpeed.AsRPM / 2}, 0, 100", + $"{emFld.MaxSpeed.AsRPM}, {emFld.MaxDriveTorque.Value()}, -300", + $"{emFld.MaxSpeed.AsRPM}, {emFld.MaxGenerationTorque.Value()}, 750", + $"{emFld.MaxSpeed.AsRPM}, 0, 100" + ).ApplyFactor(ElectricMotorMapReader.Fields.PowerElectrical, 1E3), countEm, ExecutionMode.Declaration); + return emEffMap; + } + + [TestCase] public void ComputePEVShiftLinesDeRated() { @@ -312,7 +834,7 @@ public class PEV_ShiftLineTests // }); var countEm = 2; - var emRatio = 2.0; + var emRatio = 1.0; var continuousTorque = 145.SI<NewtonMeter>() * countEm; var emFld = new ElectricMotorFullLoadCurve(EM_FullLoad_125kW_485Nm.Select(x => new ElectricMotorFullLoadCurve.FullLoadEntry() { @@ -322,6 +844,9 @@ public class PEV_ShiftLineTests FullGenerationTorque = -x[2].SI<NewtonMeter>() * countEm, }).ToList()); + var emEffMap = GetEffMap(emFld: emFld, countEm: countEm); + + var emData = new ElectricMotorData() { RatioADC = emRatio, Overload = new OverloadData() { @@ -330,10 +855,12 @@ public class PEV_ShiftLineTests EfficiencyData = new VoltageLevelData() { VoltageLevels = new List<ElectricMotorVoltageLevelData>() { new ElectricMotorVoltageLevelData() { - FullLoadCurve = emFld + FullLoadCurve = emFld, + EfficiencyMap = emEffMap } } - } + }, + TransmissionLossMap = TransmissionLossMapReader.CreateEmADCLossMap(1, emRatio, "ADC") }; var gearboxData = new Mock<IGearboxEngineeringInputData>().Object; var gear = new Mock<ITransmissionInputData>().Object; @@ -358,9 +885,10 @@ public class PEV_ShiftLineTests var runData = new VectoRunData() { GearshiftParameters = new ShiftStrategyParameters() }; var container = new Mock<IVehicleContainer>(); container.Setup(c => c.RunData).Returns(runData); - var shiftStrategy = new PEVAMTShiftStrategyPolygonCreator(runData.GearshiftParameters); - //var deRatedShiftLines = shiftStrategy.CalculateDeratedShiftLines(emData, gearboxData.Gears, - // r_dyn, axlegearRatio, GearboxType.AMT); + + var polygonCreator = new PEVAMTShiftStrategyPolygonCreator(runData.GearshiftParameters); + //var deRatedShiftLines = shiftStrategy.CalculateDeratedShiftLines(emData, gearboxData.Gears, + // r_dyn, axlegearRatio, GearboxType.AMT); for (var i = 0; i < gearboxData.Gears.Count; i++) { //var emFld = emData.EfficiencyData.VoltageLevels.First().FullLoadCurve; @@ -369,7 +897,7 @@ public class PEV_ShiftLineTests var limitedEm = new ElectricMotorData() { EfficiencyData = new VoltageLevelData() { VoltageLevels = new List<ElectricMotorVoltageLevelData>() { - new ElectricMotorVoltageLevelData() { + new DeratedVoltageLevelData(emFld.MaxSpeed) { FullLoadCurve = limitedFld } } @@ -377,11 +905,14 @@ public class PEV_ShiftLineTests RatioADC = emData.RatioADC, }; - var deratedShiftLine = shiftStrategy.ComputeElectricMotorDeclarationShiftPolygon(GearboxType.APTN, i, + var deratedShiftLine = polygonCreator.ComputeElectricMotorDeclarationShiftPolygon(GearboxType.APTN, i, gearboxData.Gears, axlegearRatio, r_dyn, emData, limitedEm); shiftPolygons.Add(deratedShiftLine); - } + } + + CommonSanityChecks(shiftPolygons, emData.EfficiencyData.MaxSpeed / emRatio); + for (var i = 0; i < Math.Min(gearboxData.Gears.Count, Math.Min(expectedDownshift.Length, expectedUpshift.Length)); i++) { foreach (var tuple in expectedDownshift[i].Zip(shiftPolygons[i].Downshift, Tuple.Create)) { Assert.AreEqual(tuple.Item1.X, tuple.Item2.AngularSpeed.AsRPM, 1e-3, "gear: {0} entry: {1}", i + 1, tuple); @@ -477,4 +1008,30 @@ public class PEV_ShiftLineTests new[] { 7290.132548,163.736,-163.736 }, new[] { 7363.77025,162.099125,-162.099125 }, }; + + + + + private void CommonSanityChecks(IEnumerable<ShiftPolygon> shiftPolygons, PerSecond emMaxSpeed) + { + var polygonList = shiftPolygons.ToList(); + foreach (var upShiftPolygon in polygonList.Select(p => p.Upshift)) { + foreach (var entry in upShiftPolygon) { + Assert.Less(entry.AngularSpeed, emMaxSpeed ); + } + } + + foreach (var shiftPolygon in polygonList) { + var upshift = shiftPolygon.Upshift; + var downshift = shiftPolygon.Downshift; + if (upshift.Count > 0 && downshift.Count > 0) { + Assert.True(downshift.All(d => d.AngularSpeed.IsSmallerOrEqual(upshift.First().AngularSpeed))); + } + } + + + + + + } } diff --git a/Testing/UnitTests/Vecto UnitTests/Utils/InputDataHelper.cs b/Testing/UnitTests/Vecto UnitTests/Utils/InputDataHelper.cs index 7021f9b29c615417231db860d31a02862d8016f7..424a7e7ea0c570de6211f922e4e43837af9028c6 100644 --- a/Testing/UnitTests/Vecto UnitTests/Utils/InputDataHelper.cs +++ b/Testing/UnitTests/Vecto UnitTests/Utils/InputDataHelper.cs @@ -50,11 +50,10 @@ namespace TUGraz.VectoCore.Tests.Utils return cycleData; } - public static TableData InputDataAsTableData(string header, string[] entries) + public static TableData InputDataAsTableData(string header, params string[] entries) { return VectoCSVFile.ReadStream(InputDataAsStream(header, entries)); } - public static string GetRandomFilename(string jobFile) { var path = Path.GetDirectoryName(Path.GetFullPath(jobFile)); diff --git a/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/SimulationComponents/GearBoxDataAdapter.cs b/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/SimulationComponents/GearBoxDataAdapter.cs index dd9893ae6d626d764064a31bc564e1618c486fb8..8e5c554882bddaffb31a3d99aa97ba99d1045bc5 100644 --- a/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/SimulationComponents/GearBoxDataAdapter.cs +++ b/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/SimulationComponents/GearBoxDataAdapter.cs @@ -462,16 +462,19 @@ namespace TUGraz.VectoCore.InputData.Reader.DataObjectAdapter.SimulationComponen var limitedEm = new ElectricMotorData() { EfficiencyData = new VoltageLevelData() { VoltageLevels = new List<ElectricMotorVoltageLevelData>() { - new ElectricMotorVoltageLevelData() { + new DeratedVoltageLevelData(em.EfficiencyData.MaxSpeed) { FullLoadCurve = limitedFld } } }, RatioADC = em.RatioADC, }; - var deratedEmShiftPolygon = shiftPolygonCalculator.ComputeElectricMotorDeclarationShiftPolygon(gearbox.Type, (int)i, + var deratedEmShiftPolygon = shiftPolygonCalculator.ComputeElectricMotorDeclarationShiftPolygon( + gearbox.Type, (int)i, gearbox.Gears, axlegearRatio, - dynamicTyreRadius, em, limitedEm); + dynamicTyreRadius, + em, + limitedEm); return deratedEmShiftPolygon; //retVal[i + 1] = shiftPolygon; } @@ -611,7 +614,7 @@ namespace TUGraz.VectoCore.InputData.Reader.DataObjectAdapter.SimulationComponen var limitedEm = new ElectricMotorData() { EfficiencyData = new VoltageLevelData() { VoltageLevels = new List<ElectricMotorVoltageLevelData>() { - new ElectricMotorVoltageLevelData() { + new DeratedVoltageLevelData(em.EfficiencyData.MaxSpeed) { FullLoadCurve = limitedFld } } diff --git a/VectoCore/VectoCore/Models/Declaration/DeclarationData.cs b/VectoCore/VectoCore/Models/Declaration/DeclarationData.cs index 47f74e23453a7be66afd6989c9b360314be72233..968a959ba8fbc29eb77855a552223061add515c1 100644 --- a/VectoCore/VectoCore/Models/Declaration/DeclarationData.cs +++ b/VectoCore/VectoCore/Models/Declaration/DeclarationData.cs @@ -58,6 +58,7 @@ using TUGraz.VectoCore.Models.SimulationComponent.Data.ElectricComponents.Batter using TUGraz.VectoCore.Models.SimulationComponent.Impl; using TUGraz.VectoCore.OutputData; using Point = TUGraz.VectoCommon.Utils.Point; +using NLog.Fluent; using ElectricSystem = TUGraz.VectoCore.Models.Declaration.Auxiliaries.ElectricSystem; namespace TUGraz.VectoCore.Models.Declaration @@ -1063,40 +1064,108 @@ namespace TUGraz.VectoCore.Models.Declaration } } - - public static ShiftPolygon ComputeElectricMotorShiftPolygon(int gearIdx, - ElectricMotorFullLoadCurve fullLoadCurveOrig, double emRatio, IList<ITransmissionInputData> gears, - double axlegearRatio, Meter dynamicTyreRadius, PerSecond downshiftMaxSpeed = null, PerSecond downshiftMinSpeed = null) + + + public static ShiftPolygon ComputeElectricMotorShiftPolygon( + int gearIdx, + ElectricMotorData electricMotorData, + IList<ITransmissionInputData> gears, + double? downshiftMaxSpeedFactor = null, + double? downShiftMinSpeedFactor = null) { - var gbxMaxTq = gears[gearIdx].MaxTorque != null ? gears[gearIdx].MaxTorque / emRatio : null; - var gbxMaxSpeed = gears[gearIdx].MaxInputSpeed != null ? gears[gearIdx].MaxInputSpeed * emRatio : null; - + if ((downshiftMaxSpeedFactor != null && !downshiftMaxSpeedFactor.Value.IsBetween(0.0, 1.0)) || + downShiftMinSpeedFactor != null && !downShiftMinSpeedFactor.Value.IsBetween(0.0, 1.0)) { + throw new VectoException("Invalid downshift factors: must be between 0.0 and 1.0"); + } + + //EM FullloadCurve + var fullLoadCurveOrig = electricMotorData.EfficiencyData.VoltageLevels.First().FullLoadCurve; + + var emRatio = electricMotorData.RatioADC; + var lossMap = electricMotorData.TransmissionLossMap; + var emMaxSpeed = electricMotorData.EfficiencyData.MaxSpeed; + + //Transform EM Fullloadcurve to include ADC losses and ratio. Convert EM to Drivetrain + var fullLoadCurveTransformed = TransformFullLoadCurve(fullLoadCurveOrig, lossMap, emRatio); + var emMaxSpeedDt = emMaxSpeed / emRatio; + + + //From now on we are on the gbx_in side. + var gbxMaxTq = gears[gearIdx].MaxTorque != null ? gears[gearIdx].MaxTorque : null; + var gbxMaxSpeed = gears[gearIdx].MaxInputSpeed != null ? gears[gearIdx].MaxInputSpeed : null; + + var fullLoadCurve = gbxMaxTq == null - ? fullLoadCurveOrig - : LimitElectricMotorFullLoadCurve(fullLoadCurveOrig, gbxMaxTq); + ? fullLoadCurveTransformed + : LimitElectricMotorFullLoadCurve(fullLoadCurveTransformed, gbxMaxTq); + if (gears.Count < 2) { throw new VectoException("ComputeShiftPolygon needs at least 2 gears. {0} gears given.", gears.Count); } - + var downShift = new List<ShiftPolygon.ShiftPolygonEntry>(); var upShift = new List<ShiftPolygon.ShiftPolygonEntry>(); if (gearIdx > 0) { - var nMax = downshiftMaxSpeed ?? fullLoadCurve.NP80low; - var nMin = downshiftMinSpeed ?? 0.1 * fullLoadCurve.RatedSpeed; - - downShift.AddRange(DownshiftLineDrive(fullLoadCurve, fullLoadCurveOrig, nMin, fullLoadCurve.NP80low)); - downShift.AddRange(DownshiftLineDrag(fullLoadCurve, fullLoadCurveOrig, nMin, nMax)); - + var nMax = downshiftMaxSpeedFactor.HasValue + ? downshiftMaxSpeedFactor.Value * fullLoadCurve.RatedSpeed + : fullLoadCurve.NP80low; + + var nMin = downShiftMinSpeedFactor.HasValue + ? downShiftMinSpeedFactor.Value * fullLoadCurve.RatedSpeed + : fullLoadCurve.RatedSpeed * 0.1; + + downShift.AddRange(DownshiftLineDrive(fullLoadCurve, fullLoadCurveTransformed, nMin, fullLoadCurve.NP80low)); + downShift.AddRange(DownshiftLineDrag(fullLoadCurve, fullLoadCurveTransformed, nMin, nMax)); + } if (gearIdx >= gears.Count - 1) { - return new ShiftPolygon(downShift, upShift); + return new ShiftPolygon(TransformShiftPolygonEntries(downShift, emRatio, lossMap), TransformShiftPolygonEntries(upShift, emRatio, lossMap)); } + + upShift.Add(new ShiftPolygon.ShiftPolygonEntry(fullLoadCurve.MaxGenerationTorque * 1.1, VectoMath.Min(emMaxSpeedDt * 0.9, gbxMaxSpeed))); + upShift.Add(new ShiftPolygon.ShiftPolygonEntry(fullLoadCurve.MaxDriveTorque * 1.1, VectoMath.Min(emMaxSpeedDt * 0.9, gbxMaxSpeed))); + return new ShiftPolygon(TransformShiftPolygonEntries(downShift, emRatio, lossMap), TransformShiftPolygonEntries(upShift, emRatio, lossMap)); + } - upShift.Add(new ShiftPolygon.ShiftPolygonEntry(fullLoadCurve.MaxGenerationTorque * 1.1, VectoMath.Min(fullLoadCurve.MaxSpeed * 0.9, gbxMaxSpeed))); - upShift.Add(new ShiftPolygon.ShiftPolygonEntry(fullLoadCurve.MaxDriveTorque * 1.1, VectoMath.Min(fullLoadCurve.MaxSpeed * 0.9, gbxMaxSpeed))); - return new ShiftPolygon(downShift, upShift); + + /// <summary> + /// Transforms the shiftpolygons from em side to drivetrain side (= gearbox in), considering the ADC ratio and losses + /// </summary> + /// <param name="entries"></param> + /// <param name="emRatio"></param> + /// <param name="lossMap"></param> + /// <returns></returns> + private static IList<ShiftPolygon.ShiftPolygonEntry> TransformShiftPolygonEntries( + IEnumerable<ShiftPolygon.ShiftPolygonEntry> entries, double emRatio, TransmissionLossMap lossMap) + { + return entries.ToList(); } + private static ElectricMotorFullLoadCurve TransformFullLoadCurve(ElectricMotorFullLoadCurve emFld, + TransmissionLossMap lossMap, double ratioAdc) + { + var fldCurve = + new ElectricMotorFullLoadCurve( + emFld.FullLoadEntries.Select(e => { + var drive = lossMap.GetOutTorqueAndSpeed(e.MotorSpeed, e.FullDriveTorque); + var generation = lossMap.GetOutTorqueAndSpeed(e.MotorSpeed, e.FullGenerationTorque); + return new ElectricMotorFullLoadCurve.FullLoadEntry() { + FullDriveTorque = drive.outTorque, + FullGenerationTorque = generation.outTorque, + MotorSpeed = drive.outAngularVelocity + }; + } + ).ToList()); + + return fldCurve; + } + + /// <summary> + /// Limit the fullload curve to the max gearbox in torque + /// </summary> + /// <param name="emFld"></param> + /// <param name="maxTq"></param> + /// <returns></returns> public static ElectricMotorFullLoadCurve LimitElectricMotorFullLoadCurve(ElectricMotorFullLoadCurve emFld, NewtonMeter maxTq) { var contTqFld = new ElectricMotorFullLoadCurve(new List<ElectricMotorFullLoadCurve.FullLoadEntry>() { diff --git a/VectoCore/VectoCore/Models/Simulation/DataBus/IElectricMotorInfo.cs b/VectoCore/VectoCore/Models/Simulation/DataBus/IElectricMotorInfo.cs index 59cde098fce6f75a9caf2a5080c2ba4615a75321..6d16bced6460b515c28f891675117ecdecfed786 100644 --- a/VectoCore/VectoCore/Models/Simulation/DataBus/IElectricMotorInfo.cs +++ b/VectoCore/VectoCore/Models/Simulation/DataBus/IElectricMotorInfo.cs @@ -12,7 +12,8 @@ namespace TUGraz.VectoCore.Models.Simulation.DataBus PerSecond ElectricMotorSpeed { get; } NewtonMeter ElectricMotorTorque { get; } PowertrainPosition Position { get; } - PerSecond MaxSpeed { get; } + PerSecond MaxSpeedDt { get; } + PerSecond RatedSpeedDt { get; } Watt DragPower(Volt volt, PerSecond electricMotorSpeed, GearshiftPosition gear); Watt MaxPowerDrive(Volt volt, PerSecond inAngularVelocity, GearshiftPosition gear); NewtonMeter GetTorqueForElectricPower(Volt volt, Watt electricPower, PerSecond avgEmSpeed, Second dt, GearshiftPosition gear, bool allowExtrapolation); diff --git a/VectoCore/VectoCore/Models/Simulation/ISimplePowertrainBuilder.cs b/VectoCore/VectoCore/Models/Simulation/ISimplePowertrainBuilder.cs index b46bbb0b0198cc77fec81fe4b1bfffe1fba80411..a2146fe114cfaa34c37f273b0b217c5d0c852bc6 100644 --- a/VectoCore/VectoCore/Models/Simulation/ISimplePowertrainBuilder.cs +++ b/VectoCore/VectoCore/Models/Simulation/ISimplePowertrainBuilder.cs @@ -9,9 +9,8 @@ namespace TUGraz.VectoCore.Models.Simulation public interface ISimplePowertrainBuilder { //ITestPowertrain CreateTestPowertrain(ISimpleVehicleContainer testContainer, IDataBus realContainer, bool createDriver); - - ITestPowertrain CreateTestPowertrain(IVehicleContainer realContainer, bool createDriver, VectoSimulationJobType? overrideJobType = null); - + ITestPowertrain CreateTestPowertrain(IVehicleContainer realContainer, bool createDriver, VectoSimulationJobType overrideJobType); + ITestPowertrain CreateTestPowertrain(IVehicleContainer realContainer, bool createDriver); ITestGenset CreateTestGenset(IVehicleContainer realContainer); /// <summary> diff --git a/VectoCore/VectoCore/Models/Simulation/Impl/SimplePowertrainBuilder.cs b/VectoCore/VectoCore/Models/Simulation/Impl/SimplePowertrainBuilder.cs index 9068c164fee5417f42242fc4c297daf1c4c0e72b..2ce2331314b74b2eb6fb821e1478056514be7f5a 100644 --- a/VectoCore/VectoCore/Models/Simulation/Impl/SimplePowertrainBuilder.cs +++ b/VectoCore/VectoCore/Models/Simulation/Impl/SimplePowertrainBuilder.cs @@ -32,12 +32,18 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl } - public ITestPowertrain CreateTestPowertrain(IVehicleContainer realContainer, bool createDriver, VectoSimulationJobType? overrideJobType) + public ITestPowertrain CreateTestPowertrain(IVehicleContainer realContainer, bool createDriver, VectoSimulationJobType overrideJobType) { var testContainer = BuildSimplePowertrain(realContainer.RunData, overrideJobType); return new TestPowertrain(testContainer, realContainer, createDriver); } + public ITestPowertrain CreateTestPowertrain(IVehicleContainer realContainer, bool createDriver) + { + var testContainer = BuildSimplePowertrain(realContainer.RunData, null); + return new TestPowertrain(testContainer, realContainer, createDriver); + } + public ITestGenset CreateTestGenset(IVehicleContainer realContainer) { var testContainer = BuildSimpleGenSet(realContainer.RunData); diff --git a/VectoCore/VectoCore/Models/Simulation/PowertrainComponentNinjectModule.cs b/VectoCore/VectoCore/Models/Simulation/PowertrainComponentNinjectModule.cs index 243fb2574b01dbf3d211a0dfc6fbc3d2b9bbcbba..9de7660fc845b4153662fd4e26b86be2f35d6826 100644 --- a/VectoCore/VectoCore/Models/Simulation/PowertrainComponentNinjectModule.cs +++ b/VectoCore/VectoCore/Models/Simulation/PowertrainComponentNinjectModule.cs @@ -147,7 +147,7 @@ namespace TUGraz.VectoCore.Models.Simulation } Bind<IElectricSystem>().To<TestpowertrainElectricSystem>().Named(_testPowertrain.Prefix); Bind<IElectricChargerPort>().To<TestpowertrainGensetChargerAdapter>().Named(_testPowertrain.Prefix); - Bind<IElectricMotor>().To<TestpowertrainElectricMotor>().Named(_testPowertrain.ElectricMotorName(false)); + Bind<IElectricMotor>().To<TestPowertrainElectricMotor>().Named(_testPowertrain.ElectricMotorName(false)); Bind<IElectricMotor>().To<TestpowertrainIEPC>().Named(_testPowertrain.ElectricMotorName(true)); Bind<IElectricMotorControl>().To<SimpleElectricMotorControl>().Named(_testPowertrain.ElectricMotorControllerName(CycleType.DistanceBased)); diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Data/ElectricComponents/ElectricMotor/ElectricMotorData.cs b/VectoCore/VectoCore/Models/SimulationComponent/Data/ElectricComponents/ElectricMotor/ElectricMotorData.cs index 3f5056383bbfe9b74c561c97df32bfc618c3bb85..41192481b74a069942ebaf2b62630793f45fb1bf 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Data/ElectricComponents/ElectricMotor/ElectricMotorData.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Data/ElectricComponents/ElectricMotor/ElectricMotorData.cs @@ -244,6 +244,36 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data { } + + public class DeratedVoltageLevelData : ElectricMotorVoltageLevelData + { + public DeratedVoltageLevelData(PerSecond maxSpeed) + { + _maxSpeed = maxSpeed; + } + + #region Overrides of ElectricMotorVoltageLevelData + public override EfficiencyMap.EfficiencyResult LookupElectricPower(PerSecond avgSpeed, NewtonMeter torque, uint gear, bool allowExtrapolation) + { + throw new NotImplementedException(); + } + public override NewtonMeter LookupTorque(Watt electricPower, PerSecond avgSpeed, NewtonMeter maxEmTorque, uint gear) + { + throw new NotImplementedException(); + } + public override NewtonMeter FullLoadDriveTorque(PerSecond avgSpeed) + { + throw new NotImplementedException(); + } + public override NewtonMeter FullGenerationTorque(PerSecond avgSpeed) + { + throw new NotImplementedException(); + } + + #endregion + } + + public class OverloadData { diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Data/Gearbox/ShiftPolygon.cs b/VectoCore/VectoCore/Models/SimulationComponent/Data/Gearbox/ShiftPolygon.cs index d9f07a552825f27e88fcd5c7f670083650b352c0..39e017012882bcf67dc8cf69723dbf9c6d6e2412 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Data/Gearbox/ShiftPolygon.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Data/Gearbox/ShiftPolygon.cs @@ -47,10 +47,10 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox private readonly List<ShiftPolygonEntry> _upShiftPolygon; private readonly List<ShiftPolygonEntry> _downShiftPolygon; - internal ShiftPolygon(List<ShiftPolygonEntry> downshift, List<ShiftPolygonEntry> upShift) + internal ShiftPolygon(IList<ShiftPolygonEntry> downshift, IList<ShiftPolygonEntry> upShift) { - _upShiftPolygon = upShift; - _downShiftPolygon = downshift; + _upShiftPolygon = upShift.ToList(); + _downShiftPolygon = downshift.ToList(); } [JsonIgnore] diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Data/Gearbox/TransmissionLossMap.cs b/VectoCore/VectoCore/Models/SimulationComponent/Data/Gearbox/TransmissionLossMap.cs index 197feb45164bbbe3ffc93c4c555fccaa48261741..7eee96a5a1e1d5d2da5c6ad3f311ba22aafe4abd 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Data/Gearbox/TransmissionLossMap.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Data/Gearbox/TransmissionLossMap.cs @@ -45,8 +45,6 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox { [ValidateObject] internal readonly IReadOnlyList<GearLossMapEntry> _entries; - private readonly double _ratio; - /// <summary> /// The Loss map. [X=Output EngineSpeed, Y=Output Torque] => Z=Torque Loss /// </summary> @@ -59,6 +57,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox public string GearName { get; private set; } + public double Ratio { get; } public string[] LossMapSerialized @@ -69,7 +68,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox public TransmissionLossMap(IReadOnlyList<GearLossMapEntry> entries, double gearRatio, string gearName, bool createInnvertedMap) { GearName = gearName; - _ratio = gearRatio; + Ratio = gearRatio; _entries = entries; _lossMap = new DelaunayMap("TransmissionLossMap " + GearName); _invertedLossMap = createInnvertedMap ? new DelaunayMap("TransmissionLossMapInv. " + GearName) : null; @@ -91,10 +90,10 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox public LossMapResult GetTorqueLoss(PerSecond outAngularVelocity, NewtonMeter outTorque) { var result = new LossMapResult(); - var torqueLoss = _lossMap.Interpolate(outAngularVelocity.Value() * _ratio, outTorque.Value() / _ratio); + var torqueLoss = _lossMap.Interpolate(outAngularVelocity.Value() * Ratio, outTorque.Value() / Ratio); if (torqueLoss.IsNaN()) { - torqueLoss = _lossMap.Extrapolate(outAngularVelocity.Value() * _ratio, outTorque.Value() / _ratio); + torqueLoss = _lossMap.Extrapolate(outAngularVelocity.Value() * Ratio, outTorque.Value() / Ratio); result.Extrapolated = true; } @@ -111,6 +110,47 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox public bool Extrapolated; public NewtonMeter Value; } + /// <summary> + /// Computes the OUTPUT torque and speed given by the input speed and input torque + /// </summary> + /// <param name="inAngularVelocity"></param> + /// <param name="inTorque"></param> + /// <param name="allowExtrapolation"></param> + /// <returns></returns> + public (NewtonMeter outTorque, PerSecond outAngularVelocity) GetOutTorqueAndSpeed(PerSecond inAngularVelocity, + NewtonMeter inTorque, bool allowExtrapolation = false) + { + var outTorque = this.GetOutTorque(inAngularVelocity, inTorque, allowExtrapolation); + var outAngularVelocity = inAngularVelocity / Ratio; + + var torqueLoss = this.GetTorqueLoss(outAngularVelocity, outTorque); + var inTorqueBackward = GetInTorque(outAngularVelocity, outTorque); + + if(!inTorque.IsEqual(inTorqueBackward, 1E-8.SI<NewtonMeter>())) + { + Log.Debug($"{nameof(TransmissionLossMap)}: Forward Calculation and Backward Calculation of DriveTorque do not match..."); + //Search outTorque: + Log.Debug("Forward Calculation and Backward Calculation do not match..."); + outTorque = SearchAlgorithm.Search(inTorque, (inTorqueBackward - inTorque) * 1e3, outTorque / 10, + getYValue: r => ((r as NewtonMeter) - inTorque) * 1e3, + evaluateFunction: x => GetInTorque(outAngularVelocity, x), + criterion: r => { + var i = r as NewtonMeter; + return (i - inTorque).Value() * 1e3; + }, + searcher: this); + } + + return (outTorque, outAngularVelocity); + } + + public NewtonMeter GetInTorque(PerSecond outAngularVelocity, NewtonMeter outTorque) + { + var torqueLoss = this.GetTorqueLoss(outAngularVelocity, outTorque); + var inTorque = outTorque / Ratio + torqueLoss.Value; + return inTorque; + } + /// <summary> /// Computes the OUTPUT torque given by the input engineSpeed and the input torque. @@ -126,12 +166,12 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox } var torqueLoss = _invertedLossMap.Interpolate(inAngularVelocity.Value(), inTorque.Value()); if (!torqueLoss.IsNaN()) { - return (inTorque - torqueLoss.SI<NewtonMeter>()) * _ratio; + return (inTorque - torqueLoss.SI<NewtonMeter>()) * Ratio; } if (allowExtrapolation) { torqueLoss = _invertedLossMap.Extrapolate(inAngularVelocity.Value(), inTorque.Value()); - return (inTorque - torqueLoss.SI<NewtonMeter>()) * _ratio; + return (inTorque - torqueLoss.SI<NewtonMeter>()) * Ratio; } throw new VectoException("TransmissionLossMap {0}: Interpolation failed. inTorque: {1}, inAngularVelocity: {2}", diff --git a/VectoCore/VectoCore/Models/SimulationComponent/IGearbox.cs b/VectoCore/VectoCore/Models/SimulationComponent/IGearbox.cs index 138d035dfff77dec75b4ac3f7290a78f34b8deb4..0514204f9ca94289f4cb8cc6af76100b5c59e14c 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/IGearbox.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/IGearbox.cs @@ -29,6 +29,9 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Models.Connector.Ports.Impl; using TUGraz.VectoCore.Models.Simulation.DataBus; using TUGraz.VectoCore.Models.SimulationComponent.Impl; using TUGraz.VectoCore.Models.SimulationComponent.Impl.Gearbox; @@ -40,27 +43,42 @@ namespace TUGraz.VectoCore.Models.SimulationComponent /// </summary> public interface IGearbox : IPowerTrainComponent, IGearboxInfo, IGearboxControl, IUpdateable { } - public interface IGearboxType {} + public interface ITypedGearbox : IGearbox {} - public interface IMTGearbox : IGearboxType {} + public interface IMTGearbox : ITypedGearbox {} - public interface IAMTGearbox : IGearboxType + public interface IAMTGearbox : ITypedGearbox { GearboxState GetPreviousState { get; } } - public interface IAPTGearbox : IGearboxType + public interface IAPTGearbox : ITypedGearbox { ATGearboxState GetPreviousState { get; } bool ShiftToLocked { get; } IIdleController IdleController { set; } + bool TorqueConverterLocked { get; } + + + + ResponseDryRun Initialize(GearshiftPosition gear, NewtonMeter outTorque, + PerSecond outAngularVelocity); + + new bool Disengaged { get; set; } + KilogramSquareMeter EngineInertia { get; } + ITorqueConverter TorqueConverter { get; } + + WattSecond ComputeShiftLosses(NewtonMeter outTorque, PerSecond outAngularVelocity, GearshiftPosition nextGearPos); } - public interface IAPTNGearbox : IGearboxType { } + public interface IAPTNGearbox : ITypedGearbox { } - public interface IPEVGearbox : IGearboxType { } + public interface IPEVGearbox : ITypedGearbox { } - public interface IIEPCGearbox : IGearboxType { } + public interface IIEPCGearbox : ITypedGearbox { } - public interface ITorqueConverter : ITorqueConverterInfo, ITorqueConverterControl, IUpdateable { } + public interface ITorqueConverter : ITorqueConverterInfo, ITorqueConverterControl, IUpdateable + { + TorqueConverterOperatingPoint FindOperatingPoint(Second absTime, Second dt, NewtonMeter nextGearboxInTorque, PerSecond nextGearboxInSpeed); + } } \ No newline at end of file diff --git a/VectoCore/VectoCore/Models/SimulationComponent/ITestPowertrain.cs b/VectoCore/VectoCore/Models/SimulationComponent/ITestPowertrain.cs index e3add8c86b39866c44ac470be4a879782972a676..f4121fd0f02245e41fb19e10fc33fc2fa4733f5d 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/ITestPowertrain.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/ITestPowertrain.cs @@ -29,8 +29,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent IBrakes Brakes { get; } ITestpowertrainElectricMotor ElectricMotor { get; } - Dictionary<PowertrainPosition, ITestpowertrainElectricMotor> ElectricMotors { get; } - Dictionary<PowertrainPosition, IElectricMotor> ElectricMotorsUpstreamTransmission { get; } + Dictionary<PowertrainPosition, ITestpowertrainElectricMotor> ElectricMotors { get; } + Dictionary<PowertrainPosition, IElectricMotor> ElectricMotorsUpstreamTransmission { get; } IDCDCConverter DCDCConverter { get; } ITorqueConverter TorqueConverter { get; } ITestpowertrainGensetChargerAdapter Charger { get; } diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/AbstractGearbox.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/AbstractGearbox.cs index fa9c458ef3e63e311583c787c3ccc6bffa96d18a..962f08e87380dbfc575d3b916b706aa22c22ea5e 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/AbstractGearbox.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/AbstractGearbox.cs @@ -152,7 +152,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl return nextGear.TorqueConverterLocked.HasValue && nextGear.TorqueConverterLocked.Value; } - protected internal WattSecond ComputeShiftLosses(NewtonMeter outTorque, PerSecond outAngularVelocity, GearshiftPosition gear) + public WattSecond ComputeShiftLosses(NewtonMeter outTorque, PerSecond outAngularVelocity, GearshiftPosition gear) { var ratio = ModelData.Gears[gear.Gear].Ratio; if (double.IsNaN(ratio)) { diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/CycleGearbox.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/CycleGearbox.cs index 226212530ae7498bb6a793172492bb16add2b1e1..81bd7362a19c41b8585586e73078245a2d8f2216 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/CycleGearbox.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/CycleGearbox.cs @@ -51,7 +51,7 @@ using TUGraz.VectoCore.Utils; namespace TUGraz.VectoCore.Models.SimulationComponent.Impl { - public class CycleGearbox : AbstractGearbox<CycleGearbox.CycleGearboxState>, IGearboxType + public class CycleGearbox : AbstractGearbox<CycleGearbox.CycleGearboxState>, ITypedGearbox { /// <summary> /// True if gearbox is disengaged (no gear is set). diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/ElectricMotor.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/ElectricMotor.cs index 56575e123e4f6e71d240373b9da4c16d82bb0dd4..5af085c3be918079c508f5587e0cfb643beb5157 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/ElectricMotor.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/ElectricMotor.cs @@ -16,9 +16,9 @@ using TUGraz.VectoCore.Utils; namespace TUGraz.VectoCore.Models.SimulationComponent.Impl { - public class TestpowertrainElectricMotor : ElectricMotor, ITestpowertrainElectricMotor + public class TestPowertrainElectricMotor : ElectricMotor, ITestpowertrainElectricMotor { - public TestpowertrainElectricMotor(IVehicleContainer container, ElectricMotorData data, + public TestPowertrainElectricMotor(IVehicleContainer container, ElectricMotorData data, IElectricMotorControl control, PowertrainPosition position) : base(container, data, control, position, false) { if (!container.IsTestPowertrain) { @@ -52,7 +52,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl public IElectricMotorControl Control { get; } protected ElectricMotorData ModelData; private PerSecond _maxSpeed; - + private PerSecond _ratedSpeed; + protected internal Joule ThermalBuffer = 0.SI<Joule>(); @@ -92,12 +93,10 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl Log.Error("Overload buffer for thermal de-rating is zero or negative! Please check electric motor data!"); } } - public double[] TransmissionRatioPerGear { get; set; } - public PowertrainPosition Position { get; } - public PerSecond MaxSpeed => _maxSpeed ?? (_maxSpeed = ModelData.EfficiencyData.MaxSpeed / ModelData.RatioADC); - + public PerSecond MaxSpeedDt => _maxSpeed ?? (_maxSpeed = ModelData.EfficiencyData.MaxSpeed / ModelData.RatioADC); + public PerSecond RatedSpeedDt => _ratedSpeed ?? (_ratedSpeed = ModelData.EfficiencyData.VoltageLevels.First().FullLoadCurve.RatedSpeed / ModelData.RatioADC); public Watt DragPower(Volt volt, PerSecond electricMotorSpeed, GearshiftPosition gear) { return ModelData.DragCurveLookup(electricMotorSpeed, gear) * electricMotorSpeed; @@ -505,10 +504,10 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl protected virtual PerSecond GetMotorSpeedLimit(Second absTime) { if (DataBus.GearboxInfo == null || DataBus.GearboxInfo.Gear.Gear == 0) { - return MaxSpeed; + return MaxSpeedDt; } - return VectoMath.Min(DataBus.GearboxInfo.GetGearData(DataBus.GearboxInfo.Gear.Gear)?.MaxSpeed, MaxSpeed); + return VectoMath.Min(DataBus.GearboxInfo.GetGearData(DataBus.GearboxInfo.Gear.Gear)?.MaxSpeed, MaxSpeedDt); } private NewtonMeter GetMaxRecuperationTorque(Volt volt, Second dt, PerSecond avgSpeed, GearshiftPosition gear) diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/Gearbox/APTGearbox.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/Gearbox/APTGearbox.cs index ef23b916fab0d836c091e7848210bbd443100960..034dcf053e71d018fa459e364702f825656eab32 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/Gearbox/APTGearbox.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/Gearbox/APTGearbox.cs @@ -51,17 +51,37 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl.Gearbox public class APTGearbox : AbstractGearbox<ATGearboxState>, IHybridControlledGearbox, IAPTGearbox { protected internal readonly IShiftStrategy _strategy; - protected internal readonly TorqueConverter TorqueConverter; + private IIdleController _idleController; internal WattSecond _powershiftLossEnergy; - protected internal KilogramSquareMeter EngineInertia; public bool TorqueConverterLocked => CurrentState.Gear.TorqueConverterLocked.Value; //set { CurrentState.TorqueConverterLocked = value; } public override bool TCLocked => Gear.TorqueConverterLocked.Value; + ITorqueConverter IAPTGearbox.TorqueConverter + { + get => TorqueConverter; + } + public TorqueConverter TorqueConverter + { + get; + private set; + } + + // public WattSecond ComputeShiftLosses(NewtonMeter outTorque, PerSecond outAngularVelocity, GearshiftPosition nextGearPos) + // { + // return base.ComputeShiftLosses(outTorque, outAngularVelocity, nextGearPos); + // } + + public KilogramSquareMeter EngineInertia + { + get; + private set; + } + public APTGearbox(IVehicleContainer container, IShiftStrategy strategy) : this(container, strategy, false) { @@ -195,8 +215,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl.Gearbox } - - internal ResponseDryRun Initialize(GearshiftPosition gear, NewtonMeter outTorque, + public ResponseDryRun Initialize(GearshiftPosition gear, NewtonMeter outTorque, PerSecond outAngularVelocity) { var effectiveRatio = gear.TorqueConverterLocked.Value @@ -608,7 +627,9 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl.Gearbox public ATGearboxState GetPreviousState => PreviousState.Clone(); - #endregion + + + #endregion } public class ATGearboxState : GearboxState diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/Shiftstrategies/AMTShiftStrategy.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/Shiftstrategies/AMTShiftStrategy.cs index e87e0803c359626d2c5833970fe23a4c4fe08f8b..29cd502e7e3bb813b7dc819f94df7f9ad6aaf36c 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/Shiftstrategies/AMTShiftStrategy.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/Shiftstrategies/AMTShiftStrategy.cs @@ -56,7 +56,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies protected ITestPowertrain TestPowertrain; - protected AMTGearbox _gearbox; + protected IAMTGearbox _gearbox; public AMTShiftStrategy(IVehicleContainer container) : base(container) { @@ -90,7 +90,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies public override IGearbox Gearbox { get => _gearbox; set { - if (value is AMTGearbox gbx) { + if (value is IAMTGearbox gbx) { _gearbox = gbx; return; } @@ -376,10 +376,22 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies protected virtual ResponseDryRun RequestDryRunWithGear( Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, GearshiftPosition tryNextGear) { - var tmpGear = Gearbox.Gear; - _gearbox.Gear = tryNextGear; - var response = (ResponseDryRun)_gearbox.Request(absTime, dt, outTorque, outAngularVelocity, true); - _gearbox.Gear = tmpGear; + // var tmpGear = Gearbox.Gear; + // _gearbox.Gear = tryNextGear; + // var response = (ResponseDryRun)_gearbox.Request(absTime, dt, outTorque, outAngularVelocity, true); + // _gearbox.Gear = tmpGear; + + + + LogEnabled = false; + TestPowertrain.UpdateComponents(); + TestPowertrain.Gearbox.SetDisengaged = false; + TestPowertrain.Gearbox.SetGear = tryNextGear; + + TestPowertrain.Container.GearboxOutPort.Initialize(outTorque, outAngularVelocity); + var response = (ResponseDryRun)TestPowertrain.Container.GearboxOutPort.Request( + 0.SI<Second>(), dt, outTorque, outAngularVelocity, true); + LogEnabled = true; return response; } } diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/Shiftstrategies/ATShiftStrategyOptimized.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/Shiftstrategies/ATShiftStrategyOptimized.cs index 1c28784d5ccaaba488bca0e83292a9679d3077ec..d46b0c35eeabfd28419b1806fe5743b825ee966d 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/Shiftstrategies/ATShiftStrategyOptimized.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/Shiftstrategies/ATShiftStrategyOptimized.cs @@ -38,7 +38,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies protected List<SchmittTrigger> LoadStageSteps = new List<SchmittTrigger>(); protected ShiftLineSet UpshiftLineTCLocked = new ShiftLineSet(); - protected APTGearbox _gearbox; + protected IAPTGearbox _gearbox; public ATShiftStrategyOptimized(IVehicleContainer container) : base(container) { @@ -68,7 +68,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies public override IGearbox Gearbox { get => _gearbox; set { - if (value is APTGearbox gbx) { + if (value is IAPTGearbox gbx) { _gearbox = gbx; return; } @@ -151,7 +151,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies } foreach (var gear in Gears.Reverse()) { - var response = _gearbox.Initialize(gear, torque, outAngularVelocity); + var response = RequestDryRunWithGear(absTime, dt, torque, outAngularVelocity, gear); + //var response = _gearbox.Initialize(gear, torque, outAngularVelocity); if (response.Engine.EngineSpeed > Container.EngineInfo.EngineRatedSpeed || response.Engine.EngineSpeed < Container.EngineInfo.EngineIdleSpeed) { continue; @@ -648,15 +649,23 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies if (shiftTimeReached && Container.DriverInfo.DrivingAction == DrivingAction.Accelerate) { if (Container.VehicleInfo.VehicleSpeed < Container.DrivingCycleInfo.CycleData.LeftSample.VehicleTargetSpeed - 10.KMPHtoMeterPerSecond() && Container.DriverInfo.DriverAcceleration < 0.SI<MeterPerSquareSecond>()) { - var tmpResponseCurr = (ResponseDryRun)_gearbox.Request(absTime, dt, outTorque, outAngularVelocity, true); + var currentGear = gear; + var tmpResponseCurr = RequestDryRunWithGear(absTime, dt, outTorque, outAngularVelocity, gear); + + // var tmpResponseCurr = (ResponseDryRun)_gearbox.Request(absTime, dt, outTorque, outAngularVelocity, true); if (_gearbox.Gear > Gears.First()) { + // var tmpGear = + // clone current state of _nextgear, set gearbox state to lower gear, issue request, restore old gearbox state - var tmp = _nextGear.Clone(); - var gbxState = new NextGearState(absTime, _gearbox); - tmp.Gear = Gears.Predecessor(_gearbox.Gear); - SetGear(tmp); - var tmpResponseDs = (ResponseDryRun)_gearbox.Request(absTime, dt, outTorque, outAngularVelocity, true); - SetGear(gbxState); + // var tmp = _nextGear.Clone(); + // var gbxState = new NextGearState(absTime, _gearbox); + // tmp.Gear = Gears.Predecessor(_gearbox.Gear); + // SetGear(tmp); + // var tmpResponseDs = (ResponseDryRun)_gearbox.Request(absTime, dt, outTorque, outAngularVelocity, true); + // SetGear(gbxState); + var tmpGear = Gears.Predecessor(currentGear); + var tmpResponseDs = RequestDryRunWithGear(absTime, dt, outTorque, outAngularVelocity, tmpGear); + // done if (tmpResponseDs.Engine.EngineSpeed.IsSmaller(Container.EngineInfo.EngineN95hSpeed) && tmpResponseDs.DeltaFullLoad - Formulas.InertiaPower( tmpResponseDs.Engine.EngineSpeed, Container.EngineInfo.EngineSpeed, EngineInertia, dt) < tmpResponseCurr.DeltaFullLoad) { @@ -773,12 +782,12 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies _nextGear.SetState(absTime, false, Gears.Predecessor(gear)); } - protected virtual void SetGear(NextGearState gbxState) - { - _gearbox.Gear = gbxState.Gear; - //_gearbox.TorqueConverterLocked = gbxState.TorqueConverterLocked; - _gearbox.Disengaged = gbxState.Disengaged; - } + // protected virtual void SetGear(NextGearState gbxState) + // { + // _gearbox.Gear = gbxState.Gear; + // //_gearbox.TorqueConverterLocked = gbxState.TorqueConverterLocked; + // _gearbox.Disengaged = gbxState.Disengaged; + // } private double GetFCRating(PerSecond engineSpeed, NewtonMeter tqCurrent) { @@ -899,10 +908,10 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies Gear = nextGearState.Gear; } - public NextGearState(Second absTime, APTGearbox gearbox) - { - SetState(absTime, gearbox); - } + // public NextGearState(Second absTime, IAPTGearbox gearbox) + // { + // SetState(absTime, gearbox); + // } public void SetState(Second absTime, bool disengaged, GearshiftPosition gear) { @@ -911,17 +920,17 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies Gear = gear; } - public void SetState(Second absTime, APTGearbox gearbox) - { - AbsTime = absTime; - Disengaged = gearbox.Disengaged; - Gear = gearbox.Gear; - } - - public NextGearState Clone() - { - return new NextGearState(this); - } + // public void SetState(Second absTime, IAPTGearbox gearbox) + // { + // AbsTime = absTime; + // Disengaged = gearbox.Disengaged; + // Gear = gearbox.Gear; + // } + // + // public NextGearState Clone() + // { + // return new NextGearState(this); + // } } } } diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/Shiftstrategies/MTShiftStrategy.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/Shiftstrategies/MTShiftStrategy.cs index c013c4943c2486835dfa9ddc79d48f7f17e71f15..90c57a49da2159e2009d670f6bb0e3364fb48b06 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/Shiftstrategies/MTShiftStrategy.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/Shiftstrategies/MTShiftStrategy.cs @@ -53,10 +53,12 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies protected GearshiftPosition DesiredGearRoadsweeping; - protected MTGearbox _gearbox; + protected IMTGearbox _gearbox; public MTShiftStrategy(IVehicleContainer container) : base(container) { + // create testcontainer + TestPowertrain = PowertrainBuilder.CreateTestPowertrain(Container, false); PreprocessorSpeed = ConfigureSpeedPreprocessor(container); container.AddPreprocessor(PreprocessorSpeed); @@ -81,8 +83,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies } } - // create testcontainer - TestPowertrain = PowertrainBuilder.CreateTestPowertrain(Container, false); + DesiredGearRoadsweeping = RunData.DriverData?.PTODriveRoadsweepingGear; } @@ -90,7 +91,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies public override IGearbox Gearbox { get => _gearbox; set { - if (value is MTGearbox gbx) { + if (value is IMTGearbox gbx) { _gearbox = gbx; return; } @@ -200,10 +201,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies while (currentGear.Gear < GearboxModelData.Gears.Count) { currentGear = Gears.Successor(currentGear); - var tmpGear = Gearbox.Gear; - _gearbox.Gear = currentGear; - var response = (ResponseDryRun)_gearbox.Request(absTime, dt, outTorque, outAngularVelocity, true); - _gearbox.Gear = tmpGear; + var response = RequestDryRunWithGear(absTime, dt, outTorque, outAngularVelocity, currentGear); inAngularVelocity = response.Engine.EngineSpeed; //ModelData.Gears[currentGear].Ratio * outAngularVelocity; inTorque = response.Clutch.PowerRequest / inAngularVelocity; @@ -226,6 +224,22 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies return currentGear; } + private ResponseDryRun RequestDryRunWithGear(Second absTime, Second dt, NewtonMeter outTorque, + PerSecond outAngularVelocity, GearshiftPosition currentGear) + { + TestPowertrain.UpdateComponents(); + var testGearbox = TestPowertrain.Gearbox; + var tmpGear = testGearbox.Gear; + + + testGearbox.SetGear = currentGear; + + var response = (ResponseDryRun)testGearbox.Request(absTime, dt, outTorque, outAngularVelocity, true); + + testGearbox.SetGear = tmpGear; + return response; + } + protected virtual GearshiftPosition DoCheckDownshift(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, NewtonMeter inTorque, PerSecond inAngularVelocity, GearshiftPosition currentGear, IResponse response1) { @@ -243,10 +257,11 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies currentGear = Gears.Predecessor(currentGear); while (currentGear.Gear > 1) { currentGear = Gears.Predecessor(currentGear); - var tmpGear = Gearbox.Gear; - _gearbox.Gear = currentGear; - var response = (ResponseDryRun)_gearbox.Request(absTime, dt, outTorque, outAngularVelocity, true); - _gearbox.Gear = tmpGear; + var response = RequestDryRunWithGear(absTime, dt, outTorque, outAngularVelocity, currentGear); + // var tmpGear = Gearbox.Gear; + // _gearbox.Gear = currentGear; + // var response = (ResponseDryRun)_gearbox.Request(absTime, dt, outTorque, outAngularVelocity, true); + // _gearbox.Gear = tmpGear; inAngularVelocity = GearboxModelData.Gears[currentGear.Gear].Ratio * outAngularVelocity; inTorque = response.Clutch.PowerRequest / inAngularVelocity; diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/Shiftstrategies/PEVAMTShiftStrategy.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/Shiftstrategies/PEVAMTShiftStrategy.cs index 50bf9fb32df0ed971f0e671f50899f85304da67c..54578edcb7b8fd9122d3e39285f65a13bf3c10a7 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/Shiftstrategies/PEVAMTShiftStrategy.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/Shiftstrategies/PEVAMTShiftStrategy.cs @@ -208,27 +208,34 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies GearshiftPosition currentGear, IResponse r) { var nextGear = currentGear; + var derated = r.ElectricMotor.DeRatingActive; // upshift - if (IsAboveUpShiftCurve(currentGear, inTorque, inAngularVelocity, r.ElectricMotor.DeRatingActive)) { + if (IsAboveUpShiftCurve(currentGear, inTorque, inAngularVelocity, derated)) { + + inTorque = null; + inAngularVelocity = null; + r = null; + nextGear = GearList.Successor(currentGear); - while (GearList.HasSuccessor(nextGear)) { // check skip gears nextGear = GearList.Successor(nextGear); - var response = RequestDryRunWithGear(absTime, dt, outTorque, outAngularVelocity, nextGear); - - inAngularVelocity = response.ElectricMotor.AngularVelocity; - inTorque = response.ElectricMotor.PowerRequest / inAngularVelocity; + var nextResponse = RequestDryRunWithGear(absTime, dt, outTorque, outAngularVelocity, nextGear); - var maxTorque = VectoMath.Min(-response.ElectricMotor.MaxDriveTorque, + var nextInAngularVelocity = nextResponse.Gearbox.InputSpeed; + var nextInTorque = nextResponse.Gearbox.InputTorque; + + var maxTorque = VectoMath.Min( + -nextResponse.ElectricMotor.MaxDriveTorque, //ADC considered !nextGear.Equals(GearList.First()) - ? GearboxModelData.Gears[nextGear.Gear].ShiftPolygon - .InterpolateDownshift(response.Engine.EngineSpeed) - : double.MaxValue.SI<NewtonMeter>()); - var reserve = 1 - inTorque / maxTorque; + ? GearboxModelData.Gears[nextGear.Gear].ShiftPolygon.InterpolateDownshift(nextInAngularVelocity) + : double.MaxValue.SI<NewtonMeter>() + ); + + var reserve = 1 - nextInTorque / maxTorque; if (reserve >= 0 /*ModelData.TorqueReserve */ && - IsAboveDownShiftCurve(nextGear, inTorque, inAngularVelocity, r.ElectricMotor.DeRatingActive)) { + IsAboveDownShiftCurve(nextGear, nextInTorque, nextInAngularVelocity, derated)) { continue; } @@ -249,7 +256,10 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies ) { return currentGear; } - + if (_shiftStrategyParameters.AllowedGearRangeFC == 0) { + return currentGear; + } + var vDrop = DataBus.VehicleInfo.VehicleSpeed - estimatedVelocityPostShift; var vehicleSpeedPostShift = DataBus.VehicleInfo.VehicleSpeed - vDrop * _shiftStrategyParameters.VelocityDropFactor; @@ -319,19 +329,17 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies if (!GearList.HasPredecessor(currentGear)) { return currentGear; } - - if (response.ElectricMotor.DeRatingActive) { - - } + var derated = response.ElectricMotor.DeRatingActive; // check with shiftline - if (response.ElectricMotor.TorqueRequestEmMap != null && IsBelowDownShiftCurve(currentGear, - response.ElectricMotor.TorqueRequestEmMap, - response.ElectricMotor.AngularVelocity, response.ElectricMotor.DeRatingActive)) { - - if (DataBus.DriverInfo.DriverBehavior == DrivingBehavior.Braking) { - var brakingGear = SelectBrakingGear(currentGear, response); - return brakingGear; - } + if (IsBelowDownShiftCurve(currentGear, inTorque, inAngularVelocity, derated)) { + inTorque = null; + inAngularVelocity = null; + + + if (DataBus.DriverInfo.DriverBehavior == DrivingBehavior.Braking) { + var brakingGear = SelectBrakingGear(currentGear, response); + return brakingGear; + } var nextGear = GearList.Predecessor(currentGear); if (SpeedTooHighForEngine(nextGear, outAngularVelocity)) { @@ -341,25 +349,33 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies while (GearList.HasPredecessor(nextGear)) { // check skip gears nextGear = GearList.Predecessor(nextGear); - var resp = RequestDryRunWithGear(absTime, dt, outTorque, outAngularVelocity, nextGear); + var nextReponse = RequestDryRunWithGear(absTime, dt, outTorque, outAngularVelocity, nextGear); - inAngularVelocity = resp.ElectricMotor.AngularVelocity; - inTorque = resp.ElectricMotor.PowerRequest / resp.ElectricMotor.AvgDrivetrainSpeed; - - if (IsAboveUpShiftCurve(nextGear, inTorque, inAngularVelocity, resp.ElectricMotor.DeRatingActive)) { + var nextInAngularVelocity = nextReponse.Gearbox.InputSpeed; + var nextInTorque = nextReponse.Gearbox.InputTorque; + + if (IsAboveUpShiftCurve(nextGear, nextInTorque, nextInAngularVelocity, derated)) { nextGear = GearList.Successor(nextGear); break; } - - var maxTorque = VectoMath.Min(resp.ElectricMotor.MaxDriveTorque == null ? null : - resp.ElectricMotor.MaxDriveTorque, - !nextGear.Equals(GearList.First()) - ? GearboxModelData.Gears[nextGear.Gear].ShiftPolygon - .InterpolateDownshift(resp.Engine.EngineSpeed) - : double.MaxValue.SI<NewtonMeter>()); - var reserve = 1 - inTorque / maxTorque; + + var maxDriveTorque = nextReponse.ElectricMotor.MaxDriveTorque; //Already on drivetrain side + + var isFirstGear = nextGear.Equals(GearList.First()); + + var maxTorque = VectoMath.Min( + (maxDriveTorque == null + ? null + : -maxDriveTorque + ), + (!isFirstGear + ? GearboxModelData.Gears[nextGear.Gear].ShiftPolygon.InterpolateDownshift(nextInAngularVelocity) + : double.MaxValue.SI<NewtonMeter>() + )); + var reserve = 1 - nextInTorque / maxTorque; if (reserve >= 0 /*ModelData.TorqueReserve */ && - IsBelowDownShiftCurve(nextGear, inTorque, inAngularVelocity, resp.ElectricMotor.DeRatingActive)) { + IsBelowDownShiftCurve(nextGear, nextInTorque, nextInAngularVelocity, derated)) { continue; } @@ -370,7 +386,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies return nextGear; } - + //Should not matter if calculated on gbx or em side. if (response.ElectricMotor.TorqueRequestEmMap != null && response.ElectricMotor.MaxRecuperationTorqueEM != null && response.ElectricMotor.TorqueRequestEmMap.IsEqual( @@ -385,14 +401,20 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies } private GearshiftPosition SelectBrakingGear(GearshiftPosition currentGear, IResponse response) - { + { var tmpGear = new GearshiftPosition(currentGear.Gear, currentGear.TorqueConverterLocked); var candidates = new Dictionary<GearshiftPosition, PerSecond>(); - var gbxOutSpeed = response.Engine.EngineSpeed / + + var gbxOutSpeed = response.Gearbox.InputSpeed / GearboxModelData.Gears[tmpGear.Gear].Ratio; + + var firstGear = GearList.Predecessor(currentGear, 1); var lastGear = GearList.Predecessor(currentGear, (uint)GearshiftParams.AllowedGearRangeFC); - var maxEmSpeed = DataBus.GetElectricMotors().First(x => x.Position != PowertrainPosition.GEN).MaxSpeed; + + var electricMotor = DataBus.GetElectricMotors().First(x => x.Position != PowertrainPosition.GEN); + var maxEmSpeedDt = electricMotor.MaxSpeedDt; //Drivetrain + foreach (var gear in GearList.IterateGears(firstGear, lastGear)) { var ratio = gear.IsLockedGear() ? GearboxModelData.Gears[gear.Gear].Ratio @@ -402,7 +424,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies continue; } - if (gbxInSpeed.IsGreater(maxEmSpeed)) { + if (gbxInSpeed.IsGreater(maxEmSpeedDt)) { continue; } candidates[gear] = gbxInSpeed; @@ -412,18 +434,20 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies return tmpGear; } - var ratedSpeed = VoltageLevels.VoltageLevels.First().FullLoadCurve.RatedSpeed; - var maxSpeedNorm = VoltageLevels.MaxSpeed / ratedSpeed; + + + var ratedSpeed = electricMotor.RatedSpeedDt; + var maxSpeedNorm = maxEmSpeedDt / ratedSpeed; var targetMotor = (_shiftStrategyParameters.PEV_TargetSpeedBrakeNorm * (maxSpeedNorm - 1) + 1) * ratedSpeed; - if (candidates.Any(x => x.Value > targetMotor / EMRatio && x.Value < VoltageLevels.MaxSpeed / EMRatio)) { - var best = candidates.Where(x => x.Value > targetMotor / EMRatio && x.Value < VoltageLevels.MaxSpeed / EMRatio) + if (candidates.Any(x => x.Value > targetMotor && x.Value < maxEmSpeedDt)) { + var best = candidates.Where(x => x.Value > targetMotor && x.Value < maxEmSpeedDt) .OrderBy(x => x.Value).First(); return best.Key; } - if (candidates.Any(x => x.Value < VoltageLevels.MaxSpeed / EMRatio)) - return candidates.Where(x => x.Value < VoltageLevels.MaxSpeed / EMRatio).MaxBy(x => x.Value).Key; + if (candidates.Any(x => x.Value < maxEmSpeedDt)) + return candidates.Where(x => x.Value < maxEmSpeedDt).MaxBy(x => x.Value).Key; else { return candidates.MaxBy(x => x.Value).Key; } @@ -439,14 +463,21 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies return currentGear; } + if (_shiftStrategyParameters.AllowedGearRangeFC == 0) { + return currentGear; + } + var results = new List<Tuple<GearshiftPosition, double>>(); foreach (var tryNextGear in GearList.IterateGears(GearList.Predecessor(currentGear), GearList.Predecessor(currentGear, (uint)_shiftStrategyParameters.AllowedGearRangeFC))) { var response = RequestDryRunWithGear(absTime, dt, outTorque, outAngularVelocity, tryNextGear); - var inAngularVelocity = GearboxModelData.Gears[tryNextGear.Gear].Ratio * outAngularVelocity; - var inTorque = response.ElectricMotor.PowerRequest / inAngularVelocity; + // var inAngularVelocity = GearboxModelData.Gears[tryNextGear.Gear].Ratio * outAngularVelocity; + // var inTorque = response.ElectricMotor.PowerRequest / inAngularVelocity; + var inAngularVelocity = response.Gearbox.InputSpeed; + var inTorque = response.Gearbox.InputTorque; + if (IsAboveUpShiftCurve(tryNextGear, inTorque, inAngularVelocity, response.ElectricMotor.DeRatingActive)) { continue; } @@ -541,9 +572,12 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies Constants.SimulationSettings.MeasuredSpeedTargetTimeInterval, outTorque, outAngularVelocity, true); - var inAngularSpeed = outAngularVelocity * GearboxModelData.Gears[gear.Gear].Ratio; - var inTorque = response.ElectricMotor.PowerRequest / inAngularSpeed; + // var inAngularSpeed = outAngularVelocity * GearboxModelData.Gears[gear.Gear].Ratio; + // var inTorque = response.Gearbox.PowerRequest / inAngularSpeed; + var inAngularSpeed = response.Gearbox.InputSpeed; + var inTorque = response.Gearbox.InputTorque; + // if in shift curve and torque reserve is provided: return the current gear if (!IsBelowDownShiftCurve(gear, inTorque, inAngularSpeed, false) && !IsAboveUpShiftCurve(gear, inTorque, inAngularSpeed, false)) { _nextGear = gear; @@ -700,7 +734,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies { return (outAngularSpeed * GearboxModelData.Gears[gear.Gear].Ratio).IsGreaterOrEqual(VectoMath.Min(GearboxModelData.Gears[gear.Gear].MaxSpeed, - DataBus.ElectricMotorInfo(EMPos).MaxSpeed)); + DataBus.ElectricMotorInfo(EMPos).MaxSpeedDt)); } public void Disengage(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity) { } diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/Shiftstrategies/ShiftPolygonCalc/PEVAMTShiftStrategyPolygonCreator.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/Shiftstrategies/ShiftPolygonCalc/PEVAMTShiftStrategyPolygonCreator.cs index e71334c2967d130814ca86ae55f1275fc52eee06..f5827b054938440dde38f308884777caeda24a7f 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/Shiftstrategies/ShiftPolygonCalc/PEVAMTShiftStrategyPolygonCreator.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/Shiftstrategies/ShiftPolygonCalc/PEVAMTShiftStrategyPolygonCreator.cs @@ -35,21 +35,26 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies.Shift throw new NotImplementedException("Not applicable to PEVAMT Gearbox."); } - public ShiftPolygon ComputeDeclarationShiftPolygon(GearboxType gearboxType, int i, EngineFullLoadCurve engineDataFullLoadCurve, - IList<ITransmissionInputData> gearboxGears, CombustionEngineData engineData, double axlegearRatio, Meter dynamicTyreRadius, - ElectricMotorData electricMotorData = null) - { - if (electricMotorData == null) { - throw new VectoException("ElectricMotorData is required to calculate Shift Polygon!"); - } - var emFld = electricMotorData.EfficiencyData.VoltageLevels.First().FullLoadCurve; + public ShiftPolygon ComputeDeclarationShiftPolygon(GearboxType gearboxType, int i, EngineFullLoadCurve engineDataFullLoadCurve, + IList<ITransmissionInputData> gearboxGears, CombustionEngineData engineData, double axlegearRatio, Meter dynamicTyreRadius, + ElectricMotorData electricMotorData = null) + { + if (electricMotorData == null) + { + throw new VectoException("ElectricMotorData is required to calculate Shift Polygon!"); + } + var emFld = electricMotorData.EfficiencyData.VoltageLevels.First().FullLoadCurve; + return ComputeDeclarationShiftPolygon(i, gearboxGears, axlegearRatio, dynamicTyreRadius, electricMotorData, + _shiftStrategyParameters.PEV_DownshiftSpeedFactor.LimitTo(0, 1), _shiftStrategyParameters.PEV_DownshiftMinSpeedFactor); + } + + public ShiftPolygon ComputeDeclarationShiftPolygon(int i, + IList<ITransmissionInputData> gearboxGears, double axlegearRatio, + Meter dynamicTyreRadius, + ElectricMotorData electricMotorData, double? downshiftMaxSpeed, double? downshiftMinSpeed) + { return DeclarationData.Gearbox.ComputeElectricMotorShiftPolygon(i, - electricMotorData.EfficiencyData.VoltageLevels.First().FullLoadCurve, - electricMotorData.RatioADC, gearboxGears, axlegearRatio, dynamicTyreRadius, - _shiftStrategyParameters.PEV_DownshiftSpeedFactor.LimitTo(0, 1) * emFld.RatedSpeed, - _shiftStrategyParameters.PEV_DownshiftMinSpeedFactor * emFld.RatedSpeed); - //return ComputeElectricMotorDeclarationShiftPolygon(gearboxType, i, gearboxGears, axlegearRatio, dynamicTyreRadius, electricMotorData, - // _shiftStrategyParameters.PEV_DownshiftSpeedFactor.LimitTo(0, 1) * emFld.RatedSpeed, _shiftStrategyParameters.PEV_DownshiftMinSpeedFactor * emFld.RatedSpeed); + electricMotorData, gearboxGears, downshiftMaxSpeed, downshiftMinSpeed); } @@ -57,13 +62,22 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl.Shiftstrategies.Shift IList<ITransmissionInputData> gearboxGears, double axlegearRatio, Meter dynamicTyreRadius, ElectricMotorData electricMotorData, ElectricMotorData emDataLimited) - { - var emFld = electricMotorData.EfficiencyData.VoltageLevels.First().FullLoadCurve; - return DeclarationData.Gearbox.ComputeElectricMotorShiftPolygon(i, - emDataLimited.EfficiencyData.VoltageLevels.First().FullLoadCurve, electricMotorData.RatioADC, - gearboxGears, axlegearRatio, dynamicTyreRadius, - _shiftStrategyParameters.PEV_DeRatedDownshiftSpeedFactor * emFld.RatedSpeed, - _shiftStrategyParameters.PEV_DownshiftMinSpeedFactor * emFld.RatedSpeed); - } + { + if (!electricMotorData.EfficiencyData.MaxSpeed.IsEqual(emDataLimited.EfficiencyData.MaxSpeed)) { + throw new VectoException("Limited em data should have the same max speed as the original data"); + } + return DeclarationData.Gearbox.ComputeElectricMotorShiftPolygon( + i, + emDataLimited, + gearboxGears, + _shiftStrategyParameters.PEV_DeRatedDownshiftSpeedFactor.LimitTo(0, 1), + _shiftStrategyParameters.PEV_DownshiftMinSpeedFactor); + + // return DeclarationData.Gearbox.ComputeElectricMotorShiftPolygon(i, + // emDataLimited.EfficiencyData.VoltageLevels.First().FullLoadCurve, electricMotorData.RatioADC, + // gearboxGears, axlegearRatio, dynamicTyreRadius, + // _shiftStrategyParameters.PEV_DeRatedDownshiftSpeedFactor, + // _shiftStrategyParameters.PEV_DownshiftMinSpeedFactor); + } } } \ No newline at end of file diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/TorqueConverter.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/TorqueConverter.cs index c085ed588e1e8b85f46ed82a8dcb544bd1b663d5..49834ecee4a73f911a6f6303eda2a2f6f46fd807 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/TorqueConverter.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/TorqueConverter.cs @@ -426,7 +426,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl return retVal; } - protected internal TorqueConverterOperatingPoint FindOperatingPoint(Second absTime, Second dt, + public TorqueConverterOperatingPoint FindOperatingPoint(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity) { diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/Vehicle.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/Vehicle.cs index 70ef9e90254a13de9e89b0d1a08ec821d1fdbe34..c98e1fc2f8eb59acc468fab3e875295b93147568 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/Vehicle.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/Vehicle.cs @@ -129,7 +129,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl var pos = positions.First(); if (pos.IsBatteryElectric()) { - var maxEMSpeed = DataBus.ElectricMotorInfo(pos).MaxSpeed; + var maxEMSpeed = DataBus.ElectricMotorInfo(pos).MaxSpeedDt; var ratio = 1.0; if (pos == PowertrainPosition.BatteryElectricE3) { @@ -142,7 +142,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl (DataBus.AngledriveInfo?.Ratio ?? 1.0); maxEMSpeed = VectoMath.Min( - DataBus.ElectricMotorInfo(pos).MaxSpeed, + DataBus.ElectricMotorInfo(pos).MaxSpeedDt, DataBus.GearboxInfo.GetGearData(DataBus.GearboxInfo.NumGears).MaxSpeed); } MaxVehicleSpeed = maxEMSpeed / ratio * DataBus.WheelsInfo.DynamicTyreRadius * 0.995;