diff --git a/VectoCore/Models/SimulationComponent/Data/Engine/FullLoadCurve.cs b/VectoCore/Models/SimulationComponent/Data/Engine/FullLoadCurve.cs index be3f694374fca11bc0dd33ce8f64581212b90252..6f5e4a7e23fa6073373ff0c47c30eff820b9cbf0 100644 --- a/VectoCore/Models/SimulationComponent/Data/Engine/FullLoadCurve.cs +++ b/VectoCore/Models/SimulationComponent/Data/Engine/FullLoadCurve.cs @@ -277,13 +277,13 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine } // non-constant torque, M(n) = k * n + d - // area = M(n1) * n + (M(n1) + M(n2))/2 => solve for n + // area = M(n1) * (n2 - n1) + (M(n1) + M(n2))/2 * (n2 - n1) => solve for n2 var retVal = VectoMath.QuadraticEquationSolver(k.Value() / 2.0, d.Value(), (k * p1.EngineSpeed * p1.EngineSpeed + 2 * p1.EngineSpeed * d).Value()); if (retVal.Count == 0) { Log.InfoFormat("No real solution found for requested area: P: {0}, p1: {1}, p2: {2}", area, p1, p2); } - return retVal.First(x => x >= p1.EngineSpeed && x <= p2.EngineSpeed); + return retVal.First(x => x >= p1.EngineSpeed.Value() && x <= p2.EngineSpeed.Value()).SI<PerSecond>(); } /// <summary> @@ -331,7 +331,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine } else { // non-constant torque, solve quadratic equation for engine speed (n) // power = M(n) * n = (k * n + d) * n = k * n^2 + d * n - retVal = VectoMath.QuadraticEquationSolver(k.Value(), d.Value(), -power.Value()); + retVal = VectoMath.QuadraticEquationSolver(k.Value(), d.Value(), -power.Value()).SI<PerSecond>().ToList(); if (retVal.Count == 0) { Log.InfoFormat("No real solution found for requested power demand: P: {0}, p1: {1}, p2: {2}", power, p1, p2); } diff --git a/VectoCore/Models/SimulationComponent/Impl/Driver.cs b/VectoCore/Models/SimulationComponent/Impl/Driver.cs index f8d224a4d643938fc3aaebf8013cb80d8dcd068b..a1a392853edd601057afac4dfc54a487c9a516ea 100644 --- a/VectoCore/Models/SimulationComponent/Impl/Driver.cs +++ b/VectoCore/Models/SimulationComponent/Impl/Driver.cs @@ -1,6 +1,9 @@ using System; +using System.CodeDom; +using System.Linq; using TUGraz.VectoCore.Exceptions; using TUGraz.VectoCore.Models.Connector.Ports; +using TUGraz.VectoCore.Models.Connector.Ports.Impl; using TUGraz.VectoCore.Models.Simulation.Data; using TUGraz.VectoCore.Models.Simulation.Impl; using TUGraz.VectoCore.Models.SimulationComponent; @@ -56,14 +59,41 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl protected IResponse DoHandleRequest(TimeSpan absTime, Meter ds, MeterPerSecond targetVelocity, Radian gradient) { - return null; + var currentSpeed = Cockpit.VehicleSpeed(); + + var requiredAverageSpeed = (targetVelocity + currentSpeed) / 2.0; + var requiredAcceleration = + (((targetVelocity - currentSpeed) * requiredAverageSpeed) / ds).Cast<MeterPerSquareSecond>(); + var maxAcceleration = DriverData.AccelerationCurve.Lookup(currentSpeed); + + if (requiredAcceleration > maxAcceleration.Acceleration) { + requiredAcceleration = maxAcceleration.Acceleration; + } + if (requiredAcceleration < maxAcceleration.Deceleration) { + requiredAcceleration = maxAcceleration.Deceleration; + } + + var solutions = VectoMath.QuadraticEquationSolver(requiredAcceleration.Value() / 2.0, currentSpeed.Value(), + -ds.Value()); + solutions = solutions.Where(x => x >= 0).ToList(); + + if (solutions.Count == 0) { + Log.WarnFormat( + "Could not find solution for computing required time interval to drive distance {0}. currentSpeed: {1}, targetSpeed: {2}, acceleration: {3}", + ds, currentSpeed, targetVelocity, requiredAcceleration); + return new ResponseFailTimeInterval(); + } + var dt = TimeSpan.FromSeconds(solutions.First()); + var retVal = Next.Request(absTime, dt, requiredAcceleration, gradient); + retVal.SimulationInterval = dt; + return retVal; } protected IResponse DoHandleRequest(TimeSpan absTime, TimeSpan dt, MeterPerSecond targetVelocity, Radian gradient) { if (!targetVelocity.IsEqual(0) || !Cockpit.VehicleSpeed().IsEqual(0)) { - throw new VectoException("TargetVelocity or VehicleVelocity is not zero!"); + throw new NotImplementedException("TargetVelocity or VehicleVelocity is not zero!"); } return Next.Request(absTime, dt, 0.SI<MeterPerSquareSecond>(), gradient); } diff --git a/VectoCoreTest/Models/SimulationComponent/DriverTest.cs b/VectoCoreTest/Models/SimulationComponent/DriverTest.cs index de1dafd650f5bce89e7fad761c2a4970f2b535dc..882212f1fbcd5df6898dfd30aef17f6d318f4e75 100644 --- a/VectoCoreTest/Models/SimulationComponent/DriverTest.cs +++ b/VectoCoreTest/Models/SimulationComponent/DriverTest.cs @@ -1,18 +1,85 @@ using System; using Microsoft.VisualStudio.TestTools.UnitTesting; +using TUGraz.VectoCore.FileIO.Reader.Impl; +using TUGraz.VectoCore.Models.Connector.Ports.Impl; using TUGraz.VectoCore.Models.Simulation.Impl; +using TUGraz.VectoCore.Models.SimulationComponent.Impl; +using TUGraz.VectoCore.Tests.Utils; +using TUGraz.VectoCore.Utils; namespace TUGraz.VectoCore.Tests.Models.SimulationComponent { [TestClass] public class DriverTest { + public const string JobFile = @"TestData\Jobs\24t Coach.vecto"; + + public const double Tolerance = 0.001; [TestMethod] public void DriverRequestTest() { - var vehicleContainer = new VehicleContainer(); + var vehicle = new MockVehicle(vehicleContainer); + + var driverData = EngineeringModeSimulationDataReader.CreateDriverDataFromFile(JobFile); + var driver = new Driver(vehicleContainer, driverData); + + driver.Connect(vehicle.OutPort()); + + vehicle.MyVehicleSpeed = 0.SI<MeterPerSecond>(); + var absTime = TimeSpan.FromSeconds(0); + var ds = 1.SI<Meter>(); + var gradient = 0.SI<Radian>(); + + var targetVelocity = 5.SI<MeterPerSecond>(); + +// var response = driver.OutPort().Request(absTime, ds, targetVelocity, gradient); + + var accelerations = new[] { + 1.01570922, 1.384540943, 1.364944972, 1.350793466, 1.331848649, 1.314995215, 1.2999934, + 1.281996392, 1.255462262 + }; + var simulationIntervals = new[] + { 1.403234648, 0.553054094, 0.405255346, 0.33653593, 0.294559444, 0.26555781, 0.243971311, 0.22711761, 0.213554656 }; + + + // accelerate from 0 to just below the target velocity and test derived simulation intervals & accelerations + for (var i = 0; i < accelerations.Length; i++) { + var tmpResponse = driver.OutPort().Request(absTime, ds, targetVelocity, gradient); + + Assert.IsInstanceOfType(tmpResponse, typeof(ResponseSuccess)); + Assert.AreEqual(Math.Round(accelerations[i], 4), vehicle.LastRequest.acceleration.Value(), Tolerance); + Assert.AreEqual(Math.Round(simulationIntervals[i], 4), tmpResponse.SimulationInterval.TotalSeconds, Tolerance); + + vehicleContainer.CommitSimulationStep(absTime.TotalSeconds, tmpResponse.SimulationInterval.TotalSeconds); + absTime += tmpResponse.SimulationInterval; + vehicle.MyVehicleSpeed += + (tmpResponse.SimulationInterval.TotalSeconds.SI<Second>() * vehicle.LastRequest.acceleration).Cast<MeterPerSecond>(); + } + + // full acceleration would exceed target velocity, driver should limit acceleration such that target velocity is reached... + var response = driver.OutPort().Request(absTime, ds, targetVelocity, gradient); + + Assert.IsInstanceOfType(response, typeof(ResponseSuccess)); + Assert.AreEqual(0.8923 /*0.899715479*/, vehicle.LastRequest.acceleration.Value(), Tolerance); + Assert.AreEqual(0.203734517, response.SimulationInterval.TotalSeconds, Tolerance); + + vehicleContainer.CommitSimulationStep(absTime.TotalSeconds, response.SimulationInterval.TotalSeconds); + absTime += response.SimulationInterval; + vehicle.MyVehicleSpeed += + (response.SimulationInterval.TotalSeconds.SI<Second>() * vehicle.LastRequest.acceleration).Cast<MeterPerSecond>(); + + Assert.AreEqual(targetVelocity.Value(), vehicle.MyVehicleSpeed.Value(), Tolerance); + + + // vehicle has reached target velocity, no further acceleration necessary... + + response = driver.OutPort().Request(absTime, ds, targetVelocity, gradient); + + Assert.IsInstanceOfType(response, typeof(ResponseSuccess)); + Assert.AreEqual(0, vehicle.LastRequest.acceleration.Value(), Tolerance); + Assert.AreEqual(0.2, response.SimulationInterval.TotalSeconds, Tolerance); } } } \ No newline at end of file diff --git a/VectoCoreTest/Utils/MockVehicle.cs b/VectoCoreTest/Utils/MockVehicle.cs new file mode 100644 index 0000000000000000000000000000000000000000..c0c5c6f6cf7f57a8578e785a02e24d9622ce39de --- /dev/null +++ b/VectoCoreTest/Utils/MockVehicle.cs @@ -0,0 +1,77 @@ +using System; +using TUGraz.VectoCore.Models.Connector.Ports; +using TUGraz.VectoCore.Models.Connector.Ports.Impl; +using TUGraz.VectoCore.Models.Simulation; +using TUGraz.VectoCore.Models.Simulation.Data; +using TUGraz.VectoCore.Models.SimulationComponent; +using TUGraz.VectoCore.Utils; + +namespace TUGraz.VectoCore.Tests.Utils +{ + public class MockVehicle : VectoSimulationComponent, IVehicle, IFvInPort, IDriverDemandOutPort + { + internal MeterPerSecond MyVehicleSpeed; + internal IFvOutPort NextComponent; + + internal RequestData LastRequest = new RequestData(); + + public MockVehicle(IVehicleContainer cockpit) : base(cockpit) {} + protected override void DoWriteModalResults(IModalDataWriter writer) {} + + protected override void DoCommitSimulationStep() {} + + public IFvInPort InPort() + { + return this; + } + + public IDriverDemandOutPort OutPort() + { + return this; + } + + public MeterPerSecond VehicleSpeed() + { + return MyVehicleSpeed; + } + + public Kilogram VehicleMass() + { + return 7500.SI<Kilogram>(); + } + + public Kilogram VehicleLoading() + { + return 0.SI<Kilogram>(); + } + + public Kilogram TotalMass() + { + return VehicleMass(); + } + + public void Connect(IFvOutPort other) + { + NextComponent = other; + } + + public IResponse Request(TimeSpan absTime, TimeSpan dt, MeterPerSquareSecond acceleration, Radian gradient) + { + LastRequest = new RequestData() { + abstime = absTime, + dt = dt, + acceleration = acceleration, + gradient = gradient + }; + return new ResponseSuccess(); + } + + public class RequestData + { + public TimeSpan abstime; + public TimeSpan dt; + public MeterPerSquareSecond acceleration; + public Radian gradient; + } + } +} \ No newline at end of file diff --git a/VectoCoreTest/VectoCoreTest.csproj b/VectoCoreTest/VectoCoreTest.csproj index e6b8bfb80f7c1805cdc9f1b8b99f3bd1c8510b4e..87c2195928c7744b51e7fe7286c48f77d0c96e92 100644 --- a/VectoCoreTest/VectoCoreTest.csproj +++ b/VectoCoreTest/VectoCoreTest.csproj @@ -89,6 +89,7 @@ <Compile Include="Models\Simulation\DrivingCycleTests.cs" /> <Compile Include="Utils\AssertHelper.cs" /> <Compile Include="Utils\MockDriver.cs" /> + <Compile Include="Utils\MockVehicle.cs" /> <Compile Include="Utils\ResultFileHelper.cs" /> <Compile Include="Utils\MockPorts.cs" /> <Compile Include="Models\Simulation\SimulationTests.cs" />