diff --git a/VectoCore/Models/Declaration/DeclarationData.cs b/VectoCore/Models/Declaration/DeclarationData.cs index a10817d271505ae7a5d2e273b19226cf23002496..c959f802ee1fbe8434d367d9697acaa512a1bb22 100644 --- a/VectoCore/Models/Declaration/DeclarationData.cs +++ b/VectoCore/Models/Declaration/DeclarationData.cs @@ -130,7 +130,7 @@ namespace TUGraz.VectoCore.Models.Declaration { public const bool Enabled = true; - public static MeterPerSquareSecond Deceleration = -0.5.SI<MeterPerSquareSecond>(); + public static readonly MeterPerSquareSecond Deceleration = -0.5.SI<MeterPerSquareSecond>(); public static readonly MeterPerSecond MinimumSpeed = 50.KMPHtoMeterPerSecond(); } diff --git a/VectoCore/Models/SimulationComponent/Impl/Driver.cs b/VectoCore/Models/SimulationComponent/Impl/Driver.cs index d10b55cbf0dfeca6746d3820ef552ab5919d5166..a7e77c55899ffb1ad92acedfbc601ee7a58085eb 100644 --- a/VectoCore/Models/SimulationComponent/Impl/Driver.cs +++ b/VectoCore/Models/SimulationComponent/Impl/Driver.cs @@ -132,13 +132,14 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl // unhandled response (overload, delta > 0) - we need to search for a valid operating point.. operatingPoint = SearchOperatingPoint(absTime, ds, gradient, operatingPoint.Acceleration, response); - operatingPoint = LimitAccelerationByDriverModel(operatingPoint, false); + operatingPoint = LimitAccelerationByDriverModel(operatingPoint, LimitationMode.LimitDecelerationDriver); Log.Debug("Found operating point for Drive/Accelerate. dt: {0}, acceleration: {1}", CurrentState.dt, CurrentState.Acceleration); retVal = NextComponent.Request(absTime, operatingPoint.SimulationInterval, operatingPoint.Acceleration, gradient); retVal.Switch(). Case<ResponseUnderload>(). + Case<ResponseGearShift>(). Case<ResponseSuccess>(). Default(r => { throw new UnexpectedResponseException("DrivingAction Accelerate after SearchOperatingPoint.", r); @@ -163,7 +164,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl { Log.Debug("DrivingAction Coast"); - return CoastOrRollAction(absTime, ds, maxVelocity, gradient); + return CoastOrRollAction(absTime, ds, maxVelocity, gradient, false); } /// <summary> @@ -178,7 +179,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl { Log.Debug("DrivingAction Roll"); - var retVal = CoastOrRollAction(absTime, ds, maxVelocity, gradient); + var retVal = CoastOrRollAction(absTime, ds, maxVelocity, gradient, true); retVal.Switch(). Case<ResponseGearShift>(() => { throw new UnexpectedResponseException("DrivingAction Roll: Gearshift during Roll action.", retVal); @@ -193,6 +194,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl /// <param name="ds"></param> /// <param name="maxVelocity"></param> /// <param name="gradient"></param> + /// <param name="rollAction"></param> /// <returns> /// * ResponseSuccess /// * ResponseDrivingCycleDistanceExceeded: vehicle is at low speed, coasting would lead to stop before ds is reached. @@ -201,7 +203,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl /// * ResponseGearShift: gearbox needs to shift gears, vehicle can not accelerate (traction interruption) /// * ResponseFailTimeInterval: /// </returns> - protected IResponse CoastOrRollAction(Second absTime, Meter ds, MeterPerSecond maxVelocity, Radian gradient) + protected IResponse CoastOrRollAction(Second absTime, Meter ds, MeterPerSecond maxVelocity, Radian gradient, + bool rollAction) { var operatingPoint = ComputeAcceleration(ds, DataBus.VehicleSpeed); @@ -228,7 +231,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl Log.Debug("Found operating point for coasting. dt: {0}, acceleration: {1}", operatingPoint.SimulationInterval, operatingPoint.Acceleration); - operatingPoint = LimitAccelerationByDriverModel(operatingPoint, true); + operatingPoint = LimitAccelerationByDriverModel(operatingPoint, + rollAction ? LimitationMode.NoLimitation : LimitationMode.LimitDecelerationLookahead); CurrentState.Acceleration = operatingPoint.Acceleration; CurrentState.dt = operatingPoint.SimulationInterval; @@ -245,7 +249,9 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl retVal.Switch(). Case<ResponseSuccess>(). - Case<ResponseUnderload>(). // driver limits acceleration, operating point may be below engine's drag load + Case<ResponseUnderload>(). // driver limits acceleration, operating point may be below engine's + //drag load resp. below 0 + //Case<ResponseOverload>(). // driver limits acceleration, operating point may be above 0 (GBX), use brakes Case<ResponseGearShift>(). Case<ResponseFailTimeInterval>(r => { retVal = new ResponseDrivingCycleDistanceExceeded() { @@ -340,19 +346,33 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl /// /// </summary> /// <param name="operatingPoint"></param> - /// <param name="limitByLookahead"></param> + /// <param name="limits"></param> /// <returns></returns> - private OperatingPoint LimitAccelerationByDriverModel(OperatingPoint operatingPoint, bool limitByLookahead) + private OperatingPoint LimitAccelerationByDriverModel(OperatingPoint operatingPoint, + LimitationMode limits) { - // todo: limit by driver model! - - if (limitByLookahead && operatingPoint.Acceleration < DeclarationData.Driver.LookAhead.Deceleration) { - Log.Debug("Limiting coasting deceleration from {0} to {1}", CurrentState.Acceleration, - DeclarationData.Driver.LookAhead.Deceleration); - operatingPoint.Acceleration = DeclarationData.Driver.LookAhead.Deceleration; + var limitApplied = false; + var originalAcceleration = operatingPoint.Acceleration; + if (((limits & LimitationMode.LimitDecelerationLookahead) != 0) && + operatingPoint.Acceleration < LookaheadDeceleration) { + operatingPoint.Acceleration = LookaheadDeceleration; + limitApplied = true; + } + var accelerationLimits = DriverData.AccelerationCurve.Lookup(DataBus.VehicleSpeed); + if (operatingPoint.Acceleration > accelerationLimits.Acceleration) { + operatingPoint.Acceleration = accelerationLimits.Acceleration; + limitApplied = true; + } + if (((limits & LimitationMode.LimitDecelerationDriver) != 0) && + operatingPoint.Acceleration < accelerationLimits.Deceleration) { + operatingPoint.Acceleration = accelerationLimits.Deceleration; + limitApplied = true; + } + if (limitApplied) { operatingPoint.SimulationInterval = ComputeTimeInterval(operatingPoint.Acceleration, operatingPoint.SimulationDistance).SimulationInterval; - Log.Debug("Changed dt due to limited coasting deceleration. dt: {0}", CurrentState.dt); + Log.Debug("Limiting acceleration from {0} to {1}, dt: {2}", originalAcceleration, + operatingPoint.Acceleration, operatingPoint.SimulationInterval); } return operatingPoint; } @@ -492,18 +512,22 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl searchInterval *= intervalFactor; retVal.Acceleration += searchInterval * -delta.Sign(); - if (retVal.Acceleration < (DriverData.AccelerationCurve.MaxDeceleration() - searchInterval) + if (retVal.Acceleration < (10 * DriverData.AccelerationCurve.MaxDeceleration() - searchInterval) || retVal.Acceleration > (DriverData.AccelerationCurve.MaxAcceleration() + searchInterval)) { + LogManager.EnableLogging(); + Log.Warn("Operating Point outside driver acceleration limits: a: {0}", retVal.Acceleration); + LogManager.DisableLogging(); throw new VectoSimulationException( - "Could not find an operating point: operating point outside of driver acceleration limits."); + "Could not find an operating point: operating point outside of driver acceleration limits. a: {0}", + retVal.Acceleration); } // TODO: move to driving mode // check for minimum acceleration, add some safety margin due to search - if (!coasting && retVal.Acceleration.Abs() < Constants.SimulationSettings.MinimumAcceleration / 5.0 - && searchInterval.Abs() < Constants.SimulationSettings.MinimumAcceleration / 20.0) { - throw new VectoSimulationException("Could not achieve minimum acceleration"); - } + //if (!coasting && retVal.Acceleration.Abs() < Constants.SimulationSettings.MinimumAcceleration / 5.0 + // && searchInterval.Abs() < Constants.SimulationSettings.MinimumAcceleration / 20.0) { + // throw new VectoSimulationException("Could not achieve minimum acceleration"); + //} var tmp = ComputeTimeInterval(retVal.Acceleration, ds); retVal.SimulationInterval = tmp.SimulationInterval; @@ -701,5 +725,14 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl public Meter SimulationDistance; public Second SimulationInterval; } + + [Flags] + protected enum LimitationMode + { + NoLimitation = 0x0, + //LimitAccelerationDriver = 0x1, + LimitDecelerationDriver = 0x2, + LimitDecelerationLookahead = 0x4 + } } } \ No newline at end of file diff --git a/VectoCore/Models/SimulationComponent/Impl/Retarder.cs b/VectoCore/Models/SimulationComponent/Impl/Retarder.cs index 232fb6aba42577f0959080fb05f4518ba9ee7ff7..c071013fa36a67d864b65a6bf07de08f04273a0a 100644 --- a/VectoCore/Models/SimulationComponent/Impl/Retarder.cs +++ b/VectoCore/Models/SimulationComponent/Impl/Retarder.cs @@ -45,6 +45,9 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl public IResponse Request(Second absTime, Second dt, NewtonMeter torque, PerSecond angularVelocity, bool dryRun = false) { + if (angularVelocity == null) { + return NextComponent.Request(absTime, dt, torque, null, dryRun); + } var retarderTorqueLoss = _lossMap.RetarderLoss(angularVelocity); _retarderLoss = retarderTorqueLoss * angularVelocity; diff --git a/VectoCoreTest/Integration/DriverStrategy/DriverStrategyTest.cs b/VectoCoreTest/Integration/DriverStrategy/DriverStrategyTest.cs index 54af18636ffc8254d52c66ec0e7bd2e67ffcfa9a..e8d421fd290dda68b42b691886ea0eb82341393b 100644 --- a/VectoCoreTest/Integration/DriverStrategy/DriverStrategyTest.cs +++ b/VectoCoreTest/Integration/DriverStrategy/DriverStrategyTest.cs @@ -119,6 +119,30 @@ namespace TUGraz.VectoCore.Tests.Integration.DriverStrategy CreatePowerTrain(cycle, "DriverStrategy_Accelerate_0_85_level.vmod").Run(); } + [TestMethod] + public void Accelerate_0_85_uphill_1() + { + var cycle = CreateCycleData(new[] { + // <s>,<v>,<grad>,<stop> + " 0, 0, 0, 2", + " 0, 85, 1, 0", + "1000, 85, 1, 0", + }); + CreatePowerTrain(cycle, "DriverStrategy_Accelerate_0_85_uphill_1.vmod").Run(); + } + + [TestMethod] + public void Accelerate_0_85_uphill_2() + { + var cycle = CreateCycleData(new[] { + // <s>,<v>,<grad>,<stop> + " 0, 0, 0, 2", + " 0, 85, 2, 0", + "1000, 85, 2, 0", + }); + CreatePowerTrain(cycle, "DriverStrategy_Accelerate_0_85_uphill_2.vmod").Run(); + } + [TestMethod] public void Accelerate_0_85_uphill_5() { @@ -173,8 +197,8 @@ namespace TUGraz.VectoCore.Tests.Integration.DriverStrategy var cycle = CreateCycleData(new[] { // <s>,<v>,<grad>,<stop> " 0, 0, 0, 2", - " 0, 85, 15, 0", - "1000, 85, 15, 0", + " 0, 85, 10, 0", + "1000, 85, 10, 0", }); CreatePowerTrain(cycle, "DriverStrategy_Accelerate_0_85_uphill_15.vmod").Run(); } @@ -585,7 +609,7 @@ namespace TUGraz.VectoCore.Tests.Integration.DriverStrategy tmp = Port.AddComponent(tmp, new Clutch(container, engineData)); var aux = new Auxiliary(container); - aux.AddConstant("", 500.SI<Watt>()); + aux.AddConstant("", 0.SI<Watt>()); tmp = Port.AddComponent(tmp, aux); diff --git a/VectoCoreTest/Models/SimulationComponent/CombustionEngineTest.cs b/VectoCoreTest/Models/SimulationComponent/CombustionEngineTest.cs index cddadc43176ce1753b6de252d1b399e2f883095f..e86498f5ae26889c9e2c970ee29cd66f768dbf6a 100644 --- a/VectoCoreTest/Models/SimulationComponent/CombustionEngineTest.cs +++ b/VectoCoreTest/Models/SimulationComponent/CombustionEngineTest.cs @@ -1,10 +1,14 @@ using System; using System.Collections.Generic; +using System.Data; using System.IO; +using System.Linq; using System.Reflection; using Microsoft.VisualStudio.TestTools.UnitTesting; +using TUGraz.VectoCore.Configuration; using TUGraz.VectoCore.Exceptions; using TUGraz.VectoCore.FileIO.Reader.Impl; +using TUGraz.VectoCore.Models.Connector.Ports.Impl; using TUGraz.VectoCore.Models.Simulation.Data; using TUGraz.VectoCore.Models.Simulation.Impl; using TUGraz.VectoCore.Models.SimulationComponent.Data; @@ -194,6 +198,71 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponent modalData.Finish(); } + [TestMethod] + public void EngineIdleJump() + { + var vehicleContainer = new VehicleContainer(); + var gearbox = new MockGearbox(vehicleContainer); + var engineData = EngineeringModeSimulationDataReader.CreateEngineDataFromFile(CoachEngine); + var engine = new CombustionEngine(vehicleContainer, engineData); + + var clutch = new Clutch(vehicleContainer, engineData); + + var aux = new Auxiliary(vehicleContainer); + aux.AddConstant("", 5000.SI<Watt>()); + + gearbox.Gear = 1; + + //gearbox.InPort().Connect(engine.OutPort()); + gearbox.InPort().Connect(clutch.OutPort()); + clutch.InPort().Connect(aux.OutPort()); + aux.InPort().Connect(engine.OutPort()); + +// var expectedResults = VectoCSVFile.Read(TestContext.DataRow["ResultFile"].ToString()); + + var requestPort = gearbox.OutPort(); + + //vehicleContainer.DataWriter = new ModalDataWriter("engine_idle_test.csv"); + var dataWriter = new MockModalDataWriter(); + vehicleContainer.DataWriter = dataWriter; + + var torque = 1200.SI<NewtonMeter>(); + var angularVelocity = 800.RPMtoRad(); + + // initialize engine... + + gearbox.Initialize(torque, angularVelocity); + + var absTime = 0.SI<Second>(); + var dt = Constants.SimulationSettings.TargetTimeInterval; + + var response = requestPort.Request(absTime, dt, torque, angularVelocity); + + Assert.IsInstanceOfType(response, typeof(ResponseSuccess)); + vehicleContainer.CommitSimulationStep(absTime, dt); + var row = dataWriter.Data.Rows.Cast<DataRow>().Last(); + Assert.AreEqual(105530.96491487339.SI<Watt>(), row[ModalResultField.Pe_eng.GetName()]); + Assert.AreEqual(5000.SI<Watt>(), row[ModalResultField.Paux.GetName()]); + Assert.AreEqual(800.RPMtoRad(), row[ModalResultField.n.GetName()]); + + absTime += dt; + + // actual test... + + gearbox.Gear = 0; + torque = 0.SI<NewtonMeter>(); + + response = gearbox.Request(absTime, dt, torque, angularVelocity); + + Assert.IsInstanceOfType(response, typeof(ResponseSuccess)); + vehicleContainer.CommitSimulationStep(absTime, dt); + row = dataWriter.Data.Rows.Cast<DataRow>().Last(); + + Assert.AreEqual(5000.SI<Watt>(), row[ModalResultField.Pe_eng.GetName()]); + Assert.AreEqual(5000.SI<Watt>(), row[ModalResultField.Paux.GetName()]); + Assert.AreEqual(800.RPMtoRad(), row[ModalResultField.n.GetName()]); + } + [TestMethod, Ignore] public void TestWriteToFile() diff --git a/VectoCoreTest/Models/SimulationComponent/DriverTest.cs b/VectoCoreTest/Models/SimulationComponent/DriverTest.cs index 9e295dfacb071071257c2cfe5f3cb0446d6955c6..3880b436eaabfddd5b178257b836c40955ec271e 100644 --- a/VectoCoreTest/Models/SimulationComponent/DriverTest.cs +++ b/VectoCoreTest/Models/SimulationComponent/DriverTest.cs @@ -53,8 +53,7 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponent tmp = AddComponent(tmp, new Clutch(vehicleContainer, engineData)); AddComponent(tmp, engine); - var gbx = new MockGearbox(vehicleContainer); - gbx.Gear = 1; + var gbx = new MockGearbox(vehicleContainer) { Gear = 1 }; var driverPort = driver.OutPort(); diff --git a/VectoCoreTest/Utils/MockGearbox.cs b/VectoCoreTest/Utils/MockGearbox.cs index a6959cdb825f05fcd7f604c2837d618ed81023c3..aa9b7c6b3158f9b0721408d2e06fd9e996863fd3 100644 --- a/VectoCoreTest/Utils/MockGearbox.cs +++ b/VectoCoreTest/Utils/MockGearbox.cs @@ -2,12 +2,13 @@ using TUGraz.VectoCore.Models.Connector.Ports; 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.Utils; namespace TUGraz.VectoCore.Tests.Utils { - public class MockGearbox : VectoSimulationComponent, IGearbox, ITnInPort, ITnOutPort + public class MockGearbox : VectoSimulationComponent, IGearbox, ITnInPort, ITnOutPort, IClutchInfo { private ITnOutPort _outPort; @@ -33,11 +34,20 @@ namespace TUGraz.VectoCore.Tests.Utils public IResponse Request(Second absTime, Second dt, NewtonMeter torque, PerSecond engineSpeed, bool dryRun = false) { + if (_outPort != null) { + if (Gear > 0) { + return _outPort.Request(absTime, dt, torque, engineSpeed, dryRun); + } + return _outPort.Request(absTime, dt, 0.SI<NewtonMeter>(), null, dryRun); + } throw new NotImplementedException(); } public IResponse Initialize(NewtonMeter torque, PerSecond angularVelocity) { + if (_outPort != null) { + return _outPort.Initialize(torque, angularVelocity); + } throw new NotImplementedException(); } @@ -48,5 +58,10 @@ namespace TUGraz.VectoCore.Tests.Utils } protected override void DoCommitSimulationStep() {} + + public bool ClutchClosed(Second absTime) + { + return true; + } } } \ No newline at end of file