diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Strategies/HybridStrategy.cs b/VectoCore/VectoCore/Models/SimulationComponent/Strategies/HybridStrategy.cs index 27ee73b461b8c0e1f03dd89b405423e75b71a23b..2c79bfab59561dbb29e7ee18ebebb8b387d148a1 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Strategies/HybridStrategy.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Strategies/HybridStrategy.cs @@ -387,12 +387,16 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies var best = eval.Where(x => !double.IsNaN(x.Score)).OrderBy(x => x.Score).FirstOrDefault(); if (best == null) { best = eval.OrderBy(x => Math.Abs((int)currentGear - x.Gear)).FirstOrDefault( - x => !DataBus.EngineCtl.CombustionEngineOn || !x.IgnoreReason.InvalidEngineSpeed()); + x => !(!x.ICEOff && x.IgnoreReason.InvalidEngineSpeed())); if (best == null /*&& dryRun*/) { var emEngaged = (!ElectricMotorCanPropellDuringTractionInterruption || (DataBus.GearboxInfo.GearEngaged(absTime) && eval.First().Response.Gearbox.Gear != 0)); if (DataBus.DriverInfo.DrivingAction == DrivingAction.Accelerate && emEngaged) { - best = eval.MinBy(x => x.Setting.MechanicalAssistPower.Sum(e => e.Value ?? 0.SI<NewtonMeter>())); + var filtered = eval.Where(x => !x.IgnoreReason.InvalidEngineSpeed()).ToArray(); + if (filtered.Length == 0) { + filtered = eval.OrderBy(x => Math.Abs((int)currentGear - x.Gear)).ToArray(); + } + best = filtered.MinBy(x => x.Setting.MechanicalAssistPower.Sum(e => e.Value ?? 0.SI<NewtonMeter>())); } if (DataBus.DriverInfo.DrivingAction == DrivingAction.Brake && emEngaged) { best = eval.MaxBy(x => x.Setting.MechanicalAssistPower.Sum(e => e.Value ?? 0.SI<NewtonMeter>())); @@ -408,7 +412,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies if (DataBus.DriverInfo.DrivingAction == DrivingAction.Accelerate && allOverload) { if (ElectricMotorCanPropellDuringTractionInterruption || DataBus.GearboxInfo.GearEngaged(absTime)) { // overload, EM can support - use solution with max EM power - best = eval.MinBy(x => x.Setting.MechanicalAssistPower.Sum(e => e.Value ?? 0.SI<NewtonMeter>())); + best = eval.OrderBy(x => Math.Abs((int)currentGear - x.Gear)).MinBy(x => x.Setting.MechanicalAssistPower.Sum(e => e.Value ?? 0.SI<NewtonMeter>())); } } if ((DataBus.DriverInfo.DrivingAction == DrivingAction.Accelerate // || @@ -426,6 +430,27 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies } else { } + + if (best != null && best.IgnoreReason.InvalidEngineSpeed() && !best.ICEOff && eval.Select(x => x.Gear).Distinct().Count() >1) { + // selected solution has invalid engine speed and engine is on and evaluation contains only one gear - allow emergency shift + if ((best.IgnoreReason & HybridConfigurationIgnoreReason.EngineSpeedAboveUpshift) != 0) { + //try upshift + var newEval = new List<HybridResultEntry>(); + EvaluateConfigsForGear( + absTime, dt, outTorque, outAngularVelocity, best.Gear + 1, AllowICEOff(absTime), newEval, + best.Setting.MechanicalAssistPower.First().Key); + best = SelectBestOption(newEval, absTime, dt, outTorque, outAngularVelocity, dryRun, currentGear); + } + if ((best.IgnoreReason & HybridConfigurationIgnoreReason.EngineSpeedBelowDownshift) != 0) { + //try downshift + var newEval = new List<HybridResultEntry>(); + EvaluateConfigsForGear( + absTime, dt, outTorque, outAngularVelocity, best.Gear - 1, AllowICEOff(absTime), newEval, + best.Setting.MechanicalAssistPower.First().Key); + best = SelectBestOption(newEval, absTime, dt, outTorque, outAngularVelocity, dryRun, currentGear); + } + } + return best; } @@ -485,59 +510,80 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies nextGear <= Math.Min(numGears, gear + gearRangeUpshift); nextGear++) { - var emOffEntry = GetEmOffResultEntry(absTime, dt, outTorque, outAngularVelocity, nextGear); + var emOffEntry = EvaluateConfigsForGear(absTime, dt, outTorque, outAngularVelocity, nextGear, allowICEOff, responses, emPos); + if (emOffEntry == null) { continue; } - - CalcualteCosts(emOffEntry.Response, dt, emOffEntry, allowICEOff); if (nextGear == gear && gearRangeUpshift == 0 && (emOffEntry.IgnoreReason & HybridConfigurationIgnoreReason.EngineSpeedTooHigh) != 0) { allowEmergencyUpshift = true; } if (nextGear == gear && gearRangeDownshift == 0 && (emOffEntry.IgnoreReason & HybridConfigurationIgnoreReason.EngineSpeedTooLow) != 0) { allowEmergencyDownshift = true; } - responses.Add(emOffEntry); - - var emTqReq = (emOffEntry.Response.ElectricMotor.PowerRequest + emOffEntry.Response.ElectricMotor.InertiaPowerDemand) / emOffEntry.Response.ElectricMotor.AngularVelocity; - IterateEMTorque(absTime, dt, outTorque, outAngularVelocity, nextGear, allowICEOff, emOffEntry.Response, emTqReq, emPos, responses); } var tmpBest = responses.Where(x => !double.IsNaN(x.Score)).OrderBy(x => x.Score).FirstOrDefault(); if (allowEmergencyUpshift && tmpBest != null && !tmpBest.ICEOff) { var nextGear = gear + 1; - var emOffEntry = GetEmOffResultEntry(absTime, dt, outTorque, outAngularVelocity, nextGear); - if (emOffEntry != null) { - CalcualteCosts(emOffEntry.Response, dt, emOffEntry, allowICEOff); - - responses.Add(emOffEntry); - - var emTqReq = - (emOffEntry.Response.ElectricMotor.PowerRequest + emOffEntry.Response.ElectricMotor.InertiaPowerDemand) / - emOffEntry.Response.ElectricMotor.AngularVelocity; - IterateEMTorque( - absTime, dt, outTorque, outAngularVelocity, nextGear, allowICEOff, emOffEntry.Response, emTqReq, emPos, - responses); - } + var emOffEntry = EvaluateConfigsForGear( + absTime, dt, outTorque, outAngularVelocity, nextGear, allowICEOff, responses, emPos); + + // GetEmOffResultEntry(absTime, dt, outTorque, outAngularVelocity, nextGear); + //if (emOffEntry != null) { + // CalcualteCosts(emOffEntry.Response, dt, emOffEntry, allowICEOff); + + // responses.Add(emOffEntry); + + // var emTqReq = + // (emOffEntry.Response.ElectricMotor.PowerRequest + emOffEntry.Response.ElectricMotor.InertiaPowerDemand) / + // emOffEntry.Response.ElectricMotor.AngularVelocity; + // IterateEMTorque( + // absTime, dt, outTorque, outAngularVelocity, nextGear, allowICEOff, emOffEntry.Response, emTqReq, emPos, + // responses); + //} } if (allowEmergencyDownshift && tmpBest != null && !tmpBest.ICEOff) { var nextGear = gear - 1; - var emOffEntry = GetEmOffResultEntry(absTime, dt, outTorque, outAngularVelocity, nextGear); - if (emOffEntry != null) { - CalcualteCosts(emOffEntry.Response, dt, emOffEntry, allowICEOff); + var emOffEntry = EvaluateConfigsForGear( + absTime, dt, outTorque, outAngularVelocity, nextGear, allowICEOff, responses, emPos); + + // GetEmOffResultEntry(absTime, dt, outTorque, outAngularVelocity, nextGear); + //if (emOffEntry != null) { + // CalcualteCosts(emOffEntry.Response, dt, emOffEntry, allowICEOff); + + // responses.Add(emOffEntry); + + // var emTqReq = + // (emOffEntry.Response.ElectricMotor.PowerRequest + emOffEntry.Response.ElectricMotor.InertiaPowerDemand) / + // emOffEntry.Response.ElectricMotor.AngularVelocity; + // IterateEMTorque( + // absTime, dt, outTorque, outAngularVelocity, nextGear, allowICEOff, emOffEntry.Response, emTqReq, emPos, + // responses); + //} + } - responses.Add(emOffEntry); + return responses; + } - var emTqReq = - (emOffEntry.Response.ElectricMotor.PowerRequest + emOffEntry.Response.ElectricMotor.InertiaPowerDemand) / - emOffEntry.Response.ElectricMotor.AngularVelocity; - IterateEMTorque( - absTime, dt, outTorque, outAngularVelocity, nextGear, allowICEOff, emOffEntry.Response, emTqReq, emPos, - responses); - } + private HybridResultEntry EvaluateConfigsForGear( + Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, uint nextGear, bool allowICEOff, + List<HybridResultEntry> responses, PowertrainPosition emPos) + { + var emOffEntry = GetEmOffResultEntry(absTime, dt, outTorque, outAngularVelocity, nextGear); + if (emOffEntry == null) { + return null; } - return responses; + CalcualteCosts(emOffEntry.Response, dt, emOffEntry, allowICEOff); + + responses.Add(emOffEntry); + + var emTqReq = (emOffEntry.Response.ElectricMotor.PowerRequest + emOffEntry.Response.ElectricMotor.InertiaPowerDemand) / + emOffEntry.Response.ElectricMotor.AngularVelocity; + IterateEMTorque( + absTime, dt, outTorque, outAngularVelocity, nextGear, allowICEOff, emOffEntry.Response, emTqReq, emPos, responses); + return emOffEntry; } private HybridResultEntry GetEmOffResultEntry( @@ -650,6 +696,53 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies var tmp = TryConfiguration(absTime, dt, outTorque, outAngularVelocity, nextGear, emPos, emTorque, u, allowIceOff); responses.Add(tmp); } + var maxEmTorqueRecuperate = firstResponse.ElectricMotor.MaxRecuperationTorque ?? 0.SI<NewtonMeter>(); + + if (maxEmTorqueRecuperate.IsGreater(0) && allowIceOff && DataBus.DriverInfo.DrivingAction != DrivingAction.Brake) { + if (ElectricMotorCanPropellDuringTractionInterruption) { + // this means that the EM is between wheels and transmission + // search EM Torque that results in 0 torque at ICE out + try { + var emTorqueICEOff = SearchAlgorithm.Search( + firstResponse.ElectricMotor.ElectricMotorPowerMech / firstResponse.ElectricMotor.AngularVelocity, + firstResponse.Engine.TorqueOutDemand, firstResponse.ElectricMotor.MaxRecuperationTorque * 0.1, + getYValue: r => { + var response = r as ResponseDryRun; + return response.Engine.TorqueOutDemand; + }, + evaluateFunction: emTq => { + var cfg = new HybridStrategyResponse() { + CombustionEngineOn = true, + GearboxInNeutral = false, + MechanicalAssistPower = new Dictionary<PowertrainPosition, NewtonMeter>() { + { emPos, emTq } + } + }; + return RequestDryRun(absTime, dt, outTorque, outAngularVelocity, nextGear, cfg); + }, + criterion: r => { + var response = r as ResponseDryRun; + return response.Engine.TorqueOutDemand.Value(); + } + ); + if (emTorqueICEOff.IsBetween(maxEmTorqueRecuperate, 0.SI<NewtonMeter>())) { + // only consider where EM is recuperating + var tmp = TryConfiguration( + absTime, dt, outTorque, outAngularVelocity, nextGear, emPos, emTorqueICEOff, + emTorqueICEOff / maxEmTorqueRecuperate, + allowIceOff); + responses.Add(tmp); + } + } catch (Exception) { + Log.Debug("Failed to find EM torque to compensate drag losses of next components."); + } + } else { + if (maxEmTorqueRecuperate.IsGreater(0) && (-emTqReq).IsBetween(maxEmTorqueRecuperate, 0.SI<NewtonMeter>())) { + var tmp = TryConfiguration(absTime, dt, outTorque, outAngularVelocity, nextGear, emPos, -emTqReq, -emTqReq / maxEmTorqueRecuperate, allowIceOff); + responses.Add(tmp); + } + } + } } } diff --git a/VectoCore/VectoCore/OutputData/ModalDataContainer.cs b/VectoCore/VectoCore/OutputData/ModalDataContainer.cs index b4ae1f97afc767430ea7d659d8cf5d9a0c3e1e11..1eb813683a7d916ed5a3566569162eed27deca0a 100644 --- a/VectoCore/VectoCore/OutputData/ModalDataContainer.cs +++ b/VectoCore/VectoCore/OutputData/ModalDataContainer.cs @@ -196,6 +196,10 @@ namespace TUGraz.VectoCore.OutputData x.Field<SI>(GetColumnName(fuel, ModalResultField.FCFinal)).Value()) : null).Where(x => x != null && x.Y > 0), out k, out d, out r); + if (double.IsInfinity(k) || double.IsNaN(k)) { + LogManager.GetLogger(typeof(ModalDataContainer).FullName).Warn("could not calculate engine correction line - k: {0}", k); + k = 0; + } _engLine[fuel.FuelType] = k.SI<KilogramPerWattSecond>(); return _engLine[fuel.FuelType]; @@ -218,6 +222,7 @@ namespace TUGraz.VectoCore.OutputData : null) .Where(x => x != null && x.X > 0 && x.Y > 0), out k, out d, out r); if (double.IsInfinity(k) || double.IsNaN(k)) { + LogManager.GetLogger(typeof(ModalDataContainer).FullName).Warn("could not calculate vehicle correction line - k: {0}", k); k = 0; } _vehLine[fuel.FuelType] = k.SI<KilogramPerWattSecond>();