From 1cb9cf32f8a6ac37e1290697d8a46d77ea08e134 Mon Sep 17 00:00:00 2001 From: Markus Quaritsch <markus.quaritsch@tugraz.at> Date: Mon, 3 Jul 2017 09:18:19 +0200 Subject: [PATCH] refactoring --- .../Models/SimulationComponent/Impl/Clutch.cs | 289 +++---- .../Impl/CombustionEngine.cs | 21 +- .../SimulationComponent/Impl/Gearbox.cs | 799 +++++++++--------- .../Impl/TorqueConverter.cs | 527 ++++++------ 4 files changed, 829 insertions(+), 807 deletions(-) diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/Clutch.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/Clutch.cs index 5af38c58dc..ab488ae867 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/Clutch.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/Clutch.cs @@ -29,145 +29,152 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.Configuration; -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.Data; -using TUGraz.VectoCore.OutputData; -using TUGraz.VectoCore.Utils; - -namespace TUGraz.VectoCore.Models.SimulationComponent.Impl -{ - public class Clutch : StatefulProviderComponent<Clutch.ClutchState, ITnOutPort, ITnInPort, ITnOutPort>, IClutch, - ITnOutPort, ITnInPort - { - private readonly PerSecond _idleSpeed; - private readonly PerSecond _ratedSpeed; - - public IIdleController IdleController { - get { return _idleController; } - set { - _idleController = value; - _idleController.RequestPort = NextComponent; - } - } - - private readonly SI _clutchSpeedSlippingFactor; - private IIdleController _idleController; - - public Clutch(IVehicleContainer container, CombustionEngineData engineData) : base(container) - { - _idleSpeed = engineData.IdleSpeed; - _ratedSpeed = engineData.FullLoadCurves[0].RatedSpeed; - _clutchSpeedSlippingFactor = Constants.SimulationSettings.ClutchClosingSpeedNorm * (_ratedSpeed - _idleSpeed) / - (_idleSpeed + Constants.SimulationSettings.ClutchClosingSpeedNorm * (_ratedSpeed - _idleSpeed)); - } - - public IResponse Initialize(NewtonMeter outTorque, PerSecond outAngularVelocity) - { - NewtonMeter torqueIn; - PerSecond engineSpeedIn; - if (DataBus.DriverBehavior == DrivingBehavior.Halted /*DataBus.VehicleStopped*/) { - engineSpeedIn = _idleSpeed; - torqueIn = 0.SI<NewtonMeter>(); - } else { - AddClutchLoss(outTorque, outAngularVelocity, true, out torqueIn, out engineSpeedIn); - } - PreviousState.SetState(torqueIn, outAngularVelocity, outTorque, outAngularVelocity); - - var retVal = NextComponent.Initialize(torqueIn, engineSpeedIn); - retVal.ClutchPowerRequest = outTorque * outAngularVelocity; - return retVal; - } - - public IResponse Request(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, - bool dryRun = false) - { - var startClutch = DataBus.VehicleStopped || !PreviousState.ClutchLoss.IsEqual(0); - if (!DataBus.ClutchClosed(absTime) && !dryRun) { - Log.Debug("Invoking IdleController..."); - var retval = IdleController.Request(absTime, dt, outTorque, null, dryRun); - retval.ClutchPowerRequest = 0.SI<Watt>(); - CurrentState.SetState(0.SI<NewtonMeter>(), retval.EngineSpeed, outTorque, outAngularVelocity); - CurrentState.ClutchLoss = 0.SI<Watt>(); - return retval; - } - if (IdleController != null) { - IdleController.Reset(); - } - - Log.Debug("from Wheels: torque: {0}, angularVelocity: {1}, power {2}", outTorque, outAngularVelocity, - Formulas.TorqueToPower(outTorque, outAngularVelocity)); - - NewtonMeter torqueIn; - PerSecond angularVelocityIn; - if (DataBus.DriverBehavior == DrivingBehavior.Halted /*DataBus.VehicleStopped*/) { - angularVelocityIn = _idleSpeed; - torqueIn = 0.SI<NewtonMeter>(); - } else { - AddClutchLoss(outTorque, outAngularVelocity, (DataBus.Gear == 1 && outTorque > 0) ||startClutch || outAngularVelocity.IsEqual(0), out torqueIn, out angularVelocityIn); - } - Log.Debug("to Engine: torque: {0}, angularVelocity: {1}, power {2}", torqueIn, angularVelocityIn, - Formulas.TorqueToPower(torqueIn, angularVelocityIn)); - - var avgOutAngularVelocity = (PreviousState.OutAngularVelocity + outAngularVelocity) / 2.0; - var avgInAngularVelocity = (PreviousState.InAngularVelocity + angularVelocityIn) / 2.0; - var clutchLoss = torqueIn * avgInAngularVelocity - outTorque * avgOutAngularVelocity; - if (!startClutch && !clutchLoss.IsEqual(0)) { - // we don't want to have negative clutch losses, so adapt input torque to match the average output power - torqueIn = outTorque * avgOutAngularVelocity / avgInAngularVelocity; - } - - var retVal = NextComponent.Request(absTime, dt, torqueIn, angularVelocityIn, dryRun); - if (!dryRun) { - CurrentState.SetState(torqueIn, angularVelocityIn, outTorque, outAngularVelocity); - CurrentState.ClutchLoss = torqueIn * avgInAngularVelocity - outTorque * avgOutAngularVelocity; - } - retVal.ClutchPowerRequest = outTorque * - ((PreviousState.OutAngularVelocity ?? 0.SI<PerSecond>()) + CurrentState.OutAngularVelocity) / 2.0; - return retVal; - } - - private void AddClutchLoss(NewtonMeter torque, PerSecond angularVelocity, bool startClutch, out NewtonMeter torqueIn, out PerSecond angularVelocityIn) - { - torqueIn = torque; - angularVelocityIn = angularVelocity; - - var engineSpeedNorm = (angularVelocity - _idleSpeed) / (_ratedSpeed - _idleSpeed); - if (startClutch && engineSpeedNorm < Constants.SimulationSettings.ClutchClosingSpeedNorm) { - // MQ: 27.5.2016: when angularVelocity is 0 (at the end of the simulation interval) don't use the - // angularVelocity but average angular velocity - // Reason: if angularVelocity = 0 also the power (torque * angularVelocity) is 0 and then - // the torque demand for the engine is 0. no drag torque although vehicle has to decelerate - // "the clutch" eats up the whole torque - var engineSpeed = VectoMath.Max(_idleSpeed, angularVelocity); - - angularVelocityIn = _clutchSpeedSlippingFactor * engineSpeed + _idleSpeed; - - } - } - - protected override void DoWriteModalResults(IModalDataContainer container) - { - if (PreviousState.InAngularVelocity == null || CurrentState.InAngularVelocity == null) { - container[ModalResultField.P_clutch_out] = 0.SI<Watt>(); - container[ModalResultField.P_clutch_loss] = 0.SI<Watt>(); - } else { - var avgOutAngularVelocity = (PreviousState.OutAngularVelocity + CurrentState.OutAngularVelocity) / 2.0; - var avgInAngularVelocity = (PreviousState.InAngularVelocity + CurrentState.InAngularVelocity) / 2.0; - container[ModalResultField.P_clutch_out] = CurrentState.OutTorque * avgOutAngularVelocity; - container[ModalResultField.P_clutch_loss] = CurrentState.InTorque * avgInAngularVelocity - - CurrentState.OutTorque * avgOutAngularVelocity; - } - } - - public class ClutchState : SimpleComponentState - { - public Watt ClutchLoss = 0.SI<Watt>(); - } - } +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Configuration; +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.Data; +using TUGraz.VectoCore.OutputData; +using TUGraz.VectoCore.Utils; + +namespace TUGraz.VectoCore.Models.SimulationComponent.Impl +{ + public class Clutch : StatefulProviderComponent<Clutch.ClutchState, ITnOutPort, ITnInPort, ITnOutPort>, IClutch, + ITnOutPort, ITnInPort + { + private readonly PerSecond _idleSpeed; + private readonly PerSecond _ratedSpeed; + + public IIdleController IdleController + { + get { return _idleController; } + set + { + _idleController = value; + _idleController.RequestPort = NextComponent; + } + } + + private readonly SI _clutchSpeedSlippingFactor; + private IIdleController _idleController; + + public Clutch(IVehicleContainer container, CombustionEngineData engineData) : base(container) + { + _idleSpeed = engineData.IdleSpeed; + _ratedSpeed = engineData.FullLoadCurves[0].RatedSpeed; + _clutchSpeedSlippingFactor = Constants.SimulationSettings.ClutchClosingSpeedNorm * (_ratedSpeed - _idleSpeed) / + (_idleSpeed + Constants.SimulationSettings.ClutchClosingSpeedNorm * (_ratedSpeed - _idleSpeed)); + } + + public IResponse Initialize(NewtonMeter outTorque, PerSecond outAngularVelocity) + { + NewtonMeter torqueIn; + PerSecond engineSpeedIn; + if (DataBus.DriverBehavior == DrivingBehavior.Halted /*DataBus.VehicleStopped*/) { + engineSpeedIn = _idleSpeed; + torqueIn = 0.SI<NewtonMeter>(); + } else { + AddClutchLoss(outTorque, outAngularVelocity, true, out torqueIn, out engineSpeedIn); + } + PreviousState.SetState(torqueIn, outAngularVelocity, outTorque, outAngularVelocity); + + var retVal = NextComponent.Initialize(torqueIn, engineSpeedIn); + retVal.ClutchPowerRequest = outTorque * outAngularVelocity; + return retVal; + } + + public IResponse Request(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, + bool dryRun = false) + { + var startClutch = DataBus.VehicleStopped || !PreviousState.ClutchLoss.IsEqual(0); + if (!DataBus.ClutchClosed(absTime) && !dryRun) { + Log.Debug("Invoking IdleController..."); + var retval = IdleController.Request(absTime, dt, outTorque, null, dryRun); + retval.ClutchPowerRequest = 0.SI<Watt>(); + CurrentState.SetState(0.SI<NewtonMeter>(), retval.EngineSpeed, outTorque, outAngularVelocity); + CurrentState.ClutchLoss = 0.SI<Watt>(); + return retval; + } + if (IdleController != null) { + IdleController.Reset(); + } + + Log.Debug("from Wheels: torque: {0}, angularVelocity: {1}, power {2}", outTorque, outAngularVelocity, + Formulas.TorqueToPower(outTorque, outAngularVelocity)); + + NewtonMeter torqueIn; + PerSecond angularVelocityIn; + + AddClutchLoss(outTorque, outAngularVelocity, + (DataBus.Gear == 1 && outTorque > 0) || startClutch || outAngularVelocity.IsEqual(0), out torqueIn, + out angularVelocityIn); + + Log.Debug("to Engine: torque: {0}, angularVelocity: {1}, power {2}", torqueIn, angularVelocityIn, + Formulas.TorqueToPower(torqueIn, angularVelocityIn)); + + var avgOutAngularVelocity = (PreviousState.OutAngularVelocity + outAngularVelocity) / 2.0; + var avgInAngularVelocity = (PreviousState.InAngularVelocity + angularVelocityIn) / 2.0; + var clutchLoss = torqueIn * avgInAngularVelocity - outTorque * avgOutAngularVelocity; + if (!startClutch && !clutchLoss.IsEqual(0)) { + // we don't want to have negative clutch losses, so adapt input torque to match the average output power + torqueIn = outTorque * avgOutAngularVelocity / avgInAngularVelocity; + } + + var retVal = NextComponent.Request(absTime, dt, torqueIn, angularVelocityIn, dryRun); + if (!dryRun) { + CurrentState.SetState(torqueIn, angularVelocityIn, outTorque, outAngularVelocity); + CurrentState.ClutchLoss = torqueIn * avgInAngularVelocity - outTorque * avgOutAngularVelocity; + } + retVal.ClutchPowerRequest = outTorque * + ((PreviousState.OutAngularVelocity ?? 0.SI<PerSecond>()) + CurrentState.OutAngularVelocity) / 2.0; + return retVal; + } + + private void AddClutchLoss(NewtonMeter torque, PerSecond angularVelocity, bool startClutch, out NewtonMeter torqueIn, + out PerSecond angularVelocityIn) + { + if (DataBus.DriverBehavior == DrivingBehavior.Halted) { + angularVelocityIn = _idleSpeed; + torqueIn = 0.SI<NewtonMeter>(); + return; + } + + torqueIn = torque; + angularVelocityIn = angularVelocity; + + var engineSpeedNorm = (angularVelocity - _idleSpeed) / (_ratedSpeed - _idleSpeed); + if (startClutch && engineSpeedNorm < Constants.SimulationSettings.ClutchClosingSpeedNorm) { + // MQ: 27.5.2016: when angularVelocity is 0 (at the end of the simulation interval) don't use the + // angularVelocity but average angular velocity + // Reason: if angularVelocity = 0 also the power (torque * angularVelocity) is 0 and then + // the torque demand for the engine is 0. no drag torque although vehicle has to decelerate + // "the clutch" eats up the whole torque + var engineSpeed = VectoMath.Max(_idleSpeed, angularVelocity); + + angularVelocityIn = _clutchSpeedSlippingFactor * engineSpeed + _idleSpeed; + } + } + + protected override void DoWriteModalResults(IModalDataContainer container) + { + if (PreviousState.InAngularVelocity == null || CurrentState.InAngularVelocity == null) { + container[ModalResultField.P_clutch_out] = 0.SI<Watt>(); + container[ModalResultField.P_clutch_loss] = 0.SI<Watt>(); + } else { + var avgOutAngularVelocity = (PreviousState.OutAngularVelocity + CurrentState.OutAngularVelocity) / 2.0; + var avgInAngularVelocity = (PreviousState.InAngularVelocity + CurrentState.InAngularVelocity) / 2.0; + container[ModalResultField.P_clutch_out] = CurrentState.OutTorque * avgOutAngularVelocity; + container[ModalResultField.P_clutch_loss] = CurrentState.InTorque * avgInAngularVelocity - + CurrentState.OutTorque * avgOutAngularVelocity; + } + } + + public class ClutchState : SimpleComponentState + { + public Watt ClutchLoss = 0.SI<Watt>(); + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs index 4321fb273c..1267b16fe0 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs @@ -175,9 +175,9 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl // if the clutch disengages the idle controller should take over! throw new VectoSimulationException("angular velocity is null! Clutch open without IdleController?"); } - if (angularVelocity < ModelData.IdleSpeed.Value() - EngineIdleSpeedStopThreshold) { - CurrentState.OperationMode = EngineOperationMode.Stopped; - } + //if (angularVelocity < ModelData.IdleSpeed.Value() - EngineIdleSpeedStopThreshold) { + // CurrentState.OperationMode = EngineOperationMode.Stopped; + //} var avgEngineSpeed = (PreviousState.EngineSpeed + angularVelocity) / 2.0; @@ -192,9 +192,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl var fullDragTorque = ModelData.FullLoadCurves[DataBus.Gear].DragLoadStationaryTorque(avgEngineSpeed); var dynamicFullLoadPower = ComputeFullLoadPower(avgEngineSpeed, dt, dryRun); - if (dynamicFullLoadPower < 0) { - dynamicFullLoadPower = 0.SI<Watt>(); - } + var dynamicFullLoadTorque = dynamicFullLoadPower / avgEngineSpeed; var inertiaTorqueLoss = Formulas.InertiaPower(angularVelocity, PreviousState.EngineSpeed, ModelData.Inertia, dt) / @@ -460,6 +458,9 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl dynFullPowerCalculated = stationaryFullLoadPower; } + if (dynFullPowerCalculated < 0) { + return 0.SI<Watt>(); + } return dynFullPowerCalculated; } @@ -590,7 +591,9 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl angularSpeed = angularSpeed.LimitTo(_engine.ModelData.IdleSpeed, _engine.EngineRatedSpeed); retVal = RequestPort.Request(absTime, dt, 0.SI<NewtonMeter>(), angularSpeed); }). - Default(r => { throw new UnexpectedResponseException("searching Idling point", r); }); + Default(r => { + throw new UnexpectedResponseException("searching Idling point", r); + }); return retVal; } @@ -647,7 +650,9 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl 0.SI<NewtonMeter>(), angularSpeed); retVal = RequestPort.Request(absTime, dt, 0.SI<NewtonMeter>(), angularSpeed); }). - Default(r => { throw new UnexpectedResponseException("searching Idling point", r); }); + Default(r => { + throw new UnexpectedResponseException("searching Idling point", r); + }); return retVal; } diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/Gearbox.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/Gearbox.cs index 8ea0d27091..6682c9725a 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/Gearbox.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/Gearbox.cs @@ -29,401 +29,406 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using TUGraz.VectoCommon.Exceptions; -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.Configuration; -using TUGraz.VectoCore.Models.Connector.Ports.Impl; -using TUGraz.VectoCore.Models.Simulation; -using TUGraz.VectoCore.Models.Simulation.Data; -using TUGraz.VectoCore.Models.Simulation.DataBus; -using TUGraz.VectoCore.OutputData; -using TUGraz.VectoCore.Utils; - -namespace TUGraz.VectoCore.Models.SimulationComponent.Impl -{ - public class Gearbox : AbstractGearbox<GearboxState> - { - /// <summary> - /// The shift strategy. - /// </summary> - private readonly IShiftStrategy _strategy; - - /// <summary> - /// Time when a gearbox shift engages a new gear (shift is finished). Is set when shifting is needed. - /// </summary> - private Second _engageTime = 0.SI<Second>(); - - /// <summary> - /// True if gearbox is disengaged (no gear is set). - /// </summary> - protected internal bool Disengaged = true; - - public Second LastUpshift { get; protected internal set; } - - public Second LastDownshift { get; protected internal set; } - - public override GearInfo NextGear - { - get { return _strategy.NextGear; } - } - - public override bool ClutchClosed(Second absTime) - { - return _engageTime.IsSmallerOrEqual(absTime); - } - - public Gearbox(IVehicleContainer container, IShiftStrategy strategy, VectoRunData runData) : base(container, runData) - { - _strategy = strategy; - _strategy.Gearbox = this; - - LastDownshift = -double.MaxValue.SI<Second>(); - LastUpshift = -double.MaxValue.SI<Second>(); - } - - public override IResponse Initialize(NewtonMeter outTorque, PerSecond outAngularVelocity) - { - var absTime = 0.SI<Second>(); - var dt = Constants.SimulationSettings.TargetTimeInterval; - - _engageTime = -double.MaxValue.SI<Second>(); - - if (Disengaged) { - Gear = _strategy.InitGear(absTime, dt, outTorque, outAngularVelocity); - } - - var inAngularVelocity = outAngularVelocity * ModelData.Gears[Gear].Ratio; - var gearboxTorqueLoss = ModelData.Gears[Gear].LossMap.GetTorqueLoss(outAngularVelocity, outTorque); - CurrentState.TorqueLossResult = gearboxTorqueLoss; - - var inTorque = outTorque / ModelData.Gears[Gear].Ratio - + gearboxTorqueLoss.Value; - - PreviousState.SetState(inTorque, inAngularVelocity, outTorque, outAngularVelocity); - PreviousState.InertiaTorqueLossOut = 0.SI<NewtonMeter>(); - PreviousState.Gear = Gear; - Disengaged = false; - - var response = NextComponent.Initialize(inTorque, inAngularVelocity); - - return response; - } - - internal ResponseDryRun Initialize(uint gear, NewtonMeter outTorque, PerSecond outAngularVelocity) - { - var oldGear = Gear; - Gear = gear; - var inAngularVelocity = outAngularVelocity * ModelData.Gears[gear].Ratio; - var torqueLossResult = ModelData.Gears[gear].LossMap.GetTorqueLoss(outAngularVelocity, outTorque); - CurrentState.TorqueLossResult = torqueLossResult; - var inTorque = outTorque / ModelData.Gears[gear].Ratio + torqueLossResult.Value; - - if (!inAngularVelocity.IsEqual(0)) { - var alpha = ModelData.Inertia.IsEqual(0) - ? 0.SI<PerSquareSecond>() - : outTorque / ModelData.Inertia; - - var inertiaPowerLoss = Formulas.InertiaPower(inAngularVelocity, alpha, ModelData.Inertia, - Constants.SimulationSettings.TargetTimeInterval); - inTorque += inertiaPowerLoss / inAngularVelocity; - } - - var response = - (ResponseDryRun) - NextComponent.Request(0.SI<Second>(), Constants.SimulationSettings.TargetTimeInterval, inTorque, - inAngularVelocity, true); //NextComponent.Initialize(inTorque, inAngularVelocity); - //response.Switch(). - // Case<ResponseSuccess>(). - // Case<ResponseOverload>(). - // Case<ResponseUnderload>(). - // Default(r => { throw new UnexpectedResponseException("Gearbox.Initialize", r); }); - - var fullLoad = DataBus.EngineStationaryFullPower(inAngularVelocity); - - Gear = oldGear; - return new ResponseDryRun { - Source = this, - EnginePowerRequest = response.EnginePowerRequest, - EngineSpeed = response.EngineSpeed, - DynamicFullLoadPower = response.DynamicFullLoadPower, - ClutchPowerRequest = response.ClutchPowerRequest, - GearboxPowerRequest = outTorque * outAngularVelocity, - DeltaFullLoad = response.EnginePowerRequest - fullLoad - }; - } - - /// <summary> - /// Requests the Gearbox to deliver torque and angularVelocity - /// </summary> - /// <returns> - /// <list type="bullet"> - /// <item><description>ResponseDryRun</description></item> - /// <item><description>ResponseOverload</description></item> - /// <item><description>ResponseGearshift</description></item> - /// </list> - /// </returns> - public override IResponse Request(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, - bool dryRun = false) - { - IterationStatistics.Increment(this, "Requests"); - - Log.Debug("Gearbox Power Request: torque: {0}, angularVelocity: {1}", outTorque, outAngularVelocity); - if (DataBus.VehicleStopped) { - _engageTime = absTime; - LastDownshift = -double.MaxValue.SI<Second>(); - LastUpshift = -double.MaxValue.SI<Second>(); - } - if (DataBus.DriverBehavior == DrivingBehavior.Halted) { - _engageTime = absTime + dt; - } - - if (DataBus.DriverBehavior == DrivingBehavior.Braking && (DataBus.BrakePower.IsGreater(0) || outTorque < 0) && - DataBus.VehicleSpeed.IsSmaller(Constants.SimulationSettings.ClutchDisengageWhenHaltingSpeed)) { - _engageTime = VectoMath.Max(_engageTime, absTime + dt); - - return RequestGearDisengaged(absTime, dt, outTorque, outAngularVelocity, dryRun); - } - - return ClutchClosed(absTime) - ? RequestGearEngaged(absTime, dt, outTorque, outAngularVelocity, dryRun) - : RequestGearDisengaged(absTime, dt, outTorque, outAngularVelocity, dryRun); - } - - /// <summary> - /// Requests the Gearbox in Disengaged mode - /// </summary> - /// <returns> - /// <list type="bullet"> - /// <item><term>ResponseDryRun</term><description>if dryRun, immediate return!</description></item> - /// <item><term>ResponseFailTimeInterval</term><description>if shiftTime would be exceeded by current step</description></item> - /// <item><term>ResponseOverload</term><description>if torque > 0</description></item> - /// <item><term>ResponseUnderload</term><description>if torque < 0</description></item> - /// <item><term>else</term><description>Response from NextComponent</description></item> - /// </list> - /// </returns> - private IResponse RequestGearDisengaged(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, - bool dryRun) - { - Disengaged = true; - Log.Debug("Current Gear: Neutral"); - - var avgAngularVelocity = (PreviousState.OutAngularVelocity + outAngularVelocity) / 2.0; - - var gear = NextGear.Gear; - - var avgOutAngularVelocity = (PreviousState.OutAngularVelocity + outAngularVelocity) / 2.0; - var inTorqueLossResult = ModelData.Gears[gear].LossMap.GetTorqueLoss(avgOutAngularVelocity, outTorque); - var inTorque = outTorque / ModelData.Gears[gear].Ratio + inTorqueLossResult.Value; - - var inAngularVelocity = outAngularVelocity * ModelData.Gears[gear].Ratio; - var inertiaTorqueLossOut = !inAngularVelocity.IsEqual(0) - ? Formulas.InertiaPower(outAngularVelocity, PreviousState.OutAngularVelocity, ModelData.Inertia, dt) / - avgOutAngularVelocity - : 0.SI<NewtonMeter>(); - inTorque += inertiaTorqueLossOut / ModelData.Gears[gear].Ratio; - var avgInAngularVelocity = (PreviousState.InAngularVelocity + inAngularVelocity) / 2.0; - - if (dryRun) { - // if gearbox is disengaged the 0[W]-line is the limit for drag and full load. - var delta = inTorque * avgInAngularVelocity; - return new ResponseDryRun { - Source = this, - GearboxPowerRequest = delta, - DeltaDragLoad = delta, - DeltaFullLoad = delta, - }; - } - - var shiftTimeExceeded = absTime.IsSmaller(_engageTime) && - _engageTime.IsSmaller(absTime + dt, Constants.SimulationSettings.LowerBoundTimeInterval); - // allow 5% tolerance of shift time - if (shiftTimeExceeded && _engageTime - absTime > Constants.SimulationSettings.LowerBoundTimeInterval / 2) { - return new ResponseFailTimeInterval { - Source = this, - DeltaT = _engageTime - absTime, - GearboxPowerRequest = outTorque * (PreviousState.OutAngularVelocity + outAngularVelocity) / 2.0 - }; - } - - if ((inTorque * avgInAngularVelocity).IsGreater(0.SI<Watt>(), Constants.SimulationSettings.LineSearchTolerance)) { - return new ResponseOverload { - Source = this, - Delta = inTorque * avgInAngularVelocity, - GearboxPowerRequest = inTorque * avgInAngularVelocity - }; - } - - if ((inTorque * avgInAngularVelocity).IsSmaller(0.SI<Watt>(), Constants.SimulationSettings.LineSearchTolerance)) { - return new ResponseUnderload { - Source = this, - Delta = inTorque * avgInAngularVelocity, - GearboxPowerRequest = inTorque * avgInAngularVelocity - }; - } - - //var inTorque = 0.SI<NewtonMeter>(); - if (avgInAngularVelocity.Equals(0.SI<PerSecond>())) { - inTorque = 0.SI<NewtonMeter>(); - } - - CurrentState.SetState(inTorque, inAngularVelocity, outTorque, - outAngularVelocity); - CurrentState.Gear = gear; - CurrentState.TransmissionTorqueLoss = inTorque * ModelData.Gears[gear].Ratio - outTorque; - - var response = NextComponent.Request(absTime, dt, 0.SI<NewtonMeter>(), inAngularVelocity); - - //CurrentState.InAngularVelocity = response.EngineSpeed; - - response.GearboxPowerRequest = outTorque * avgAngularVelocity; - - return response; - } - - /// <summary> - /// Requests the gearbox in engaged mode. Sets the gear if no gear was set previously. - /// </summary> - /// <returns> - /// <list type="bullet"> - /// <item><term>ResponseGearShift</term><description>if a shift is needed.</description></item> - /// <item><term>else</term><description>Response from NextComponent.</description></item> - /// </list> - /// </returns> - private IResponse RequestGearEngaged(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, - bool dryRun) - { - // Set a Gear if no gear was set and engineSpeed is not zero - //if (!Disengaged && DataBus.VehicleStopped && !outAngularVelocity.IsEqual(0)) - //{ - // Gear = _strategy.InitGear(absTime, dt, outTorque, outAngularVelocity); - //} - if (Disengaged && !outAngularVelocity.IsEqual(0)) { - Disengaged = false; - var lastGear = Gear; - Gear = DataBus.VehicleStopped - ? _strategy.InitGear(absTime, dt, outTorque, outAngularVelocity) - : _strategy.Engage(absTime, dt, outTorque, outAngularVelocity); - if (!DataBus.VehicleStopped) { - if (Gear > lastGear) { - LastUpshift = absTime; - } - if (Gear < lastGear) { - LastDownshift = absTime; - } - } - Log.Debug("Gearbox engaged gear {0}", Gear); - } - - var inAngularVelocity = outAngularVelocity * ModelData.Gears[Gear].Ratio; - var avgInAngularVelocity = (PreviousState.InAngularVelocity + inAngularVelocity) / 2.0; - var avgOutAngularVelocity = (PreviousState.OutAngularVelocity + outAngularVelocity) / 2.0; - var inTorqueLossResult = ModelData.Gears[Gear].LossMap.GetTorqueLoss(avgOutAngularVelocity, outTorque); - var inTorque = !avgInAngularVelocity.IsEqual(0) - ? outTorque * (avgOutAngularVelocity / avgInAngularVelocity) - : outTorque / ModelData.Gears[Gear].Ratio; - inTorque += inTorqueLossResult.Value; - - var inertiaTorqueLossOut = !inAngularVelocity.IsEqual(0) - ? Formulas.InertiaPower(outAngularVelocity, PreviousState.OutAngularVelocity, ModelData.Inertia, dt) / - avgOutAngularVelocity - : 0.SI<NewtonMeter>(); - inTorque += inertiaTorqueLossOut / ModelData.Gears[Gear].Ratio; - - if (dryRun) { - var inertiaTorqueLossIn = avgOutAngularVelocity.IsEqual(0, 1e-9) - ? 0.SI<NewtonMeter>() - : Formulas.InertiaPower(outAngularVelocity, PreviousState.OutAngularVelocity, ModelData.Inertia, dt) / - avgOutAngularVelocity / ModelData.Gears[Gear].Ratio; - var dryRunResponse = NextComponent.Request(absTime, dt, inTorque + inertiaTorqueLossIn, inAngularVelocity, true); - dryRunResponse.GearboxPowerRequest = outTorque * (PreviousState.OutAngularVelocity + outAngularVelocity) / 2.0; - return dryRunResponse; - } - - var response = NextComponent.Request(absTime, dt, inTorque, inAngularVelocity); - var shiftAllowed = !inAngularVelocity.IsEqual(0) && !DataBus.VehicleSpeed.IsEqual(0); - - if (response is ResponseSuccess && shiftAllowed) { - var shiftRequired = _strategy.ShiftRequired(absTime, dt, outTorque, outAngularVelocity, inTorque, - response.EngineSpeed, Gear, _engageTime); - - if (shiftRequired) { - _engageTime = absTime + ModelData.TractionInterruption; - - Log.Debug("Gearbox is shifting. absTime: {0}, dt: {1}, interuptionTime: {2}, out: ({3}, {4}), in: ({5}, {6})", - absTime, - dt, _engageTime, outTorque, outAngularVelocity, inTorque, inAngularVelocity); - - Disengaged = true; - _strategy.Disengage(absTime, dt, outTorque, outAngularVelocity); - Log.Info("Gearbox disengaged"); - - return new ResponseGearShift { - Source = this, - SimulationInterval = ModelData.TractionInterruption, - GearboxPowerRequest = outTorque * (PreviousState.OutAngularVelocity + outAngularVelocity) / 2.0 - }; - } - } - - // this code has to be _after_ the check for a potential gear-shift! - // (the above block issues dry-run requests and thus may update the CurrentState!) - // begin critical section - CurrentState.TransmissionTorqueLoss = inTorque * ModelData.Gears[Gear].Ratio - outTorque; - // MQ 19.2.2016: check! inertia is related to output side, torque loss accounts to input side - CurrentState.InertiaTorqueLossOut = inertiaTorqueLossOut; - - - CurrentState.TorqueLossResult = inTorqueLossResult; - CurrentState.SetState(inTorque, inAngularVelocity, outTorque, outAngularVelocity); - CurrentState.Gear = Gear; - // end critical section - - - response.GearboxPowerRequest = outTorque * (PreviousState.OutAngularVelocity + CurrentState.OutAngularVelocity) / 2.0; - - return response; - } - - protected override void DoWriteModalResults(IModalDataContainer container) - { - var avgInAngularSpeed = (PreviousState.InAngularVelocity + CurrentState.InAngularVelocity) / 2.0; - var avgOutAngularSpeed = (PreviousState.OutAngularVelocity + CurrentState.OutAngularVelocity) / 2.0; - // (PreviousState.OutAngularVelocity + - //CurrentState.OutAngularVelocity) / 2.0 * ModelData.Gears[Gear].Ratio; - var inPower = CurrentState.InTorque * avgInAngularSpeed; - var outPower = CurrentState.OutTorque * avgOutAngularSpeed; - container[ModalResultField.Gear] = Disengaged || DataBus.VehicleStopped ? 0 : Gear; - container[ModalResultField.P_gbx_loss] = inPower - outPower; - //CurrentState.TransmissionTorqueLoss * avgOutAngularSpeed; - container[ModalResultField.P_gbx_inertia] = CurrentState.InertiaTorqueLossOut * avgOutAngularSpeed; - container[ModalResultField.P_gbx_in] = inPower; - container[ModalResultField.n_gbx_out_avg] = (PreviousState.OutAngularVelocity + - CurrentState.OutAngularVelocity) / 2.0; - container[ModalResultField.T_gbx_out] = CurrentState.OutTorque; - } - - protected override void DoCommitSimulationStep() - { - if (!Disengaged) { - if (CurrentState.TorqueLossResult != null && CurrentState.TorqueLossResult.Extrapolated) { - Log.Warn( - "Gear {0} LossMap data was extrapolated: range for loss map is not sufficient: n:{1}, torque:{2}, ratio:{3}", - Gear, CurrentState.OutAngularVelocity.ConvertTo().Rounds.Per.Minute, CurrentState.OutTorque, - ModelData.Gears[Gear].Ratio); - if (DataBus.ExecutionMode == ExecutionMode.Declaration) { - throw new VectoException( - "Gear {0} LossMap data was extrapolated in Declaration Mode: range for loss map is not sufficient: n:{1}, torque:{2}, ratio:{3}", - Gear, CurrentState.InAngularVelocity.ConvertTo().Rounds.Per.Minute, CurrentState.InTorque, - ModelData.Gears[Gear].Ratio); - } - } - } - if (DataBus.VehicleStopped) { - Disengaged = true; - _engageTime = -double.MaxValue.SI<Second>(); - } - base.DoCommitSimulationStep(); - } - } +using TUGraz.VectoCommon.Exceptions; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Configuration; +using TUGraz.VectoCore.Models.Connector.Ports.Impl; +using TUGraz.VectoCore.Models.Simulation; +using TUGraz.VectoCore.Models.Simulation.Data; +using TUGraz.VectoCore.Models.Simulation.DataBus; +using TUGraz.VectoCore.OutputData; +using TUGraz.VectoCore.Utils; + +namespace TUGraz.VectoCore.Models.SimulationComponent.Impl +{ + public class Gearbox : AbstractGearbox<GearboxState> + { + /// <summary> + /// The shift strategy. + /// </summary> + private readonly IShiftStrategy _strategy; + + /// <summary> + /// Time when a gearbox shift engages a new gear (shift is finished). Is set when shifting is needed. + /// </summary> + private Second _engageTime = 0.SI<Second>(); + + /// <summary> + /// True if gearbox is disengaged (no gear is set). + /// </summary> + protected internal bool Disengaged = true; + + public Second LastUpshift { get; protected internal set; } + + public Second LastDownshift { get; protected internal set; } + + public override GearInfo NextGear + { + get { return _strategy.NextGear; } + } + + public override bool ClutchClosed(Second absTime) + { + return _engageTime.IsSmallerOrEqual(absTime); + } + + public Gearbox(IVehicleContainer container, IShiftStrategy strategy, VectoRunData runData) : base(container, runData) + { + _strategy = strategy; + _strategy.Gearbox = this; + + LastDownshift = -double.MaxValue.SI<Second>(); + LastUpshift = -double.MaxValue.SI<Second>(); + } + + public override IResponse Initialize(NewtonMeter outTorque, PerSecond outAngularVelocity) + { + var absTime = 0.SI<Second>(); + var dt = Constants.SimulationSettings.TargetTimeInterval; + + _engageTime = -double.MaxValue.SI<Second>(); + + if (Disengaged) { + Gear = _strategy.InitGear(absTime, dt, outTorque, outAngularVelocity); + } + + var inAngularVelocity = outAngularVelocity * ModelData.Gears[Gear].Ratio; + var gearboxTorqueLoss = ModelData.Gears[Gear].LossMap.GetTorqueLoss(outAngularVelocity, outTorque); + CurrentState.TorqueLossResult = gearboxTorqueLoss; + + var inTorque = outTorque / ModelData.Gears[Gear].Ratio + + gearboxTorqueLoss.Value; + + PreviousState.SetState(inTorque, inAngularVelocity, outTorque, outAngularVelocity); + PreviousState.InertiaTorqueLossOut = 0.SI<NewtonMeter>(); + PreviousState.Gear = Gear; + Disengaged = false; + + var response = NextComponent.Initialize(inTorque, inAngularVelocity); + + return response; + } + + internal ResponseDryRun Initialize(uint gear, NewtonMeter outTorque, PerSecond outAngularVelocity) + { + var oldGear = Gear; + Gear = gear; + var inAngularVelocity = outAngularVelocity * ModelData.Gears[gear].Ratio; + var torqueLossResult = ModelData.Gears[gear].LossMap.GetTorqueLoss(outAngularVelocity, outTorque); + CurrentState.TorqueLossResult = torqueLossResult; + var inTorque = outTorque / ModelData.Gears[gear].Ratio + torqueLossResult.Value; + + if (!inAngularVelocity.IsEqual(0)) { + var alpha = ModelData.Inertia.IsEqual(0) + ? 0.SI<PerSquareSecond>() + : outTorque / ModelData.Inertia; + + var inertiaPowerLoss = Formulas.InertiaPower(inAngularVelocity, alpha, ModelData.Inertia, + Constants.SimulationSettings.TargetTimeInterval); + inTorque += inertiaPowerLoss / inAngularVelocity; + } + + var response = + (ResponseDryRun) + NextComponent.Request(0.SI<Second>(), Constants.SimulationSettings.TargetTimeInterval, inTorque, + inAngularVelocity, true); //NextComponent.Initialize(inTorque, inAngularVelocity); + //response.Switch(). + // Case<ResponseSuccess>(). + // Case<ResponseOverload>(). + // Case<ResponseUnderload>(). + // Default(r => { throw new UnexpectedResponseException("Gearbox.Initialize", r); }); + + var fullLoad = DataBus.EngineStationaryFullPower(inAngularVelocity); + + Gear = oldGear; + return new ResponseDryRun { + Source = this, + EnginePowerRequest = response.EnginePowerRequest, + EngineSpeed = response.EngineSpeed, + DynamicFullLoadPower = response.DynamicFullLoadPower, + ClutchPowerRequest = response.ClutchPowerRequest, + GearboxPowerRequest = outTorque * outAngularVelocity, + DeltaFullLoad = response.EnginePowerRequest - fullLoad + }; + } + + /// <summary> + /// Requests the Gearbox to deliver torque and angularVelocity + /// </summary> + /// <returns> + /// <list type="bullet"> + /// <item><description>ResponseDryRun</description></item> + /// <item><description>ResponseOverload</description></item> + /// <item><description>ResponseGearshift</description></item> + /// </list> + /// </returns> + public override IResponse Request(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, + bool dryRun = false) + { + IterationStatistics.Increment(this, "Requests"); + + Log.Debug("Gearbox Power Request: torque: {0}, angularVelocity: {1}", outTorque, outAngularVelocity); + if (DataBus.VehicleStopped) { + _engageTime = absTime; + LastDownshift = -double.MaxValue.SI<Second>(); + LastUpshift = -double.MaxValue.SI<Second>(); + } + if (DataBus.DriverBehavior == DrivingBehavior.Halted) { + _engageTime = absTime + dt; + } + + if (DataBus.DriverBehavior == DrivingBehavior.Braking && (DataBus.BrakePower.IsGreater(0) || outTorque < 0) && + DataBus.VehicleSpeed.IsSmaller(Constants.SimulationSettings.ClutchDisengageWhenHaltingSpeed)) { + _engageTime = VectoMath.Max(_engageTime, absTime + dt); + + return RequestGearDisengaged(absTime, dt, outTorque, outAngularVelocity, dryRun); + } + + return ClutchClosed(absTime) + ? RequestGearEngaged(absTime, dt, outTorque, outAngularVelocity, dryRun) + : RequestGearDisengaged(absTime, dt, outTorque, outAngularVelocity, dryRun); + } + + /// <summary> + /// Requests the Gearbox in Disengaged mode + /// </summary> + /// <returns> + /// <list type="bullet"> + /// <item><term>ResponseDryRun</term><description>if dryRun, immediate return!</description></item> + /// <item><term>ResponseFailTimeInterval</term><description>if shiftTime would be exceeded by current step</description></item> + /// <item><term>ResponseOverload</term><description>if torque > 0</description></item> + /// <item><term>ResponseUnderload</term><description>if torque < 0</description></item> + /// <item><term>else</term><description>Response from NextComponent</description></item> + /// </list> + /// </returns> + private IResponse RequestGearDisengaged(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, + bool dryRun) + { + Disengaged = true; + Log.Debug("Current Gear: Neutral"); + + var avgAngularVelocity = (PreviousState.OutAngularVelocity + outAngularVelocity) / 2.0; + + var gear = NextGear.Gear; + + var avgOutAngularVelocity = (PreviousState.OutAngularVelocity + outAngularVelocity) / 2.0; + var inTorqueLossResult = ModelData.Gears[gear].LossMap.GetTorqueLoss(avgOutAngularVelocity, outTorque); + var inTorque = outTorque / ModelData.Gears[gear].Ratio + inTorqueLossResult.Value; + + var inAngularVelocity = outAngularVelocity * ModelData.Gears[gear].Ratio; + var inertiaTorqueLossOut = !inAngularVelocity.IsEqual(0) + ? Formulas.InertiaPower(outAngularVelocity, PreviousState.OutAngularVelocity, ModelData.Inertia, dt) / + avgOutAngularVelocity + : 0.SI<NewtonMeter>(); + inTorque += inertiaTorqueLossOut / ModelData.Gears[gear].Ratio; + var avgInAngularVelocity = (PreviousState.InAngularVelocity + inAngularVelocity) / 2.0; + + if (dryRun) { + // if gearbox is disengaged the 0[W]-line is the limit for drag and full load. + var delta = inTorque * avgInAngularVelocity; + return new ResponseDryRun { + Source = this, + GearboxPowerRequest = delta, + DeltaDragLoad = delta, + DeltaFullLoad = delta, + }; + } + + var shiftTimeExceeded = absTime.IsSmaller(_engageTime) && + _engageTime.IsSmaller(absTime + dt, Constants.SimulationSettings.LowerBoundTimeInterval); + // allow 5% tolerance of shift time + if (shiftTimeExceeded && _engageTime - absTime > Constants.SimulationSettings.LowerBoundTimeInterval / 2) { + return new ResponseFailTimeInterval { + Source = this, + DeltaT = _engageTime - absTime, + GearboxPowerRequest = outTorque * (PreviousState.OutAngularVelocity + outAngularVelocity) / 2.0 + }; + } + + if ((inTorque * avgInAngularVelocity).IsGreater(0.SI<Watt>(), Constants.SimulationSettings.LineSearchTolerance)) { + return new ResponseOverload { + Source = this, + Delta = inTorque * avgInAngularVelocity, + GearboxPowerRequest = inTorque * avgInAngularVelocity + }; + } + + if ((inTorque * avgInAngularVelocity).IsSmaller(0.SI<Watt>(), Constants.SimulationSettings.LineSearchTolerance)) { + return new ResponseUnderload { + Source = this, + Delta = inTorque * avgInAngularVelocity, + GearboxPowerRequest = inTorque * avgInAngularVelocity + }; + } + + //var inTorque = 0.SI<NewtonMeter>(); + if (avgInAngularVelocity.Equals(0.SI<PerSecond>())) { + inTorque = 0.SI<NewtonMeter>(); + } + + CurrentState.SetState(inTorque, inAngularVelocity, outTorque, + outAngularVelocity); + CurrentState.Gear = gear; + CurrentState.TransmissionTorqueLoss = inTorque * ModelData.Gears[gear].Ratio - outTorque; + + var response = NextComponent.Request(absTime, dt, 0.SI<NewtonMeter>(), inAngularVelocity); + + //CurrentState.InAngularVelocity = response.EngineSpeed; + + response.GearboxPowerRequest = outTorque * avgAngularVelocity; + + return response; + } + + /// <summary> + /// Requests the gearbox in engaged mode. Sets the gear if no gear was set previously. + /// </summary> + /// <returns> + /// <list type="bullet"> + /// <item><term>ResponseGearShift</term><description>if a shift is needed.</description></item> + /// <item><term>else</term><description>Response from NextComponent.</description></item> + /// </list> + /// </returns> + private IResponse RequestGearEngaged(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, + bool dryRun) + { + // Set a Gear if no gear was set and engineSpeed is not zero + //if (!Disengaged && DataBus.VehicleStopped && !outAngularVelocity.IsEqual(0)) + //{ + // Gear = _strategy.InitGear(absTime, dt, outTorque, outAngularVelocity); + //} + if (Disengaged && !outAngularVelocity.IsEqual(0)) { + ReEngageGear(absTime, dt, outTorque, outAngularVelocity); + Log.Debug("Gearbox engaged gear {0}", Gear); + } + + var inAngularVelocity = outAngularVelocity * ModelData.Gears[Gear].Ratio; + var avgInAngularVelocity = (PreviousState.InAngularVelocity + inAngularVelocity) / 2.0; + var avgOutAngularVelocity = (PreviousState.OutAngularVelocity + outAngularVelocity) / 2.0; + var inTorqueLossResult = ModelData.Gears[Gear].LossMap.GetTorqueLoss(avgOutAngularVelocity, outTorque); + var inTorque = !avgInAngularVelocity.IsEqual(0) + ? outTorque * (avgOutAngularVelocity / avgInAngularVelocity) + : outTorque / ModelData.Gears[Gear].Ratio; + inTorque += inTorqueLossResult.Value; + + var inertiaTorqueLossOut = !inAngularVelocity.IsEqual(0) + ? Formulas.InertiaPower(outAngularVelocity, PreviousState.OutAngularVelocity, ModelData.Inertia, dt) / + avgOutAngularVelocity + : 0.SI<NewtonMeter>(); + inTorque += inertiaTorqueLossOut / ModelData.Gears[Gear].Ratio; + + if (dryRun) { + var inertiaTorqueLossIn = avgOutAngularVelocity.IsEqual(0, 1e-9) + ? 0.SI<NewtonMeter>() + : Formulas.InertiaPower(outAngularVelocity, PreviousState.OutAngularVelocity, ModelData.Inertia, dt) / + avgOutAngularVelocity / ModelData.Gears[Gear].Ratio; + var dryRunResponse = NextComponent.Request(absTime, dt, inTorque + inertiaTorqueLossIn, inAngularVelocity, true); + dryRunResponse.GearboxPowerRequest = outTorque * (PreviousState.OutAngularVelocity + outAngularVelocity) / 2.0; + return dryRunResponse; + } + + var response = NextComponent.Request(absTime, dt, inTorque, inAngularVelocity); + var shiftAllowed = !inAngularVelocity.IsEqual(0) && !DataBus.VehicleSpeed.IsEqual(0); + + if (response is ResponseSuccess && shiftAllowed) { + var shiftRequired = _strategy.ShiftRequired(absTime, dt, outTorque, outAngularVelocity, inTorque, + response.EngineSpeed, Gear, _engageTime); + + if (shiftRequired) { + _engageTime = absTime + ModelData.TractionInterruption; + + Log.Debug("Gearbox is shifting. absTime: {0}, dt: {1}, interuptionTime: {2}, out: ({3}, {4}), in: ({5}, {6})", + absTime, + dt, _engageTime, outTorque, outAngularVelocity, inTorque, inAngularVelocity); + + Disengaged = true; + _strategy.Disengage(absTime, dt, outTorque, outAngularVelocity); + Log.Info("Gearbox disengaged"); + + return new ResponseGearShift { + Source = this, + SimulationInterval = ModelData.TractionInterruption, + GearboxPowerRequest = outTorque * (PreviousState.OutAngularVelocity + outAngularVelocity) / 2.0 + }; + } + } + + // this code has to be _after_ the check for a potential gear-shift! + // (the above block issues dry-run requests and thus may update the CurrentState!) + // begin critical section + CurrentState.TransmissionTorqueLoss = inTorque * ModelData.Gears[Gear].Ratio - outTorque; + // MQ 19.2.2016: check! inertia is related to output side, torque loss accounts to input side + CurrentState.InertiaTorqueLossOut = inertiaTorqueLossOut; + + + CurrentState.TorqueLossResult = inTorqueLossResult; + CurrentState.SetState(inTorque, inAngularVelocity, outTorque, outAngularVelocity); + CurrentState.Gear = Gear; + // end critical section + + + response.GearboxPowerRequest = outTorque * (PreviousState.OutAngularVelocity + CurrentState.OutAngularVelocity) / 2.0; + + return response; + } + + private void ReEngageGear(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity) + { + Disengaged = false; + var lastGear = Gear; + Gear = DataBus.VehicleStopped + ? _strategy.InitGear(absTime, dt, outTorque, outAngularVelocity) + : _strategy.Engage(absTime, dt, outTorque, outAngularVelocity); + if (!DataBus.VehicleStopped) { + if (Gear > lastGear) { + LastUpshift = absTime; + } + if (Gear < lastGear) { + LastDownshift = absTime; + } + } + } + + protected override void DoWriteModalResults(IModalDataContainer container) + { + var avgInAngularSpeed = (PreviousState.InAngularVelocity + CurrentState.InAngularVelocity) / 2.0; + var avgOutAngularSpeed = (PreviousState.OutAngularVelocity + CurrentState.OutAngularVelocity) / 2.0; + // (PreviousState.OutAngularVelocity + + //CurrentState.OutAngularVelocity) / 2.0 * ModelData.Gears[Gear].Ratio; + var inPower = CurrentState.InTorque * avgInAngularSpeed; + var outPower = CurrentState.OutTorque * avgOutAngularSpeed; + container[ModalResultField.Gear] = Disengaged || DataBus.VehicleStopped ? 0 : Gear; + container[ModalResultField.P_gbx_loss] = inPower - outPower; + //CurrentState.TransmissionTorqueLoss * avgOutAngularSpeed; + container[ModalResultField.P_gbx_inertia] = CurrentState.InertiaTorqueLossOut * avgOutAngularSpeed; + container[ModalResultField.P_gbx_in] = inPower; + container[ModalResultField.n_gbx_out_avg] = (PreviousState.OutAngularVelocity + + CurrentState.OutAngularVelocity) / 2.0; + container[ModalResultField.T_gbx_out] = CurrentState.OutTorque; + } + + protected override void DoCommitSimulationStep() + { + if (!Disengaged) { + if (CurrentState.TorqueLossResult != null && CurrentState.TorqueLossResult.Extrapolated) { + Log.Warn( + "Gear {0} LossMap data was extrapolated: range for loss map is not sufficient: n:{1}, torque:{2}, ratio:{3}", + Gear, CurrentState.OutAngularVelocity.ConvertTo().Rounds.Per.Minute, CurrentState.OutTorque, + ModelData.Gears[Gear].Ratio); + if (DataBus.ExecutionMode == ExecutionMode.Declaration) { + throw new VectoException( + "Gear {0} LossMap data was extrapolated in Declaration Mode: range for loss map is not sufficient: n:{1}, torque:{2}, ratio:{3}", + Gear, CurrentState.InAngularVelocity.ConvertTo().Rounds.Per.Minute, CurrentState.InTorque, + ModelData.Gears[Gear].Ratio); + } + } + } + if (DataBus.VehicleStopped) { + Disengaged = true; + _engageTime = -double.MaxValue.SI<Second>(); + } + base.DoCommitSimulationStep(); + } + } } \ 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 8a5db4a93a..0e5eb487fa 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/TorqueConverter.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/TorqueConverter.cs @@ -29,265 +29,270 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System.Collections.Generic; -using TUGraz.VectoCommon.Exceptions; -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.Configuration; -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.Simulation.DataBus; -using TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox; -using TUGraz.VectoCore.OutputData; - -namespace TUGraz.VectoCore.Models.SimulationComponent.Impl -{ - public class TorqueConverter : StatefulVectoSimulationComponent<TorqueConverter.TorqueConverterComponentState>, - ITnInPort, ITnOutPort - { - protected readonly IGearboxInfo Gearbox; - protected readonly IShiftStrategy ShiftStrategy; - protected readonly TorqueConverterData ModelData; - private readonly KilogramSquareMeter _engineInertia; - - public ITnOutPort NextComponent { protected internal get; set; } - - public TorqueConverter(IGearboxInfo gearbox, IShiftStrategy shiftStrategy, IVehicleContainer container, - TorqueConverterData tcData, VectoRunData runData) : base(container) - { - Gearbox = gearbox; - ShiftStrategy = shiftStrategy; - ModelData = tcData; - _engineInertia = runData != null && runData.EngineData != null - ? runData.EngineData.Inertia - : 0.SI<KilogramSquareMeter>(); - } - - public void Connect(ITnOutPort other) - { - NextComponent = other; - } - - public IResponse Initialize(NewtonMeter outTorque, PerSecond outAngularVelocity) - { - var operatingPointList = ModelData.FindOperatingPoint(outTorque, outAngularVelocity, DataBus.EngineIdleSpeed); - TorqueConverterOperatingPoint operatingPoint; - if (operatingPointList.Count > 0) { - operatingPoint = SelectOperatingPoint(operatingPointList); - } else { - Log.Warn( - "TorqueConverter Initialize: No operating point found. Using output as input values as fallback for initialize."); - var inAngularVelocity = outAngularVelocity.LimitTo(DataBus.EngineIdleSpeed, DataBus.EngineN95hSpeed); - operatingPoint = new TorqueConverterOperatingPoint { - OutAngularVelocity = outAngularVelocity, - OutTorque = outTorque, - InAngularVelocity = inAngularVelocity, - InTorque = outTorque * (outAngularVelocity / inAngularVelocity) - }; - } - var retVal = NextComponent.Initialize(operatingPoint.InTorque, operatingPoint.InAngularVelocity); - PreviousState.SetState(operatingPoint.InTorque, operatingPoint.InAngularVelocity, operatingPoint.OutTorque, - operatingPoint.OutAngularVelocity); - return retVal; - } - - public IResponse Request(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, - bool dryRun = false) - { - var operatingPoint = FindOperatingPoint(outTorque, outAngularVelocity); - var avgEngineSpeed = (PreviousState.InAngularVelocity + operatingPoint.InAngularVelocity) / 2; - var avgPower = (PreviousState.InAngularVelocity * PreviousState.InTorque + - operatingPoint.InAngularVelocity * operatingPoint.InTorque) / 2; - var inTorque = avgPower / avgEngineSpeed; - - if (dryRun) { - // dry run request - var engineResponse = (ResponseDryRun) - NextComponent.Request(absTime, dt, inTorque, operatingPoint.InAngularVelocity, true); - - var engineOK = engineResponse.DeltaDragLoad.IsGreaterOrEqual(0) && engineResponse.DeltaFullLoad.IsSmallerOrEqual(0); - if (DataBus.DriverBehavior != DrivingBehavior.Braking && engineOK && operatingPoint.Creeping) { - var delta = (outTorque - operatingPoint.OutTorque) * - (PreviousState.OutAngularVelocity + operatingPoint.OutAngularVelocity) / 2.0; - return new ResponseDryRun() { - Source = this, - DeltaFullLoad = delta, - DeltaDragLoad = delta, - TorqueConverterOperatingPoint = operatingPoint - }; - } - - var dryOperatingPointMax = GetMaxPowerOperatingPoint(dt, outAngularVelocity, engineResponse, - PreviousState.InTorque * PreviousState.InAngularVelocity); - var avgOutSpeedMax = (PreviousState.OutAngularVelocity + dryOperatingPointMax.OutAngularVelocity) / 2.0; - var deltaMax = (outTorque - dryOperatingPointMax.OutTorque) * avgOutSpeedMax; - - var dryOperatingPointMin = GetDragPowerOperatingPoint(dt, outAngularVelocity, engineResponse, - PreviousState.InTorque * PreviousState.InAngularVelocity); - var avgOutSpeedMin = (PreviousState.OutAngularVelocity + dryOperatingPointMin.OutAngularVelocity) / 2.0; - var deltaMin = (outTorque - dryOperatingPointMin.OutTorque) * avgOutSpeedMin; - - return new ResponseDryRun { - Source = this, - DeltaFullLoad = 2 * deltaMax, - DeltaDragLoad = 2 * deltaMin, - TorqueConverterOperatingPoint = dryOperatingPointMax - }; - } - - // normal request - - // check if out-side of the operating point is equal to requested values - if (!outAngularVelocity.IsEqual(operatingPoint.OutAngularVelocity) || !outTorque.IsEqual(operatingPoint.OutTorque)) { - var delta = (outTorque - operatingPoint.OutTorque) * - (PreviousState.OutAngularVelocity + operatingPoint.OutAngularVelocity) / 2.0; - if (!delta.IsEqual(0, Constants.SimulationSettings.LineSearchTolerance)) { - if (delta > 0) { - return new ResponseOverload { Source = this, Delta = delta, TorqueConverterOperatingPoint = operatingPoint }; - } else { - return new ResponseUnderload { Source = this, Delta = delta, TorqueConverterOperatingPoint = operatingPoint }; - } - } - } - - CurrentState.SetState(inTorque, operatingPoint.InAngularVelocity, outTorque, outAngularVelocity); - CurrentState.OperatingPoint = operatingPoint; - - var retVal = NextComponent.Request(absTime, dt, inTorque, operatingPoint.InAngularVelocity); - - // check if shift is required - var ratio = Gearbox.GetGearData(Gearbox.Gear).TorqueConverterRatio; - if (retVal is ResponseSuccess && - ShiftStrategy.ShiftRequired(absTime, dt, outTorque * ratio, outAngularVelocity / ratio, inTorque, - operatingPoint.InAngularVelocity, Gearbox.Gear, Gearbox.LastShift)) { - return new ResponseGearShift { Source = this }; - } - return retVal; - } - - private TorqueConverterOperatingPoint GetDragPowerOperatingPoint(Second dt, PerSecond outAngularVelocity, - ResponseDryRun engineResponse, Watt previousPower) - { - try { - var operatingPoint = ModelData.FindOperatingPointForPowerDemand( - engineResponse.DragPower - engineResponse.AuxiliariesPowerDemand, - DataBus.EngineSpeed, outAngularVelocity, _engineInertia, dt, previousPower); - var maxInputSpeed = VectoMath.Min(ModelData.TorqueConverterSpeedLimit, DataBus.EngineRatedSpeed); - if (operatingPoint.InAngularVelocity.IsGreater(maxInputSpeed)) { - operatingPoint = ModelData.FindOperatingPoint(maxInputSpeed, outAngularVelocity); - } - if (operatingPoint.InAngularVelocity.IsSmaller(DataBus.EngineIdleSpeed)) { - operatingPoint = ModelData.FindOperatingPoint(DataBus.EngineIdleSpeed, outAngularVelocity); - } - return operatingPoint; - } catch (VectoException ve) { - Log.Error(ve, "TorqueConverter: Failed to find operating point for DragPower {0}", engineResponse.DragPower); - var retVal = ModelData.FindOperatingPoint(engineResponse.EngineSpeed, outAngularVelocity); - retVal.Creeping = true; - return retVal; - } - } - - private TorqueConverterOperatingPoint GetMaxPowerOperatingPoint(Second dt, PerSecond outAngularVelocity, - ResponseDryRun engineResponse, Watt previousPower) - { - try { - var operatingPoint = ModelData.FindOperatingPointForPowerDemand( - engineResponse.DynamicFullLoadPower - engineResponse.AuxiliariesPowerDemand, - DataBus.EngineSpeed, outAngularVelocity, _engineInertia, dt, previousPower); - var maxInputSpeed = VectoMath.Min(ModelData.TorqueConverterSpeedLimit, DataBus.EngineRatedSpeed); - if (operatingPoint.InAngularVelocity.IsGreater(maxInputSpeed)) { - operatingPoint = ModelData.FindOperatingPoint(maxInputSpeed, outAngularVelocity); - } - return operatingPoint; - } catch (VectoException ve) { - Log.Error(ve, "TorqueConverter: Failed to find operating point for MaxPower {0}", - engineResponse.DynamicFullLoadPower); - var tqOperatingPoint = ModelData.FindOperatingPoint(DataBus.EngineIdleSpeed, outAngularVelocity); - tqOperatingPoint.Creeping = true; - return tqOperatingPoint; - } - } - - protected internal TorqueConverterOperatingPoint FindOperatingPoint(NewtonMeter outTorque, - PerSecond outAngularVelocity) - { - var operatingPointList = ModelData.FindOperatingPoint(outTorque, outAngularVelocity, DataBus.EngineIdleSpeed); - if (operatingPointList.Count == 0) { - Log.Debug("TorqueConverter: Failed to find torque converter operating point, fallback: creeping"); - var tqOperatingPoint = ModelData.FindOperatingPoint(DataBus.EngineIdleSpeed, outAngularVelocity); - tqOperatingPoint.Creeping = true; - return tqOperatingPoint; - } - - var operatingPoint = SelectOperatingPoint(operatingPointList); - if (operatingPoint.InAngularVelocity.IsSmaller(DataBus.EngineIdleSpeed)) { - throw new VectoException( - "TorqueConverter: Invalid operating point, inAngularVelocity would be below engine's idle speed: {0}", - operatingPoint.InAngularVelocity); - } - var maxInputSpeed = VectoMath.Min(ModelData.TorqueConverterSpeedLimit, DataBus.EngineRatedSpeed); - if (operatingPoint.InAngularVelocity.IsGreater(maxInputSpeed)) { - operatingPoint = ModelData.FindOperatingPoint(maxInputSpeed, outAngularVelocity); - } - return operatingPoint; - } - - private TorqueConverterOperatingPoint SelectOperatingPoint(IList<TorqueConverterOperatingPoint> operatingPointList) - { - if (operatingPointList.Count == 1) { - return operatingPointList[0]; - } - - foreach (var x in operatingPointList) { - if ((x.InTorque * x.InAngularVelocity).IsSmallerOrEqual(DataBus.EngineStationaryFullPower(x.InAngularVelocity), - Constants.SimulationSettings.LineSearchTolerance.SI<Watt>()) && - (x.InTorque * x.InAngularVelocity).IsGreaterOrEqual(DataBus.EngineDragPower(x.InAngularVelocity), - Constants.SimulationSettings.LineSearchTolerance.SI<Watt>())) { - return x; - } - } - - return operatingPointList[0]; - } - - protected override void DoWriteModalResults(IModalDataContainer container) - { - if (CurrentState.OperatingPoint == null) { - container[ModalResultField.TorqueConverterTorqueRatio] = 1.0; - container[ModalResultField.TorqueConverterSpeedRatio] = 1.0; - } else { - container[ModalResultField.TorqueConverterTorqueRatio] = CurrentState.OperatingPoint.TorqueRatio; - container[ModalResultField.TorqueConverterSpeedRatio] = CurrentState.OperatingPoint.SpeedRatio; - } - container[ModalResultField.TC_TorqueIn] = CurrentState.InTorque; - container[ModalResultField.TC_TorqueOut] = CurrentState.OutTorque; - container[ModalResultField.TC_angularSpeedIn] = CurrentState.InAngularVelocity; - container[ModalResultField.TC_angularSpeedOut] = CurrentState.OutAngularVelocity; - - var avgOutVelocity = (PreviousState.OutAngularVelocity + CurrentState.OutAngularVelocity) / 2.0; - var avgInVelocity = (PreviousState.InAngularVelocity + CurrentState.InAngularVelocity) / 2.0; - container[ModalResultField.P_TC_out] = CurrentState.OutTorque * avgOutVelocity; - container[ModalResultField.P_TC_loss] = CurrentState.InTorque * avgInVelocity - - CurrentState.OutTorque * avgOutVelocity; - } - - protected override void DoCommitSimulationStep() - { - AdvanceState(); - } - - public void Locked(NewtonMeter inTorque, PerSecond inAngularVelocity, NewtonMeter outTorque, - PerSecond outAngularVelocity) - { - CurrentState.SetState(inTorque, inAngularVelocity, outTorque, outAngularVelocity); - } - - public class TorqueConverterComponentState : SimpleComponentState - { - public TorqueConverterOperatingPoint OperatingPoint; - } - } +using System.Collections.Generic; +using TUGraz.VectoCommon.Exceptions; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Configuration; +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.Simulation.DataBus; +using TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox; +using TUGraz.VectoCore.OutputData; + +namespace TUGraz.VectoCore.Models.SimulationComponent.Impl +{ + public class TorqueConverter : StatefulVectoSimulationComponent<TorqueConverter.TorqueConverterComponentState>, + ITnInPort, ITnOutPort + { + protected readonly IGearboxInfo Gearbox; + protected readonly IShiftStrategy ShiftStrategy; + protected readonly TorqueConverterData ModelData; + private readonly KilogramSquareMeter _engineInertia; + + public ITnOutPort NextComponent { protected internal get; set; } + + public TorqueConverter(IGearboxInfo gearbox, IShiftStrategy shiftStrategy, IVehicleContainer container, + TorqueConverterData tcData, VectoRunData runData) : base(container) + { + Gearbox = gearbox; + ShiftStrategy = shiftStrategy; + ModelData = tcData; + _engineInertia = runData != null && runData.EngineData != null + ? runData.EngineData.Inertia + : 0.SI<KilogramSquareMeter>(); + } + + public void Connect(ITnOutPort other) + { + NextComponent = other; + } + + public IResponse Initialize(NewtonMeter outTorque, PerSecond outAngularVelocity) + { + var operatingPointList = ModelData.FindOperatingPoint(outTorque, outAngularVelocity, DataBus.EngineIdleSpeed); + TorqueConverterOperatingPoint operatingPoint; + if (operatingPointList.Count > 0) { + operatingPoint = SelectOperatingPoint(operatingPointList); + } else { + Log.Warn( + "TorqueConverter Initialize: No operating point found. Using output as input values as fallback for initialize."); + var inAngularVelocity = outAngularVelocity.LimitTo(DataBus.EngineIdleSpeed, DataBus.EngineN95hSpeed); + operatingPoint = new TorqueConverterOperatingPoint { + OutAngularVelocity = outAngularVelocity, + OutTorque = outTorque, + InAngularVelocity = inAngularVelocity, + InTorque = outTorque * (outAngularVelocity / inAngularVelocity) + }; + } + var retVal = NextComponent.Initialize(operatingPoint.InTorque, operatingPoint.InAngularVelocity); + PreviousState.SetState(operatingPoint.InTorque, operatingPoint.InAngularVelocity, operatingPoint.OutTorque, + operatingPoint.OutAngularVelocity); + return retVal; + } + + public IResponse Request(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, + bool dryRun = false) + { + var operatingPoint = FindOperatingPoint(outTorque, outAngularVelocity); + var avgEngineSpeed = (PreviousState.InAngularVelocity + operatingPoint.InAngularVelocity) / 2; + var avgPower = (PreviousState.InAngularVelocity * PreviousState.InTorque + + operatingPoint.InAngularVelocity * operatingPoint.InTorque) / 2; + var inTorque = avgPower / avgEngineSpeed; + + if (dryRun) { + return HandleDryRun(absTime, dt, outTorque, outAngularVelocity, inTorque, operatingPoint); + } + + // normal request + + // check if out-side of the operating point is equal to requested values + if (!outAngularVelocity.IsEqual(operatingPoint.OutAngularVelocity) || !outTorque.IsEqual(operatingPoint.OutTorque)) { + var delta = (outTorque - operatingPoint.OutTorque) * + (PreviousState.OutAngularVelocity + operatingPoint.OutAngularVelocity) / 2.0; + if (!delta.IsEqual(0, Constants.SimulationSettings.LineSearchTolerance)) { + return delta > 0 + ? new ResponseOverload { Source = this, Delta = delta, TorqueConverterOperatingPoint = operatingPoint } + : (IResponse) + new ResponseUnderload { Source = this, Delta = delta, TorqueConverterOperatingPoint = operatingPoint }; + } + } + + CurrentState.SetState(inTorque, operatingPoint.InAngularVelocity, outTorque, outAngularVelocity); + CurrentState.OperatingPoint = operatingPoint; + + var retVal = NextComponent.Request(absTime, dt, inTorque, operatingPoint.InAngularVelocity); + + // check if shift is required + var ratio = Gearbox.GetGearData(Gearbox.Gear).TorqueConverterRatio; + if (retVal is ResponseSuccess && + ShiftStrategy.ShiftRequired(absTime, dt, outTorque * ratio, outAngularVelocity / ratio, inTorque, + operatingPoint.InAngularVelocity, Gearbox.Gear, Gearbox.LastShift)) { + return new ResponseGearShift { Source = this }; + } + return retVal; + } + + private IResponse HandleDryRun(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, + NewtonMeter inTorque, TorqueConverterOperatingPoint operatingPoint) + { +// dry run request + var engineResponse = (ResponseDryRun) + NextComponent.Request(absTime, dt, inTorque, operatingPoint.InAngularVelocity, true); + + var engineOK = engineResponse.DeltaDragLoad.IsGreaterOrEqual(0) && engineResponse.DeltaFullLoad.IsSmallerOrEqual(0); + if (DataBus.DriverBehavior != DrivingBehavior.Braking && engineOK && operatingPoint.Creeping) { + var delta = (outTorque - operatingPoint.OutTorque) * + (PreviousState.OutAngularVelocity + operatingPoint.OutAngularVelocity) / 2.0; + return new ResponseDryRun() { + Source = this, + DeltaFullLoad = delta, + DeltaDragLoad = delta, + TorqueConverterOperatingPoint = operatingPoint + }; + } + + var dryOperatingPointMax = GetMaxPowerOperatingPoint(dt, outAngularVelocity, engineResponse, + PreviousState.InTorque * PreviousState.InAngularVelocity); + var avgOutSpeedMax = (PreviousState.OutAngularVelocity + dryOperatingPointMax.OutAngularVelocity) / 2.0; + var deltaMax = (outTorque - dryOperatingPointMax.OutTorque) * avgOutSpeedMax; + + var dryOperatingPointMin = GetDragPowerOperatingPoint(dt, outAngularVelocity, engineResponse, + PreviousState.InTorque * PreviousState.InAngularVelocity); + var avgOutSpeedMin = (PreviousState.OutAngularVelocity + dryOperatingPointMin.OutAngularVelocity) / 2.0; + var deltaMin = (outTorque - dryOperatingPointMin.OutTorque) * avgOutSpeedMin; + + return new ResponseDryRun { + Source = this, + DeltaFullLoad = 2 * deltaMax, + DeltaDragLoad = 2 * deltaMin, + TorqueConverterOperatingPoint = dryOperatingPointMax + }; + } + + private TorqueConverterOperatingPoint GetDragPowerOperatingPoint(Second dt, PerSecond outAngularVelocity, + ResponseDryRun engineResponse, Watt previousPower) + { + try { + var operatingPoint = ModelData.FindOperatingPointForPowerDemand( + engineResponse.DragPower - engineResponse.AuxiliariesPowerDemand, + DataBus.EngineSpeed, outAngularVelocity, _engineInertia, dt, previousPower); + var maxInputSpeed = VectoMath.Min(ModelData.TorqueConverterSpeedLimit, DataBus.EngineRatedSpeed); + if (operatingPoint.InAngularVelocity.IsGreater(maxInputSpeed)) { + operatingPoint = ModelData.FindOperatingPoint(maxInputSpeed, outAngularVelocity); + } + if (operatingPoint.InAngularVelocity.IsSmaller(DataBus.EngineIdleSpeed)) { + operatingPoint = ModelData.FindOperatingPoint(DataBus.EngineIdleSpeed, outAngularVelocity); + } + return operatingPoint; + } catch (VectoException ve) { + Log.Error(ve, "TorqueConverter: Failed to find operating point for DragPower {0}", engineResponse.DragPower); + var retVal = ModelData.FindOperatingPoint(engineResponse.EngineSpeed, outAngularVelocity); + retVal.Creeping = true; + return retVal; + } + } + + private TorqueConverterOperatingPoint GetMaxPowerOperatingPoint(Second dt, PerSecond outAngularVelocity, + ResponseDryRun engineResponse, Watt previousPower) + { + try { + var operatingPoint = ModelData.FindOperatingPointForPowerDemand( + engineResponse.DynamicFullLoadPower - engineResponse.AuxiliariesPowerDemand, + DataBus.EngineSpeed, outAngularVelocity, _engineInertia, dt, previousPower); + var maxInputSpeed = VectoMath.Min(ModelData.TorqueConverterSpeedLimit, DataBus.EngineRatedSpeed); + if (operatingPoint.InAngularVelocity.IsGreater(maxInputSpeed)) { + operatingPoint = ModelData.FindOperatingPoint(maxInputSpeed, outAngularVelocity); + } + return operatingPoint; + } catch (VectoException ve) { + Log.Error(ve, "TorqueConverter: Failed to find operating point for MaxPower {0}", + engineResponse.DynamicFullLoadPower); + var tqOperatingPoint = ModelData.FindOperatingPoint(DataBus.EngineIdleSpeed, outAngularVelocity); + tqOperatingPoint.Creeping = true; + return tqOperatingPoint; + } + } + + protected internal TorqueConverterOperatingPoint FindOperatingPoint(NewtonMeter outTorque, + PerSecond outAngularVelocity) + { + var operatingPointList = ModelData.FindOperatingPoint(outTorque, outAngularVelocity, DataBus.EngineIdleSpeed); + if (operatingPointList.Count == 0) { + Log.Debug("TorqueConverter: Failed to find torque converter operating point, fallback: creeping"); + var tqOperatingPoint = ModelData.FindOperatingPoint(DataBus.EngineIdleSpeed, outAngularVelocity); + tqOperatingPoint.Creeping = true; + return tqOperatingPoint; + } + + var operatingPoint = SelectOperatingPoint(operatingPointList); + if (operatingPoint.InAngularVelocity.IsSmaller(DataBus.EngineIdleSpeed)) { + throw new VectoException( + "TorqueConverter: Invalid operating point, inAngularVelocity would be below engine's idle speed: {0}", + operatingPoint.InAngularVelocity); + } + var maxInputSpeed = VectoMath.Min(ModelData.TorqueConverterSpeedLimit, DataBus.EngineRatedSpeed); + if (operatingPoint.InAngularVelocity.IsGreater(maxInputSpeed)) { + operatingPoint = ModelData.FindOperatingPoint(maxInputSpeed, outAngularVelocity); + } + return operatingPoint; + } + + private TorqueConverterOperatingPoint SelectOperatingPoint(IList<TorqueConverterOperatingPoint> operatingPointList) + { + if (operatingPointList.Count == 1) { + return operatingPointList[0]; + } + + foreach (var x in operatingPointList) { + if ((x.InTorque * x.InAngularVelocity).IsSmallerOrEqual(DataBus.EngineStationaryFullPower(x.InAngularVelocity), + Constants.SimulationSettings.LineSearchTolerance.SI<Watt>()) && + (x.InTorque * x.InAngularVelocity).IsGreaterOrEqual(DataBus.EngineDragPower(x.InAngularVelocity), + Constants.SimulationSettings.LineSearchTolerance.SI<Watt>())) { + return x; + } + } + + return operatingPointList[0]; + } + + protected override void DoWriteModalResults(IModalDataContainer container) + { + if (CurrentState.OperatingPoint == null) { + container[ModalResultField.TorqueConverterTorqueRatio] = 1.0; + container[ModalResultField.TorqueConverterSpeedRatio] = 1.0; + } else { + container[ModalResultField.TorqueConverterTorqueRatio] = CurrentState.OperatingPoint.TorqueRatio; + container[ModalResultField.TorqueConverterSpeedRatio] = CurrentState.OperatingPoint.SpeedRatio; + } + container[ModalResultField.TC_TorqueIn] = CurrentState.InTorque; + container[ModalResultField.TC_TorqueOut] = CurrentState.OutTorque; + container[ModalResultField.TC_angularSpeedIn] = CurrentState.InAngularVelocity; + container[ModalResultField.TC_angularSpeedOut] = CurrentState.OutAngularVelocity; + + var avgOutVelocity = (PreviousState.OutAngularVelocity + CurrentState.OutAngularVelocity) / 2.0; + var avgInVelocity = (PreviousState.InAngularVelocity + CurrentState.InAngularVelocity) / 2.0; + container[ModalResultField.P_TC_out] = CurrentState.OutTorque * avgOutVelocity; + container[ModalResultField.P_TC_loss] = CurrentState.InTorque * avgInVelocity - + CurrentState.OutTorque * avgOutVelocity; + } + + protected override void DoCommitSimulationStep() + { + AdvanceState(); + } + + public void Locked(NewtonMeter inTorque, PerSecond inAngularVelocity, NewtonMeter outTorque, + PerSecond outAngularVelocity) + { + CurrentState.SetState(inTorque, inAngularVelocity, outTorque, outAngularVelocity); + } + + public class TorqueConverterComponentState : SimpleComponentState + { + public TorqueConverterOperatingPoint OperatingPoint; + } + } } \ No newline at end of file -- GitLab