diff --git a/VectoCore/Exceptions/VectoSimulationException.cs b/VectoCore/Exceptions/VectoSimulationException.cs index 72c4d12c4402b7efecc0b19ca3972ddc6e88101f..ec56daa69d127fd7fd7e9a5ad49e126acbacafa4 100644 --- a/VectoCore/Exceptions/VectoSimulationException.cs +++ b/VectoCore/Exceptions/VectoSimulationException.cs @@ -1,5 +1,6 @@ using System; using JetBrains.Annotations; +using TUGraz.VectoCore.Models.Connector.Ports; namespace TUGraz.VectoCore.Exceptions { @@ -11,4 +12,14 @@ namespace TUGraz.VectoCore.Exceptions [StringFormatMethod("message")] public VectoSimulationException(string message, params object[] args) : base(message, args) {} } + + public class UnexpectedResponseException : VectoSimulationException + { + public IResponse Response; + + public UnexpectedResponseException(string message, IResponse resp) : base(message + " {0}", resp) + { + Response = resp; + } + } } \ No newline at end of file diff --git a/VectoCore/Models/Simulation/DataBus/IClutchInfo.cs b/VectoCore/Models/Simulation/DataBus/IClutchInfo.cs index 6b227c4786a459e3fe38f6967ba5a16bf0eedb77..678def6c13540432b19bf872e0da173c2301913b 100644 --- a/VectoCore/Models/Simulation/DataBus/IClutchInfo.cs +++ b/VectoCore/Models/Simulation/DataBus/IClutchInfo.cs @@ -5,6 +5,6 @@ namespace TUGraz.VectoCore.Models.Simulation.DataBus { public interface IClutchInfo { - ClutchState ClutchState(); + bool ClutchClosed(); } } \ No newline at end of file diff --git a/VectoCore/Models/Simulation/Impl/VehicleContainer.cs b/VectoCore/Models/Simulation/Impl/VehicleContainer.cs index 70921712cc03f0336eed851cec940c52e73f513a..f07a8b5d0613585a1be70bc109e693e1afc3971b 100644 --- a/VectoCore/Models/Simulation/Impl/VehicleContainer.cs +++ b/VectoCore/Models/Simulation/Impl/VehicleContainer.cs @@ -200,9 +200,9 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl set { Brakes.BreakPower = value; } } - public ClutchState ClutchState() + public bool ClutchClosed() { - return Clutch.ClutchState(); + return Clutch.ClutchClosed(); } } } \ No newline at end of file diff --git a/VectoCore/Models/SimulationComponent/IDriverActions.cs b/VectoCore/Models/SimulationComponent/IDriverActions.cs index 014ad52344202557bc400ed09e387372d0499079..42af0aa96ce596da1063bc00d75eaa157066dc0a 100644 --- a/VectoCore/Models/SimulationComponent/IDriverActions.cs +++ b/VectoCore/Models/SimulationComponent/IDriverActions.cs @@ -9,14 +9,20 @@ namespace TUGraz.VectoCore.Models.SimulationComponent /// <summary> /// perform an 'acceleration driving action', i.e., accelerate the vehicle to the given target velocity but limit the /// acceleration by the driver model (acceleration/deceleration curve). The acceleration is adjusted such that the engine - /// is not overloaded + /// is not overloaded. Brakes are not activated. /// </summary> /// <param name="absTime"></param> /// <param name="ds"></param> /// <param name="targetVelocity"></param> /// <param name="gradient"></param> - /// <returns></returns> - IResponse DrivingActionAccelerate(Second absTime, Meter ds, MeterPerSecond targetVelocity, Radian gradient); + /// <param name="previousResponse"></param> + /// <returns> + /// * ResponseSuccess + /// * ResponseUnderload: engine's operating point is below drag curve (vehicle accelerates more than driver model allows; engine's drag load is not sufficient for limited acceleration + /// * ResponseGearShift: gearbox needs to shift gears, vehicle can not accelerate (traction interruption) + /// </returns> + IResponse DrivingActionAccelerate(Second absTime, Meter ds, MeterPerSecond targetVelocity, Radian gradient, + IResponse previousResponse = null); /// <summary> /// perform a 'coasting driving action', i.e., the engine is operating at the full drag load. adjust the acceleration such that @@ -26,7 +32,13 @@ namespace TUGraz.VectoCore.Models.SimulationComponent /// <param name="ds"></param> /// <param name="maxVelocity"></param> /// <param name="gradient"></param> - /// <returns></returns> + /// <returns> + /// * ResponseSuccess + /// * ResponseDrivingCycleDistanceExceeded: vehicle is at low speed, coasting would lead to stop before ds is reached. + /// * ResponseSpeedLimitExceeded: vehicle accelerates during coasting which would lead to exceeding the given maxVelocity (e.g., driving downhill, engine's drag load is not sufficient) + /// * ResponseUnderload: engine's operating point is below drag curve (vehicle accelerates more than driver model allows; engine's drag load is not sufficient for limited acceleration + /// * ResponseGearShift: gearbox needs to shift gears, vehicle can not accelerate (traction interruption) + /// </returns> IResponse DrivingActionCoast(Second absTime, Meter ds, MeterPerSecond maxVelocity, Radian gradient); /// <summary> @@ -37,8 +49,13 @@ namespace TUGraz.VectoCore.Models.SimulationComponent /// <param name="ds"></param> /// <param name="nextTargetSpeed"></param> /// <param name="gradient"></param> - /// <returns></returns> - IResponse DrivingActionBrake(Second absTime, Meter ds, MeterPerSecond nextTargetSpeed, Radian gradient); + /// <param name="previousResponse"></param> + /// <returns> + /// * ResponseSuccess + /// * ResponseDrivingCycleDistanceExceeded: vehicle is at low speed, coasting would lead to stop before ds is reached. + /// </returns> + IResponse DrivingActionBrake(Second absTime, Meter ds, MeterPerSecond nextTargetSpeed, Radian gradient, + IResponse previousResponse = null); /// <summary> /// perform a 'roll driving action', i.e., the clutch is open and the vehicle rolls without motoring. adjust the acceleration diff --git a/VectoCore/Models/SimulationComponent/Impl/AxleGear.cs b/VectoCore/Models/SimulationComponent/Impl/AxleGear.cs index a83ff477195c16fa62b4fc4c6be85e2809bee802..eb341a0eb6159faceb92cf62a3825107e904cab6 100644 --- a/VectoCore/Models/SimulationComponent/Impl/AxleGear.cs +++ b/VectoCore/Models/SimulationComponent/Impl/AxleGear.cs @@ -37,7 +37,9 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl Log.Debug("request: torque: {0}, angularVelocity: {1}", outTorque, outAngularVelocity); var inAngularVelocity = outAngularVelocity * _gearData.Ratio; - var inTorque = _gearData.LossMap.GearboxInTorque(inAngularVelocity, outTorque); + var inTorque = outAngularVelocity.IsEqual(0) + ? 0.SI<NewtonMeter>() + : _gearData.LossMap.GearboxInTorque(inAngularVelocity, outTorque); var retVal = _nextComponent.Request(absTime, dt, inTorque, inAngularVelocity, dryRun); diff --git a/VectoCore/Models/SimulationComponent/Impl/Brakes.cs b/VectoCore/Models/SimulationComponent/Impl/Brakes.cs index 0408d2fe864301ac2fff75b2b9b2659f3cd5701f..f90c825e72067f477797efcbcbcfd9e9c2be9477 100644 --- a/VectoCore/Models/SimulationComponent/Impl/Brakes.cs +++ b/VectoCore/Models/SimulationComponent/Impl/Brakes.cs @@ -40,7 +40,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl if (!dryRun && BreakPower < 0) { throw new VectoSimulationException("Negative Braking Power is not allowed!"); } - return Next.Request(absTime, dt, torque - BreakTorque, angularVelocity, dryRun); + return Next.Request(absTime, dt, torque - torque.Sign() * BreakTorque, angularVelocity, dryRun); } public IResponse Initialize(NewtonMeter torque, PerSecond angularVelocity) diff --git a/VectoCore/Models/SimulationComponent/Impl/Clutch.cs b/VectoCore/Models/SimulationComponent/Impl/Clutch.cs index c7e53997cdbe9bcc949548dd59d7c8cb1a159811..dd78583ce6979a252f44495daa8b8fea6ccc6ea5 100644 --- a/VectoCore/Models/SimulationComponent/Impl/Clutch.cs +++ b/VectoCore/Models/SimulationComponent/Impl/Clutch.cs @@ -15,7 +15,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl private readonly PerSecond _ratedSpeed; private ITnOutPort _nextComponent; private const double ClutchEff = 1; - private ClutchState _clutchState = SimulationComponent.ClutchState.ClutchOpened; + private ClutchState _clutchState = SimulationComponent.ClutchState.ClutchSlipping; public Clutch(IVehicleContainer cockpit, CombustionEngineData engineData) @@ -113,9 +113,9 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl Formulas.TorqueToPower(torqueIn, engineSpeedIn)); } - public ClutchState ClutchState() + public bool ClutchClosed() { - return DataBus.Gear == 0 ? SimulationComponent.ClutchState.ClutchOpened : _clutchState; + return DataBus.Gear != 0; } } } \ No newline at end of file diff --git a/VectoCore/Models/SimulationComponent/Impl/DefaultDriverStrategy.cs b/VectoCore/Models/SimulationComponent/Impl/DefaultDriverStrategy.cs index 5a6a80b241c41ac814883fe5ece511512abd97e4..639e5bfe1a53bf8fa9a7d56f5388770510504aab 100644 --- a/VectoCore/Models/SimulationComponent/Impl/DefaultDriverStrategy.cs +++ b/VectoCore/Models/SimulationComponent/Impl/DefaultDriverStrategy.cs @@ -49,12 +49,12 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl case DrivingMode.DrivingModeDrive: var currentDistance = Driver.DataBus.Distance(); var nextAction = GetNextDrivingAction(currentDistance); - if (currentDistance.IsEqual(nextAction.ActionDistance)) { + if (nextAction != null && currentDistance.IsEqual(nextAction.ActionDistance)) { CurrentDrivingMode = DrivingMode.DrivingModeBrake; BrakeTrigger = nextAction; break; } - if (currentDistance + ds > nextAction.ActionDistance) { + if (nextAction != null && currentDistance + ds > nextAction.ActionDistance) { return new ResponseDrivingCycleDistanceExceeded() { MaxDistance = nextAction.ActionDistance - currentDistance }; @@ -92,17 +92,17 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl for (var i = 0; i < lookaheadData.Count; i++) { var entry = lookaheadData[i]; if (entry.VehicleTargetSpeed < currentSpeed) { - var breakingDistance = Driver.ComputeDecelerationDistance(entry.VehicleTargetSpeed); - Log.Debug("distance to decelerate from {0} to {1}: {2}", currentSpeed, entry.VehicleTargetSpeed, - breakingDistance); - Log.Debug("adding 'Braking' starting at distance {0}", entry.Distance - breakingDistance); - nextActions.Add( - new DrivingBehaviorEntry { - Action = DefaultDriverStrategy.DrivingBehavior.Braking, - ActionDistance = entry.Distance - breakingDistance, - TriggerDistance = entry.Distance, - NextTargetSpeed = entry.VehicleTargetSpeed - }); + //var breakingDistance = Driver.ComputeDecelerationDistance(entry.VehicleTargetSpeed); + //Log.Debug("distance to decelerate from {0} to {1}: {2}", currentSpeed, entry.VehicleTargetSpeed, + // breakingDistance); + //Log.Debug("adding 'Braking' starting at distance {0}", entry.Distance - breakingDistance); + //nextActions.Add( + // new DrivingBehaviorEntry { + // Action = DefaultDriverStrategy.DrivingBehavior.Braking, + // ActionDistance = entry.Distance - breakingDistance, + // TriggerDistance = entry.Distance, + // NextTargetSpeed = entry.VehicleTargetSpeed + // }); var coastingDistance = Formulas.DecelerationDistance(currentSpeed, entry.VehicleTargetSpeed, DeclarationData.Driver.LookAhead.Deceleration); Log.Debug("adding 'Coasting' starting at distance {0}", entry.Distance - coastingDistance); @@ -124,6 +124,9 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl } } + if (nextActions.Count == 0) { + return null; + } return nextActions.OrderBy(x => x.ActionDistance).First(); } } @@ -147,7 +150,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl public IResponse Request(Second absTime, Meter ds, MeterPerSecond targetVelocity, Radian gradient) { IResponse response = null; - if (DriverStrategy.Driver.DataBus.ClutchState() != ClutchState.ClutchOpened) { + if (DriverStrategy.Driver.DataBus.ClutchClosed()) { // drive along response = DriverStrategy.Driver.DrivingActionAccelerate(absTime, ds, targetVelocity, gradient); response.Switch(). @@ -159,14 +162,14 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl response = DriverStrategy.Driver.DrivingActionBrake(absTime, ds, targetVelocity, gradient); }); }). - Case<ResponseUnderload>(() => { - response = DriverStrategy.Driver.DrivingActionBrake(absTime, ds, targetVelocity, gradient); + Case<ResponseUnderload>(r => { + response = DriverStrategy.Driver.DrivingActionBrake(absTime, ds, targetVelocity, gradient, r); }); } else { response = DriverStrategy.Driver.DrivingActionRoll(absTime, ds, targetVelocity, gradient); response.Switch(). - Case<ResponseUnderload>(() => { - response = DriverStrategy.Driver.DrivingActionBrake(absTime, ds, targetVelocity, gradient); + Case<ResponseUnderload>(r => { + response = DriverStrategy.Driver.DrivingActionBrake(absTime, ds, targetVelocity, gradient, r); }); } return response; @@ -197,15 +200,15 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl Case<ResponseGearShift>(() => { response = DriverStrategy.Driver.DrivingActionRoll(absTime, ds, targetVelocity, gradient); response.Switch(). - Case<ResponseOverload>(() => { - // overload may happen if driver limits acceleration when rolling downhill + Case<ResponseUnderload>(r => { + // under-load may happen if driver limits acceleration when rolling downhill response = DriverStrategy.Driver.DrivingActionBrake(absTime, ds, DriverStrategy.BrakeTrigger.NextTargetSpeed, - gradient); + gradient, r); }); }). - Case<ResponseOverload>(() => { + Case<ResponseUnderload>(r => { response = DriverStrategy.Driver.DrivingActionBrake(absTime, ds, DriverStrategy.BrakeTrigger.NextTargetSpeed, - gradient); + gradient, r); }); return response; } @@ -226,10 +229,10 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl case BrakingPhase.Coast: response = DriverStrategy.Driver.DrivingActionCoast(absTime, ds, targetVelocity, gradient); response.Switch(). - Case<ResponseOverload>(() => { + Case<ResponseUnderload>(r => { // coast would decelerate more than driver's max deceleration => issue brakes to decelerate with driver's max deceleration response = DriverStrategy.Driver.DrivingActionBrake(absTime, ds, DriverStrategy.BrakeTrigger.NextTargetSpeed, - gradient); + gradient, r); Phase = BrakingPhase.Brake; }); break; diff --git a/VectoCore/Models/SimulationComponent/Impl/Driver.cs b/VectoCore/Models/SimulationComponent/Impl/Driver.cs index 81b9ddb8d13ac1cc482727bde925a4e93280ac71..6673af957aab27ba7a10111a7e425ee2b62516d3 100644 --- a/VectoCore/Models/SimulationComponent/Impl/Driver.cs +++ b/VectoCore/Models/SimulationComponent/Impl/Driver.cs @@ -32,6 +32,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl { DriverData = driverData; DriverStrategy = strategy; + strategy.Driver = this; } public IDriverDemandInPort InPort() @@ -62,6 +63,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl //DoHandleRequest(absTime, ds, targetVelocity, gradient); CurrentState.Response = retVal; + retVal.SimulationInterval = CurrentState.dt; + return retVal; } @@ -76,6 +79,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl //DoHandleRequest(absTime, dt, targetVelocity, gradient); CurrentState.Response = retVal; + retVal.SimulationInterval = CurrentState.dt; + return retVal; } @@ -144,32 +149,21 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl get { return DataBus; } } - /// <summary> - /// - /// </summary> - /// <param name="absTime"></param> - /// <param name="ds"></param> - /// <param name="targetVelocity"></param> - /// <param name="gradient"></param> - /// <returns></returns> - public IResponse DrivingActionAccelerate(Second absTime, Meter ds, MeterPerSecond targetVelocity, Radian gradient) + public IResponse DrivingActionAccelerate(Second absTime, Meter ds, MeterPerSecond targetVelocity, Radian gradient, + IResponse previousResponse = null) { + Log.Debug("DrivingAction Accelerate"); var operatingPoint = ComputeAcceleration(ds, targetVelocity); - if (operatingPoint.SimulationInterval <= 0) { - return new ResponseFailTimeInterval(); - } - IResponse retVal = null; - var response = Next.Request(absTime, operatingPoint.SimulationInterval, operatingPoint.Acceleration, gradient); + var response = previousResponse ?? + Next.Request(absTime, operatingPoint.SimulationInterval, operatingPoint.Acceleration, gradient); + response.Switch(). Case<ResponseSuccess>(r => { - r.SimulationInterval = operatingPoint.SimulationInterval; retVal = r; // => return }). - Case<ResponseOverload>(() => { - // do nothing, searchOperatingPoint is called later on - }). + Case<ResponseOverload>(). // do nothing, searchOperatingPoint is called later on Case<ResponseUnderload>(r => { // Delta is negative we are already below the Drag-load curve. activate breaks retVal = r; // => return, strategy should brake @@ -178,7 +172,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl retVal = r; }). Default(r => { - throw new VectoException(string.Format("Unknown Response: {0}", r)); + throw new UnexpectedResponseException("DrivingAction Accelerate", r); }); if (retVal == null) { @@ -190,7 +184,12 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl CurrentState.dt, CurrentState.Acceleration); retVal = Next.Request(absTime, operatingPoint.SimulationInterval, operatingPoint.Acceleration, gradient); - retVal.SimulationInterval = operatingPoint.SimulationInterval; + retVal.Switch(). + Case<ResponseUnderload>(). + Case<ResponseSuccess>(). + Default(r => { + throw new UnexpectedResponseException("DrivingAction Accelerate after SearchOperatingPoint", r); + }); } CurrentState.Acceleration = operatingPoint.Acceleration; CurrentState.dt = operatingPoint.SimulationInterval; @@ -209,10 +208,23 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl /// <returns></returns> public IResponse DrivingActionCoast(Second absTime, Meter ds, MeterPerSecond maxVelocity, Radian gradient) { + Log.Debug("DrivingAction Coast"); + return CoastOrRollAction(absTime, ds, maxVelocity, gradient); } + public IResponse DrivingActionRoll(Second absTime, Meter ds, MeterPerSecond maxVelocity, Radian gradient) + { + Log.Debug("DrivingAction Roll"); + + var retVal = CoastOrRollAction(absTime, ds, maxVelocity, gradient); + retVal.Switch().Case<ResponseGearShift>(() => { + throw new UnexpectedResponseException("DrivingAction Roll: Gearshift during Roll action", retVal); + }); + return retVal; + } + /// <summary> /// /// </summary> @@ -220,20 +232,17 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl /// <param name="ds"></param> /// <param name="maxVelocity"></param> /// <param name="gradient"></param> - /// <returns></returns> - public IResponse DrivingActionRoll(Second absTime, Meter ds, MeterPerSecond maxVelocity, Radian gradient) - { - return CoastOrRollAction(absTime, ds, maxVelocity, gradient); - } - + /// <returns> + /// * ResponseSuccess + /// * ResponseDrivingCycleDistanceExceeded: vehicle is at low speed, coasting would lead to stop before ds is reached. + /// * ResponseSpeedLimitExceeded: vehicle accelerates during coasting which would lead to exceeding the given maxVelocity (e.g., driving downhill, engine's drag load is not sufficient) + /// * ResponseUnderload: engine's operating point is below drag curve (vehicle accelerates more than driver model allows; engine's drag load is not sufficient for limited acceleration + /// * ResponseGearShift: gearbox needs to shift gears, vehicle can not accelerate (traction interruption) + /// </returns> protected IResponse CoastOrRollAction(Second absTime, Meter ds, MeterPerSecond maxVelocity, Radian gradient) { var operatingPoint = ComputeAcceleration(ds, 0.SI<MeterPerSecond>()); - if (operatingPoint.SimulationInterval <= 0) { - return new ResponseFailTimeInterval(); - } - CurrentState.Acceleration = operatingPoint.Acceleration; var response = Next.Request(absTime, operatingPoint.SimulationInterval, operatingPoint.Acceleration, gradient, @@ -248,7 +257,6 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl operatingPoint.SimulationDistance, ds); return new ResponseDrivingCycleDistanceExceeded { MaxDistance = operatingPoint.SimulationDistance, - SimulationInterval = CurrentState.dt }; } @@ -270,45 +278,42 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl CurrentState.Response = retVal; retVal.Switch(). - Case<ResponseSuccess>(r => r.SimulationInterval = CurrentState.dt). - Case<ResponseOverload>(() => { - /* an overload may occur due to limiting the acceleration. strategy has to handle this */ - }). - Case<ResponseGearShift>(r => retVal = r). + Case<ResponseSuccess>(). + Case<ResponseUnderload>(). // driver limits acceleration, operating point may be below engine's drag load + Case<ResponseGearShift>(). Default(() => { - throw new VectoSimulationException("unhandled response from powertrain: {0}", retVal); + throw new UnexpectedResponseException("CoastOrRoll Action: unhandled response from powertrain", retVal); }); - - return retVal; //new ResponseDrivingCycleDistanceExceeded() { SimulationInterval = CurrentState.dt }; + return retVal; } - /// <summary> - /// - /// </summary> - /// <param name="absTime"></param> - /// <param name="ds"></param> - /// <param name="nextTargetSpeed"></param> - /// <param name="gradient"></param> - /// <returns></returns> - public IResponse DrivingActionBrake(Second absTime, Meter ds, MeterPerSecond nextTargetSpeed, Radian gradient) + public IResponse DrivingActionBrake(Second absTime, Meter ds, MeterPerSecond nextTargetSpeed, Radian gradient, + IResponse previousResponse = null) { + Log.Debug("DrivingAction Brake"); + + IResponse retVal = null; + var operatingPoint = ComputeAcceleration(ds, nextTargetSpeed); - // todo: still required? - if (operatingPoint.SimulationInterval <= 0) { - return new ResponseFailTimeInterval(); - } + var response = previousResponse ?? + Next.Request(absTime, operatingPoint.SimulationInterval, operatingPoint.Acceleration, gradient); - var response = - (ResponseDryRun) - Next.Request(absTime, operatingPoint.SimulationInterval, operatingPoint.Acceleration, gradient, true); + response.Switch(). + Case<ResponseSuccess>(r => retVal = r). + Case<ResponseOverload>(r => retVal = r). + Case<ResponseUnderload>(). // will be handled in SearchBrakingPower + Case<ResponseGearShift>(). // will be handled in SearchBrakingPower + Default(r => { + throw new UnexpectedResponseException("DrivingAction Brake: first request", r); + }); - if (response.DeltaDragLoad > 0) { - throw new VectoSimulationException("Braking not required, above drag load! Use engine brake!"); + if (retVal != null) { + return retVal; } - operatingPoint = SearchBreakingPower(absTime, operatingPoint.SimulationDistance, gradient, + operatingPoint = SearchBrakingPower(absTime, operatingPoint.SimulationDistance, gradient, operatingPoint.Acceleration, response); if (!ds.IsEqual(operatingPoint.SimulationDistance)) { @@ -317,20 +322,23 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl operatingPoint.SimulationDistance, ds); return new ResponseDrivingCycleDistanceExceeded { MaxDistance = operatingPoint.SimulationDistance, - SimulationInterval = operatingPoint.SimulationInterval }; } Log.Debug("Found operating point for breaking. dt: {0}, acceleration: {1}", operatingPoint.SimulationInterval, operatingPoint.Acceleration); - var retVal = Next.Request(absTime, operatingPoint.SimulationInterval, operatingPoint.Acceleration, gradient); + retVal = Next.Request(absTime, operatingPoint.SimulationInterval, operatingPoint.Acceleration, gradient); + retVal.Switch(). + Case<ResponseSuccess>(). + Default(r => { + throw new UnexpectedResponseException("DrivingAction Brake: request failed after braking power was found", r); + }); CurrentState.Acceleration = operatingPoint.Acceleration; CurrentState.dt = operatingPoint.SimulationInterval; CurrentState.Response = retVal; - retVal.SimulationInterval = CurrentState.dt; return retVal; } @@ -359,15 +367,16 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl } /// <summary> - /// + /// Performs a search for the required braking power such that the vehicle accelerates with the given acceleration. + /// Returns a new operating point (a, ds, dt) where ds may be shorter due to vehicle stopping /// </summary> /// <param name="absTime"></param> /// <param name="ds"></param> /// <param name="gradient"></param> /// <param name="acceleration"></param> /// <param name="initialResponse"></param> - /// <returns></returns> - private OperatingPoint SearchBreakingPower(Second absTime, Meter ds, Radian gradient, + /// <returns>operating point (a, ds, dt) such that the vehicle accelerates with the given acceleration.</returns> + private OperatingPoint SearchBrakingPower(Second absTime, Meter ds, Radian gradient, MeterPerSquareSecond acceleration, IResponse initialResponse) { var debug = new List<dynamic>(); // only used while testing @@ -378,11 +387,13 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl Watt origDelta = null; initialResponse.Switch(). Case<ResponseGearShift>(r => origDelta = r.GearboxPowerRequest). - Case<ResponseDryRun>(r => origDelta = DataBus.ClutchState() == ClutchState.ClutchClosed - ? r.DeltaDragLoad + Case<ResponseUnderload>(r => origDelta = DataBus.ClutchClosed() + ? r.Delta : r.GearboxPowerRequest); var delta = origDelta; + debug.Add(new { brakingPower = 0.SI<Watt>(), searchInterval, delta }); + var breakingPower = origDelta.Abs(); // double the searchInterval until a good interval was found @@ -390,27 +401,29 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl var retryCount = 0; //ResponseDryRun response; do { - debug.Add(new { breakingPower, searchInterval, delta }); - - // check if a correct searchInterval was found (when the delta changed signs, we stepped through the 0-point) - // from then on the searchInterval can be bisected. - if (origDelta.Sign() != delta.Sign()) { - intervalFactor = 0.5; - } - - breakingPower += searchInterval * -delta.Sign(); - searchInterval *= intervalFactor; - operatingPoint = ComputeTimeInterval(operatingPoint.Acceleration, ds); DataBus.BreakPower = breakingPower; var response = (ResponseDryRun) Next.Request(absTime, operatingPoint.SimulationInterval, operatingPoint.Acceleration, gradient, true); - delta = DataBus.ClutchState() == ClutchState.ClutchClosed ? response.DeltaDragLoad : response.GearboxPowerRequest; + delta = DataBus.ClutchClosed() ? response.DeltaDragLoad : response.GearboxPowerRequest; + if (delta.IsEqual(0, Constants.SimulationSettings.EngineFLDPowerTolerance)) { Log.Debug("found operating point in {0} iterations, delta: {1}", debug.Count, delta); return operatingPoint; } + + debug.Add(new { breakingPower, searchInterval, delta }); + + // check if a correct searchInterval was found (when the delta changed signs, we stepped through the 0-point) + // from then on the searchInterval can be bisected. + if (origDelta.Sign() != delta.Sign()) { + intervalFactor = 0.5; + } + + searchInterval *= intervalFactor; + breakingPower += searchInterval * -delta.Sign(); + } while (retryCount++ < Constants.SimulationSettings.DriverSearchLoopThreshold); Log.Warn("Exceeded max iterations when searching for operating point!"); @@ -446,7 +459,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl var retVal = new OperatingPoint() { Acceleration = acceleration, SimulationDistance = ds }; - var actionRoll = DataBus.ClutchState() == ClutchState.ClutchOpened; + var actionRoll = !DataBus.ClutchClosed(); Watt origDelta = null; if (actionRoll) { @@ -536,9 +549,9 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl } retVal.Acceleration = requiredAcceleration; - var operatingPoint = ComputeTimeInterval(retVal.Acceleration, ds); + retVal = ComputeTimeInterval(retVal.Acceleration, ds); - if (ds.IsEqual(operatingPoint.SimulationDistance)) { + if (ds.IsEqual(retVal.SimulationDistance)) { return retVal; } @@ -546,7 +559,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl // can be reached within ds. Log.Error( "Unexpected Condition: Distance has been adjusted from {0} to {1}, currentVelocity: {2} acceleration: {3}, targetVelocity: {4}", - operatingPoint.SimulationDistance, ds, currentSpeed, CurrentState.Acceleration, targetVelocity); + retVal.SimulationDistance, ds, currentSpeed, CurrentState.Acceleration, targetVelocity); throw new VectoSimulationException("Simulation distance unexpectedly adjusted!"); } @@ -566,10 +579,11 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl /// <summary> /// Computes the time interval for driving the given distance ds with the vehicle's current speed and the given acceleration. /// If the distance ds can not be reached (i.e., the vehicle would halt before ds is reached) then the distance parameter is adjusted. - /// The computed time interval is returned via the out parameter dt + /// Returns a new operating point (a, ds, dt) /// </summary> /// <param name="acceleration"></param> /// <param name="ds"></param> + /// <returns>Operating point (a, ds, dt)</returns> private OperatingPoint ComputeTimeInterval(MeterPerSquareSecond acceleration, Meter ds) { if (!(ds > 0)) { @@ -633,7 +647,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl DataBus.Gear = 0; DataBus.BreakPower = double.PositiveInfinity.SI<Watt>(); var retVal = Next.Request(absTime, dt, 0.SI<MeterPerSquareSecond>(), gradient); - retVal.SimulationInterval = dt; + CurrentState.dt = dt; DataBus.Gear = oldGear; return retVal; } diff --git a/VectoCore/Models/SimulationComponent/Impl/Gearbox.cs b/VectoCore/Models/SimulationComponent/Impl/Gearbox.cs index 9ad907db91e0af903c93d895f46eddb19565ad68..831d1ab14e035c6c960a282ea0a3bc4abc2f2d90 100644 --- a/VectoCore/Models/SimulationComponent/Impl/Gearbox.cs +++ b/VectoCore/Models/SimulationComponent/Impl/Gearbox.cs @@ -26,7 +26,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl /// <summary> /// Time when a gearbox shift is finished. Is set when shifting is needed. /// </summary> - private Second _shiftTime = double.NegativeInfinity.SI<Second>(); + private Second _shiftTime = double.PositiveInfinity.SI<Second>(); /// <summary> /// The power loss for the mod data. @@ -83,7 +83,11 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl if (!outTorque.IsEqual(0)) { // if clutch is open the gearbox can't provide a torque - return new ResponseOverload() { Delta = outTorque * outEngineSpeed }; + return new ResponseOverload { + Delta = outTorque * outEngineSpeed, + Source = this, + GearboxPowerRequest = outTorque * outEngineSpeed + }; } // if shiftTime still not reached (only happens during shifting): apply zero-request if (_shiftTime > absTime) { @@ -110,7 +114,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl // Check if shift is needed and eventually return ResponseGearShift if (_shiftTime + Data.ShiftTime < absTime && - (ShouldShiftUp(inEngineSpeed, inTorque) || ShouldShiftDown(inEngineSpeed, inTorque))) { + (ShouldShiftUp(Gear, inEngineSpeed, inTorque) || ShouldShiftDown(Gear, inEngineSpeed, inTorque))) { _shiftTime = absTime + Data.TractionInterruption; Gear = 0; @@ -140,12 +144,12 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl var inTorque = Data.Gears[gear].LossMap.GearboxInTorque(inEngineSpeed, outTorque); do { - if (ShouldShiftUp(inEngineSpeed, inTorque)) { + if (ShouldShiftUp(gear, inEngineSpeed, inTorque)) { gear++; continue; } - if (ShouldShiftDown(inEngineSpeed, inTorque)) { + if (ShouldShiftDown(gear, inEngineSpeed, inTorque)) { gear--; continue; } @@ -157,26 +161,26 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl /// <summary> /// Tests if the gearbox should shift down. /// </summary> - private bool ShouldShiftDown(PerSecond inEngineSpeed, NewtonMeter inTorque) + private bool ShouldShiftDown(uint gear, PerSecond inEngineSpeed, NewtonMeter inTorque) { - if (Gear <= 1) { + if (gear <= 1) { return false; } - var downSection = Data.Gears[Gear].ShiftPolygon.Downshift.GetSection(entry => entry.AngularSpeed < inEngineSpeed); + var downSection = Data.Gears[gear].ShiftPolygon.Downshift.GetSection(entry => entry.AngularSpeed < inEngineSpeed); return IsOnLeftSide(inEngineSpeed, inTorque, downSection.Item1, downSection.Item2); } /// <summary> /// Tests if the gearbox should shift up. /// </summary> - private bool ShouldShiftUp(PerSecond inEngineSpeed, NewtonMeter inTorque) + private bool ShouldShiftUp(uint gear, PerSecond inEngineSpeed, NewtonMeter inTorque) { - if (Gear >= Data.Gears.Count) { + if (gear >= Data.Gears.Count) { return false; } - var upSection = Data.Gears[Gear].ShiftPolygon.Upshift.GetSection(entry => entry.AngularSpeed < inEngineSpeed); + var upSection = Data.Gears[gear].ShiftPolygon.Upshift.GetSection(entry => entry.AngularSpeed < inEngineSpeed); return IsOnRightSide(inEngineSpeed, inTorque, upSection.Item1, upSection.Item2); } @@ -206,7 +210,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl public IResponse Initialize(NewtonMeter torque, PerSecond engineSpeed) { - Gear = 0; + Gear = FindGear(torque, engineSpeed); return Next.Initialize(torque, engineSpeed); } diff --git a/VectoCore/Utils/SI.cs b/VectoCore/Utils/SI.cs index fda1c43fa2971c688a9c6eda57a9cdcc710739ac..eb5cc3b41b7ad7e0df444e36c86db1a1eeb8c584 100644 --- a/VectoCore/Utils/SI.cs +++ b/VectoCore/Utils/SI.cs @@ -162,6 +162,7 @@ namespace TUGraz.VectoCore.Utils /// </summary> public class MeterPerSquareSecond : SIBase<MeterPerSquareSecond> { + [DebuggerHidden] static MeterPerSquareSecond() { Register(val => new MeterPerSquareSecond(val)); diff --git a/VectoCore/Utils/SwitchExtension.cs b/VectoCore/Utils/SwitchExtension.cs index c607083281902faa52afa6241cd2d4758f5edce8..6cb0d33d0672b160a9a61710a6409e9d7afaa46f 100644 --- a/VectoCore/Utils/SwitchExtension.cs +++ b/VectoCore/Utils/SwitchExtension.cs @@ -36,10 +36,17 @@ namespace TUGraz.VectoCore.Utils return Case<TFilter>(_ => action()); } + [DebuggerHidden] + public Switch<T> Case<TFilter>() where TFilter : T + { + return Case<TFilter>(() => {}); + } + + [DebuggerHidden] public Switch<T> Case<TFilter>(Action<TFilter> action) where TFilter : T { - if (!_handled && _value is TFilter) { + if (!_handled && _value.GetType() == typeof(TFilter)) { action((TFilter)_value); _handled = true; } diff --git a/VectoCoreTest/Integration/SimulationRuns/FullPowertrain.cs b/VectoCoreTest/Integration/SimulationRuns/FullPowertrain.cs index d9495be84a9a01c64eb7cbb4320c40ed771b9761..3d6a844022f582d2ff21b66f33c0a197c1983d12 100644 --- a/VectoCoreTest/Integration/SimulationRuns/FullPowertrain.cs +++ b/VectoCoreTest/Integration/SimulationRuns/FullPowertrain.cs @@ -76,7 +76,7 @@ namespace TUGraz.VectoCore.Tests.Integration.SimulationRuns response = cyclePort.Request(absTime, ds); response.Switch(). Case<ResponseDrivingCycleDistanceExceeded>(r => ds = r.MaxDistance). - Case<ResponseCycleFinished>(r => { }). + Case<ResponseCycleFinished>(r => {}). Case<ResponseSuccess>(r => { container.CommitSimulationStep(absTime, r.SimulationInterval); absTime += r.SimulationInterval; @@ -145,8 +145,10 @@ namespace TUGraz.VectoCore.Tests.Integration.SimulationRuns response.Switch(). Case<ResponseDrivingCycleDistanceExceeded>(r => ds = r.MaxDistance). - Case<ResponseCycleFinished>(r => { }). - Case<ResponseGearShift>(r => { Log.Debug("Gearshift"); }). + Case<ResponseCycleFinished>(r => {}). + Case<ResponseGearShift>(r => { + Log.Debug("Gearshift"); + }). Case<ResponseSuccess>(r => { container.CommitSimulationStep(absTime, r.SimulationInterval); absTime += r.SimulationInterval; @@ -192,7 +194,7 @@ namespace TUGraz.VectoCore.Tests.Integration.SimulationRuns cyclePort.Initialize(); - container.Gear = 0; + //container.Gear = 0; var absTime = 0.SI<Second>(); var ds = Constants.SimulationSettings.DriveOffDistance; var response = cyclePort.Request(absTime, ds); @@ -200,7 +202,7 @@ namespace TUGraz.VectoCore.Tests.Integration.SimulationRuns container.CommitSimulationStep(absTime, response.SimulationInterval); absTime += response.SimulationInterval; - container.Gear = 1; + //container.Gear = 1; var cnt = 0; while (!(response is ResponseCycleFinished) && container.Distance().Value() < 17000) { Log.Info("Test New Request absTime: {0}, ds: {1}", absTime, ds); @@ -214,8 +216,10 @@ namespace TUGraz.VectoCore.Tests.Integration.SimulationRuns response.Switch(). Case<ResponseDrivingCycleDistanceExceeded>(r => ds = r.MaxDistance). - Case<ResponseCycleFinished>(r => { }). - Case<ResponseGearShift>(r => { Log.Debug("Gearshift"); }). + Case<ResponseCycleFinished>(r => {}). + Case<ResponseGearShift>(r => { + Log.Debug("Gearshift"); + }). Case<ResponseSuccess>(r => { container.CommitSimulationStep(absTime, r.SimulationInterval); absTime += r.SimulationInterval; @@ -228,7 +232,10 @@ namespace TUGraz.VectoCore.Tests.Integration.SimulationRuns modalWriter.Finish(); } }). - Default(r => Assert.Fail("Unexpected Response: {0}", r)); + Default(r => { + modalWriter.Finish(); + Assert.Fail("Unexpected Response: {0}", r); + }); } modalWriter.Finish(); Assert.IsInstanceOfType(response, typeof(ResponseCycleFinished)); diff --git a/VectoCoreTest/app.config b/VectoCoreTest/app.config index b9fc82b72b412787b48895da9c5ccb501157bd12..8d34600b34fc1c5fd1ffb93754778b76ca3a03b8 100644 --- a/VectoCoreTest/app.config +++ b/VectoCoreTest/app.config @@ -1,23 +1,25 @@ <?xml version="1.0" encoding="utf-8"?> + <configuration> - <configSections> - <section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog" /> - </configSections> - <startup> - <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> - </startup> - <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd NLog.xsd" - autoReload="true" - throwExceptions="false" - internalLogLevel="Off" internalLogFile="c:\temp\nlog-internal.log" > - <targets> - <target xsi:type="Console" name="ConsoleLogger" error="true" /> - <target xsi:type="File" name="LogFile" fileName="${basedir}/logs/log.txt" layout="${longdate} [${processid}@${machinename}] ${callsite} ${level:uppercase=true}: ${message}" /> - </targets> - <rules> - <logger name="*" minlevel="Info" writeTo="LogFile" /> - </rules> - </nlog> + <configSections> + <section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog" /> + </configSections> + <startup> + <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> + </startup> + <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd NLog.xsd" + autoReload="true" + throwExceptions="false" + internalLogLevel="Off" internalLogFile="c:\temp\nlog-internal.log"> + <targets> + <target xsi:type="Console" name="ConsoleLogger" error="true" /> + <target xsi:type="File" name="LogFile" fileName="${basedir}/logs/log.txt" + layout="${longdate} [${processid}@${machinename}] ${callsite} ${level:uppercase=true}: ${message}" /> + </targets> + <rules> + <logger name="*" minlevel="Info" writeTo="LogFile" /> + </rules> + </nlog> </configuration> \ No newline at end of file