From fa5e5fbafccab965f96a8f224b242ff98394167f Mon Sep 17 00:00:00 2001 From: Markus Quaritsch <quaritsch@ivt.tugraz.at> Date: Tue, 7 Feb 2023 06:21:37 +0100 Subject: [PATCH] refactoring code in hybrid strategy brake action: reduce complexity (invert if) --- .../Strategies/HybridStrategy.cs | 583 ++++++++++-------- 1 file changed, 320 insertions(+), 263 deletions(-) diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Strategies/HybridStrategy.cs b/VectoCore/VectoCore/Models/SimulationComponent/Strategies/HybridStrategy.cs index 7603173eaa..323d8401a4 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Strategies/HybridStrategy.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Strategies/HybridStrategy.cs @@ -183,6 +183,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies TestPowertrain.HybridController.Initialize(Controller.PreviousState.OutTorque, Controller.PreviousState.OutAngularVelocity); TestPowertrain.Brakes.BrakePower = DataBus.Brakes.BrakePower; + TestPowertrain.DCDCConverter?.UpdateFrom(DataBus.DCDCConverter); if (nextGear.Engaged && !nextGear.Equals(TestPowertrain.Gearbox.Gear)) { if (!AllowEmergencyShift && ModelData.GearboxData.Gears[nextGear.Gear].Ratio > ModelData.GearshiftParameters.RatioEarlyUpshiftFC) { @@ -863,324 +864,380 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies var vehiclespeedBelowThreshold = DataBus.VehicleInfo.VehicleSpeed.IsSmaller(disengageSpeedThreshold) && (DataBus.DriverInfo.NextBrakeTriggerSpeed?.IsEqual(0) ?? false); - if (ElectricMotorCanPropellDuringTractionInterruption || DataBus.GearboxInfo.GearEngaged(absTime)) { - - if (vehiclespeedBelowThreshold && emPos.IsOneOf(PowertrainPosition.HybridP2, PowertrainPosition.HybridP1, PowertrainPosition.IHPC)) { - if (DataBus.GearboxInfo.GearboxType.AutomaticTransmission()) { - var firstgear = ResponseEmOff; - firstgear.Gear = GearList.First(); - eval.Add(firstgear); - return; - } else { - var off = ResponseEmOff; - off.Setting.GearboxInNeutral = true; - eval.Add(off); - return; - } - } - - GearshiftPosition nextGear; - if (!DataBus.GearboxInfo.GearEngaged(absTime)) { - nextGear = new GearshiftPosition(0); - } else if (PreviousState.GearboxEngaged) { - nextGear = DataBus.GearboxInfo.Gear; + if (!ElectricMotorCanPropellDuringTractionInterruption && !DataBus.GearboxInfo.GearEngaged(absTime)) { + var off = ResponseEmOff; + if (vehiclespeedBelowThreshold && + (emPos == PowertrainPosition.HybridP2 || emPos == PowertrainPosition.HybridP1)) { + off.Setting.GearboxInNeutral = true; } else { - nextGear = Controller.ShiftStrategy.NextGear; + off.Setting.GearboxInNeutral = PreviousState.Solution?.Setting.GearboxInNeutral ?? false; } - if (!nextGear.IsLockedGear()) { - eval.Add(ResponseEmOff); + eval.Add(off); + return; + } + + GearshiftPosition nextGear; + if (!DataBus.GearboxInfo.GearEngaged(absTime)) { + nextGear = new GearshiftPosition(0); + } else if (PreviousState.GearboxEngaged) { + nextGear = DataBus.GearboxInfo.Gear; + } else { + nextGear = Controller.ShiftStrategy.NextGear; + } + + if (vehiclespeedBelowThreshold && emPos.IsOneOf(PowertrainPosition.HybridP2, + PowertrainPosition.HybridP1, PowertrainPosition.IHPC)) { + if (DataBus.GearboxInfo.GearboxType.AutomaticTransmission()) { + var firstgear = ResponseEmOff; + firstgear.Gear = GearList.First(); + eval.Add(firstgear); return; } - var disengaged = nextGear.Gear == 0; - //if (!disengaged && outAngularVelocity.IsEqual(0)) { - // var stop = ResponseEmOff; - // stop.Gear = new GearshiftPosition(0); - // eval.Add(stop); - // return; - //} - var currentGear = nextGear; - var tmp = new HybridStrategyResponse { + var testDisengage = new HybridStrategyResponse { CombustionEngineOn = DataBus.EngineInfo.EngineOn, // AllowICEOff(absTime), GearboxInNeutral = false, NextGear = nextGear, MechanicalAssistPower = ElectricMotorsOff }; - var response = RequestDryRun(absTime, dt, outTorque, outAngularVelocity, nextGear, tmp); - debug.Add($"[AHS.HBA-0] DryRun Gear={nextGear}", response); - - var endSpeed = DataBus.VehicleInfo.VehicleSpeed + - DataBus.DriverInfo.DriverAcceleration * ModelData.GearboxData.TractionInterruption; - if (EngineSpeedTooLow(response) - && (DataBus.GearboxInfo.GearboxType.ManualTransmission() || DataBus.GearboxInfo.GearboxType == GearboxType.IHPC) - && endSpeed.IsSmallerOrEqual(disengageSpeedThreshold, 0.1.KMPHtoMeterPerSecond())) { - var responseEmOff = ResponseEmOff; - // if the engine speed is too low but the gear is engaged in this timestep, use the gear as calculated before. - // on re-engage the engine speed is checked and a lower gear is engaged. then the hybrid strategy is called again. - responseEmOff.Gear = (!PreviousState.GearboxEngaged && DataBus.GearboxInfo.GearEngaged(absTime)) ? currentGear : new GearshiftPosition(0); - responseEmOff.Setting.GearboxEngaged = false; - responseEmOff.Setting.GearboxInNeutral = (!PreviousState.GearboxEngaged && DataBus.GearboxInfo.GearEngaged(absTime)) ? false : true; - eval.Add(responseEmOff); - return; + var testDisengageResponse = RequestDryRun(absTime, dt, outTorque, outAngularVelocity, nextGear, + testDisengage); + + var off = ResponseEmOff; + + if (testDisengageResponse.Clutch.PowerRequest.IsSmaller(0)) { + // only disengage if the torque at the clutch is negative - i.e. no propulsion needed + off.Setting.GearboxInNeutral = true; } - if (GearList.HasPredecessor(nextGear) - && EngineSpeedTooLow(response) - && (!vehiclespeedBelowThreshold || AllowEmergencyShift)) { - // engine speed would fall below idling speed - consider downshift - var estimatedVelocityPostShift = VelocityDropData.Valid - ? VelocityDropData.Interpolate(DataBus.VehicleInfo.VehicleSpeed, - DataBus.DrivingCycleInfo.RoadGradient ?? 0.SI<Radian>()) - : DataBus.VehicleInfo.VehicleSpeed; - var postShiftBelowThreshold = estimatedVelocityPostShift.IsSmaller(disengageSpeedThreshold); - if (postShiftBelowThreshold) { - var downshift = ResponseEmOff; - downshift.Gear = GearList.Predecessor(nextGear); - eval.Add(downshift); - return; - } - do { - nextGear = GearList.Predecessor(nextGear); - response = RequestDryRun(absTime, dt, outTorque, outAngularVelocity, nextGear, tmp); - debug.Add($"[AHS.HBA-1] DryRun Gear={nextGear}", response); - } while (GearList.HasPredecessor(nextGear) && response == null); - } - - if (nextGear.Equals(GearList.First()) && EngineSpeedTooLow(response)) { - // disengage gearbox... - var responseEmOff = ResponseEmOff; - responseEmOff.Gear = new GearshiftPosition(0); - responseEmOff.Setting.GearboxEngaged = false; - responseEmOff.Setting.GearboxInNeutral = true; - eval.Add(responseEmOff); - return; + eval.Add(off); + return; + } + + if (!nextGear.IsLockedGear()) { + var off = ResponseEmOff; + var offResponse = RequestDryRun(absTime, dt, outTorque, outAngularVelocity, nextGear, off.Setting); + if (offResponse.Source is ATGearbox && offResponse is ResponseOverload && GearList.HasPredecessor(nextGear)) { + off.Gear = GearList.Predecessor(nextGear); } + eval.Add(ResponseEmOff); + return; + } + + var disengaged = nextGear.Gear == 0; + //if (!disengaged && outAngularVelocity.IsEqual(0)) { + // var stop = ResponseEmOff; + // stop.Gear = new GearshiftPosition(0); + // eval.Add(stop); + // return; + //} + var currentGear = nextGear; + var tmp = new HybridStrategyResponse { + CombustionEngineOn = DataBus.EngineInfo.EngineOn, // AllowICEOff(absTime), + GearboxInNeutral = false, + NextGear = nextGear, + MechanicalAssistPower = ElectricMotorsOff + }; + var response = RequestDryRun(absTime, dt, outTorque, outAngularVelocity, nextGear, tmp); + debug.Add($"[AHS.HBA-0] DryRun Gear={nextGear}", response); + + var endSpeed = DataBus.VehicleInfo.VehicleSpeed + + DataBus.DriverInfo.DriverAcceleration * ModelData.GearboxData.TractionInterruption; + if (EngineSpeedTooLow(response) + && (DataBus.GearboxInfo.GearboxType.ManualTransmission() || + DataBus.GearboxInfo.GearboxType == GearboxType.IHPC) + && endSpeed.IsSmallerOrEqual(disengageSpeedThreshold, 0.1.KMPHtoMeterPerSecond())) { + var responseEmOff = ResponseEmOff; + // if the engine speed is too low but the gear is engaged in this timestep, use the gear as calculated before. + // on re-engage the engine speed is checked and a lower gear is engaged. then the hybrid strategy is called again. + responseEmOff.Gear = (!PreviousState.GearboxEngaged && DataBus.GearboxInfo.GearEngaged(absTime)) + ? currentGear + : new GearshiftPosition(0); + responseEmOff.Setting.GearboxEngaged = false; + responseEmOff.Setting.GearboxInNeutral = + (!PreviousState.GearboxEngaged && DataBus.GearboxInfo.GearEngaged(absTime)) ? false : true; + eval.Add(responseEmOff); + return; + } - if (DataBus.GearboxInfo.GearboxType.AutomaticTransmission() && response == null && nextGear.Equals(GearList.First())) { + if (GearList.HasPredecessor(nextGear) + && EngineSpeedTooLow(response) + && (!vehiclespeedBelowThreshold || AllowEmergencyShift)) { + // engine speed would fall below idling speed - consider downshift + var estimatedVelocityPostShift = VelocityDropData.Valid + ? VelocityDropData.Interpolate(DataBus.VehicleInfo.VehicleSpeed, + DataBus.DrivingCycleInfo.RoadGradient ?? 0.SI<Radian>()) + : DataBus.VehicleInfo.VehicleSpeed; + var postShiftBelowThreshold = estimatedVelocityPostShift.IsSmaller(disengageSpeedThreshold); + if (postShiftBelowThreshold) { var downshift = ResponseEmOff; - downshift.Gear = nextGear; + downshift.Gear = GearList.Predecessor(nextGear); eval.Add(downshift); return; } - if (tmp.CombustionEngineOn) { - var firstEntry = new HybridResultEntry(); - CalculateCosts(response, dt, firstEntry, AllowICEOff(absTime), dryRun); - var minimumShiftTimePassed = (DataBus.GearboxInfo.LastShift + ModelData.GearshiftParameters.TimeBetweenGearshifts).IsSmallerOrEqual(absTime); - if (DataBus.GearboxInfo.GearEngaged(absTime) && !vehiclespeedBelowThreshold) { - var reEngaged = !PreviousState.GearboxEngaged && DataBus.GearboxInfo.GearEngaged(absTime); - if ((firstEntry.IgnoreReason.EngineSpeedBelowDownshift() && !firstEntry.IgnoreReason.EngineTorqueDemandTooHigh() || - firstEntry.IgnoreReason.EngineSpeedTooLow()) && !reEngaged) { - // ICE torque below FLD is OK as EM may regenerate and shift ICE operating point on drag line - // for negative torques the shift line is vertical anyway ;-) - var best = FindBestGearForBraking(nextGear, response); - if (!best.Equals(currentGear)) { - // downshift required! - var downshift = ResponseEmOff; - //downshift.Gear = GearList.Predecessor(nextGear); - downshift.Gear = best; // GearList.Predecessor(nextGear); - downshift.Setting.GearboxInNeutral = best.Gear == 0; - downshift.Setting.ShiftRequired = best.Gear == 0; - eval.Add(downshift); - return; - } + do { + nextGear = GearList.Predecessor(nextGear); + response = RequestDryRun(absTime, dt, outTorque, outAngularVelocity, nextGear, tmp); + debug.Add($"[AHS.HBA-1] DryRun Gear={nextGear}", response); + } while (GearList.HasPredecessor(nextGear) && response == null); + } + + if (nextGear.Equals(GearList.First()) && EngineSpeedTooLow(response)) { + // disengage gearbox... + var responseEmOff = ResponseEmOff; + responseEmOff.Gear = new GearshiftPosition(0); + responseEmOff.Setting.GearboxEngaged = false; + responseEmOff.Setting.GearboxInNeutral = true; + eval.Add(responseEmOff); + return; + } + + if (DataBus.GearboxInfo.GearboxType.AutomaticTransmission() && response == null && + nextGear.Equals(GearList.First())) { + var downshift = ResponseEmOff; + downshift.Gear = nextGear; + eval.Add(downshift); + return; + } + + if (tmp.CombustionEngineOn) { + var firstEntry = new HybridResultEntry(); + CalculateCosts(response, dt, firstEntry, AllowICEOff(absTime), dryRun); + var minimumShiftTimePassed = + (DataBus.GearboxInfo.LastShift + ModelData.GearshiftParameters.TimeBetweenGearshifts) + .IsSmallerOrEqual(absTime); + if (DataBus.GearboxInfo.GearEngaged(absTime) && !vehiclespeedBelowThreshold) { + var reEngaged = !PreviousState.GearboxEngaged && DataBus.GearboxInfo.GearEngaged(absTime); + if ((firstEntry.IgnoreReason.EngineSpeedBelowDownshift() && + !firstEntry.IgnoreReason.EngineTorqueDemandTooHigh() || + firstEntry.IgnoreReason.EngineSpeedTooLow()) && !reEngaged) { + // ICE torque below FLD is OK as EM may regenerate and shift ICE operating point on drag line + // for negative torques the shift line is vertical anyway ;-) + var best = FindBestGearForBraking(nextGear, response); + if (!best.Equals(currentGear)) { + // downshift required! + var downshift = ResponseEmOff; + //downshift.Gear = GearList.Predecessor(nextGear); + downshift.Gear = best; // GearList.Predecessor(nextGear); + downshift.Setting.GearboxInNeutral = best.Gear == 0; + downshift.Setting.ShiftRequired = best.Gear == 0; + eval.Add(downshift); + return; } } + } - if (!nextGear.Equals(currentGear) && !firstEntry.IgnoreReason.InvalidEngineSpeed()) { - firstEntry.Gear = nextGear; - firstEntry.Setting = tmp; - eval.Add(firstEntry); - } + if (!nextGear.Equals(currentGear) && !firstEntry.IgnoreReason.InvalidEngineSpeed()) { + firstEntry.Gear = nextGear; + firstEntry.Setting = tmp; + eval.Add(firstEntry); } + } - var deltaDragTqFirst = disengaged ? - (response as ResponseDryRun).Gearbox.InputTorque //.DeltaDragLoadTorque - : response.Engine.TotalTorqueDemand - response.Engine.DragTorque; + var deltaDragTqFirst = disengaged + ? (response as ResponseDryRun).Gearbox.InputTorque //.DeltaDragLoadTorque + : response.Engine.TotalTorqueDemand - response.Engine.DragTorque; - if (!response.Engine.EngineOn && DataBus.GearboxInfo.GearboxType.AutomaticTransmission()) { - deltaDragTqFirst = response.Gearbox.InputTorque; - } + if (!response.Engine.EngineOn && DataBus.GearboxInfo.GearboxType.AutomaticTransmission()) { + deltaDragTqFirst = response.Gearbox.InputTorque; + } - if (deltaDragTqFirst.IsGreater(0)) { - // braking requested but engine operating point is not below drag curve. - if (ElectricMotorCanPropellDuringTractionInterruption) { - if (DataBus.GearboxInfo.GearEngaged(absTime)) { - eval.AddRange(FindSolution(absTime, dt, outTorque, outAngularVelocity, dryRun)); - } else { - EvaluateConfigsForGear( - absTime, dt, outTorque, outAngularVelocity, nextGear, AllowICEOff(absTime), eval, emPos, dryRun); - } - } else if (DataBus.GearboxInfo.GearEngaged(absTime)) { + if (deltaDragTqFirst.IsGreater(0)) { + // braking requested but engine operating point is not below drag curve. + if (ElectricMotorCanPropellDuringTractionInterruption) { + if (DataBus.GearboxInfo.GearEngaged(absTime)) { eval.AddRange(FindSolution(absTime, dt, outTorque, outAngularVelocity, dryRun)); } else { - eval.Add(ResponseEmOff); + EvaluateConfigsForGear( + absTime, dt, outTorque, outAngularVelocity, nextGear, AllowICEOff(absTime), eval, emPos, + dryRun); } - return; - } - - if (!response.Gearbox.Gear.Engaged && !ElectricMotorCanPropellDuringTractionInterruption) { - // we are disengaged and EM cannot recuperate - switch EM off + } else if (DataBus.GearboxInfo.GearEngaged(absTime)) { + eval.AddRange(FindSolution(absTime, dt, outTorque, outAngularVelocity, dryRun)); + } else { eval.Add(ResponseEmOff); - return; - } - - if (response.ElectricMotor.MaxRecuperationTorque == null) { - var retVal = ResponseEmOff; - retVal.Gear = disengaged ? new GearshiftPosition(0) : response.Gearbox.Gear; - eval.Add(retVal); - return; } - var maxRecuperation = new HybridStrategyResponse { - CombustionEngineOn = DataBus.EngineInfo.EngineOn, // AllowICEOff(absTime), - GearboxInNeutral = false, - NextGear = nextGear, - MechanicalAssistPower = new Dictionary<PowertrainPosition, Tuple<PerSecond, NewtonMeter>> { - { emPos, Tuple.Create(response.ElectricMotor.AngularVelocity, VectoMath.Max(response.ElectricMotor.MaxRecuperationTorque, 0.SI<NewtonMeter>())) } - } - }; - var maxRecuperationResponse = RequestDryRun(absTime, dt, outTorque, outAngularVelocity, nextGear, maxRecuperation); - debug.Add("[AHS.HBA-2] DryRun maxRecuperationResponse", maxRecuperationResponse); - var deltaDragTqMaxRecuperation = disengaged - ? (maxRecuperationResponse as ResponseDryRun).Gearbox.InputTorque //.DeltaDragLoadTorque - : maxRecuperationResponse.Engine.TotalTorqueDemand - maxRecuperationResponse.Engine.DragTorque; + return; + } - var isAPTWithTorqueConverter = DataBus.GearboxInfo.GearboxType.AutomaticTransmission() && - DataBus.GearboxInfo.GearboxType != GearboxType.IHPC; - if (!maxRecuperationResponse.Engine.EngineOn && isAPTWithTorqueConverter) { - deltaDragTqMaxRecuperation = maxRecuperationResponse.Gearbox.InputTorque; - } + if (!response.Gearbox.Gear.Engaged && !ElectricMotorCanPropellDuringTractionInterruption) { + // we are disengaged and EM cannot recuperate - switch EM off + eval.Add(ResponseEmOff); + return; + } - if (deltaDragTqMaxRecuperation.IsEqual(0)) { - // with max recuperation we are already at the drag curve (e.g. because search braking power was invoked before - eval.Add( - new HybridResultEntry { - ICEOff = !DataBus.EngineInfo.EngineOn, - Gear = nextGear, - Setting = maxRecuperation - }); - return; - } + if (response.ElectricMotor.MaxRecuperationTorque == null) { + var retVal = ResponseEmOff; + retVal.Gear = disengaged ? new GearshiftPosition(0) : response.Gearbox.Gear; + eval.Add(retVal); + return; + } - if (deltaDragTqMaxRecuperation.IsSmaller(0) && - maxRecuperationResponse.ElectricSystem.RESSPowerDemand.IsBetween(maxRecuperationResponse.ElectricSystem.MaxPowerDrag, maxRecuperationResponse.ElectricSystem.MaxPowerDrive)) { - // even with full recuperation (and no braking) the operating point is below the drag curve (and the battery can handle it) - use full recuperation - eval.Add( - new HybridResultEntry { - ICEOff = !DataBus.EngineInfo.EngineOn, - Gear = nextGear, - Setting = new HybridStrategyResponse { - CombustionEngineOn = DataBus.EngineInfo.EngineOn, - GearboxInNeutral = false, - NextGear = nextGear, - MechanicalAssistPower = new Dictionary<PowertrainPosition, Tuple<PerSecond, NewtonMeter>> { - { emPos, Tuple.Create(response.ElectricMotor.AngularVelocity, response.ElectricMotor.MaxRecuperationTorque) } - } - } - }); - return; + var maxRecuperation = new HybridStrategyResponse { + CombustionEngineOn = DataBus.EngineInfo.EngineOn, // AllowICEOff(absTime), + GearboxInNeutral = false, + NextGear = nextGear, + MechanicalAssistPower = new Dictionary<PowertrainPosition, Tuple<PerSecond, NewtonMeter>> { + { + emPos, + Tuple.Create(response.ElectricMotor.AngularVelocity, + VectoMath.Max(response.ElectricMotor.MaxRecuperationTorque, 0.SI<NewtonMeter>())) + } } + }; + var maxRecuperationResponse = + RequestDryRun(absTime, dt, outTorque, outAngularVelocity, nextGear, maxRecuperation); + debug.Add("[AHS.HBA-2] DryRun maxRecuperationResponse", maxRecuperationResponse); + var deltaDragTqMaxRecuperation = disengaged + ? (maxRecuperationResponse as ResponseDryRun).Gearbox.InputTorque //.DeltaDragLoadTorque + : maxRecuperationResponse.Engine.TotalTorqueDemand - maxRecuperationResponse.Engine.DragTorque; + + var isAPTWithTorqueConverter = DataBus.GearboxInfo.GearboxType.AutomaticTransmission() && + DataBus.GearboxInfo.GearboxType != GearboxType.IHPC; + if (!maxRecuperationResponse.Engine.EngineOn && isAPTWithTorqueConverter) { + deltaDragTqMaxRecuperation = maxRecuperationResponse.Gearbox.InputTorque; + } + + if (deltaDragTqMaxRecuperation.IsEqual(0)) { + // with max recuperation we are already at the drag curve (e.g. because search braking power was invoked before + eval.Add( + new HybridResultEntry { + ICEOff = !DataBus.EngineInfo.EngineOn, + Gear = nextGear, + Setting = maxRecuperation + }); + return; + } - // full recuperation is not possible - ICE would need to propel - search max possible EM torque - var emRecuperationTq = SearchAlgorithm.Search( - maxRecuperationResponse.ElectricMotor.ElectricMotorPowerMech / - maxRecuperationResponse.ElectricMotor.AngularVelocity, - maxRecuperationResponse.Engine.TorqueOutDemand, maxRecuperationResponse.ElectricMotor.MaxRecuperationTorque * 0.1, - getYValue: resp => { - var r = resp as IResponse; - var deltaDragLoad = disengaged - ? (r as ResponseDryRun).Gearbox.InputTorque //.DeltaDragLoadTorque - : r.Engine.TotalTorqueDemand - r.Engine.DragTorque; - if (!r.Engine.EngineOn && isAPTWithTorqueConverter) { - deltaDragLoad = r.Gearbox.InputTorque; - } - return deltaDragLoad; - }, - evaluateFunction: emTq => { - var cfg = new HybridStrategyResponse { - CombustionEngineOn = DataBus.EngineInfo.EngineOn, - GearboxInNeutral = false, - NextGear = nextGear, - MechanicalAssistPower = new Dictionary<PowertrainPosition, Tuple<PerSecond, NewtonMeter>> { - { emPos, Tuple.Create(response.ElectricMotor.AngularVelocity, emTq) } - } - }; - return RequestDryRun(absTime, dt, outTorque, outAngularVelocity, DataBus.GearboxInfo.GearEngaged(absTime) ? nextGear : new GearshiftPosition(0), cfg); - }, - criterion: resp => { - var r = resp as IResponse; - var deltaDragLoad = disengaged - ? (r as ResponseDryRun).Gearbox.InputTorque //.DeltaDragLoadTorque - : r.Engine.TotalTorqueDemand - r.Engine.DragTorque; - if (!r.Engine.EngineOn && isAPTWithTorqueConverter) { - deltaDragLoad = r.Gearbox.InputTorque; - } - return deltaDragLoad.Value(); - }, - searcher: this - ); - if (emRecuperationTq.IsBetween( - response.ElectricMotor.MaxDriveTorque ?? 0.SI<NewtonMeter>(), response.ElectricMotor.MaxRecuperationTorque ?? 0.SI<NewtonMeter>())) { - var entry = new HybridResultEntry { + if (deltaDragTqMaxRecuperation.IsSmaller(0) && + maxRecuperationResponse.ElectricSystem.RESSPowerDemand.IsBetween( + maxRecuperationResponse.ElectricSystem.MaxPowerDrag, + maxRecuperationResponse.ElectricSystem.MaxPowerDrive)) { + // even with full recuperation (and no braking) the operating point is below the drag curve (and the battery can handle it) - use full recuperation + eval.Add( + new HybridResultEntry { ICEOff = !DataBus.EngineInfo.EngineOn, Gear = nextGear, Setting = new HybridStrategyResponse { CombustionEngineOn = DataBus.EngineInfo.EngineOn, GearboxInNeutral = false, NextGear = nextGear, - MechanicalAssistPower = new Dictionary<PowertrainPosition, Tuple<PerSecond, NewtonMeter>> { - { emPos, Tuple.Create(response.ElectricMotor.AngularVelocity, emRecuperationTq) } - } + MechanicalAssistPower = + new Dictionary<PowertrainPosition, Tuple<PerSecond, NewtonMeter>> { + { + emPos, + Tuple.Create(response.ElectricMotor.AngularVelocity, + response.ElectricMotor.MaxRecuperationTorque) + } + } } - }; - entry.Response = RequestDryRun(absTime, dt, outTorque, outAngularVelocity, nextGear, entry.Setting); - if (entry.Response.ElectricSystem.ConsumerPower.IsGreater(0)) { - eval.Add(entry); - } else { - // for the found operating point, although recuperating no electric energy is generated. leave EM off - var off = ResponseEmOff; - if (vehiclespeedBelowThreshold && (emPos == PowertrainPosition.HybridP2 || emPos == PowertrainPosition.HybridP1)) { - off.Setting.GearboxInNeutral = true; - } else { - off.Setting.GearboxInNeutral = PreviousState.Solution?.Setting.GearboxInNeutral ?? false; + }); + return; + } + + // full recuperation is not possible - ICE would need to propel - search max possible EM torque + var emRecuperationTq = SearchAlgorithm.Search( + maxRecuperationResponse.ElectricMotor.ElectricMotorPowerMech / + maxRecuperationResponse.ElectricMotor.AngularVelocity, + maxRecuperationResponse.Engine.TorqueOutDemand, + maxRecuperationResponse.ElectricMotor.MaxRecuperationTorque * 0.1, + getYValue: resp => { + var r = resp as IResponse; + var deltaDragLoad = disengaged + ? (r as ResponseDryRun).Gearbox.InputTorque //.DeltaDragLoadTorque + : r.Engine.TotalTorqueDemand - r.Engine.DragTorque; + if (!r.Engine.EngineOn && isAPTWithTorqueConverter) { + deltaDragLoad = r.Gearbox.InputTorque; + } + + return deltaDragLoad; + }, + evaluateFunction: emTq => { + var cfg = new HybridStrategyResponse { + CombustionEngineOn = DataBus.EngineInfo.EngineOn, + GearboxInNeutral = false, + NextGear = nextGear, + MechanicalAssistPower = new Dictionary<PowertrainPosition, Tuple<PerSecond, NewtonMeter>> { + { emPos, Tuple.Create(response.ElectricMotor.AngularVelocity, emTq) } } + }; + return RequestDryRun(absTime, dt, outTorque, outAngularVelocity, + DataBus.GearboxInfo.GearEngaged(absTime) ? nextGear : new GearshiftPosition(0), cfg); + }, + criterion: resp => { + var r = resp as IResponse; + var deltaDragLoad = disengaged + ? (r as ResponseDryRun).Gearbox.InputTorque //.DeltaDragLoadTorque + : r.Engine.TotalTorqueDemand - r.Engine.DragTorque; + if (!r.Engine.EngineOn && isAPTWithTorqueConverter) { + deltaDragLoad = r.Gearbox.InputTorque; + } - eval.Add(off); + return deltaDragLoad.Value(); + }, + searcher: this + ); + if (emRecuperationTq.IsBetween( + response.ElectricMotor.MaxDriveTorque ?? 0.SI<NewtonMeter>(), + response.ElectricMotor.MaxRecuperationTorque ?? 0.SI<NewtonMeter>())) { + var entry = new HybridResultEntry { + ICEOff = !DataBus.EngineInfo.EngineOn, + Gear = nextGear, + Setting = new HybridStrategyResponse { + CombustionEngineOn = DataBus.EngineInfo.EngineOn, + GearboxInNeutral = false, + NextGear = nextGear, + MechanicalAssistPower = new Dictionary<PowertrainPosition, Tuple<PerSecond, NewtonMeter>> { + { emPos, Tuple.Create(response.ElectricMotor.AngularVelocity, emRecuperationTq) } + } } + }; + entry.Response = RequestDryRun(absTime, dt, outTorque, outAngularVelocity, nextGear, entry.Setting); + if (entry.Response.ElectricSystem.ConsumerPower.IsGreater(0)) { + eval.Add(entry); } else { - if (emRecuperationTq.IsGreater(0)) { - var voltage = DataBus.BatteryInfo.InternalVoltage; - var maxbatDragTq = DataBus.ElectricMotorInfo(emPos).GetTorqueForElectricPower(voltage, - response.ElectricSystem.MaxPowerDrag, response.ElectricMotor.AngularVelocity, dt, nextGear, - false); - eval.Add( - new HybridResultEntry { - ICEOff = !DataBus.EngineInfo.EngineOn, - Gear = nextGear, - Setting = new HybridStrategyResponse { - CombustionEngineOn = DataBus.EngineInfo.EngineOn, - GearboxInNeutral = false, - NextGear = nextGear, - MechanicalAssistPower = new Dictionary<PowertrainPosition, Tuple<PerSecond, NewtonMeter>> { - { emPos, Tuple.Create(response.ElectricMotor.AngularVelocity, VectoMath.Min(maxbatDragTq, response.ElectricMotor.MaxRecuperationTorque)) } - } - } - }); + // for the found operating point, although recuperating no electric energy is generated. leave EM off + var off = ResponseEmOff; + if (vehiclespeedBelowThreshold && + (emPos == PowertrainPosition.HybridP2 || emPos == PowertrainPosition.HybridP1)) { + off.Setting.GearboxInNeutral = true; } else { - eval.Add(ResponseEmOff); + off.Setting.GearboxInNeutral = PreviousState.Solution?.Setting.GearboxInNeutral ?? false; } + + eval.Add(off); } } else { - var off = ResponseEmOff; - if (vehiclespeedBelowThreshold && (emPos == PowertrainPosition.HybridP2 || emPos == PowertrainPosition.HybridP1)) { - off.Setting.GearboxInNeutral = true; + if (emRecuperationTq.IsGreater(0)) { + var voltage = DataBus.BatteryInfo.InternalVoltage; + var maxbatDragTq = DataBus.ElectricMotorInfo(emPos).GetTorqueForElectricPower(voltage, + response.ElectricSystem.MaxPowerDrag, response.ElectricMotor.AngularVelocity, dt, nextGear, + false); + eval.Add( + new HybridResultEntry { + ICEOff = !DataBus.EngineInfo.EngineOn, + Gear = nextGear, + Setting = new HybridStrategyResponse { + CombustionEngineOn = DataBus.EngineInfo.EngineOn, + GearboxInNeutral = false, + NextGear = nextGear, + MechanicalAssistPower = + new Dictionary<PowertrainPosition, Tuple<PerSecond, NewtonMeter>> { + { + emPos, + Tuple.Create(response.ElectricMotor.AngularVelocity, + VectoMath.Min(maxbatDragTq, + response.ElectricMotor.MaxRecuperationTorque)) + } + } + } + }); } else { - off.Setting.GearboxInNeutral = PreviousState.Solution?.Setting.GearboxInNeutral ?? false; + eval.Add(ResponseEmOff); } - - eval.Add(off); } } -- GitLab