diff --git a/VectoCore/Models/Connector/Ports/IDriverDemandPort.cs b/VectoCore/Models/Connector/Ports/IDriverDemandPort.cs index 9aceb90bcf4dc674abe4f4f807a20153e88dd2b3..700937f2a72d9f0d1dd74eec8637e5cbfce972bc 100644 --- a/VectoCore/Models/Connector/Ports/IDriverDemandPort.cs +++ b/VectoCore/Models/Connector/Ports/IDriverDemandPort.cs @@ -57,5 +57,6 @@ namespace TUGraz.VectoCore.Models.Connector.Ports IResponse Request(Second absTime, Second dt, MeterPerSquareSecond acceleration, Radian gradient, bool dryRun = false); IResponse Initialize(MeterPerSecond vehicleSpeed, Radian roadGradient); + IResponse Initialize(MeterPerSecond vehicleSpeed, MeterPerSquareSecond startAcceleration, Radian roadGradient); } } \ No newline at end of file diff --git a/VectoCore/Models/Connector/Ports/IDrivingCyclePort.cs b/VectoCore/Models/Connector/Ports/IDrivingCyclePort.cs index b4f21bedd3467ac754ae00dd68e44a4926c681b3..e3b3520adbd16ca94a1fe43c95df628e974fb0f2 100644 --- a/VectoCore/Models/Connector/Ports/IDrivingCyclePort.cs +++ b/VectoCore/Models/Connector/Ports/IDrivingCyclePort.cs @@ -67,5 +67,8 @@ namespace TUGraz.VectoCore.Models.Connector.Ports IResponse Request(Second absTime, Second dt, MeterPerSecond targetVelocity, Radian gradient); IResponse Initialize(MeterPerSecond vehicleSpeed, Radian roadGradient); + + + IResponse Initialize(MeterPerSecond vehicleSpeed, MeterPerSquareSecond startAcceleration, Radian roadGradient); } } \ No newline at end of file diff --git a/VectoCore/Models/Simulation/DataBus/IEngineInfo.cs b/VectoCore/Models/Simulation/DataBus/IEngineInfo.cs index 6d68eac685e07dfb1b1613bb308eb543d16ae65c..dce3be2c1a9b5005541a2b050ebc23ae6c5e608c 100644 --- a/VectoCore/Models/Simulation/DataBus/IEngineInfo.cs +++ b/VectoCore/Models/Simulation/DataBus/IEngineInfo.cs @@ -11,5 +11,9 @@ namespace TUGraz.VectoCore.Models.Simulation.DataBus /// [rad/s] The current engine speed. /// </summary> PerSecond EngineSpeed { get; } + + Watt EngineStationaryFullPower(PerSecond angularSpeed); + + PerSecond EngineIdleSpeed { get; } } } \ No newline at end of file diff --git a/VectoCore/Models/Simulation/DataBus/IGearboxInfo.cs b/VectoCore/Models/Simulation/DataBus/IGearboxInfo.cs index 47aab9812ef3e85981e3dabe32013db317c42013..2ee60dd78788294eb48618f875cf694e4d56d1d7 100644 --- a/VectoCore/Models/Simulation/DataBus/IGearboxInfo.cs +++ b/VectoCore/Models/Simulation/DataBus/IGearboxInfo.cs @@ -1,4 +1,6 @@ -namespace TUGraz.VectoCore.Models.Simulation.DataBus +using TUGraz.VectoCore.Utils; + +namespace TUGraz.VectoCore.Models.Simulation.DataBus { /// <summary> /// Defines a method to access shared data of the gearbox. @@ -10,5 +12,10 @@ /// </summary> /// <returns></returns> uint Gear { get; } + + + MeterPerSecond StartSpeed { get; } + + MeterPerSquareSecond StartAcceleration { get; } } } \ No newline at end of file diff --git a/VectoCore/Models/Simulation/Impl/VehicleContainer.cs b/VectoCore/Models/Simulation/Impl/VehicleContainer.cs index 8b2384cd94fd8e06767feaa9297990c32e9cfc9e..f32ea44cd22fc8cb6683534971a1db2ddff836ee 100644 --- a/VectoCore/Models/Simulation/Impl/VehicleContainer.cs +++ b/VectoCore/Models/Simulation/Impl/VehicleContainer.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Diagnostics; using TUGraz.VectoCore.Exceptions; using TUGraz.VectoCore.Models.Connector.Ports; using TUGraz.VectoCore.Models.Simulation.Data; @@ -42,6 +43,18 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl } } + [DebuggerHidden] + public MeterPerSecond StartSpeed + { + get { return Gearbox.StartSpeed; } + } + + [DebuggerHidden] + public MeterPerSquareSecond StartAcceleration + { + get { return Gearbox.StartAcceleration; } + } + #endregion #region IEngineCockpit @@ -57,6 +70,16 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl } } + public Watt EngineStationaryFullPower(PerSecond angularSpeed) + { + return Engine.EngineStationaryFullPower(angularSpeed); + } + + public PerSecond EngineIdleSpeed + { + get { return Engine.EngineIdleSpeed; } + } + #endregion #region IVehicleCockpit diff --git a/VectoCore/Models/SimulationComponent/Data/Engine/EngineFullLoadCurve.cs b/VectoCore/Models/SimulationComponent/Data/Engine/EngineFullLoadCurve.cs index eddb404fdade890e8f38352563f911d1d8a51d92..f0b5d7e1c0f27f5691f3d422c9cbe07e912b38e3 100644 --- a/VectoCore/Models/SimulationComponent/Data/Engine/EngineFullLoadCurve.cs +++ b/VectoCore/Models/SimulationComponent/Data/Engine/EngineFullLoadCurve.cs @@ -11,9 +11,6 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine /// </summary> public class EngineFullLoadCurve : FullLoadCurve { - private Watt _maxPower; - - private PerSecond _ratedSpeed; private PerSecond _preferredSpeed; private PerSecond _engineSpeedLo; // 55% of Pmax private PerSecond _engineSpeedHi; // 70% of Pmax @@ -48,31 +45,6 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine } - /// <summary> - /// Get the engine's rated speed from the given full-load curve (i.e. engine speed with max. power) - /// </summary> - public PerSecond RatedSpeed - { - get - { - if (_ratedSpeed == null) { - ComputeRatedSpeed(); - } - return _ratedSpeed; - } - } - - public Watt MaxPower - { - get - { - if (_maxPower == null) { - ComputeRatedSpeed(); - } - return _maxPower; - } - } - /// <summary> /// Get the engine's preferred speed from the given full-load curve (i.e. Speed at 51% torque/speed-integral between idling and N95h.) /// </summary> @@ -114,23 +86,6 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine get { return FullLoadEntries.Min(x => x.TorqueDrag); } } - /// <summary> - /// Compute the engine's rated speed from the given full-load curve (i.e. engine speed with max. power) - /// </summary> - private void ComputeRatedSpeed() - { - var max = new Tuple<PerSecond, Watt>(0.SI<PerSecond>(), 0.SI<Watt>()); - for (var idx = 1; idx < FullLoadEntries.Count; idx++) { - var currentMax = FindMaxPower(FullLoadEntries[idx - 1], FullLoadEntries[idx]); - if (currentMax.Item2 > max.Item2) { - max = currentMax; - } - } - - _ratedSpeed = max.Item1; - _maxPower = max.Item2; - } - private void ComputePreferredSpeed() { @@ -229,36 +184,6 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine return area; } - private Tuple<PerSecond, Watt> FindMaxPower(FullLoadCurveEntry p1, FullLoadCurveEntry p2) - { - if (p1.EngineSpeed.IsEqual(p2.EngineSpeed)) { - return Tuple.Create(p1.EngineSpeed, p1.TorqueFullLoad * p1.EngineSpeed); - } - - if (p2.EngineSpeed < p1.EngineSpeed) { - var tmp = p1; - p1 = p2; - p2 = tmp; - } - - // y = kx + d - var k = (p2.TorqueFullLoad - p1.TorqueFullLoad) / (p2.EngineSpeed - p1.EngineSpeed); - var d = p2.TorqueFullLoad - k * p2.EngineSpeed; - if (k.IsEqual(0)) { - return Tuple.Create(p2.EngineSpeed, p2.TorqueFullLoad * p2.EngineSpeed); - } - var engineSpeedMaxPower = -d / (2 * k); - if (engineSpeedMaxPower.IsSmaller(p1.EngineSpeed) || engineSpeedMaxPower.IsGreater(p2.EngineSpeed)) { - if (k.IsGreater(0)) { - return Tuple.Create(p2.EngineSpeed, p2.TorqueFullLoad * p2.EngineSpeed); - } - return Tuple.Create(p1.EngineSpeed, p1.TorqueFullLoad * p1.EngineSpeed); - } - //return null; - var engineTorqueMaxPower = FullLoadStationaryTorque(engineSpeedMaxPower); - return Tuple.Create(engineSpeedMaxPower, engineTorqueMaxPower * engineSpeedMaxPower); - } - #region Equality members protected bool Equals(EngineFullLoadCurve other) diff --git a/VectoCore/Models/SimulationComponent/Data/FullLoadCurve.cs b/VectoCore/Models/SimulationComponent/Data/FullLoadCurve.cs index 93bcc671d2c4bc4ba5270045da2094067fe9569d..a5fc727b839759ca9a5d2be5d5e178851cb75883 100644 --- a/VectoCore/Models/SimulationComponent/Data/FullLoadCurve.cs +++ b/VectoCore/Models/SimulationComponent/Data/FullLoadCurve.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Data; using System.Diagnostics.Contracts; @@ -14,6 +15,9 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data internal List<FullLoadCurveEntry> FullLoadEntries; internal LookupData<PerSecond, Second> PT1Data; + protected PerSecond _ratedSpeed; + protected Watt _maxPower; + public static FullLoadCurve ReadFromFile(string fileName, bool declarationMode = false) { var data = VectoCSVFile.Read(fileName); @@ -85,6 +89,67 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data }).ToList(); } + /// <summary> + /// Get the rated speed from the given full-load curve (i.e. speed with max. power) + /// </summary> + public PerSecond RatedSpeed + { + get { return (_ratedSpeed ?? ComputeRatedSpeed().Item1); } + } + + public Watt MaxPower + { + get { return (_maxPower ?? ComputeRatedSpeed().Item2); } + } + + + /// <summary> + /// Compute the engine's rated speed from the given full-load curve (i.e. engine speed with max. power) + /// </summary> + protected Tuple<PerSecond, Watt> ComputeRatedSpeed() + { + var max = new Tuple<PerSecond, Watt>(0.SI<PerSecond>(), 0.SI<Watt>()); + for (var idx = 1; idx < FullLoadEntries.Count; idx++) { + var currentMax = FindMaxPower(FullLoadEntries[idx - 1], FullLoadEntries[idx]); + if (currentMax.Item2 > max.Item2) { + max = currentMax; + } + } + + _ratedSpeed = max.Item1; + _maxPower = max.Item2; + + return max; + } + + private Tuple<PerSecond, Watt> FindMaxPower(FullLoadCurveEntry p1, FullLoadCurveEntry p2) + { + if (p1.EngineSpeed.IsEqual(p2.EngineSpeed)) { + return Tuple.Create(p1.EngineSpeed, p1.TorqueFullLoad * p1.EngineSpeed); + } + + if (p2.EngineSpeed < p1.EngineSpeed) { + var tmp = p1; + p1 = p2; + p2 = tmp; + } + + // y = kx + d + var k = (p2.TorqueFullLoad - p1.TorqueFullLoad) / (p2.EngineSpeed - p1.EngineSpeed); + var d = p2.TorqueFullLoad - k * p2.EngineSpeed; + if (k.IsEqual(0)) { + return Tuple.Create(p2.EngineSpeed, p2.TorqueFullLoad * p2.EngineSpeed); + } + var engineSpeedMaxPower = -d / (2 * k); + if (engineSpeedMaxPower.IsSmaller(p1.EngineSpeed) || engineSpeedMaxPower.IsGreater(p2.EngineSpeed)) { + if (k.IsGreater(0)) { + return Tuple.Create(p2.EngineSpeed, p2.TorqueFullLoad * p2.EngineSpeed); + } + return Tuple.Create(p1.EngineSpeed, p1.TorqueFullLoad * p1.EngineSpeed); + } + var engineTorqueMaxPower = FullLoadStationaryTorque(engineSpeedMaxPower); + return Tuple.Create(engineSpeedMaxPower, engineTorqueMaxPower * engineSpeedMaxPower); + } public virtual NewtonMeter FullLoadStationaryTorque(PerSecond angularVelocity) { diff --git a/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs b/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs index 987226cbb16876dfca8ba2e6310b2147f8746b9c..7f42b08de9ce25f2372e0cd299bd1c098ad6cb33 100644 --- a/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs +++ b/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using TUGraz.VectoCore.Configuration; using TUGraz.VectoCore.Exceptions; using TUGraz.VectoCore.Models.Connector.Ports; @@ -53,8 +54,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl PreviousState.EngineSpeed = _data.IdleSpeed; PreviousState.dt = 1.SI<Second>(); - StationaryIdleFullLoadPower = Formulas.TorqueToPower(_data.FullLoadCurve.FullLoadStationaryTorque(_data.IdleSpeed), - _data.IdleSpeed); + StationaryIdleFullLoadPower = _data.FullLoadCurve.FullLoadStationaryTorque(_data.IdleSpeed) * _data.IdleSpeed; } #region IEngineCockpit @@ -64,6 +64,16 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl get { return PreviousState.EngineSpeed; } } + public Watt EngineStationaryFullPower(PerSecond angularSpeed) + { + return _data.FullLoadCurve.FullLoadStationaryTorque(angularSpeed) * angularSpeed; + } + + public PerSecond EngineIdleSpeed + { + get { return _data.IdleSpeed; } + } + #endregion #region ITnOutProvider @@ -162,7 +172,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl PreviousState.DynamicFullLoadPower = PreviousState.StationaryFullLoadPower; PreviousState.FullDragPower = Formulas.TorqueToPower(PreviousState.FullDragTorque, engineSpeed); - return new ResponseSuccess(); + return new ResponseSuccess { Source = this, EnginePowerRequest = PreviousState.EnginePower }; } #endregion diff --git a/VectoCore/Models/SimulationComponent/Impl/DistanceBasedDrivingCycle.cs b/VectoCore/Models/SimulationComponent/Impl/DistanceBasedDrivingCycle.cs index 8c08e42bdf766a13c8a3ff303cc1739fd769be08..bfa91261aeba1bc18db83932c8699d976eb6c9f1 100644 --- a/VectoCore/Models/SimulationComponent/Impl/DistanceBasedDrivingCycle.cs +++ b/VectoCore/Models/SimulationComponent/Impl/DistanceBasedDrivingCycle.cs @@ -187,7 +187,15 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl Altitude = first.Altitude, }; CurrentState = PreviousState.Clone(); - //return new ResponseSuccess(); + + if (CycleIntervalIterator.LeftSample.VehicleTargetSpeed.IsEqual(0)) { + var retVal = NextComponent.Initialize(DataBus.StartSpeed, DataBus.StartAcceleration, + CycleIntervalIterator.LeftSample.RoadGradient); + if (!(retVal is ResponseSuccess)) { + throw new UnexpectedResponseException("Couldn't find start gear.", retVal); + } + } + return NextComponent.Initialize(CycleIntervalIterator.LeftSample.VehicleTargetSpeed, CycleIntervalIterator.LeftSample.RoadGradient); } diff --git a/VectoCore/Models/SimulationComponent/Impl/Driver.cs b/VectoCore/Models/SimulationComponent/Impl/Driver.cs index e74ecdb28096e51fe49da06df47dcc4e4db6a7b7..0134f5c76b681c9458c5080a4d1341928ba39368 100644 --- a/VectoCore/Models/SimulationComponent/Impl/Driver.cs +++ b/VectoCore/Models/SimulationComponent/Impl/Driver.cs @@ -52,7 +52,6 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl public IResponse Initialize(MeterPerSecond vehicleSpeed, Radian roadGradient) { - //LookaheadDeceleration = DriverData.AccelerationCurve.MinDeceleration(); if (DriverData.LookAheadCoasting.Deceleration < DriverData.AccelerationCurve.MinDeceleration()) { Log.Warn( "LookAhead Coasting Deceleration is lower than Driver's min. Deceleration. Coasting may start too late. Lookahead dec.: {0}, Driver min. deceleration: {1}", @@ -61,6 +60,11 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl return NextComponent.Initialize(vehicleSpeed, roadGradient); } + public IResponse Initialize(MeterPerSecond vehicleSpeed, MeterPerSquareSecond startAcceleration, Radian roadGradient) + { + return NextComponent.Initialize(vehicleSpeed, startAcceleration, roadGradient); + } + public IResponse Request(Second absTime, Meter ds, MeterPerSecond targetVelocity, Radian gradient) { diff --git a/VectoCore/Models/SimulationComponent/Impl/EngineOnlyGearbox.cs b/VectoCore/Models/SimulationComponent/Impl/EngineOnlyGearbox.cs index 9a565c4e1704060da713f66cde98608acfd8ccd5..b4e542fb5056b61349fe2cb5525de049fbba9620 100644 --- a/VectoCore/Models/SimulationComponent/Impl/EngineOnlyGearbox.cs +++ b/VectoCore/Models/SimulationComponent/Impl/EngineOnlyGearbox.cs @@ -39,6 +39,16 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl //set { } } + public MeterPerSecond StartSpeed + { + get { throw new VectoSimulationException("Not Implemented: EngineOnlyGearbox has no StartSpeed value."); } + } + + public MeterPerSquareSecond StartAcceleration + { + get { throw new VectoSimulationException("Not Implemented: EngineOnlyGearbox has no StartAcceleration value."); } + } + #endregion #region ITnInPort diff --git a/VectoCore/Models/SimulationComponent/Impl/Gearbox.cs b/VectoCore/Models/SimulationComponent/Impl/Gearbox.cs index 36330009a794f80bba8673f91ddfdf72df3985c8..3290f4ea605f912bf17f81e578c5c1b52c0695a4 100644 --- a/VectoCore/Models/SimulationComponent/Impl/Gearbox.cs +++ b/VectoCore/Models/SimulationComponent/Impl/Gearbox.cs @@ -1,5 +1,6 @@ using System.Diagnostics; using TUGraz.VectoCore.Configuration; +using TUGraz.VectoCore.Exceptions; using TUGraz.VectoCore.Models.Connector.Ports; using TUGraz.VectoCore.Models.Connector.Ports.Impl; using TUGraz.VectoCore.Models.Simulation; @@ -30,7 +31,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl /// <summary> /// Time when a gearbox shift engages a new gear (shift is finished). Is set when shifting is needed. /// </summary> - private Second _shiftTime = double.NegativeInfinity.SI<Second>(); + private Second _shiftTime = 0.SI<Second>(); /// <summary> /// True if gearbox is disengaged (no gear is set). @@ -61,7 +62,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl { // TODO: do not set a default strategy! gearbox should be called with explicit shift strategy! this is just for debug if (strategy == null) { - strategy = new AMTShiftStrategy(gearboxData); + strategy = new AMTShiftStrategy(gearboxData, container); } Data = gearboxData; _strategy = strategy; @@ -94,36 +95,90 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl /// </summary> public uint Gear { get; set; } + [DebuggerHidden] + public MeterPerSecond StartSpeed + { + get { return Data.StartSpeed; } + } + + [DebuggerHidden] + public MeterPerSquareSecond StartAcceleration + { + get { return Data.StartAcceleration; } + } + #endregion #region ITnOutPort public IResponse Initialize(NewtonMeter outTorque, PerSecond outEngineSpeed) { - _shiftTime = double.NegativeInfinity.SI<Second>(); - _disengaged = true; - - // for initializing the engine: var absTime = 0.SI<Second>(); var dt = Constants.SimulationSettings.TargetTimeInterval; + _shiftTime = double.NegativeInfinity.SI<Second>(); - Gear = _strategy.InitGear(absTime, dt, outTorque, outEngineSpeed); + if (_disengaged) { + Gear = _strategy.InitGear(absTime, dt, outTorque, outEngineSpeed); + } var inEngineSpeed = outEngineSpeed * Data.Gears[Gear].Ratio; var inTorque = Data.Gears[Gear].LossMap.GearboxInTorque(inEngineSpeed, outTorque); _powerLoss = inTorque * inEngineSpeed - outTorque * outEngineSpeed; - var torqueLossInertia = !inEngineSpeed.IsEqual(0) - ? Formulas.InertiaPower(inEngineSpeed, _previousInEnginespeed, Data.Inertia, dt) / inEngineSpeed - : 0.SI<NewtonMeter>(); + var torqueLossInertia = inEngineSpeed.IsEqual(0) + ? 0.SI<NewtonMeter>() + : Formulas.InertiaPower(inEngineSpeed, _previousInEnginespeed, Data.Inertia, dt) / inEngineSpeed; - _previousInEnginespeed = inEngineSpeed; inTorque += torqueLossInertia; var response = NextComponent.Initialize(inTorque, inEngineSpeed); + if (response is ResponseSuccess) { + _previousInEnginespeed = inEngineSpeed; + _disengaged = false; + } return response; } + + internal ResponseDryRun Initialize(uint gear, NewtonMeter outTorque, PerSecond outEngineSpeed) + { + var inEngineSpeed = outEngineSpeed * Data.Gears[gear].Ratio; + var inTorque = Data.Gears[gear].LossMap.GearboxInTorque(inEngineSpeed, outTorque); + + _powerLoss = inTorque * inEngineSpeed - outTorque * outEngineSpeed; + + PerSquareSecond alpha; + if (Data.Inertia.IsEqual(0)) { + alpha = 0.SI<PerSquareSecond>(); + } else { + alpha = outTorque / Data.Inertia; + } + + var torqueLossInertia = inEngineSpeed.IsEqual(0) + ? 0.SI<NewtonMeter>() + : Formulas.InertiaPower(inEngineSpeed, alpha, Data.Inertia, Constants.SimulationSettings.TargetTimeInterval) / + inEngineSpeed; + + inTorque += torqueLossInertia; + var response = NextComponent.Initialize(inTorque, inEngineSpeed); + + response.Switch(). + Case<ResponseSuccess>(). + Case<ResponseOverload>(). + Case<ResponseUnderload>(). + Default(r => { + throw new UnexpectedResponseException("Gearbox.Initialize", r); + }); + + var fullLoadGearbox = Data.Gears[gear].FullLoadCurve.FullLoadStationaryTorque(inEngineSpeed) * inEngineSpeed; + var fullLoadEngine = DataBus.EngineStationaryFullPower(inEngineSpeed); + return new ResponseDryRun { + Source = this, + EnginePowerRequest = response.EnginePowerRequest, + DeltaFullLoad = response.EnginePowerRequest - VectoMath.Min(fullLoadGearbox, fullLoadEngine) + }; + } + /// <summary> /// Requests the Gearbox to deliver outTorque and outEngineSpeed /// </summary> diff --git a/VectoCore/Models/SimulationComponent/Impl/ShiftStrategy.cs b/VectoCore/Models/SimulationComponent/Impl/ShiftStrategy.cs index 6dc6e3669b2b6151240af6c74fdab874a4294218..7ae4f076bc1a35df70232a4236724ad8ea898735 100644 --- a/VectoCore/Models/SimulationComponent/Impl/ShiftStrategy.cs +++ b/VectoCore/Models/SimulationComponent/Impl/ShiftStrategy.cs @@ -1,5 +1,6 @@ using System; using TUGraz.VectoCore.Models.Connector.Ports.Impl; +using TUGraz.VectoCore.Models.Simulation.DataBus; using TUGraz.VectoCore.Models.SimulationComponent.Data; using TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox; using TUGraz.VectoCore.Utils; @@ -11,17 +12,21 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl public abstract class ShiftStrategy : IShiftStrategy { + protected IDataBus DataBus; + protected GearboxData Data; + public abstract uint Engage(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outEngineSpeed); public abstract void Disengage(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outEngineSpeed); public abstract bool ShiftRequired(uint gear, NewtonMeter torque, PerSecond angularSpeed); public abstract uint InitGear(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outEngineSpeed); - protected GearboxData Data; + public Gearbox Gearbox { get; set; } - protected ShiftStrategy(GearboxData data) + protected ShiftStrategy(GearboxData data, IDataBus dataBus) { + DataBus = dataBus; Data = data; } @@ -81,7 +86,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl /// </summary> protected uint PreviousGear; - public AMTShiftStrategy(GearboxData data) : base(data) + public AMTShiftStrategy(GearboxData data, IDataBus dataBus) : base(data, dataBus) { PreviousGear = 1; } @@ -130,14 +135,39 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl public override uint InitGear(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outEngineSpeed) { - return GetGear(absTime, dt, outTorque, outEngineSpeed, skipGears: true, torqueReserve: Data.StartTorqueReserve); + if (DataBus.VehicleSpeed.IsEqual(0)) { + for (var gear = (uint)Data.Gears.Count; gear > 1; gear--) { + var inAngularSpeed = outEngineSpeed * Data.Gears[gear].Ratio; + + if (inAngularSpeed > Data.Gears[gear].FullLoadCurve.RatedSpeed) { + continue; + } + + var response = Gearbox.Initialize(gear, outTorque, outEngineSpeed); + + var currentPower = response.EnginePowerRequest; + var inTorque = currentPower / inAngularSpeed; + + var fullLoadPower = currentPower - response.DeltaFullLoad; + var reserve = 1 - (currentPower / fullLoadPower).Cast<Scalar>(); + + if (!IsBelowDownShiftCurve(gear, inTorque, inAngularSpeed) && inAngularSpeed > DataBus.EngineIdleSpeed && + reserve >= Data.StartTorqueReserve / 100) { + return gear; + } + } + return 1; + } + + // todo else + return 1; } } //TODO Implementd MTShiftStrategy public class MTShiftStrategy : ShiftStrategy { - public MTShiftStrategy(GearboxData data) : base(data) {} + public MTShiftStrategy(GearboxData data, IDataBus bus) : base(data, bus) {} public override uint Engage(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outEngineSpeed) { @@ -163,7 +193,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl // TODO Implement ATShiftStrategy public class ATShiftStrategy : ShiftStrategy { - public ATShiftStrategy(GearboxData data) : base(data) {} + public ATShiftStrategy(GearboxData data, IDataBus bus) : base(data, bus) {} public override uint Engage(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outEngineSpeed) { diff --git a/VectoCore/Models/SimulationComponent/Impl/Vehicle.cs b/VectoCore/Models/SimulationComponent/Impl/Vehicle.cs index d14230ccdc7d0df24354c67fd1dbd7931c7154f1..8db5eeff4e39a49823ef9e5d5ca866c17f41a1f3 100644 --- a/VectoCore/Models/SimulationComponent/Impl/Vehicle.cs +++ b/VectoCore/Models/SimulationComponent/Impl/Vehicle.cs @@ -80,6 +80,13 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl return NextComponent.Initialize(vehicleAccelerationForce, vehicleSpeed); } + public IResponse Initialize(MeterPerSecond vehicleSpeed, MeterPerSquareSecond startAcceleration, Radian roadGradient) + { + var vehicleAccelerationForce = DriverAcceleration(startAcceleration) + RollingResistance(roadGradient) + + AirDragResistance() + SlopeResistance(roadGradient); + return NextComponent.Initialize(vehicleAccelerationForce, vehicleSpeed); + } + public IResponse Request(Second absTime, Second dt, MeterPerSquareSecond accelleration, Radian gradient, bool dryRun = false) { diff --git a/VectoCore/Utils/Formulas.cs b/VectoCore/Utils/Formulas.cs index 2687c0b60f0f36da45ecaad7bd5abb9350d5f46e..92236f2ea3e7990c5ef3ef66d4b9be23e96478c7 100644 --- a/VectoCore/Utils/Formulas.cs +++ b/VectoCore/Utils/Formulas.cs @@ -37,7 +37,7 @@ namespace TUGraz.VectoCore.Utils /// Calculates power loss caused by inertia. /// https://en.wikipedia.org/wiki/Angular_acceleration /// alpha = delta_omega / dt - /// torque = I * alpha + /// tau = I * alpha /// </summary> /// <param name="currentOmega">The current omega (new angularSpeed).</param> /// <param name="previousOmega">The previous omega (old angularSpeed).</param> @@ -54,5 +54,13 @@ namespace TUGraz.VectoCore.Utils var torque = inertia * alpha; return (torque * avgOmega).Cast<Watt>(); } + + + public static Watt InertiaPower(PerSecond omega, PerSquareSecond alpha, KilogramSquareMeter inertia, Second dt) + { + var torque = inertia * alpha; + var power = torque * (omega + alpha / 2 * dt); + return power; + } } } \ No newline at end of file diff --git a/VectoCore/Utils/SI.cs b/VectoCore/Utils/SI.cs index 7e07437f85047e115152df7a44caefc3fa69d55d..b5ef5de8534c7fe21adcac355413d5b6f1d4f608 100644 --- a/VectoCore/Utils/SI.cs +++ b/VectoCore/Utils/SI.cs @@ -143,6 +143,22 @@ namespace TUGraz.VectoCore.Utils private Radian(double val) : base(new SI(val).Radian) {} } + /// <summary> + /// SI Class for PerSquareSecond [1/s�]. + /// </summary> + public class PerSquareSecond : SIBase<PerSquareSecond> + { + [JsonConstructor, DebuggerHidden] + private PerSquareSecond(double val) : base(new SI(val).Per.Square.Second) {} + + [DebuggerHidden] + public static PerSecond operator *(PerSquareSecond perSquareSecond, Second second) + { + return ((perSquareSecond as SI) * second).Cast<PerSecond>(); + } + } + + /// <summary> /// SI Class for Meter per square second [m/s�]. /// </summary> @@ -227,6 +243,12 @@ namespace TUGraz.VectoCore.Utils { [JsonConstructor, DebuggerHidden] protected KilogramSquareMeter(double val) : base(new SI(val).Kilo.Gramm.Square.Meter) {} + + [DebuggerHidden] + public static NewtonMeter operator *(KilogramSquareMeter kilogramSquareMeter, PerSquareSecond perSquareSecond) + { + return ((kilogramSquareMeter as SI) * perSquareSecond).Cast<NewtonMeter>(); + } } /// <summary> @@ -387,6 +409,13 @@ namespace TUGraz.VectoCore.Utils return ((newtonMeter as SI) / watt).Cast<Second>(); } + [DebuggerHidden] + public static PerSquareSecond operator /(NewtonMeter newtonMeter, KilogramSquareMeter kgKilogramSquareMeter) + { + return ((newtonMeter as SI) / kgKilogramSquareMeter).Cast<PerSquareSecond>(); + } + + [DebuggerHidden] public static PerSecond operator /(NewtonMeter newtonMeter, NewtonMeterSecond newtonMeterSecond) { diff --git a/VectoCoreTest/Models/SimulationComponent/GearboxPowertrainTest.cs b/VectoCoreTest/Models/SimulationComponent/GearboxPowertrainTest.cs new file mode 100644 index 0000000000000000000000000000000000000000..ba4021f0dd7ac8eaccb67627bad76afaad7bd506 --- /dev/null +++ b/VectoCoreTest/Models/SimulationComponent/GearboxPowertrainTest.cs @@ -0,0 +1,235 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using TUGraz.VectoCore.FileIO.Reader; +using TUGraz.VectoCore.FileIO.Reader.Impl; +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.Impl; +using TUGraz.VectoCore.Models.SimulationComponent; +using TUGraz.VectoCore.Models.SimulationComponent.Data; +using TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox; +using TUGraz.VectoCore.Models.SimulationComponent.Impl; +using TUGraz.VectoCore.Tests.Utils; +using TUGraz.VectoCore.Utils; +using Wheels = TUGraz.VectoCore.Models.SimulationComponent.Impl.Wheels; + +namespace TUGraz.VectoCore.Tests.Models.SimulationComponent +{ + [TestClass] + public class GearboxPowertrainTest + { + public const string AccelerationFile = @"TestData\Components\Truck.vacc"; + + public const string EngineFile = @"TestData\Components\40t_Long_Haul_Truck.veng"; + + public const string AxleGearLossMap = @"TestData\Components\Axle.vtlm"; + public const string GearboxLossMap = @"TestData\Components\Indirect Gear.vtlm"; + public const string GearboxShiftPolygonFile = @"TestData\Components\ShiftPolygons.vgbs"; + public const string GearboxFullLoadCurveFile = @"TestData\Components\Gearbox.vfld"; + + [TestMethod] + public void Gearbox_Initialize_Empty() + { + var cycle = CreateCycleData(new[] { + // <s>,<v>,<grad>,<stop> + " 0, 0, 2.95016969027809, 1", + "1000, 60, 2.95016969027809, 0", + }); + var container = CreatePowerTrain(cycle, "Gearbox_Initialize.vmod", 7500.0.SI<Kilogram>(), 0.SI<Kilogram>()); + var retVal = container.Cycle.Initialize(); + Assert.AreEqual(5u, container.Gear); + Assert.IsInstanceOfType(retVal, typeof(ResponseSuccess)); + + AssertHelper.AreRelativeEqual(560.RPMtoRad(), container.EngineSpeed); + + var absTime = 0.SI<Second>(); + var ds = 1.SI<Meter>(); + + retVal = container.Cycle.Request(absTime, ds); + absTime += retVal.SimulationInterval; + + AssertHelper.AreRelativeEqual(560.RPMtoRad(), container.EngineSpeed); + container.Cycle.Request(absTime, ds); + + AssertHelper.AreRelativeEqual(593.RPMtoRad(), container.EngineSpeed); + } + + [TestMethod] + public void Gearbox_Initialize_RefLoad() + { + var cycle = CreateCycleData(new[] { + // <s>,<v>,<grad>,<stop> + " 0, 0, 2.95016969027809, 0", + "1000, 60, 2.95016969027809, 0", + }); + var container = CreatePowerTrain(cycle, "Gearbox_Initialize.vmod", 7500.0.SI<Kilogram>(), 19300.SI<Kilogram>()); + var retVal = container.Cycle.Initialize(); + Assert.AreEqual(4u, container.Gear); + Assert.IsInstanceOfType(retVal, typeof(ResponseSuccess)); + } + + + // =============================== + + public DrivingCycleData CreateCycleData(string[] entries) + { + var cycleData = new MemoryStream(); + var writer = new StreamWriter(cycleData); + writer.WriteLine("<s>,<v>,<grad>,<stop>"); + foreach (var entry in entries) { + writer.WriteLine(entry); + } + writer.Flush(); + cycleData.Seek(0, SeekOrigin.Begin); + return DrivingCycleDataReader.ReadFromStream(cycleData, CycleType.DistanceBased); + } + + public VehicleContainer CreatePowerTrain(DrivingCycleData cycleData, string modFileName, Kilogram massExtra, + Kilogram loading) + { + var modalWriter = new ModalDataWriter(modFileName); + var sumWriter = new TestSumWriter(); + var container = new VehicleContainer(modalWriter, sumWriter); + + + var engineData = EngineeringModeSimulationDataReader.CreateEngineDataFromFile(EngineFile); + //var cycleData = DrivingCycleDataReader.ReadFromFileDistanceBased(CoachCycleFile); + var axleGearData = CreateAxleGearData(); + var gearboxData = CreateGearboxData(engineData); + var vehicleData = CreateVehicleData(massExtra, loading); + var driverData = CreateDriverData(AccelerationFile); + + var cycle = new DistanceBasedDrivingCycle(container, cycleData); + dynamic tmp = Port.AddComponent(cycle, new Driver(container, driverData, new DefaultDriverStrategy())); + tmp = Port.AddComponent(tmp, new Vehicle(container, vehicleData)); + tmp = Port.AddComponent(tmp, new Wheels(container, vehicleData.DynamicTyreRadius)); + tmp = Port.AddComponent(tmp, new Brakes(container)); + tmp = Port.AddComponent(tmp, new AxleGear(container, axleGearData)); + tmp = Port.AddComponent(tmp, new Gearbox(container, gearboxData)); + tmp = Port.AddComponent(tmp, new Clutch(container, engineData)); + + var aux = new Auxiliary(container); + aux.AddConstant("", 0.SI<Watt>()); + + tmp = Port.AddComponent(tmp, aux); + + Port.AddComponent(tmp, new CombustionEngine(container, engineData)); + + return container; + } + + + // ========================================= + + private static GearboxData CreateGearboxData(CombustionEngineData engineData) + { + var ratios = new[] { 14.93, 11.64, 9.02, 7.04, 5.64, 4.4, 3.39, 2.65, 2.05, 1.6, 1.28, 1.0, }; + + return new GearboxData { + Gears = ratios.Select((ratio, i) => + Tuple.Create((uint)i, + new GearData { + FullLoadCurve = FullLoadCurve.ReadFromFile(GearboxFullLoadCurveFile), + LossMap = TransmissionLossMap.ReadFromFile(GearboxLossMap, ratio), + Ratio = ratio, + //ShiftPolygon = ShiftPolygon.ReadFromFile(GearboxShiftPolygonFile), + ShiftPolygon = DeclarationData.Gearbox.ComputeShiftPolygon(engineData.FullLoadCurve, engineData.IdleSpeed) + })) + .ToDictionary(k => k.Item1 + 1, v => v.Item2), + ShiftTime = 2.SI<Second>(), + Inertia = 0.SI<KilogramSquareMeter>(), + TractionInterruption = 1.SI<Second>(), + StartAcceleration = 0.6.SI<MeterPerSquareSecond>(), + StartSpeed = 2.SI<MeterPerSecond>(), + }; + } + + + private static GearData CreateAxleGearData() + { + var ratio = 2.59; + return new GearData { + Ratio = ratio, + LossMap = TransmissionLossMap.ReadFromFile(AxleGearLossMap, ratio) + }; + } + + private static VehicleData CreateVehicleData(Kilogram massExtra, Kilogram loading) + { + var axles = new List<Axle> { + new Axle { + AxleWeightShare = 0.2, + Inertia = 14.9.SI<KilogramSquareMeter>(), + RollResistanceCoefficient = 0.0055, + TwinTyres = false, + TyreTestLoad = 31300.SI<Newton>() + }, + new Axle { + AxleWeightShare = 0.2, + Inertia = 14.9.SI<KilogramSquareMeter>(), + RollResistanceCoefficient = 0.0065, + TwinTyres = true, + TyreTestLoad = 31300.SI<Newton>() + }, + new Axle { + AxleWeightShare = 0.55 / 3, + TwinTyres = DeclarationData.Trailer.TwinTyres, + RollResistanceCoefficient = DeclarationData.Trailer.RollResistanceCoefficient, + TyreTestLoad = DeclarationData.Trailer.TyreTestLoad.SI<Newton>(), + Inertia = DeclarationData.Wheels.Lookup(DeclarationData.Trailer.WheelsType).Inertia + }, + new Axle { + AxleWeightShare = 0.55 / 3, + TwinTyres = DeclarationData.Trailer.TwinTyres, + RollResistanceCoefficient = DeclarationData.Trailer.RollResistanceCoefficient, + TyreTestLoad = DeclarationData.Trailer.TyreTestLoad.SI<Newton>(), + Inertia = DeclarationData.Wheels.Lookup(DeclarationData.Trailer.WheelsType).Inertia + }, + new Axle { + AxleWeightShare = 0.55 / 3, + TwinTyres = DeclarationData.Trailer.TwinTyres, + RollResistanceCoefficient = DeclarationData.Trailer.RollResistanceCoefficient, + TyreTestLoad = DeclarationData.Trailer.TyreTestLoad.SI<Newton>(), + Inertia = DeclarationData.Wheels.Lookup(DeclarationData.Trailer.WheelsType).Inertia + } + }; + return new VehicleData { + AxleConfiguration = AxleConfiguration.AxleConfig_4x2, + CrossSectionArea = 9.5.SI<SquareMeter>(), + CrossWindCorrectionMode = CrossWindCorrectionMode.NoCorrection, + DragCoefficient = 1, + CurbWeight = 7100.SI<Kilogram>(), + CurbWeigthExtra = massExtra, + Loading = loading, + DynamicTyreRadius = 0.4882675.SI<Meter>(), + Retarder = new RetarderData { Type = RetarderData.RetarderType.None }, + AxleData = axles, + SavedInDeclarationMode = false, + }; + } + + private static DriverData CreateDriverData(string accelerationFile) + { + return new DriverData { + AccelerationCurve = AccelerationCurveData.ReadFromFile(accelerationFile), + LookAheadCoasting = new DriverData.LACData { + Enabled = true, + MinSpeed = 50.KMPHtoMeterPerSecond(), + Deceleration = -0.5.SI<MeterPerSquareSecond>(), + }, + OverSpeedEcoRoll = new DriverData.OverSpeedEcoRollData { + Mode = DriverData.DriverMode.Off + }, + StartStop = new VectoRunData.StartStopData { + Enabled = false, + } + }; + } + } +} \ No newline at end of file diff --git a/VectoCoreTest/Models/SimulationComponentData/CombustionEngineDataTest.cs b/VectoCoreTest/Models/SimulationComponentData/CombustionEngineDataTest.cs index 9a068976ebf2538987de6181ecf278be6598a46b..17aa17c21e7885a5cce897319e5e4e983efcece1 100644 --- a/VectoCoreTest/Models/SimulationComponentData/CombustionEngineDataTest.cs +++ b/VectoCoreTest/Models/SimulationComponentData/CombustionEngineDataTest.cs @@ -5,11 +5,10 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponentData [TestClass] public class CombustionEngineDataTest { - [TestMethod] public void TestEquals() { - + Assert.Fail(); } } } \ No newline at end of file diff --git a/VectoCoreTest/Utils/MockDriver.cs b/VectoCoreTest/Utils/MockDriver.cs index 129324fc5db78b87094f6c1e4d9bd7e16b9e420a..102ede1c712201bf0269b05b091cfdf79fe89e89 100644 --- a/VectoCoreTest/Utils/MockDriver.cs +++ b/VectoCoreTest/Utils/MockDriver.cs @@ -55,6 +55,11 @@ namespace TUGraz.VectoCore.Tests.Utils return new ResponseSuccess(); } + public IResponse Initialize(MeterPerSecond vehicleSpeed, MeterPerSquareSecond startAcceleration, Radian roadGradient) + { + throw new NotImplementedException(); + } + public void Connect(IDriverDemandOutPort other) { _next = other; diff --git a/VectoCoreTest/Utils/MockGearbox.cs b/VectoCoreTest/Utils/MockGearbox.cs index edd87fab87f18cde39fcbf757ef4135aad0b64c0..5507253ace0f8601c0ebf9cc6ea5e08c1ee7281c 100644 --- a/VectoCoreTest/Utils/MockGearbox.cs +++ b/VectoCoreTest/Utils/MockGearbox.cs @@ -25,6 +25,8 @@ namespace TUGraz.VectoCore.Tests.Utils } public uint Gear { get; set; } + public MeterPerSecond StartSpeed { get; private set; } + public MeterPerSquareSecond StartAcceleration { get; private set; } public void Connect(ITnOutPort other) diff --git a/VectoCoreTest/Utils/MockPorts.cs b/VectoCoreTest/Utils/MockPorts.cs index 94eccca59ea5675b0614027b6e7928f9864ec470..d4a3e06052483138fe6c27d5a7c381c562af7322 100644 --- a/VectoCoreTest/Utils/MockPorts.cs +++ b/VectoCoreTest/Utils/MockPorts.cs @@ -87,6 +87,11 @@ namespace TUGraz.VectoCore.Tests.Utils { throw new NotImplementedException(); } + + public IResponse Initialize(MeterPerSecond vehicleSpeed, MeterPerSquareSecond startAcceleration, Radian roadGradient) + { + throw new NotImplementedException(); + } } public class MockFvOutPort : LoggingObject, IFvOutPort diff --git a/VectoCoreTest/Utils/MockVehicle.cs b/VectoCoreTest/Utils/MockVehicle.cs index 3cad80e63baa4d11b87722b3323873cca813e926..c30b292f07de0445bad895ba618f18cef7b2da19 100644 --- a/VectoCoreTest/Utils/MockVehicle.cs +++ b/VectoCoreTest/Utils/MockVehicle.cs @@ -72,6 +72,11 @@ namespace TUGraz.VectoCore.Tests.Utils throw new NotImplementedException(); } + public IResponse Initialize(MeterPerSecond vehicleSpeed, MeterPerSquareSecond startAcceleration, Radian roadGradient) + { + throw new NotImplementedException(); + } + public class RequestData { public Second abstime; diff --git a/VectoCoreTest/VectoCoreTest.csproj b/VectoCoreTest/VectoCoreTest.csproj index 229f1e6c2b46bb1331a943ed076280cb60c0748c..426838a9f99e00a416bad5caf4c762863c12a250 100644 --- a/VectoCoreTest/VectoCoreTest.csproj +++ b/VectoCoreTest/VectoCoreTest.csproj @@ -64,6 +64,7 @@ <Compile Include="Integration\DriverStrategy\DriverStrategyTest.cs" /> <Compile Include="Integration\EngineOnlyCycle\EngineOnlyCycleTest.cs" /> <Compile Include="Integration\SimulationRuns\FullPowertrain.cs" /> + <Compile Include="Models\SimulationComponent\GearboxPowertrainTest.cs" /> <Compile Include="Utils\Port.cs" /> <Compile Include="Models\SimulationComponentData\AuxiliaryTypeHelperTest.cs" /> <Compile Include="Models\SimulationComponentData\CombustionEngineDataTest.cs" />