From cabb240d5771443a60296ee9388fa16dc847aa61 Mon Sep 17 00:00:00 2001 From: Markus Quaritsch <markus.quaritsch@tugraz.at> Date: Thu, 18 Feb 2016 10:44:11 +0100 Subject: [PATCH] improved handling of overload/underload situations --- .../Impl/CombustionEngine.cs | 140 ++++++++++-------- .../Impl/EngineOnlyCombustionEngine.cs | 2 +- 2 files changed, 82 insertions(+), 60 deletions(-) diff --git a/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs b/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs index 51727350e7..b281cdbfc7 100644 --- a/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs +++ b/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs @@ -136,101 +136,111 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl protected virtual IResponse DoHandleRequest(Second absTime, Second dt, NewtonMeter torqueOut, PerSecond angularVelocity, bool dryRun) { - CurrentState.dt = dt; - CurrentState.EngineSpeed = angularVelocity; - CurrentState.EngineTorqueOut = torqueOut; - if (angularVelocity == null) { - // TODO: clarify what to do if engine speed is undefined (clutch open) - angularVelocity = PreviousState.EngineSpeed; + // 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; - //todo: _currentState.EnginePowerLoss = enginePowerLoss; } + CurrentState.dt = dt; + CurrentState.EngineSpeed = angularVelocity; var avgEngineSpeed = (PreviousState.EngineSpeed + CurrentState.EngineSpeed) / 2.0; - - NewtonMeter deltaGbxFld = null; - var curve = DataBus.GearFullLoadCurve; - if (curve != null) { - // if the current gear has a full-load curve, limit the max. torque to the - // gbx. full-load and continue (remmber the delta for further below) - var gearboxFullLoad = curve.FullLoadStationaryTorque(avgEngineSpeed); - var maxGbxTorque = VectoMath.Limit(torqueOut, -gearboxFullLoad, gearboxFullLoad); - if (!torqueOut.IsEqual(maxGbxTorque)) { - deltaGbxFld = torqueOut - maxGbxTorque; - } - CurrentState.EngineTorqueOut = maxGbxTorque; - } - - var auxTorqueDemand = EngineAux == null - ? 0.SI<NewtonMeter>() - : EngineAux.PowerDemand(absTime, dt, CurrentState.EngineTorqueOut, angularVelocity, dryRun); - + CurrentState.EngineTorqueOut = torqueOut; + CurrentState.FullDragTorque = ModelData.FullLoadCurve.DragLoadStationaryTorque(avgEngineSpeed); + var dynamicFullLoadPower = ComputeFullLoadPower(angularVelocity, dt); + CurrentState.DynamicFullLoadTorque = dynamicFullLoadPower / avgEngineSpeed; CurrentState.InertiaTorqueLoss = Formulas.InertiaPower(angularVelocity, PreviousState.EngineSpeed, ModelData.Inertia, dt) / avgEngineSpeed; - var totalTorqueDemand = CurrentState.EngineTorqueOut + auxTorqueDemand + CurrentState.InertiaTorqueLoss; - CurrentState.EngineTorque = totalTorqueDemand; - CurrentState.FullDragTorque = ModelData.FullLoadCurve.DragLoadStationaryTorque(avgEngineSpeed); - var dynamicFullLoadPower = ComputeFullLoadPower(angularVelocity, dt); - CurrentState.DynamicFullLoadTorque = dynamicFullLoadPower / avgEngineSpeed; + var auxTorqueDemand = EngineAux == null + ? 0.SI<NewtonMeter>() + : EngineAux.PowerDemand(absTime, dt, CurrentState.EngineTorqueOut, angularVelocity, dryRun); + // compute the torque the engine has to provide. powertrain + aux + its own inertia + var totalTorqueDemand = torqueOut + auxTorqueDemand + CurrentState.InertiaTorqueLoss; Log.Debug("EngineInertiaTorque: {0}", CurrentState.InertiaTorqueLoss); Log.Debug("Drag Curve: torque: {0}, power: {1}", CurrentState.FullDragTorque, CurrentState.FullDragTorque * avgEngineSpeed); - Log.Debug("FullLoad: torque: {0}, power: {1}", CurrentState.DynamicFullLoadTorque, dynamicFullLoadPower); + Log.Debug("Dynamic FullLoad: torque: {0}, power: {1}", CurrentState.DynamicFullLoadTorque, dynamicFullLoadPower); + + ValidatePowerDemand(totalTorqueDemand); // requires CurrentState.FullDragTorque and DynamicfullLoad to be set! + + // get max. torque as limited by gearbox. gearbox only limits torqueOut! + //NewtonMeter deltaGbxFld = null; + NewtonMeter gearboxFullLoad = null; + var curve = DataBus.GearFullLoadCurve; + if (curve != null) { + // if the current gear has a full-load curve, limit the max. torque to the + // gbx. full-load and continue (remmber the delta for further below) + gearboxFullLoad = curve.FullLoadStationaryTorque(avgEngineSpeed); + //var maxGbxTorque = VectoMath.Limit(torqueOut, -gearboxFullLoad, gearboxFullLoad); + //if (!torqueOut.IsEqual(maxGbxTorque)) { + // deltaGbxFld = torqueOut - maxGbxTorque; + //} + //CurrentState.EngineTorqueOut = maxGbxTorque; + } + + //CurrentState.EngineTorque = totalTorqueDemand; - ValidatePowerDemand(); + var deltaFull = ComputeDelta(torqueOut, totalTorqueDemand, CurrentState.DynamicFullLoadTorque, gearboxFullLoad, true); + var deltaDrag = ComputeDelta(torqueOut, totalTorqueDemand, CurrentState.FullDragTorque, + gearboxFullLoad != null ? -gearboxFullLoad : null, false); if (dryRun) { return new ResponseDryRun { - DeltaFullLoad = (CurrentState.EngineTorque - CurrentState.DynamicFullLoadTorque) * avgEngineSpeed, - DeltaDragLoad = (CurrentState.EngineTorque - CurrentState.FullDragTorque) * avgEngineSpeed, - EnginePowerRequest = CurrentState.EngineTorque * avgEngineSpeed, + DeltaFullLoad = deltaFull * avgEngineSpeed, + DeltaDragLoad = deltaDrag * avgEngineSpeed, + EnginePowerRequest = torqueOut * avgEngineSpeed, AuxiliariesPowerDemand = auxTorqueDemand * avgEngineSpeed, }; } - var maxEngineTorque = VectoMath.Limit(CurrentState.EngineTorque, CurrentState.FullDragTorque, - CurrentState.DynamicFullLoadTorque); + if (deltaFull.IsGreater(0.SI<NewtonMeter>()) && + deltaDrag.IsSmaller(0.SI<NewtonMeter>())) { + throw new VectoSimulationException( + "Unexpected condition: requested torque_out is above gearbox full-load and engine is below drag load! deltaFull: {0}, deltaDrag: {1}", + deltaFull, deltaDrag); + } - NewtonMeter deltaEngineFld = null; - if (!maxEngineTorque.IsEqual(CurrentState.EngineTorque)) { - deltaEngineFld = CurrentState.EngineTorque - maxEngineTorque; + var minTorque = CurrentState.FullDragTorque; + var maxTorque = CurrentState.DynamicFullLoadTorque; + if (gearboxFullLoad != null) { + minTorque = VectoMath.Min(minTorque, -gearboxFullLoad); + maxTorque = VectoMath.Max(maxTorque, gearboxFullLoad); } - // set engine torque and power to max value - CurrentState.EngineTorque = maxEngineTorque; + CurrentState.EngineTorque = VectoMath.Limit(totalTorqueDemand, minTorque, maxTorque); CurrentState.EnginePower = CurrentState.EngineTorque * avgEngineSpeed; - Watt delta = null; - if (deltaGbxFld != null && deltaEngineFld != null) { - delta = deltaEngineFld * avgEngineSpeed; - } else if (deltaGbxFld != null) { - delta = deltaGbxFld * avgEngineSpeed; - } else if (deltaEngineFld != null) { - delta = deltaEngineFld * avgEngineSpeed; - } - if (delta != null && delta.IsGreater(0.SI<Watt>(), Constants.SimulationSettings.EnginePowerSearchTolerance)) { - Log.Debug("requested engine power exceeds fullload power: delta: {0}", deltaEngineFld); + //NewtonMeter deltaEngineFld = null; + //Watt delta = null; + //if (!CurrentState.EngineTorque.IsEqual(totalTorqueDemand)) { + // delta = (torqueOut - CurrentState.EngineTorque) * avgEngineSpeed; + //} + + + if (torqueOut.IsGreater(0.SI<NewtonMeter>()) && + (deltaFull * avgEngineSpeed).IsGreater(0.SI<Watt>(), Constants.SimulationSettings.EnginePowerSearchTolerance)) { + Log.Debug("requested engine power exceeds fullload power: delta: {0}", deltaFull); return new ResponseOverload { AbsTime = absTime, - Delta = delta, + Delta = deltaFull * avgEngineSpeed, EnginePowerRequest = totalTorqueDemand * avgEngineSpeed, Source = this, AuxiliariesPowerDemand = auxTorqueDemand * avgEngineSpeed, }; } - if (delta != null && delta.IsSmaller(0.SI<Watt>(), Constants.SimulationSettings.EnginePowerSearchTolerance)) { - Log.Debug("requested engine power is below drag power: delta: {0}", deltaEngineFld); + if (torqueOut.IsSmaller(0.SI<NewtonMeter>()) && + (deltaDrag * avgEngineSpeed).IsSmaller(0.SI<Watt>(), Constants.SimulationSettings.EnginePowerSearchTolerance)) { + Log.Debug("requested engine power is below drag power: delta: {0}", deltaDrag); return new ResponseUnderload { AbsTime = absTime, - Delta = delta, + Delta = deltaDrag * avgEngineSpeed, EnginePowerRequest = totalTorqueDemand * avgEngineSpeed, Source = this, AuxiliariesPowerDemand = auxTorqueDemand * avgEngineSpeed, @@ -245,6 +255,18 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl }; } + private NewtonMeter ComputeDelta(NewtonMeter torqueOut, NewtonMeter totalTorqueDemand, NewtonMeter maxEngineTorque, + NewtonMeter maxGbxtorque, bool motoring) + { + var deltaGbx = maxGbxtorque != null ? torqueOut - maxGbxtorque : null; + var deltaEngine = totalTorqueDemand - maxEngineTorque; + + if (deltaGbx == null) { + return deltaEngine; + } + return motoring ? VectoMath.Max(deltaGbx, deltaEngine) : VectoMath.Min(deltaGbx, deltaEngine); + } + public IResponse Initialize(NewtonMeter torque, PerSecond angularSpeed) { var auxDemand = EngineAux == null ? 0.SI<NewtonMeter>() : EngineAux.Initialize(torque, angularSpeed); @@ -265,14 +287,14 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl /// <summary> /// Validates the requested power demand [W]. /// </summary> - protected virtual void ValidatePowerDemand() + protected virtual void ValidatePowerDemand(NewtonMeter torqueDemand) { - if (CurrentState.FullDragTorque >= 0 && CurrentState.EngineTorque < 0) { + if (CurrentState.FullDragTorque >= 0 && torqueDemand < 0) { throw new VectoSimulationException("P_engine_drag > 0! Tq_drag: {1}, Tq_eng: {2}, n_eng_avg: {0} [1/min] ", CurrentState.EngineSpeed.Value().RadToRPM(), CurrentState.FullDragTorque, CurrentState.EngineTorque); } - if (CurrentState.DynamicFullLoadTorque <= 0 && CurrentState.EngineTorque > 0) { + if (CurrentState.DynamicFullLoadTorque <= 0 && torqueDemand > 0) { throw new VectoSimulationException("P_engine_full < 0! Tq_drag: {1}, Tq_eng: {2}, n_eng_avg: {0} [1/min] ", CurrentState.EngineSpeed.Value().RadToRPM(), CurrentState.FullDragTorque, CurrentState.EngineTorque); } diff --git a/VectoCore/Models/SimulationComponent/Impl/EngineOnlyCombustionEngine.cs b/VectoCore/Models/SimulationComponent/Impl/EngineOnlyCombustionEngine.cs index 7e5cecedf1..f0e19c13b7 100644 --- a/VectoCore/Models/SimulationComponent/Impl/EngineOnlyCombustionEngine.cs +++ b/VectoCore/Models/SimulationComponent/Impl/EngineOnlyCombustionEngine.cs @@ -58,7 +58,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl var dynamicFullLoadPower = ComputeFullLoadPower(angularVelocity, dt); CurrentState.DynamicFullLoadTorque = dynamicFullLoadPower / avgEngineSpeed; - ValidatePowerDemand(); + ValidatePowerDemand(totalTorqueDemand); CurrentState.EngineTorque = LimitEnginePower(CurrentState.EngineTorque, avgEngineSpeed, absTime); -- GitLab