diff --git a/VectoCommon/VectoCommon/Models/PowertrainPosition.cs b/VectoCommon/VectoCommon/Models/PowertrainPosition.cs index cf25a4c8e7714f609364984a89ec29a3a2921368..a56c9cade93e42ce4b591a80f36d507b9c486b89 100644 --- a/VectoCommon/VectoCommon/Models/PowertrainPosition.cs +++ b/VectoCommon/VectoCommon/Models/PowertrainPosition.cs @@ -18,6 +18,7 @@ namespace TUGraz.VectoCommon.InputData { BatteryElectricE4, BatteryElectricE3, BatteryElectricE2, + Generator } public static class PowertrainPositionHelper diff --git a/VectoCore/VectoCore/Models/Simulation/Data/ModalResultField.cs b/VectoCore/VectoCore/Models/Simulation/Data/ModalResultField.cs index 6241b2ba4c6654602803c9718672e255a2467604..059fc62251cd9dddc84b48640a453c9a4532d5d4 100644 --- a/VectoCore/VectoCore/Models/Simulation/Data/ModalResultField.cs +++ b/VectoCore/VectoCore/Models/Simulation/Data/ModalResultField.cs @@ -415,7 +415,11 @@ namespace TUGraz.VectoCore.Models.Simulation.Data [ModalResultField(typeof(SI), caption: "P_E2_mech [kW]", outputFactor: 1e-3)] P_electricMotor_mech_B2, - // --> + + [ModalResultField(typeof(SI), caption: "P_Generator_mech [kW]", outputFactor: 1e-3)] + P_electricMotor_mech_Gen, + + // --> [ModalResultField(typeof(SI), caption: "P_REESS_T [kW]", outputFactor: 1e-3)] P_reess_terminal, [ModalResultField(typeof(SI), caption: "P_REESS_int [kW]", outputFactor: 1e-3)] P_reess_int, diff --git a/VectoCore/VectoCore/Models/Simulation/DataBus/IDataBus.cs b/VectoCore/VectoCore/Models/Simulation/DataBus/IDataBus.cs index 715e43c85e5e655ad7657a03a8ccb82a863e8eec..f013632e136a3101729f081182b8df8cd30876c8 100644 --- a/VectoCore/VectoCore/Models/Simulation/DataBus/IDataBus.cs +++ b/VectoCore/VectoCore/Models/Simulation/DataBus/IDataBus.cs @@ -98,5 +98,7 @@ namespace TUGraz.VectoCore.Models.Simulation.DataBus bool HasElectricMotor { get; } PowertrainPosition[] ElectricMotorPositions { get; } + + VectoSimulationJobType VehicleArchitecutre { get; } } } \ No newline at end of file diff --git a/VectoCore/VectoCore/Models/Simulation/DataBus/IElectricMotorInfo.cs b/VectoCore/VectoCore/Models/Simulation/DataBus/IElectricMotorInfo.cs index 6da75642290ea0dd9a3d6a25539b4c61a28431d2..9c65c7585e9c48cee154e80b36d6d46c8d9b00dc 100644 --- a/VectoCore/VectoCore/Models/Simulation/DataBus/IElectricMotorInfo.cs +++ b/VectoCore/VectoCore/Models/Simulation/DataBus/IElectricMotorInfo.cs @@ -13,5 +13,7 @@ namespace TUGraz.VectoCore.Models.Simulation.DataBus Watt DragPower(Volt volt, PerSecond electricMotorSpeed); Watt MaxPowerDrive(Volt volt, PerSecond inAngularVelocity); NewtonMeter GetTorqueForElectricPower(Volt volt, Watt electricPower, PerSecond avgEmSpeed, Second dt); + + bool DeRatingActive { get; } } } \ No newline at end of file diff --git a/VectoCore/VectoCore/Models/Simulation/Impl/PCCEcoRollEngineStopPreprocessor.cs b/VectoCore/VectoCore/Models/Simulation/Impl/PCCEcoRollEngineStopPreprocessor.cs index 3a363abd3abfcedd74e5808fc3dc96c2aa375dfc..d2b1379ec1550d6139d663c702fa8d296f6cc1eb 100644 --- a/VectoCore/VectoCore/Models/Simulation/Impl/PCCEcoRollEngineStopPreprocessor.cs +++ b/VectoCore/VectoCore/Models/Simulation/Impl/PCCEcoRollEngineStopPreprocessor.cs @@ -142,7 +142,8 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl criterion: response => { var r = (ResponseDryRun)response; return (r.Gearbox?.PowerRequest ?? r.ElectricMotor?.TotalTorqueDemand * r.ElectricMotor?.AvgDrivetrainSpeed).Value(); - } + }, + searcher: this ); } catch (VectoSearchAbortedException) { return gradient; diff --git a/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs b/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs index a464d94aa519c295a1c710619c8eb1cb5c90d0b9..d2464bf61cfe163e07df4be19075c9b6b2e7b9fe 100644 --- a/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs +++ b/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs @@ -677,6 +677,115 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl .AddAuxiliaries(container, data); } + public void BuildSimpleSerialHybridPowertrain(VectoRunData data, VehicleContainer container) + { + var es = new ElectricSystem(container); + if (data.BatteryData != null) { + var battery = new BatterySystem(container, data.BatteryData); + battery.Initialize(data.BatteryData.InitialSoC); + es.Connect(battery); + } + + if (data.SuperCapData != null) { + var superCap = new SuperCap(container, data.SuperCapData); + superCap.Initialize(data.SuperCapData.InitialSoC); + es.Connect(superCap); + } + + //var battery = new Battery(container, data.BatteryData); + //battery.Initialize(data.BatteryData.InitialSoC); + //es.Connect(battery); + + var aux = new ElectricAuxiliary(container); + aux.AddConstant("P_aux_el", data.ElectricAuxDemand ?? 0.SI<Watt>()); + es.Connect(aux); + es.Connect(new GensetChargerAdapter(null)); + + var ctl = new SimpleHybridController(container, es); + + var pos = data.ElectricMachinesData.Select(x => x.Item1).First(x => x != PowertrainPosition.Generator); + + var vehicle = new Vehicle(container, data.VehicleData, data.AirdragData); + var powertrain = vehicle + .AddComponent(new Wheels(container, data.VehicleData.DynamicTyreRadius, + data.VehicleData.WheelsInertia)) + .AddComponent(ctl) + .AddComponent(new Brakes(container)); + + switch (pos) { + case PowertrainPosition.HybridPositionNotSet: + throw new VectoException("invalid powertrain position"); + case PowertrainPosition.BatteryElectricE2: + var gearbox = data.GearboxData.Type.AutomaticTransmission() + ? (IHybridControlledGearbox)new ATGearbox(container, ctl.ShiftStrategy) + : new Gearbox(container, ctl.ShiftStrategy); + powertrain = powertrain.AddComponent(new AxleGear(container, data.AxleGearData)) + .AddComponent(data.AngledriveData != null + ? new Angledrive(container, data.AngledriveData) + : null) + .AddComponent((IGearbox)gearbox, data.Retarder, container) + .AddComponent(GetElectricMachine(PowertrainPosition.BatteryElectricE2, data.ElectricMachinesData, + container, + es, ctl)); + ctl.Gearbox = gearbox; + + break; + case PowertrainPosition.BatteryElectricE3: + powertrain = powertrain.AddComponent(new AxleGear(container, data.AxleGearData)) + .AddComponent(GetElectricMachine(PowertrainPosition.BatteryElectricE3, data.ElectricMachinesData, + container, + es, ctl)); + new DummyGearboxInfo(container); + //new MockEngineInfo(container); + new ATClutchInfo(container); + break; + case PowertrainPosition.BatteryElectricE4: + powertrain = powertrain.AddComponent(GetElectricMachine(PowertrainPosition.BatteryElectricE4, data.ElectricMachinesData, + container, + es, ctl)); + new DummyGearboxInfo(container); + //new MockEngineInfo(container); + new ATClutchInfo(container); + break; + case PowertrainPosition.HybridP0: + case PowertrainPosition.HybridP1: + case PowertrainPosition.HybridP2_5: + case PowertrainPosition.HybridP2: + case PowertrainPosition.HybridP3: + case PowertrainPosition.HybridP4: + + throw new VectoException("testcase does not support parallel powertrain configurations"); + default: + throw new ArgumentOutOfRangeException(nameof(pos), pos, null); + } + + } + + public void BuildSimpleGenSet(VectoRunData data, VehicleContainer container) + { + var es = new ElectricSystem(container); + if (data.BatteryData != null) { + var battery = new BatterySystem(container, data.BatteryData); + battery.Initialize(data.BatteryData.InitialSoC); + es.Connect(battery); + } + + if (data.SuperCapData != null) { + var superCap = new SuperCap(container, data.SuperCapData); + superCap.Initialize(data.SuperCapData.InitialSoC); + es.Connect(superCap); + } + + //var ctl = new SimpleHybridController(container, es); + var ctl = new GensetMotorController(container, es); + + var genSet = GetElectricMachine(PowertrainPosition.Generator, data.ElectricMachinesData, container, es, ctl) + .AddComponent(new StopStartCombustionEngine(container, data.EngineData)); + + new ATClutchInfo(container); + new DummyGearboxInfo(container, new GearshiftPosition(0)); + } + public void BuildSimpleHybridPowertrain(VectoRunData data, VehicleContainer container) { //if (data.Cycle.CycleType != CycleType.DistanceBased) { @@ -714,7 +823,7 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl throw new VectoException("Gearbox can not be used for parallel hybrid"); } - var ctl = new SimpleHybridController(container, es, clutch); + var ctl = new SimpleHybridController(container, es); ctl.Gearbox = gbx; ctl.Engine = engine; @@ -1141,6 +1250,27 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl } } + public class GensetMotorController : IElectricMotorControl + { + public GensetMotorController(IVehicleContainer container, ElectricSystem es) + { + + } + + #region Implementation of IElectricMotorControl + + public NewtonMeter MechanicalAssistPower(Second absTime, Second dt, NewtonMeter outTorque, PerSecond prevOutAngularVelocity, + PerSecond currOutAngularVelocity, NewtonMeter maxDriveTorque, NewtonMeter maxRecuperationTorque, + PowertrainPosition position, bool dryRun) + { + return EMTorque; + } + + public NewtonMeter EMTorque { get; set; } + + #endregion + } + public class DummyElectricMotorControl : IElectricMotorControl { #region Implementation of IElectricMotorControl diff --git a/VectoCore/VectoCore/Models/Simulation/Impl/VehicleContainer.cs b/VectoCore/VectoCore/Models/Simulation/Impl/VehicleContainer.cs index 4b3973fa2a840e66bff85ed755ba63625c56e224..817b0520a4240aeadd09742cfddd7ecc8bae02d7 100644 --- a/VectoCore/VectoCore/Models/Simulation/Impl/VehicleContainer.cs +++ b/VectoCore/VectoCore/Models/Simulation/Impl/VehicleContainer.cs @@ -246,6 +246,8 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl public PowertrainPosition[] ElectricMotorPositions => ElectricMotors.Keys.ToArray(); + public VectoSimulationJobType VehicleArchitecutre => RunData.JobType; + public virtual bool HasCombustionEngine { get; private set; } public virtual bool HasGearbox { get; private set; } diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Data/ElectricMotor/EfficiencyMap.cs b/VectoCore/VectoCore/Models/SimulationComponent/Data/ElectricMotor/EfficiencyMap.cs index 823cc7d8563d7e63eb422fc1e24d4004ce94d7d0..4df9c70a3c7a034acd0af0f875d48f3ab0616bad 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Data/ElectricMotor/EfficiencyMap.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Data/ElectricMotor/EfficiencyMap.cs @@ -161,7 +161,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.ElectricMotor criterion: x => { var myX = (EfficiencyResult)x; return (myX.ElectricalPower - batPower).Value(); - }); + }, + searcher: this); var tmp = LookupElectricPower(avgSpeed, retVal, true); if ((tmp.ElectricalPower - batPower).IsGreater(Constants.SimulationSettings.InterpolateSearchTolerance)) { // searched operating point is not accurate enough... @@ -176,7 +177,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.ElectricMotor criterion: x => { var myX = (EfficiencyResult)x; return (myX.ElectricalPower - batPower).Value() * 1e3; - }); + }, + searcher: this); } return retVal; } catch (VectoSearchFailedException vsfe) { diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Data/ElectricMotor/ElectricMotorData.cs b/VectoCore/VectoCore/Models/SimulationComponent/Data/ElectricMotor/ElectricMotorData.cs index c8f2e69bcc6db03b79920edd5b66335e9044d548..e61002f6f45ea283931bcc61d852082baa3252a4 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Data/ElectricMotor/ElectricMotorData.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Data/ElectricMotor/ElectricMotorData.cs @@ -68,7 +68,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data interval: 10.SI<NewtonMeter>(), getYValue: x => (Watt)x - electricPower, evaluateFunction: x => LookupElectricPower(voltage, avgSpeed, x, true).ElectricalPower, - criterion: x => ((Watt)x - electricPower).Value() + criterion: x => ((Watt)x - electricPower).Value(), + searcher: this ); return searchResult; diff --git a/VectoCore/VectoCore/Models/SimulationComponent/ElectricSystem.cs b/VectoCore/VectoCore/Models/SimulationComponent/ElectricSystem.cs index 3cecf2e8b025422c005393c32dd18d3861b6ee51..2e3c4eec48c75de0ddecb430416d0dd6eed10732 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/ElectricSystem.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/ElectricSystem.cs @@ -15,7 +15,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent protected readonly List<IElectricAuxPort> Consumers = new List<IElectricAuxPort>(); - protected IElectricChargerPort Charger; + protected internal IElectricChargerPort Charger; protected IElectricEnergyStorage Battery; diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs index 79f76c00a893cd75fa0965ea3240f9af8663f334..ac304a412001432e5035395607bea58fa378b933 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs @@ -718,7 +718,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl Constants.SimulationSettings.EngineIdlingSearchInterval, getYValue: result => ((ResponseDryRun)result).DeltaDragLoad, evaluateFunction: n => RequestPort.Request(absTime, dt, 0.SI<NewtonMeter>(), n, true), - criterion: result => ((ResponseDryRun)result).DeltaDragLoad.Value()); + criterion: result => ((ResponseDryRun)result).DeltaDragLoad.Value(), + searcher: this); Log.Debug("Found operating point for idling. absTime: {0}, dt: {1}, torque: {2}, angularSpeed: {3}", absTime, dt, 0.SI<NewtonMeter>(), angularSpeed); if (angularSpeed < _engine.ModelData.IdleSpeed) { @@ -732,7 +733,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl Constants.SimulationSettings.EngineIdlingSearchInterval, getYValue: result => ((ResponseDryRun)result).DeltaFullLoad, evaluateFunction: n => RequestPort.Request(absTime, dt, 0.SI<NewtonMeter>(), n, true), - criterion: result => ((ResponseDryRun)result).DeltaFullLoad.Value()); + criterion: result => ((ResponseDryRun)result).DeltaFullLoad.Value(), + searcher: this); Log.Debug("Found operating point for idling. absTime: {0}, dt: {1}, torque: {2}, angularSpeed: {3}", absTime, dt, 0.SI<NewtonMeter>(), angularSpeed2); angularSpeed2 = angularSpeed2.LimitTo(_engine.ModelData.IdleSpeed, engineMaxSpeed); @@ -787,7 +789,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl Constants.SimulationSettings.EngineIdlingSearchInterval, getYValue: result => ((ResponseDryRun)result).DeltaDragLoad, evaluateFunction: n => RequestPort.Request(absTime, dt, 0.SI<NewtonMeter>(), n, true), - criterion: result => ((ResponseDryRun)result).DeltaDragLoad.Value()); + criterion: result => ((ResponseDryRun)result).DeltaDragLoad.Value(), + searcher: this); Log.Debug("Found operating point for idling. absTime: {0}, dt: {1}, torque: {2}, angularSpeed: {3}", absTime, dt, 0.SI<NewtonMeter>(), angularSpeed); retVal = RequestPort.Request(absTime, dt, 0.SI<NewtonMeter>(), angularSpeed, false); diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/CycleGearbox.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/CycleGearbox.cs index a30715f3873a4573a9e9dd91b4d094dcfa0e5647..dd37bc17dcad64c08544385ca33ae49909f8e021 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/CycleGearbox.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/CycleGearbox.cs @@ -390,7 +390,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl Constants.SimulationSettings.EngineIdlingSearchInterval, getYValue: result => ((ResponseDryRun)result).DeltaDragLoad, evaluateFunction: n => NextComponent.Request(absTime, dt, 0.SI<NewtonMeter>(), n, true), - criterion: result => ((ResponseDryRun)result).DeltaDragLoad.Value()); + criterion: result => ((ResponseDryRun)result).DeltaDragLoad.Value(), + searcher: this); } catch (VectoException) { Log.Warn("CycleGearbox could not find motoring speed for disengaged state."); } diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/Driver.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/Driver.cs index ccc0f78eca2c4636fdce3fbd1d219ee60e91a038..163782fcc2787768e6603437e3d6f5cfa19cf989 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/Driver.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/Driver.cs @@ -590,7 +590,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl criterion: tOp => { var t = (Tuple<Tuple<TorqueConverterOperatingPoint, NewtonMeter>, NewtonMeter, NewtonMeter>)tOp; return GetTCDelta(t.Item1, t.Item2, t.Item3).Value(); - }); + }, + searcher: this); } catch (Exception e) { Log.Error(e, "Failed to find engine speed for valid torque converter operating point! absTime: {0}", absTime); @@ -671,7 +672,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl var r = (ResponseDryRun)resp; return (tcOp.Item1.OutTorque - r.TorqueConverter.TorqueConverterTorqueDemand).Value(); - } + }, + searcher: this ); return acceleration; } @@ -1082,7 +1084,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl return DataBus.GearboxInfo.GearboxType.AutomaticTransmission() && response.DeltaDragLoad.Value().IsSmallerOrEqual(-double.MaxValue / 20); }, - forceLineSearch: DataBus.GearboxInfo.GearboxType.AutomaticTransmission() && !DataBus.GearboxInfo.TCLocked); + forceLineSearch: DataBus.GearboxInfo.GearboxType.AutomaticTransmission() && !DataBus.GearboxInfo.TCLocked, + searcher: this); return operatingPoint; } catch (VectoSearchFailedException vse) { @@ -1117,7 +1120,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl : response.Gearbox.PowerRequest; return Math.Min(delta.Value(), 0); }, - forceLineSearch: true); + forceLineSearch: true, + searcher: this); return operatingPoint; } catch (Exception e2) { Log.Error("Failed to find operating point for braking power (attempt 2)! absTime: {0} {1}", absTime, e2); @@ -1207,7 +1211,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl return true; } return r != null && !actionRoll && !allowDistanceDecrease && !ds.IsEqual(r.Driver.OperatingPoint.SimulationDistance); - }); + }, + searcher: this); return ComputeTimeInterval(retVal.Acceleration, retVal.SimulationDistance); } catch (VectoException ve) { switch (ve) { @@ -1279,7 +1284,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl return r != null && !allowDistanceDecrease && !ds.IsEqual(r.Driver.OperatingPoint.SimulationDistance); }, - forceLineSearch: true); + forceLineSearch: true, + searcher: this); return ComputeTimeInterval(retVal.Acceleration, retVal.SimulationDistance); } catch (VectoException ve2) { Log.Error(ve2); diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/DummyGearboxInfo.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/DummyGearboxInfo.cs index 32b108d69df67cce0396ff904cdd21bc1771f0fb..74ee79b2c1000f1b4084ef1899fc9d936ffccc2a 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/DummyGearboxInfo.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/DummyGearboxInfo.cs @@ -11,9 +11,9 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl { public class DummyGearboxInfo : VectoSimulationComponent, IGearboxInfo { - public DummyGearboxInfo(VehicleContainer container) : base(container) + public DummyGearboxInfo(VehicleContainer container, GearshiftPosition gear = null) : base(container) { - + Gear = gear ?? new GearshiftPosition(1); } #region Overrides of VectoSimulationComponent @@ -28,7 +28,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl public GearboxType GearboxType => GearboxType.AMT; - public GearshiftPosition Gear => new GearshiftPosition(1); + public GearshiftPosition Gear { get; } public bool TCLocked => true; @@ -49,7 +49,9 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl public GearData GetGearData(uint gear) { - throw new NotImplementedException(); + return new GearData() { + MaxSpeed = null, + }; } public GearshiftPosition NextGear => throw new NotImplementedException(); diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/ElectricMotor.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/ElectricMotor.cs index 3df3a7789afbdaeba85ae679b9f9527f8a49ca06..61b078923c0ca938f86c779da79407951419328a 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/ElectricMotor.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/ElectricMotor.cs @@ -22,14 +22,15 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl public class ElectricMotor : StatefulProviderComponent<ElectricMotorState, ITnOutPort, ITnInPort, ITnOutPort>, IPowerTrainComponent, IElectricMotor, ITnOutPort, ITnInPort { - protected IElectricSystem ElectricPower; + protected internal IElectricSystem ElectricPower; internal IElectricMotorControl Control { get; } protected ElectricMotorData ModelData; private PerSecond _maxSpeed; protected internal Joule ThermalBuffer = 0.SI<Joule>(); - protected internal bool DeRatingActive; + public bool DeRatingActive { get; protected internal set; } + public Joule OverloadBuffer { get; } public NewtonMeter ContinuousTorque { get; } @@ -446,7 +447,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl } - protected NewtonMeter ConvertEmTorqueToDrivetrain(PerSecond emSpeed, NewtonMeter emTorque) + protected internal NewtonMeter ConvertEmTorqueToDrivetrain(PerSecond emSpeed, NewtonMeter emTorque) { var dtTorque = ModelData.TransmissionLossMap.GetOutTorque(emSpeed, emTorque); @@ -460,7 +461,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl criterion: r => { var i = r as NewtonMeter; return (i - emTorque).Value() * 1e3; - }); + }, + searcher: this); } return dtTorque; @@ -566,6 +568,10 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl ElectricPower = powersupply; } + protected internal PerSecond ConvertEmSpeedToDrivetrain(PerSecond emSpeed) + { + return emSpeed / ModelData.RatioADC; + } } public class ElectricMotorState // : SimpleComponentState diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/GensetChargerAdapter.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/GensetChargerAdapter.cs new file mode 100644 index 0000000000000000000000000000000000000000..a3d464490b92d65f22a17a9b1ba257001e3ae5dd --- /dev/null +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/GensetChargerAdapter.cs @@ -0,0 +1,74 @@ +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Models.Connector.Ports.Impl; + +namespace TUGraz.VectoCore.Models.SimulationComponent.Impl +{ + public class GensetChargerAdapter : IElectricChargerPort + { + protected IElectricSystem es; + protected Watt PowerGenerated; + + public GensetChargerAdapter(ElectricMotor motor) + { + es = new ChargeElectricSystem(this); + motor?.Connect(es); + PowerGenerated = 0.SI<Watt>(); + } + + #region Implementation of IElectricChargerPort + + public Watt Initialize() + { + PowerGenerated = 0.SI<Watt>(); + return PowerGenerated; + } + + public Watt PowerDemand(Second absTime, Second dt, Watt powerDemandEletricMotor, Watt auxPower, bool dryRun) + { + return PowerGenerated; + } + + public Watt ChargingPower + { + set { PowerGenerated = value; } + } + + #endregion + + public class ChargeElectricSystem : IElectricSystem + { + protected GensetChargerAdapter Adapter; + + + public ChargeElectricSystem(GensetChargerAdapter adapter) + { + Adapter = adapter; + } + + #region Implementation of IElectricSystemInfo + + public Watt ElectricAuxPower => 0.SI<Watt>(); + public Watt ChargePower => 0.SI<Watt>(); + public Watt BatteryPower => 0.SI<Watt>(); + public Watt ConsumerPower => 0.SI<Watt>(); + public IElectricSystemResponse Request(Second absTime, Second dt, Watt powerDemand, bool dryRun = false) + { + if (!dryRun) { + Adapter.PowerGenerated = powerDemand; + } + + return new ElectricSystemResponseSuccess(this) { + RESSResponse = new RESSResponseSuccess(this) { + MaxChargePower = double.MaxValue.SI<Watt>(), + MaxDischargePower = -double.MaxValue.SI<Watt>(), + AbsTime = absTime, + }, + ConsumerPower = powerDemand + }; + } + + #endregion + } + } +} \ No newline at end of file diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/MeasuredSpeedDrivingCycle.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/MeasuredSpeedDrivingCycle.cs index 631fd2c9821f2833aa9c45a0d6bacebaeec11dc6..22c140fce2d05af5ea80f7c4cf5c97a6351cddc3 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/MeasuredSpeedDrivingCycle.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/MeasuredSpeedDrivingCycle.cs @@ -193,7 +193,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl getYValue: result => ((ResponseDryRun)result).DeltaEngineSpeed, // ReSharper disable once AccessToModifiedClosure evaluateFunction: x => NextComponent.Request(absTime, dt, x, gradient, true), - criterion: y => ((ResponseDryRun)y).DeltaEngineSpeed.Value()); + criterion: y => ((ResponseDryRun)y).DeltaEngineSpeed.Value(), + searcher: this); Log.Info("Found operating point for driver acceleration. absTime: {0}, dt: {1}, acceleration: {2}, gradient: {3}", absTime, dt, acceleration, gradient); break; @@ -240,7 +241,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl }, criterion: y => DataBus.ClutchInfo.ClutchClosed(absTime) ? ((ResponseDryRun)y).DeltaDragLoad.Value() - : ((ResponseDryRun)y).Gearbox.PowerRequest.Value()); + : ((ResponseDryRun)y).Gearbox.PowerRequest.Value(), + searcher: this); Log.Info( "Found operating point for braking. absTime: {0}, dt: {1}, acceleration: {2}, gradient: {3}, BrakePower: {4}", absTime, dt, acceleration, gradient, DataBus.Brakes.BrakePower); @@ -254,7 +256,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl Constants.SimulationSettings.OperatingPointInitialSearchIntervalAccelerating, getYValue: result => ((ResponseDryRun)result).DeltaFullLoad, evaluateFunction: x => NextComponent.Request(absTime, dt, x, gradient, true), - criterion: y => ((ResponseDryRun)y).DeltaFullLoad.Value()); + criterion: y => ((ResponseDryRun)y).DeltaFullLoad.Value(), + searcher: this); } var response = NextComponent.Request(absTime, dt, acceleration, gradient, false); @@ -270,7 +273,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl getYValue: result => ((ResponseDryRun)result).DeltaFullLoad, evaluateFunction: x => NextComponent.Request(absTime, dt, x, gradient, true), criterion: - y => ((ResponseDryRun)y).DeltaFullLoad.Value()); + y => ((ResponseDryRun)y).DeltaFullLoad.Value(), + searcher: this); Log.Info( "Found operating point for driver acceleration. absTime: {0}, dt: {1}, acceleration: {2}, gradient: {3}", absTime, dt, acceleration, gradient); @@ -286,7 +290,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl }, criterion: y => DataBus.ClutchInfo.ClutchClosed(absTime) ? ((ResponseDryRun)y).DeltaDragLoad.Value() - : ((ResponseDryRun)y).Gearbox.PowerRequest.Value()); + : ((ResponseDryRun)y).Gearbox.PowerRequest.Value(), + searcher: this); Log.Info( "Found operating point for braking. absTime: {0}, dt: {1}, acceleration: {2}, gradient: {3}, BrakePower: {4}", absTime, dt, acceleration, gradient, DataBus.Brakes.BrakePower); @@ -300,7 +305,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl Constants.SimulationSettings.OperatingPointInitialSearchIntervalAccelerating, getYValue: result => ((ResponseDryRun)result).DeltaFullLoad, evaluateFunction: x => NextComponent.Request(absTime, dt, x, gradient, true), - criterion: y => ((ResponseDryRun)y).DeltaFullLoad.Value()); + criterion: y => ((ResponseDryRun)y).DeltaFullLoad.Value(), + searcher: this); } } var response = NextComponent.Request(absTime, dt, acceleration, gradient, false); diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/PowertrainDrivingCycle.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/PowertrainDrivingCycle.cs index 1c8ee412bba22725e1a01068789efb6c0db3d9c3..693fe029533d2430580a1815dac2fdffd9019170 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/PowertrainDrivingCycle.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/PowertrainDrivingCycle.cs @@ -127,7 +127,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl var torque = SearchAlgorithm.Search(CycleIterator.LeftSample.Torque, r.Delta, torqueInterval, getYValue: result => ((ResponseDryRun)result).DeltaDragLoad, evaluateFunction: t => NextComponent.Request(absTime, dt, t, angularVelocity, true), - criterion: y => ((ResponseDryRun)y).DeltaDragLoad.Value()); + criterion: y => ((ResponseDryRun)y).DeltaDragLoad.Value(), + searcher: this); response = NextComponent.Request(absTime, dt, torque, angularVelocity, false); CurrentState.InTorque = torque; break; @@ -135,7 +136,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl var torque2 = SearchAlgorithm.Search(CycleIterator.LeftSample.Torque, r.Delta, 50.SI<NewtonMeter>(), getYValue: result => ((ResponseDryRun)result).DeltaFullLoad, evaluateFunction: t => NextComponent.Request(absTime, dt, t, angularVelocity, true), - criterion: y => ((ResponseDryRun)y).DeltaFullLoad.Value()); + criterion: y => ((ResponseDryRun)y).DeltaFullLoad.Value(), + searcher: this); response = NextComponent.Request(absTime, dt, torque2, angularVelocity, false); CurrentState.InAngularVelocity = angularVelocity; CurrentState.InTorque = torque2; @@ -145,7 +147,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl 1.RPMtoRad(), getYValue: result => ((ResponseDryRun)result).DeltaEngineSpeed, evaluateFunction: x => NextComponent.Request(absTime, dt, CurrentState.InTorque, x, true), - criterion: y => ((ResponseDryRun)y).DeltaEngineSpeed.Value()); + criterion: y => ((ResponseDryRun)y).DeltaEngineSpeed.Value(), + searcher: this); break; case ResponseFailTimeInterval r: dt = r.DeltaT; diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/SerialHybridController.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/SerialHybridController.cs new file mode 100644 index 0000000000000000000000000000000000000000..98c7bf2139b64b7e4ee0c8bd8dfbb645dc4a7918 --- /dev/null +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/SerialHybridController.cs @@ -0,0 +1,285 @@ +using System; +using System.Collections.Generic; +using TUGraz.VectoCommon.Exceptions; +using TUGraz.VectoCommon.InputData; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Models.Connector.Ports; +using TUGraz.VectoCore.Models.Connector.Ports.Impl; +using TUGraz.VectoCore.Models.Simulation; +using TUGraz.VectoCore.Models.SimulationComponent.Data; +using TUGraz.VectoCore.OutputData; +using TUGraz.VectoCore.Utils; + +namespace TUGraz.VectoCore.Models.SimulationComponent.Impl +{ + public class SerialHybridController : StatefulProviderComponent<SerialHybridController.HybridControllerState, + ITnOutPort, ITnInPort, ITnOutPort>, IHybridController, ITnOutPort, ITnInPort + { + protected readonly Dictionary<PowertrainPosition, ElectricMotorController> _electricMotorCtl; + + private Dictionary<PowertrainPosition, Tuple<PerSecond, NewtonMeter>> _electricMotorTorque = + new Dictionary<PowertrainPosition, Tuple<PerSecond, NewtonMeter>>(); + + protected readonly IHybridControlStrategy _hybridStrategy; + + private HybridStrategyResponse CurrentStrategySettings = null; + + protected DebugData DebugData = new DebugData(); + + protected ITnOutPort GenSetPort; + + public SerialHybridController(IVehicleContainer container, IHybridControlStrategy strategy, IElectricSystem es) : base(container) + { + GenSet = new TnInPortWrapper(this); + _electricMotorCtl = new Dictionary<PowertrainPosition, ElectricMotorController>(); + //_shiftStrategy = container.RunData.GearboxData.Type.AutomaticTransmission() + // ? new HybridController.HybridCtlATShiftStrategy(this, container) + // : new HybridController.HybridCtlShiftStrategy(this, container); + _hybridStrategy = strategy; + strategy.Controller = this; + + ElectricSystem = es; + } + + + + public IHybridControlStrategy Strategy => _hybridStrategy; + + public IElectricSystem ElectricSystem { get; } + + + public IHybridControlledGearbox Gearbox { protected get; set; } + public ICombustionEngine Engine { protected get; set; } + + //public + + #region Overrides of VectoSimulationComponent + + protected override void DoWriteModalResults(Second time, Second simulationInterval, IModalDataContainer container) + { + Strategy.WriteModalResults(time, simulationInterval, container); + } + + #endregion + + #region Implementation of ITnOutPort + + public IResponse Request(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, bool dryRun) + { + var strategyResponse = Strategy.Request(absTime, dt, outTorque, outAngularVelocity, dryRun); + + if (strategyResponse is HybridStrategyLimitedResponse ovl) { + if (dryRun) { + return new ResponseDryRun(this) { + DeltaDragLoad = ovl.Delta, + DeltaFullLoad = ovl.Delta, + // TODO! delta full/drag torque + DeltaEngineSpeed = ovl.DeltaEngineSpeed, + Gearbox = { + InputTorque = ovl.GearboxResponse?.InputTorque, + InputSpeed = ovl.GearboxResponse?.InputSpeed, + OutputTorque = ovl.GearboxResponse?.OutputTorque, + OutputSpeed = ovl.GearboxResponse?.OutputSpeed, + PowerRequest = ovl.GearboxResponse?.PowerRequest, + Gear = ovl.GearboxResponse?.Gear + } + + }; + } + + return new ResponseOverload(this) { + Delta = ovl.Delta + }; + } + + var strategySettings = strategyResponse as HybridStrategyResponse; + ApplyStrategySettings(strategySettings); + CurrentStrategySettings = strategySettings; + if (!dryRun) { + CurrentState.SetState(outTorque, outAngularVelocity, outTorque, outAngularVelocity); + CurrentState.StrategyResponse = strategySettings; + } + + // Todo: re-think for S2 configuration.... + //if (!dryRun && /*!DataBus.EngineInfo.EngineOn &&*/ strategySettings.ShiftRequired) { + // DataBus.GearboxCtl.TriggerGearshift(absTime, dt); + // _shiftStrategy.SetNextGear(strategySettings.NextGear); + // SelectedGear = strategySettings.NextGear; + // if (!DataBus.GearboxInfo.GearboxType.AutomaticTransmission()) { + // return new ResponseGearShift(this); + // } + //} + + var gensetResponse = GenSetPort.Request(absTime, dt, 0.SI<NewtonMeter>(), _electricMotorTorque[PowertrainPosition.Generator].Item1, dryRun); + + if (!(gensetResponse is ResponseSuccess || gensetResponse is ResponseDryRun)) { + throw new VectoException("Invalid operating point for Genset provided by strategy! {0}", gensetResponse); + } + + var retVal = NextComponent.Request(absTime, dt, outTorque, outAngularVelocity, dryRun); + DebugData.Add(new { + DrivingAction = DataBus.DriverInfo.DrivingAction, + StrategySettings = strategySettings, + Response = retVal, + DryRun = dryRun + }); + retVal.HybridController.StrategySettings = strategySettings; + var modifiedResponse = Strategy.AmendResponse(retVal, absTime, dt, outTorque, outAngularVelocity, dryRun); + + return modifiedResponse; + } + + private void ApplyStrategySettings(HybridStrategyResponse strategySettings) + { + if (Gearbox != null) { + Gearbox.SwitchToNeutral = strategySettings.GearboxInNeutral; + } + + Engine.CombustionEngineOn = strategySettings.CombustionEngineOn; + _electricMotorTorque = strategySettings.MechanicalAssistPower; + //if (DataBus.VehicleInfo.VehicleStopped && strategySettings.NextGear.Gear != 0) { + //_shiftStrategy.SetNextGear(strategySettings.NextGear); + //} + } + + protected override void DoCommitSimulationStep(Second time, Second simulationInterval) + { + base.DoCommitSimulationStep(time, simulationInterval); + Strategy.CommitSimulationStep(time, simulationInterval); + DebugData = new DebugData(); + } + + public IResponse Initialize(NewtonMeter outTorque, PerSecond outAngularVelocity) + { + PreviousState.SetState(outTorque, outAngularVelocity, outTorque, outAngularVelocity); + var strategyResponse = Strategy.Initialize(outTorque, outAngularVelocity); + PreviousState.StrategyResponse = strategyResponse as HybridStrategyResponse; + _electricMotorTorque = PreviousState.StrategyResponse.MechanicalAssistPower; + var retVal = NextComponent.Initialize(outTorque, outAngularVelocity); + if (DataBus.GearboxInfo != null) { + SelectedGear = DataBus.GearboxInfo.Gear; + } + + + GenSetPort.Initialize(0.SI<NewtonMeter>(), DataBus.EngineInfo.EngineIdleSpeed); + + return retVal; + } + + #endregion + + #region Implementation of IHybridControllerInfo + + public GearshiftPosition SelectedGear { get; protected set; } + public PerSecond ICESpeed { get; } + public bool GearboxEngaged { get; } + public Second SimulationInterval => CurrentStrategySettings.SimulationInterval; + public PerSecond ElectricMotorSpeed(PowertrainPosition pos) + { + return CurrentStrategySettings.MechanicalAssistPower[pos].Item1; + } + + #endregion + + #region Implementation of IHybridControllerCtl + + public void RepeatDrivingAction(Second absTime) + { + Strategy.RepeatDrivingAction(absTime); + } + + #endregion + + #region Implementation of IHybridController + + public IShiftStrategy ShiftStrategy { get; } + SimpleComponentState IHybridController.PreviousState => PreviousState; + public ITnInProvider GenSet { get; } + + public IElectricMotorControl ElectricMotorControl(PowertrainPosition pos) + { + return _electricMotorCtl[pos]; + } + + public void AddElectricMotor(PowertrainPosition pos, ElectricMotorData motorData) + { + if (_electricMotorCtl.ContainsKey(pos)) { + throw new VectoException("Electric motor already registered as position {0}", pos); + } + + _electricMotorCtl[pos] = new ElectricMotorController(this, motorData); + } + + + + #endregion + + private NewtonMeter MechanicalAssistPower(PowertrainPosition pos, Second absTime, Second dt, + NewtonMeter outTorque, PerSecond prevOutAngularVelocity, PerSecond currOutAngularVelocity, bool dryRun) + { + return _electricMotorTorque[pos]?.Item2; + + //return CurrentState.StrategyResponse.MechanicalAssistPower[pos]; + } + + ///======================================================================================= + + public class HybridControllerState : SimpleComponentState + { + public HybridStrategyResponse StrategyResponse { get; set; } + } + + ///======================================================================================= + private class TnInPortWrapper : ITnInProvider, ITnInPort + { + protected SerialHybridController Controller; + + public TnInPortWrapper(SerialHybridController ctl) + { + Controller = ctl; + } + + #region Implementation of ITnInProvider + + public ITnInPort InPort() + { + return this; + } + + #endregion + + #region Implementation of ITnInPort + + public void Connect(ITnOutPort other) + { + Controller.GenSetPort = other; + } + + #endregion + } + + ///======================================================================================= + + public class ElectricMotorController : IElectricMotorControl + { + protected SerialHybridController _controller; + protected ElectricMotorData ElectricMotorData; + + public ElectricMotorController(SerialHybridController hybridController, ElectricMotorData motorData) + { + _controller = hybridController; + ElectricMotorData = motorData; + } + + public NewtonMeter MechanicalAssistPower(Second absTime, Second dt, NewtonMeter outTorque, + PerSecond prevOutAngularVelocity, PerSecond currOutAngularVelocity, + NewtonMeter maxDriveTorque, NewtonMeter maxRecuperationTorque, PowertrainPosition position, bool dryRun) + { + return _controller.MechanicalAssistPower(position, absTime, dt, outTorque, prevOutAngularVelocity, + currOutAngularVelocity, dryRun); + } + } + + } +} \ No newline at end of file diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/SimpleHybridController.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/SimpleHybridController.cs index 6f7fa740d71ecb03431373df3259472d09636d50..6e393d7bb1760c5192c1e5f22ca805af855a000e 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/SimpleHybridController.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/SimpleHybridController.cs @@ -23,7 +23,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl { private Dictionary<PowertrainPosition, Tuple<PerSecond, NewtonMeter>> _electricMotorTorque = new Dictionary<PowertrainPosition, Tuple<PerSecond, NewtonMeter>>(); - public SimpleHybridController(VehicleContainer container, ElectricSystem es, SwitchableClutch clutch) : base(container) + public SimpleHybridController(VehicleContainer container, ElectricSystem es) : base(container) { ElectricSystem = es; //this.clutch = clutch; @@ -117,8 +117,13 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl { public void ApplyStrategySettings(HybridStrategyResponse strategySettings) { - Gearbox.SwitchToNeutral = strategySettings.GearboxInNeutral; - Engine.CombustionEngineOn = strategySettings.CombustionEngineOn; + if (Gearbox != null) { + Gearbox.SwitchToNeutral = strategySettings.GearboxInNeutral; + } + + if (Engine != null) { + Engine.CombustionEngineOn = strategySettings.CombustionEngineOn; + } _electricMotorTorque = strategySettings.MechanicalAssistPower; } diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/Vehicle.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/Vehicle.cs index 1d94509c1fe9b6a5f361782cca641afacd26156d..d59ac9aefc691246e420c6f661fb860be0b82e30 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/Vehicle.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/Vehicle.cs @@ -87,7 +87,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl protected virtual void SetMaxVehicleSpeed() { - if (DataBus.PowertrainInfo.HasCombustionEngine) { + if (DataBus.PowertrainInfo.VehicleArchitecutre != VectoSimulationJobType.SerialHybridVehicle && DataBus.PowertrainInfo.HasCombustionEngine) { if (DataBus.GearboxInfo == null || DataBus.AxlegearInfo == null) { throw new VectoException("Powertrain with combustion engine requires gearbox and axlegear!"); //return; @@ -101,7 +101,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl if (DataBus.PowertrainInfo.HasElectricMotor) { - var positions = DataBus.PowertrainInfo.ElectricMotorPositions; + var positions = DataBus.PowertrainInfo.ElectricMotorPositions.Where(x => x != PowertrainPosition.Generator).ToArray(); + ; if (positions.Length > 1) { throw new VectoException("Multiple electrical machines are currently not supported"); } diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/VelocitySpeedGearshiftPreprocessor.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/VelocitySpeedGearshiftPreprocessor.cs index 806ce19c832edc5f0ddb06c8689c8a2afb10e8f4..8542399f7b412a002e7916095d0dbfd3c50b1ee7 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/VelocitySpeedGearshiftPreprocessor.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/VelocitySpeedGearshiftPreprocessor.cs @@ -176,7 +176,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl abortCriterion: (response, cnt) => { var r = (ResponseDryRun)response; return r != null && (vehicle.VehicleSpeed + r.Driver.Acceleration * simulationInterval) < 0.KMPHtoMeterPerSecond(); - } + }, + searcher: this ); var step = vehicle.Request(absTime, simulationInterval, acceleration, gradient); if (!(step is ResponseSuccess)) { diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Strategies/GensetPreprocessor.cs b/VectoCore/VectoCore/Models/SimulationComponent/Strategies/GensetPreprocessor.cs new file mode 100644 index 0000000000000000000000000000000000000000..c37df4055de9428ba6c97bab1cb035323f8773e4 --- /dev/null +++ b/VectoCore/VectoCore/Models/SimulationComponent/Strategies/GensetPreprocessor.cs @@ -0,0 +1,160 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.InputData.Reader.DataObjectAdapter; +using TUGraz.VectoCore.Models.Connector.Ports.Impl; +using TUGraz.VectoCore.Models.Declaration; +using TUGraz.VectoCore.Models.Simulation; +using TUGraz.VectoCore.Models.SimulationComponent.Data; +using TUGraz.VectoCore.Models.SimulationComponent.Data.ElectricMotor; +using TUGraz.VectoCore.Models.SimulationComponent.Data.Engine; + +namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies +{ + public class GensetPreprocessor : ISimulationPreprocessor + { + protected TestGenset Genset; + private CombustionEngineData IceData; + private ElectricMotorData EmData; + protected GenSetCharacteristics OptimalPoints; + + public GensetPreprocessor(GenSetCharacteristics optimalPoints, TestGenset testGenSet, CombustionEngineData engineData, + ElectricMotorData electricMotorData) + { + Genset = testGenSet; + IceData = engineData; + EmData = electricMotorData; + OptimalPoints = optimalPoints; + } + + #region Implementation of ISimulationPreprocessor + + public void RunPreprocessing() + { + var voltage = EmData.EfficiencyData.VoltageLevels.First().Voltage; + + IterateElectricPower(voltage); + + MaxElectricPower(voltage, false); + + MaxElectricPower(voltage, true); + } + + private void MaxElectricPower(Volt voltage, bool emDerated) + { + var continuousTq = emDerated ? Genset.ElectricMotor.ContinuousTorque : double.MaxValue.SI<NewtonMeter>(); + var emFldDrivetrain = new ElectricMotorFullLoadCurve(EmData.EfficiencyData.VoltageLevels[0].FullLoadCurve + .FullLoadEntries.Select(x => + new ElectricMotorFullLoadCurve.FullLoadEntry() { + FullGenerationTorque = + Genset.ElectricMotor.ConvertEmTorqueToDrivetrain(x.MotorSpeed, VectoMath.Min(continuousTq ,x.FullGenerationTorque)), + FullDriveTorque = + Genset.ElectricMotor.ConvertEmTorqueToDrivetrain(x.MotorSpeed, VectoMath.Max(-continuousTq, x.FullDriveTorque)), + MotorSpeed = Genset.ElectricMotor.ConvertEmSpeedToDrivetrain(x.MotorSpeed) + }).ToList()); + var iceFld = new ElectricMotorFullLoadCurve(IceData.FullLoadCurves[0].FullLoadEntries.Select(x => + new ElectricMotorFullLoadCurve.FullLoadEntry() { + FullDriveTorque = -x.TorqueFullLoad, + FullGenerationTorque = 0.SI<NewtonMeter>(), + MotorSpeed = x.EngineSpeed + }).ToList()); + + var combinedFldEntries = AbstractSimulationDataAdapter.IntersectEMFullLoadCurves(iceFld, emFldDrivetrain).FullLoadEntries.Select(x => + new EngineFullLoadCurve.FullLoadCurveEntry() { + EngineSpeed = x.MotorSpeed, + TorqueFullLoad = -x.FullDriveTorque, + TorqueDrag = 0.SI<NewtonMeter>() + }).Where(x => x.EngineSpeed > IceData.IdleSpeed && x.EngineSpeed < IceData.FullLoadCurves[0].N95hSpeed).ToList(); + + var combinedFld = new EngineFullLoadCurve(combinedFldEntries, null); + var absTime = 0.SI<Second>(); + var dt = 1.SI<Second>(); + + var ratedSpeed = combinedFld.RatedSpeed; + Genset.ElectricMotorCtl.EMTorque = combinedFld.FullLoadStationaryTorque(ratedSpeed); + Genset.ElectricMotor.Initialize(combinedFld.FullLoadStationaryTorque(ratedSpeed), ratedSpeed); + var response = Genset.ElectricMotor.Request(absTime, dt, 0.SI<NewtonMeter>(), ratedSpeed); + + if (response is ResponseSuccess) { + var fc = IceData.Fuels.Sum(x => + x.ConsumptionMap.GetFuelConsumptionValue(response.Engine.TotalTorqueDemand, + response.Engine.EngineSpeed)); + var tmp = new GenSetOperatingPoint() { + ICEOn = true, + ElectricPower = response.ElectricSystem.ConsumerPower, + ICESpeed = ratedSpeed, + ICETorque = Genset.ElectricMotorCtl.EMTorque, + FuelConsumption = fc, + EMSpeed = response.ElectricMotor.AngularVelocity, + EMTorque = response.ElectricMotor.TorqueRequestEmMap + }; + if (emDerated) { + OptimalPoints.MaxPowerDeRated = tmp; + } else { + OptimalPoints.MaxPower = tmp; + } + } + } + + private void IterateElectricPower(Volt voltage) + { + var maxPower = IceData.FullLoadCurves[0].MaxPower; + + var speedRange = IceData.FullLoadCurves[0].RatedSpeed - IceData.IdleSpeed; + var maxSpeedNorm = (IceData.FullLoadCurves[0].N95hSpeed - IceData.IdleSpeed) / speedRange; + + var absTime = 0.SI<Second>(); + var dt = 1.SI<Second>(); + + var tolerance = 0.5 / 100; + + var stepsPwr = 0.05; + for (var i = stepsPwr; i <= 1; i += stepsPwr) { + var pwr = i * maxPower; + var stepsSpeed = 0.05; + var genPts = new List<GenSetOperatingPoint>(); + var responses = new List<Tuple<PerSecond, IResponse>>(); + for (var n = 0.0; n <= maxSpeedNorm; n += stepsSpeed) { + var speed = n * speedRange + IceData.IdleSpeed; + + try { + Genset.ElectricMotor.Initialize(0.SI<NewtonMeter>(), speed); + var tq = Genset.ElectricMotor.GetTorqueForElectricPower(voltage, pwr, speed * EmData.RatioADC, dt); + + if (tq == null || tq.IsSmallerOrEqual(0)) { + continue; + } + + Genset.ElectricMotorCtl.EMTorque = tq; + + var response = Genset.ElectricMotor.Request(absTime, dt, 0.SI<NewtonMeter>(), speed); + responses.Add(Tuple.Create(speed, response)); + if (response is ResponseSuccess) { + var fc = IceData.Fuels.Sum(x => + x.ConsumptionMap.GetFuelConsumptionValue(response.Engine.TotalTorqueDemand, + response.Engine.EngineSpeed)); + genPts.Add(new GenSetOperatingPoint() { + ICEOn = true, + ElectricPower = pwr, + ICESpeed = speed, + ICETorque = tq, + FuelConsumption = fc, + EMSpeed = response.ElectricMotor.AngularVelocity, + EMTorque = response.ElectricMotor.TorqueRequestEmMap + }); + } + } catch (Exception) { } + } + + if (genPts.Any()) { + var min = genPts.MinBy(x => x.FuelConsumption.Value()).FuelConsumption; + OptimalPoints.OptimalPoints[pwr] = genPts.Where(x => x.FuelConsumption / min < (1 + tolerance)).ToList(); + } + } + } + + #endregion + } +} \ No newline at end of file diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Strategies/HybridStrategy.cs b/VectoCore/VectoCore/Models/SimulationComponent/Strategies/HybridStrategy.cs index ca55fe5b8753a06585c50b01e4b305021e045ab0..eb8278df26ef59e67dfcf51b21d43ffa5a6b4c9a 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Strategies/HybridStrategy.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Strategies/HybridStrategy.cs @@ -958,7 +958,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies var r = (IResponse)resp; var deltaMaxTq = r.Engine.TotalTorqueDemand - r.Engine.DynamicFullLoadTorque; return (deltaMaxTq * avgEngineSpeed).Value(); - }); + }, + searcher: this); var rqMaxTorque = RequestDryRun(absTime, dt, maxTorque, outAngularVelocity, currentGear, maxEmDriveSetting); // limiting to ICE FLD with max propulsion - delta gearbox torque var rqMaxGbxInTq = GetGearboxInTorqueLimitedVehiclePorpTorque(rqMaxTorque, emPos); @@ -1238,7 +1239,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies deltaDragLoad = response.Gearbox.InputTorque; } return deltaDragLoad.Value(); - } + }, + searcher: this ); if (emRecuperationTq.IsBetween( firstResponse.ElectricMotor.MaxDriveTorque ?? 0.SI<NewtonMeter>(), firstResponse.ElectricMotor.MaxRecuperationTorque ?? 0.SI<NewtonMeter>())) { @@ -1923,7 +1925,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies var response = r as IResponse; return response.Engine.TorqueOutDemand.Value(); }, - abortCriterion: (r, c) => r == null + abortCriterion: (r, c) => r == null, + searcher: this ); if (emTorqueICEOff.IsBetween( firstResponse.ElectricMotor.MaxDriveTorque, VectoMath.Min(0.SI<NewtonMeter>(), firstResponse.ElectricMotor.MaxRecuperationTorque))) { @@ -1962,7 +1965,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies var response = r as IResponse; return (response.Engine.TotalTorqueDemand - response.Engine.DynamicFullLoadTorque).Value(); }, - abortCriterion: (r, c) => r == null + abortCriterion: (r, c) => r == null, + searcher: this ); if (emTorqueICEMax.IsBetween(maxEmTorque, 0.SI<NewtonMeter>())) { // only consider where EM is recuperating @@ -2018,7 +2022,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies var response = r as IResponse; return response.Engine.TorqueOutDemand.Value(); }, - abortCriterion: (r, c) => r == null + abortCriterion: (r, c) => r == null, + searcher: this ); if (emTorqueICEOff.IsBetween(maxEmTorqueRecuperate, 0.SI<NewtonMeter>())) { // only consider where EM is recuperating diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Strategies/SerialHybridStrategy.cs b/VectoCore/VectoCore/Models/SimulationComponent/Strategies/SerialHybridStrategy.cs new file mode 100644 index 0000000000000000000000000000000000000000..69dcf8652669fb011632d9330831306505942272 --- /dev/null +++ b/VectoCore/VectoCore/Models/SimulationComponent/Strategies/SerialHybridStrategy.cs @@ -0,0 +1,669 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using TUGraz.VectoCommon.Exceptions; +using TUGraz.VectoCommon.InputData; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Models.BusAuxiliaries.DownstreamModules.Impl.Electrics; +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.Simulation.Impl; +using TUGraz.VectoCore.Models.SimulationComponent.Data; +using TUGraz.VectoCore.Models.SimulationComponent.Impl; +using TUGraz.VectoCore.OutputData; +using TUGraz.VectoCore.Utils; + +namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies +{ + public class SerialHybridStrategy : AbstractSerialHybridStrategy + { + public enum StateMachineState + { + Undefined, + Acc_S0, // GEN = 0 + Acc_S1, // P_GEN = P_opt, SoC <= SoC_min && P_demand < P_opt || SoC >= SoC_min && SoC <= SoC_target && P_demand <= P_opt + Acc_S2, // P_GEN = P_max, SoC <= S + Acc_S3, // P_GEN = P_max, P_drive = P_GEN + + Break_S0, + Break_S1, + Break_S2, + } + + protected DryRunSolutionState DryRunSolution { get; set; } + + + public SerialHybridStrategy(VectoRunData runData, IVehicleContainer container) : base(runData, container) { } + + + public override IHybridStrategyResponse Initialize(NewtonMeter outTorque, PerSecond outAngularVelocity) + { + EmPosition = DataBus.PowertrainInfo.ElectricMotorPositions.FirstOrDefault(x => + x != PowertrainPosition.Generator); + + var retVal = new HybridStrategyResponse() + { MechanicalAssistPower = new Dictionary<PowertrainPosition, Tuple<PerSecond, NewtonMeter>>() }; + + foreach (var em in ModelData.ElectricMachinesData) { + retVal.MechanicalAssistPower[em.Item1] = null; + } + + GenSetCharacteristics.ContinuousTorque = + (DataBus.ElectricMotorInfo(PowertrainPosition.Generator) as ElectricMotor).ContinuousTorque; + + PreviousState.AngularVelocity = outAngularVelocity; + PreviousState.GearboxEngaged = true; + PreviousState.GearshiftTriggerTstmp = -double.MaxValue.SI<Second>(); + PreviousState.SMState = DataBus.BatteryInfo.StateOfCharge > StrategyParameters.TargetSoC + ? StateMachineState.Acc_S0 + : DataBus.BatteryInfo.StateOfCharge > StrategyParameters.MinSoC + ? StateMachineState.Acc_S1 + : StateMachineState.Acc_S2; + CurrentState.SMState = PreviousState.SMState; + CurrentState.GearshiftTriggerTstmp = -double.MaxValue.SI<Second>(); + return retVal; + } + + public override IHybridStrategyResponse Request(Second absTime, Second dt, NewtonMeter outTorque, + PerSecond outAngularVelocity, + bool dryRun) + { + + if (DryRunSolution != null && DryRunSolution.DrivingAction != DataBus.DriverInfo.DrivingAction) { + DryRunSolution = null; + } + + //if (!dryRun && DryRunSolution != null && !DryRunSolution.Solution.IgnoreReason.AllOK()) { + // DryRunSolution = null; + //} + + if (dryRun && DryRunSolution != null && DryRunSolution.DrivingAction == DataBus.DriverInfo.DrivingAction) { + var tmp = new HybridStrategyResponse() { + SimulationInterval = dt, + CombustionEngineOn = DryRunSolution.ICEOn, + MechanicalAssistPower = DryRunSolution.Settings + }; + return tmp; + } + + + var maxPowerGenset = GetMaxElectricPowerGenerated(absTime, dt); + + var drivetrainDemand = GetDrivetrainPowerDemand(absTime, dt, outTorque, outAngularVelocity, maxPowerGenset); + var emResponse = drivetrainDemand.Response.ElectricMotor; + + //if (((-emResponse.TorqueRequest).IsSmaller(emResponse.MaxDriveTorque ?? 0.SI<NewtonMeter>(), 1e-3) || + // (-emResponse.TorqueRequest).IsGreater(emResponse.MaxRecuperationTorque ?? 0.SI<NewtonMeter>(), 1e-3))) { + // var delta = emResponse.TorqueRequest - + // (-emResponse.TorqueRequest).LimitTo(emResponse.MaxDriveTorque ?? 0.SI<NewtonMeter>(), + // emResponse.MaxRecuperationTorque ?? 0.SI<NewtonMeter>()); + // return new HybridStrategyLimitedResponse() { + // Delta = delta * emResponse.AvgDrivetrainSpeed + // }; + //} + + switch (DataBus.DriverInfo.DrivingAction) { + case DrivingAction.Halt: + case DrivingAction.Roll: + case DrivingAction.Coast: + case DrivingAction.Accelerate: + CurrentState.SMState = GetStateAccelerate(drivetrainDemand, maxPowerGenset, dt); + break; + case DrivingAction.Brake: + CurrentState.SMState = GetStateBrake(drivetrainDemand); + break; + default: + throw new ArgumentOutOfRangeException(); + } + + GenSetOperatingPoint genSetOperatingPoint; + var emTorque = (-emResponse.TorqueRequest).LimitTo(emResponse.MaxDriveTorque ?? 0.SI<NewtonMeter>(), + emResponse.MaxRecuperationTorque ?? 0.SI<NewtonMeter>()); + switch (CurrentState.SMState) { + case StateMachineState.Acc_S0: + genSetOperatingPoint = GensetOff; + // update drivetrain demand if genset uses a different operating point - we are above target SoC, battery might get full + var tmp = GensetOff; + tmp.ElectricPower = 0.SI<Watt>(); + drivetrainDemand = GetDrivetrainPowerDemand(absTime, dt, outTorque, outAngularVelocity, tmp); + emResponse = drivetrainDemand.Response.ElectricMotor; + emTorque = (-emResponse.TorqueRequest).LimitTo(emResponse.MaxDriveTorque ?? 0.SI<NewtonMeter>(), + emResponse.MaxRecuperationTorque ?? 0.SI<NewtonMeter>()); + break; + case StateMachineState.Acc_S1: + var optimalPoint = DataBus.ElectricMotorInfo(PowertrainPosition.Generator).DeRatingActive ? + GenSetCharacteristics.OptimalPointDeRated + : GenSetCharacteristics.OptimalPoint; + genSetOperatingPoint = ApproachGensetOperatingPoint(absTime, dt, optimalPoint); + // update drivetrain demand if genset uses a different operating point? - probably not needed as SoC needs to increase anyway + //drivetrainDemand = GetDrivetrainPowerDemand(absTime, dt, outTorque, outAngularVelocity, genSetOperatingPoint); + //emResponse = drivetrainDemand.Response.ElectricMotor; + //emTorque = (-emResponse.TorqueRequest).LimitTo(emResponse.MaxDriveTorque ?? 0.SI<NewtonMeter>(), + // emResponse.MaxRecuperationTorque ?? 0.SI<NewtonMeter>()); + break; + case StateMachineState.Acc_S2: + genSetOperatingPoint = MaxGensetPower(absTime, dt, drivetrainDemand, maxPowerGenset); + break; + case StateMachineState.Acc_S3: + genSetOperatingPoint = MaxGensetPower(absTime, dt, drivetrainDemand, maxPowerGenset); + emTorque = TestPowertrain.ElectricMotor.GetTorqueForElectricPower( + DataBus.BatteryInfo.InternalVoltage, drivetrainDemand.Response.ElectricSystem.MaxPowerDrive, + drivetrainDemand.Response.ElectricMotor.AngularVelocity, dt).LimitTo(emResponse.MaxDriveTorque ?? 0.SI<NewtonMeter>(), + emResponse.MaxRecuperationTorque ?? 0.SI<NewtonMeter>()); + break; + case StateMachineState.Break_S0: + case StateMachineState.Break_S1: + case StateMachineState.Break_S2: + genSetOperatingPoint = DataBus.EngineInfo.EngineOn ? ApproachGensetOperatingPoint(absTime, dt, GensetIdle) : GensetOff; + + // update drivetrain demand if genset uses a different operating point - we are above target SoC, battery might get full + var tmpBr = GensetOff; + tmpBr.ElectricPower = 0.SI<Watt>(); + drivetrainDemand = GetDrivetrainPowerDemand(absTime, dt, outTorque, outAngularVelocity, tmpBr); + emResponse = drivetrainDemand.Response.ElectricMotor; + if (emTorque > 0 && emResponse.MaxRecuperationTorque == null) { + // we could recuperate, but max recuperation is null - so battery is full. turn off EM + emTorque = null; + } else { + emTorque = (-emResponse.TorqueRequest).LimitTo(emResponse.MaxDriveTorque ?? 0.SI<NewtonMeter>(), + emResponse.MaxRecuperationTorque ?? 0.SI<NewtonMeter>()); + } + break; + default: + throw new ArgumentOutOfRangeException(); + } + + var setting = new Dictionary<PowertrainPosition, Tuple<PerSecond, NewtonMeter>>() { + { + EmPosition, + Tuple.Create(drivetrainDemand.AvgEmDrivetrainSpeed, emTorque) + }, { + PowertrainPosition.Generator, + Tuple.Create(genSetOperatingPoint.ICESpeed, genSetOperatingPoint.ICETorque) + }, + } + ; + + DryRunSolution = new DryRunSolutionState(DataBus.DriverInfo.DrivingAction, setting, genSetOperatingPoint.ICEOn); + + return new HybridStrategyResponse() { + SimulationInterval = dt, + CombustionEngineOn = genSetOperatingPoint.ICEOn, + MechanicalAssistPower = setting + }; + + } + + protected StateMachineState GetStateAccelerate(DrivetrainDemand drivetrainDemand, + GenSetOperatingPoint maxPowerGenset, Second dt) + { + var reqBatteryPower = maxPowerGenset.ElectricPower + drivetrainDemand.ElectricPowerDemand; + if (DataBus.BatteryInfo.StateOfCharge.IsEqual(StrategyParameters.MinSoC, 0.01) && reqBatteryPower < 0 && drivetrainDemand.ElectricPowerDemand < drivetrainDemand.Response.ElectricSystem.MaxPowerDrive) { + return StateMachineState.Acc_S3; + } + + var optimalGensetPoint = DataBus.ElectricMotorInfo(PowertrainPosition.Generator).DeRatingActive + ? GenSetCharacteristics.OptimalPointDeRated + : GenSetCharacteristics.OptimalPoint; + switch (PreviousState.SMState) { + case StateMachineState.Acc_S0: + if (DataBus.BatteryInfo.StateOfCharge < StrategyParameters.MinSoC) { + return -drivetrainDemand.ElectricPowerDemand < + optimalGensetPoint.ElectricPower + ? StateMachineState.Acc_S1 + : StateMachineState.Acc_S2; + } + + break; + case StateMachineState.Acc_S1: + if (/*DataBus.BatteryInfo.StateOfCharge >= StrategyParameters.MinSoC &&*/ + DataBus.BatteryInfo.StateOfCharge < StrategyParameters.TargetSoC + && -drivetrainDemand.ElectricPowerDemand > + optimalGensetPoint.ElectricPower) { + return StateMachineState.Acc_S2; + } + + if (DataBus.BatteryInfo.StateOfCharge >= StrategyParameters.TargetSoC) { + return StateMachineState.Acc_S0; + } + + break; + case StateMachineState.Acc_S2: + if (DataBus.BatteryInfo.StateOfCharge >= StrategyParameters.TargetSoC) { + return StateMachineState.Acc_S0; + } + + if (DataBus.BatteryInfo.StateOfCharge >= StrategyParameters.MinSoC && + DataBus.BatteryInfo.StateOfCharge < StrategyParameters.TargetSoC + && -drivetrainDemand.ElectricPowerDemand <= + optimalGensetPoint.ElectricPower) { + return StateMachineState.Acc_S1; + } + break; + case StateMachineState.Break_S0: + return StateMachineState.Acc_S0; + case StateMachineState.Break_S1: + return StateMachineState.Acc_S1; + case StateMachineState.Break_S2: + return StateMachineState.Acc_S2; + default: + throw new ArgumentOutOfRangeException(); + } + + return PreviousState.SMState; + } + + protected StateMachineState GetStateBrake(DrivetrainDemand drivetrainDemand) + { + switch (PreviousState.SMState) { + case StateMachineState.Acc_S0: + return StateMachineState.Break_S0; + case StateMachineState.Acc_S1: + return StateMachineState.Break_S1; + case StateMachineState.Acc_S2: + return StateMachineState.Break_S2; + case StateMachineState.Acc_S3: + return StateMachineState.Break_S2; + case StateMachineState.Break_S0: + break; + case StateMachineState.Break_S1: + break; + case StateMachineState.Break_S2: + break; + default: + throw new ArgumentOutOfRangeException(); + } + + return PreviousState.SMState; + } + } + + public abstract class AbstractSerialHybridStrategy : LoggingObject, IHybridControlStrategy + { + protected VectoRunData ModelData; + protected IDataBus DataBus; + + protected HybridStrategyParameters StrategyParameters; + + protected Dictionary<PowertrainPosition, Tuple<PerSecond, NewtonMeter>> ElectricMotorsOff; + + protected StrategyState CurrentState = new StrategyState(); + protected StrategyState PreviousState = new StrategyState(); + + protected TestPowertrain<Gearbox> TestPowertrain; + protected TestGenset TestGenSet; + protected GenSetCharacteristics GenSetCharacteristics = new GenSetCharacteristics(); + + protected PowertrainPosition EmPosition; + + + public AbstractSerialHybridStrategy (VectoRunData runData, IVehicleContainer container) + { + DataBus = container; + ModelData = runData; + if (ModelData.ElectricMachinesData.Select(x => x.Item1).Where(x => x != PowertrainPosition.Generator).Distinct().Count() > 1) { + throw new VectoException("More than one electric motors are currently not supported"); + } + StrategyParameters = ModelData.HybridStrategyParameters; + if (StrategyParameters == null) { + throw new VectoException("Model parameters for hybrid strategy required!"); + } + + ElectricMotorsOff = ModelData.ElectricMachinesData + .Select(x => new KeyValuePair<PowertrainPosition, NewtonMeter>(x.Item1, null)) + .ToDictionary(x => x.Key, x => new Tuple<PerSecond, NewtonMeter>(null, x.Value)); + + + + // create testcontainer + var modData = new ModalDataContainer(runData, null, null); + var builder = new PowertrainBuilder(modData); + var testContainer = new SimplePowertrainContainer(runData); + builder.BuildSimpleSerialHybridPowertrain(runData, testContainer); + + TestPowertrain = new TestPowertrain<Gearbox>(testContainer, DataBus); + + var gensetContainer = new SimplePowertrainContainer(runData); + builder.BuildSimpleGenSet(runData, gensetContainer); + TestGenSet = new TestGenset(gensetContainer, DataBus); + + + container.AddPreprocessor(new GensetPreprocessor(GenSetCharacteristics ,TestGenSet, runData.EngineData, + runData.ElectricMachinesData.FirstOrDefault(x => x.Item1 == PowertrainPosition.Generator)?.Item2)); + } + + #region Implementation of IHybridControlStrategy + + protected GenSetOperatingPoint MaxGensetPower(Second absTime, Second dt, + DrivetrainDemand drivetrainDemand, + GenSetOperatingPoint maxPowerGenset) + { + var electricPowerDemand = drivetrainDemand.ElectricPowerDemand; + + var gensetLimit = DataBus.ElectricMotorInfo(PowertrainPosition.Generator).DeRatingActive + ? GenSetCharacteristics.MaxPowerDeRated + : GenSetCharacteristics.MaxPower; + if (maxPowerGenset.ElectricPower.IsSmaller(gensetLimit.ElectricPower)) { + gensetLimit = maxPowerGenset; + } + + //if (electricPowerDemand.IsGreater(gensetLimit.ElectricPower)) { + return ApproachGensetOperatingPoint(absTime, dt, gensetLimit); + //} + + //var pair = GenSetCharacteristics.OptimalPoints.Keys.GetSection(x => + // x.IsSmaller(drivetrainDemand.ElectricPowerDemand)); + + //return ApproachGensetOperatingPoint(absTime, dt, GenSetCharacteristics.OptimalPoints[pair.Item2].MinBy(x => x.FuelConsumption)); + //GenSetCharacteristics. + } + + public GenSetOperatingPoint GensetOff => new + GenSetOperatingPoint + { + ICEOn = false, + ICESpeed = ModelData.EngineData.IdleSpeed, + ICETorque = null, + EMTorque = null + }; + + public GenSetOperatingPoint GensetIdle => new GenSetOperatingPoint() { + ICEOn = true, + ICESpeed = ModelData.EngineData.IdleSpeed, + ICETorque = 0.SI<NewtonMeter>(), + EMTorque = null, + }; + + protected DrivetrainDemand GetDrivetrainPowerDemand(Second absTime, Second dt, NewtonMeter outTorque, + PerSecond outAngularVelocity, GenSetOperatingPoint maxPowerGenset) + { + TestPowertrain.ElectricMotor.ThermalBuffer = + (DataBus.ElectricMotorInfo(EmPosition) as ElectricMotor).ThermalBuffer; + TestPowertrain.ElectricMotor.DeRatingActive = + (DataBus.ElectricMotorInfo(EmPosition) as ElectricMotor).DeRatingActive; + + TestPowertrain.Battery?.Initialize(DataBus.BatteryInfo.StateOfCharge); + if (TestPowertrain.Battery != null) { + TestPowertrain.Battery.PreviousState.PulseDuration = + (DataBus.BatteryInfo as Battery).PreviousState.PulseDuration; + TestPowertrain.Battery.PreviousState.PowerDemand = + (DataBus.BatteryInfo as Battery).PreviousState.PowerDemand; + } + if (TestPowertrain.BatterySystem != null) { + var batSystem = DataBus.BatteryInfo as BatterySystem; + foreach (var bsKey in batSystem.Batteries.Keys) { + for (var i = 0; i < batSystem.Batteries[bsKey].Batteries.Count; i++) { + TestPowertrain.BatterySystem.Batteries[bsKey].Batteries[i] + .Initialize(batSystem.Batteries[bsKey].Batteries[i].StateOfCharge); + } + } + TestPowertrain.BatterySystem.PreviousState.PulseDuration = + (DataBus.BatteryInfo as BatterySystem).PreviousState.PulseDuration; + TestPowertrain.BatterySystem.PreviousState.PowerDemand = (DataBus.BatteryInfo as BatterySystem).PreviousState.PowerDemand; + } + + TestPowertrain.Charger.ChargingPower = maxPowerGenset.ElectricPower; + TestPowertrain.HybridController.Initialize(Controller.PreviousState.OutTorque, + Controller.PreviousState.OutAngularVelocity); + var testResponse = + TestPowertrain.HybridController.NextComponent.Request(absTime, dt, outTorque, outAngularVelocity, false); + + TestPowertrain.HybridController.ApplyStrategySettings(new HybridStrategyResponse() { + CombustionEngineOn = false, + MechanicalAssistPower = new Dictionary<PowertrainPosition, Tuple<PerSecond, NewtonMeter>>() { + { + EmPosition, + Tuple.Create(testResponse.ElectricMotor.AvgDrivetrainSpeed, -testResponse.ElectricMotor.TorqueRequest) + } + } + }); + var testResponse2 = + TestPowertrain.HybridController.NextComponent.Request(absTime, dt, outTorque, outAngularVelocity, + false); + return new DrivetrainDemand(){ + AvgEmDrivetrainSpeed = testResponse2.ElectricMotor.AvgDrivetrainSpeed, + EmTorqueDemand = testResponse2.ElectricMotor.TorqueRequest, + ElectricPowerDemand = testResponse2.ElectricSystem.ConsumerPower, + Response = testResponse2 + }; + } + + public class DrivetrainDemand + { + public PerSecond AvgEmDrivetrainSpeed { get; set; } + public NewtonMeter EmTorqueDemand { get; set; } + + public Watt ElectricPowerDemand { get; set; } + public IResponse Response { get; set; } + } + + protected GenSetOperatingPoint GetMaxElectricPowerGenerated(Second absTime, Second dt) + { + var genDerated = DataBus.ElectricMotorInfo(PowertrainPosition.Generator).DeRatingActive; + return ApproachGensetOperatingPoint(absTime, dt, + genDerated ? GenSetCharacteristics.MaxPowerDeRated : GenSetCharacteristics.MaxPower); + } + + protected GenSetOperatingPoint ApproachGensetOperatingPoint(Second absTime, Second dt, GenSetOperatingPoint op) + { + TestGenSet.CombustionEngine.Initialize( + (DataBus.EngineInfo as CombustionEngine).PreviousState.EngineTorque, + (DataBus.EngineInfo as CombustionEngine).PreviousState.EngineSpeed); + TestGenSet.CombustionEngine.PreviousState.EngineOn = //true; + (DataBus.EngineInfo as CombustionEngine).PreviousState.EngineOn; + TestGenSet.CombustionEngine.PreviousState.EnginePower = + (DataBus.EngineInfo as CombustionEngine).PreviousState.EnginePower; + TestGenSet.CombustionEngine.PreviousState.dt = (DataBus.EngineInfo as CombustionEngine).PreviousState.dt; + TestGenSet.CombustionEngine.PreviousState.EngineSpeed = + (DataBus.EngineInfo as CombustionEngine).PreviousState.EngineSpeed; + TestGenSet.CombustionEngine.PreviousState.EngineTorque = + (DataBus.EngineInfo as CombustionEngine).PreviousState.EngineTorque; + TestGenSet.CombustionEngine.PreviousState.EngineTorqueOut = + (DataBus.EngineInfo as CombustionEngine).PreviousState.EngineTorqueOut; + TestGenSet.CombustionEngine.PreviousState.DynamicFullLoadTorque = + (DataBus.EngineInfo as CombustionEngine).PreviousState.DynamicFullLoadTorque; + + switch (TestGenSet.CombustionEngine.EngineAux) { + case EngineAuxiliary engineAux: + engineAux.PreviousState.AngularSpeed = + ((DataBus.EngineInfo as CombustionEngine).EngineAux as EngineAuxiliary).PreviousState + .AngularSpeed; + break; + case BusAuxiliariesAdapter busAux: + busAux.PreviousState.AngularSpeed = + ((DataBus.EngineInfo as CombustionEngine).EngineAux as BusAuxiliariesAdapter).PreviousState + .AngularSpeed; + if (busAux.ElectricStorage is SimpleBattery bat) { + bat.SOC = ((DataBus.EngineInfo as CombustionEngine).EngineAux as BusAuxiliariesAdapter) + .ElectricStorage + .SOC; + } + + break; + } + TestGenSet.ElectricMotor.ThermalBuffer = + (DataBus.ElectricMotorInfo(PowertrainPosition.Generator) as ElectricMotor).ThermalBuffer; + TestGenSet.ElectricMotor.DeRatingActive = + (DataBus.ElectricMotorInfo(PowertrainPosition.Generator) as ElectricMotor).DeRatingActive; + + var iceSpeed = op.ICESpeed; + var emTqDt = op.ICETorque; + + TestGenSet.ElectricMotorCtl.EMTorque = emTqDt; + var r1 = TestGenSet.ElectricMotor.Request(absTime, dt, 0.SI<NewtonMeter>(), iceSpeed); + if (r1 is ResponseOverload ovl) { + emTqDt = SearchAlgorithm.Search(emTqDt, ovl.Delta, emTqDt * 0.1, + getYValue: r => { + var dryRun = r as ResponseDryRun; + return dryRun.DeltaFullLoad; + }, + evaluateFunction: + x => { + TestGenSet.ElectricMotorCtl.EMTorque = x; + return TestGenSet.ElectricMotor.Request(absTime, dt, 0.SI<NewtonMeter>(), iceSpeed, true); + }, + criterion: r => { + var dryRun = r as ResponseDryRun; + return dryRun.DeltaFullLoad.Value(); + }, + searcher: this); + TestGenSet.ElectricMotorCtl.EMTorque = emTqDt; + r1 = TestGenSet.ElectricMotor.Request(absTime, dt, 0.SI<NewtonMeter>(), iceSpeed); + } + + if (r1 is ResponseUnderload udl) { + iceSpeed = SearchAlgorithm.Search(iceSpeed, udl.Delta, iceSpeed * 0.01, + getYValue: r => { + var dryRun = r as ResponseDryRun; + return dryRun.DeltaDragLoad; + }, + evaluateFunction: x => { + return TestGenSet.ElectricMotor.Request(absTime, dt, 0.SI<NewtonMeter>(), x, true); + }, + criterion: r => { + var dryRun = r as ResponseDryRun; + return dryRun.DeltaDragLoad.Value(); + }, + searcher: this); + r1 = TestGenSet.ElectricMotor.Request(absTime, dt, 0.SI<NewtonMeter>(), iceSpeed); + } + + return new GenSetOperatingPoint() { + ICEOn = true, + ElectricPower = r1.ElectricSystem.ConsumerPower, + ICETorque = emTqDt, + ICESpeed = iceSpeed, + EMSpeed = r1.ElectricMotor.AngularVelocity, + EMTorque = r1.ElectricMotor.TorqueRequestEmMap + }; + } + + public abstract IHybridStrategyResponse Initialize(NewtonMeter outTorque, PerSecond outAngularVelocity); + + public abstract IHybridStrategyResponse Request(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, + bool dryRun); + + public IResponse AmendResponse(IResponse response, Second absTime, Second dt, NewtonMeter outTorque, + PerSecond outAngularVelocity, bool dryRun) + { + return response; + } + + public void CommitSimulationStep(Second time, Second simulationInterval) + { + var iceStart = PreviousState.ICEStartTStmp; + PreviousState = CurrentState; + if (!DataBus.EngineCtl.CombustionEngineOn) { + PreviousState.ICEStartTStmp = iceStart; + } else { + // ice is on, set start-timestamp if it was off + if (!PreviousState.ICEOn) { + PreviousState.ICEStartTStmp = time; + } + } + CurrentState = new StrategyState(); + CurrentState.ICEStartTStmp = PreviousState.ICEStartTStmp; + CurrentState.GearshiftTriggerTstmp = PreviousState.GearshiftTriggerTstmp; + CurrentState.ICEOn = DataBus.EngineCtl.CombustionEngineOn; + AllowEmergencyShift = false; + //DebugData = new DebugData(); + + //throw new NotImplementedException(); + } + + public IHybridController Controller { get; set; } + public PerSecond MinICESpeed { get; } + public bool AllowEmergencyShift { get; set; } + public void WriteModalResults(Second time, Second simulationInterval, IModalDataContainer container) + { + //throw new NotImplementedException(); + } + + public void OperatingpointChangedDuringRequest(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, + bool dryRun, IResponse retVal) + { + throw new NotImplementedException(); + } + + public void RepeatDrivingAction(Second absTime) + { + + } + + #endregion + + public class StrategyState + { + public PerSecond AngularVelocity { get; set; } + public HybridStrategyResponse Response { get; set; } + public List<HybridResultEntry> Evaluations; + public HybridResultEntry Solution { get; set; } + + public bool GearboxEngaged { get; set; } + + public Second ICEStartTStmp { get; set; } + + public Second GearshiftTriggerTstmp { get; set; } + public NewtonMeter MaxGbxTq { get; set; } + public bool ICEOn { get; set; } + + public SerialHybridStrategy.StateMachineState SMState { get; set; } + } + + public class DryRunSolutionState + { + public DryRunSolutionState(DrivingAction drivingAction, Dictionary<PowertrainPosition, Tuple<PerSecond, NewtonMeter>> settings, bool iceOn) + { + DrivingAction = drivingAction; + Settings = settings; + ICEOn = iceOn; + } + + + public DrivingAction DrivingAction { get; } + + public bool ICEOn { get; } + + public Dictionary<PowertrainPosition, Tuple<PerSecond, NewtonMeter>> Settings { get; } + } + } + + public class GenSetCharacteristics + { + public Dictionary<Watt, List<GenSetOperatingPoint>> OptimalPoints = new Dictionary<Watt, List<GenSetOperatingPoint>>(); + + public GenSetOperatingPoint MaxPower; + + public GenSetOperatingPoint MaxPowerDeRated; + private GenSetOperatingPoint _optimalPoint; + private GenSetOperatingPoint _optimalPointDerated; + + public GenSetOperatingPoint OptimalPoint => _optimalPoint ?? (_optimalPoint = + OptimalPoints.Values.SelectMany(x => x).MinBy(x => x.FuelConsumption / x.ElectricPower)); + + public GenSetOperatingPoint OptimalPointDeRated => _optimalPointDerated ?? (_optimalPointDerated = + OptimalPoints.Values.SelectMany(x => x).Where(x => x.EMTorque.IsSmaller(ContinuousTorque)).MinBy(x => x.FuelConsumption / x.ElectricPower)); + + public NewtonMeter ContinuousTorque { get; set; } + } + + public class GenSetOperatingPoint + { + public bool ICEOn; + + public Watt ElectricPower; + + public PerSecond ICESpeed; + + public NewtonMeter ICETorque; + + public KilogramPerSecond FuelConsumption; + + public PerSecond EMSpeed; + + public NewtonMeter EMTorque; + } +} \ No newline at end of file diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Strategies/TestPowertrain.cs b/VectoCore/VectoCore/Models/SimulationComponent/Strategies/TestPowertrain.cs index 3d3ac2e8a7fe99d18396d2e4fceef46ed16d2304..45011d3dcacf8c0214b26894d33adccbd209a3c8 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Strategies/TestPowertrain.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Strategies/TestPowertrain.cs @@ -11,7 +11,25 @@ using TUGraz.VectoCore.Models.SimulationComponent.Data; using TUGraz.VectoCore.Models.SimulationComponent.Impl; using TUGraz.VectoCore.OutputData; -namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies { +namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies +{ + + public class TestGenset + { + + public SimplePowertrainContainer Container; + public StopStartCombustionEngine CombustionEngine; + public ElectricMotor ElectricMotor; + public GensetMotorController ElectricMotorCtl; + + public TestGenset(SimplePowertrainContainer container, IDataBus realContainer) + { + Container = container; + CombustionEngine = Container.EngineInfo as StopStartCombustionEngine; + ElectricMotor = container.ElectricMotors.FirstOrDefault(x => x.Key == PowertrainPosition.Generator).Value as ElectricMotor; + ElectricMotorCtl = ElectricMotor.Control as GensetMotorController; + } + } public class TestPowertrain<T> where T: class, IHybridControlledGearbox, IGearbox { public SimplePowertrainContainer Container; @@ -26,6 +44,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies { public StopStartCombustionEngine CombustionEngine; public ElectricMotor ElectricMotor; + public GensetChargerAdapter Charger; public Dictionary<PowertrainPosition, ElectricMotor> ElectricMotorsUpstreamTransmission = new Dictionary<PowertrainPosition, ElectricMotor>(); public TorqueConverter TorqueConverter; public DCDCConverter DCDCConverter; @@ -43,16 +62,15 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Strategies { Clutch = Container.ClutchInfo as Clutch; CombustionEngine = Container.EngineInfo as StopStartCombustionEngine; ElectricMotor = container.ElectricMotors.FirstOrDefault().Value as ElectricMotor; + Charger = (ElectricMotor?.ElectricPower as ElectricSystem)?.Charger as GensetChargerAdapter; foreach (var pos in container.ElectricMotorPositions) { if (pos == PowertrainPosition.HybridP1 || pos == PowertrainPosition.HybridP2 || pos == PowertrainPosition.HybridP2_5 || pos == PowertrainPosition.HybridP3) { ElectricMotorsUpstreamTransmission[pos] = container.ElectricMotors[pos] as ElectricMotor; } } - if (Gearbox == null) { - } - - if (Gearbox.GearboxType.AutomaticTransmission()) { + + if (Gearbox != null && Gearbox.GearboxType.AutomaticTransmission()) { TorqueConverter = Container.TorqueConverterInfo as TorqueConverter; if (TorqueConverter == null) { throw new VectoException("Torque converter missing for automatic transmission: {0}", Container.TorqueConverterInfo?.GetType().FullName); diff --git a/VectoCore/VectoCore/Utils/SearchAlgorithm.cs b/VectoCore/VectoCore/Utils/SearchAlgorithm.cs index 8f86e626f6df667d569b3f269c7457fc958b6002..0830a8a2b3bf5766e7ece06172a71b885773a886 100644 --- a/VectoCore/VectoCore/Utils/SearchAlgorithm.cs +++ b/VectoCore/VectoCore/Utils/SearchAlgorithm.cs @@ -55,10 +55,10 @@ namespace TUGraz.VectoCore.Utils /// </code> /// </summary> public static T Search<T>(T x, SI y, T interval, Func<object, SI> getYValue, Func<T, object> evaluateFunction, - Func<object, double> criterion, bool forceLineSearch = false) where T : SIBase<T> + Func<object, double> criterion, bool forceLineSearch = false, object searcher = null) where T : SIBase<T> { var iterationCount = 0; - return Search(x, y, interval, getYValue, evaluateFunction, criterion, null, ref iterationCount, forceLineSearch); + return Search(x, y, interval, getYValue, evaluateFunction, criterion, null, ref iterationCount, forceLineSearch, searcher); } /// <summary> @@ -72,10 +72,10 @@ namespace TUGraz.VectoCore.Utils /// </code> /// </summary> public static T Search<T>(T x, SI y, T interval, Func<object, SI> getYValue, Func<T, object> evaluateFunction, - Func<object, double> criterion, Func<object, int, bool> abortCriterion, bool forceLineSearch = false) where T : SIBase<T> + Func<object, double> criterion, Func<object, int, bool> abortCriterion, bool forceLineSearch = false, object searcher = null) where T : SIBase<T> { var iterationCount = 0; - return Search(x, y, interval, getYValue, evaluateFunction, criterion, abortCriterion, ref iterationCount, forceLineSearch); + return Search(x, y, interval, getYValue, evaluateFunction, criterion, abortCriterion, ref iterationCount, forceLineSearch, searcher); } /// <summary> @@ -89,7 +89,8 @@ namespace TUGraz.VectoCore.Utils /// </code> /// </summary> public static T Search<T>(T x, SI y, T interval, Func<object, SI> getYValue, Func<T, object> evaluateFunction, - Func<object, double> criterion, Func<object, int, bool> abortCriterion, ref int iterationCount, bool forceLineSearch) where T : SIBase<T> + Func<object, double> criterion, Func<object, int, bool> abortCriterion, ref int iterationCount, + bool forceLineSearch, object searcher) where T : SIBase<T> { T result; try { diff --git a/VectoCore/VectoCore/VectoCore.csproj b/VectoCore/VectoCore/VectoCore.csproj index f0226fda9c9db1f80179092109fc0187e89f94fe..daca6edbc086f6d3ecab4b7e4bc28647e6a0eab0 100644 --- a/VectoCore/VectoCore/VectoCore.csproj +++ b/VectoCore/VectoCore/VectoCore.csproj @@ -310,6 +310,7 @@ <Compile Include="Models\SimulationComponent\Impl\APTNShiftStrategy.cs" /> <Compile Include="Models\SimulationComponent\Impl\BatterySystem.cs" /> <Compile Include="Models\SimulationComponent\Impl\DummyAxleGearInfo.cs" /> + <Compile Include="Models\SimulationComponent\Impl\GensetChargerAdapter.cs" /> <Compile Include="Models\SimulationComponent\Impl\PEVGearbox.cs" /> <Compile Include="Models\SimulationComponent\Impl\PTODriveAuxiliary.cs" /> <Compile Include="Models\SimulationComponent\Impl\RoadSweeperAuxiliary.cs" /> @@ -439,7 +440,10 @@ <Compile Include="Models\SimulationComponent\IElectricMotorControl.cs" /> <Compile Include="Models\SimulationComponent\IHybridControlledGearbox.cs" /> <Compile Include="Models\SimulationComponent\Impl\PEVAMTShiftStrategy.cs" /> + <Compile Include="Models\SimulationComponent\Impl\SerialHybridController.cs" /> <Compile Include="Models\SimulationComponent\Impl\ShiftLineSet.cs" /> + <Compile Include="Models\SimulationComponent\Strategies\GensetPreprocessor.cs" /> + <Compile Include="Models\SimulationComponent\Strategies\SerialHybridStrategy.cs" /> <Compile Include="Models\Simulation\DataBus\IDCDCConverter.cs" /> <Compile Include="Models\Simulation\DataBus\IHybridControllerInfo.cs" /> <Compile Include="Models\SimulationComponent\IHybridControlStrategy.cs" /> @@ -1033,8 +1037,8 @@ <SubType>Designer</SubType> </EmbeddedResource> <EmbeddedResource Include="Resources\XSD\VectoDeclarationDefinitions.2.3.xsd"> - <SubType>Designer</SubType> - </EmbeddedResource> + <SubType>Designer</SubType> + </EmbeddedResource> <EmbeddedResource Include="Resources\XSD\VectoDeclarationDefinitions.2.4.xsd"> <SubType>Designer</SubType> </EmbeddedResource> diff --git a/VectoCore/VectoCoreTest/Integration/Hybrid/SerialHybridTest.cs b/VectoCore/VectoCoreTest/Integration/Hybrid/SerialHybridTest.cs new file mode 100644 index 0000000000000000000000000000000000000000..b8870bb4a6111860e50ec07a05da0b9443622633 --- /dev/null +++ b/VectoCore/VectoCoreTest/Integration/Hybrid/SerialHybridTest.cs @@ -0,0 +1,637 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using NUnit.Framework; +using TUGraz.VectoCommon.Exceptions; +using TUGraz.VectoCommon.InputData; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Configuration; +using TUGraz.VectoCore.InputData.Impl; +using TUGraz.VectoCore.InputData.Reader.ComponentData; +using TUGraz.VectoCore.Models.Declaration; +using TUGraz.VectoCore.Models.Simulation.Data; +using TUGraz.VectoCore.Models.Simulation.Impl; +using TUGraz.VectoCore.Models.SimulationComponent; +using TUGraz.VectoCore.Models.SimulationComponent.Data; +using TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox; +using TUGraz.VectoCore.Models.SimulationComponent.Impl; +using TUGraz.VectoCore.Models.SimulationComponent.Strategies; +using TUGraz.VectoCore.OutputData; +using TUGraz.VectoCore.OutputData.FileIO; +using TUGraz.VectoCore.Tests.Utils; +using TUGraz.VectoCore.Utils; +using ElectricSystem = TUGraz.VectoCore.Models.SimulationComponent.ElectricSystem; +using Wheels = TUGraz.VectoCore.Models.SimulationComponent.Impl.Wheels; + + +namespace TUGraz.VectoCore.Tests.Integration.Hybrid +{ + [TestFixture] + public class SerialHybridTest + { + public const string MotorFile = @"TestData\Hybrids\ElectricMotor\GenericEMotor.vem"; + public const string BatFile = @"TestData\Hybrids\Battery\GenericBattery.vbat"; + + public const string AccelerationFile = @"TestData\Components\Truck.vacc"; + public const string MotorFile240kW = @"TestData\Hybrids\ElectricMotor\GenericEMotor240kW.vem"; + + public const string GeneratorFile = @"TestData\Hybrids\ElectricMotor\GenericGenerator.vem"; + + public const string GearboxIndirectLoss = @"TestData\Components\Indirect Gear.vtlm"; + public const string GearboxDirectLoss = @"TestData\Components\Direct Gear.vtlm"; + + + + public const bool PlotGraphs = true; + + [OneTimeSetUp] + public void RunBeforeAnyTests() + { + Directory.SetCurrentDirectory(TestContext.CurrentContext.TestDirectory); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - + + + [ + TestCase(30, 0.7, 0, 0, TestName = "S3 Hybrid ConstantSpeed 30km/h SoC: 0.7, level"), + TestCase(50, 0.7, 0, 0, TestName = "S3 Hybrid ConstantSpeed 50km/h SoC: 0.7, level"), + TestCase(80, 0.7, 0, 0, TestName = "S3 Hybrid ConstantSpeed 80km/h SoC: 0.7, level"), + + TestCase(30, 0.25, 0, 0, TestName = "S3 Hybrid ConstantSpeed 30km/h SoC: 0.25, level"), + TestCase(50, 0.25, 0, 0, TestName = "S3 Hybrid ConstantSpeed 50km/h SoC: 0.25, level"), + TestCase(80, 0.25, 0, 0, TestName = "S3 Hybrid ConstantSpeed 80km/h SoC: 0.25, level"), + + TestCase(30, 0.5, 5, 0, TestName = "S3 Hybrid ConstantSpeed 30km/h SoC: 0.5, UH 5%"), + TestCase(50, 0.5, 5, 0, TestName = "S3 Hybrid ConstantSpeed 50km/h SoC: 0.5, UH 5%"), + TestCase(80, 0.5, 5, 0, TestName = "S3 Hybrid ConstantSpeed 80km/h SoC: 0.5, UH 5%"), + + TestCase(30, 0.5, -5, 0, TestName = "S3 Hybrid ConstantSpeed 30km/h SoC: 0.5, DH 5%"), + TestCase(50, 0.5, -5, 0, TestName = "S3 Hybrid ConstantSpeed 50km/h SoC: 0.5, DH 5%"), + TestCase(80, 0.5, -5, 0, TestName = "S3 Hybrid ConstantSpeed 80km/h SoC: 0.5, DH 5%"), + + TestCase(30, 0.25, 0, 1000, TestName = "S3 Hybrid ConstantSpeed 30km/h SoC: 0.25, level P_auxEl: 1kW"), + TestCase(30, 0.25, 0, 5000, TestName = "S3 Hybrid ConstantSpeed 30km/h SoC: 0.25, level P_auxEl: 5kW"), + ] + public void S3HybridConstantSpeed(double vmax, double initialSoC, double slope, double pAuxEl) + { + var cycleData = string.Format( + @" 0, {0}, {1}, 0 + 7000, {0}, {1}, 0", vmax, slope); + var cycle = SimpleDrivingCycles.CreateCycleData(cycleData); + + const bool largeMotor = true; + + var modFilename = $"SimpleParallelHybrid-S3_constant_{vmax}-{initialSoC}_{slope}_{pAuxEl}.vmod"; + const PowertrainPosition pos = PowertrainPosition.BatteryElectricE3; + var job = CreateEngineeringRun( + cycle, modFilename, initialSoC, pos, 4.6, largeMotor: true, largeGen: true, pAuxEl: pAuxEl); + var run = job.Runs.First().Run; + + var hybridController = (SerialHybridController)((VehicleContainer)run.GetContainer()).HybridController; + Assert.NotNull(hybridController); + + var modData = ((ModalDataContainer)((VehicleContainer)run.GetContainer()).ModData).Data; + + var data = run.GetContainer().RunData; + //File.WriteAllText( + // $"{modFilename}.json", + // JsonConvert.SerializeObject(data, Formatting.Indented)); + + run.Run(); + Assert.IsTrue(run.FinishedWithoutErrors); + + Assert.IsTrue(modData.Rows.Count > 0); + var graphWriter = GetGraphWriter(new[] { ModalResultField.P_electricMotor_mech_B3, ModalResultField.P_electricMotor_mech_Gen }); + graphWriter.Write(modFilename); + } + + [ + TestCase(30, 0.7, 0, TestName = "S3 Hybrid DriveOff 30km/h SoC: 0.7, level"), + TestCase(80, 0.7, 0, TestName = "S3 Hybrid DriveOff 80km/h SoC: 0.7, level"), + TestCase(30, 0.22, 0, TestName = "S3 Hybrid DriveOff 30km/h SoC: 0.22, level") + ] + public void S3HybridDriveOff(double vmax, double initialSoC, double slope) + { + var cycleData = string.Format( + @" 0, 0, {1}, 3 + 700, {0}, {1}, 0", vmax, slope); + var cycle = SimpleDrivingCycles.CreateCycleData(cycleData); + + const bool largeMotor = true; + + var modFilename = $"SimpleParallelHybrid-S3_acc_{vmax}-{initialSoC}_{slope}.vmod"; + const PowertrainPosition pos = PowertrainPosition.BatteryElectricE3; + var job = CreateEngineeringRun( + cycle, modFilename, initialSoC, pos, 1.0, largeMotor: true); + var run = job.Runs.First().Run; + + var hybridController = (SerialHybridController)((VehicleContainer)run.GetContainer()).HybridController; + Assert.NotNull(hybridController); + + var modData = ((ModalDataContainer)((VehicleContainer)run.GetContainer()).ModData).Data; + + run.Run(); + Assert.IsTrue(run.FinishedWithoutErrors); + + Assert.IsTrue(modData.Rows.Count > 0); + + var graphWriter = GetGraphWriter(new[] { ModalResultField.P_electricMotor_mech_B3, ModalResultField.P_electricMotor_mech_Gen }); + graphWriter.Write(modFilename); + } + + [TestCase(50, 0.79, 0, TestName = "S3 Hybrid Brake Standstill 50km/h SoC: 0.79, level"), + TestCase(50, 0.25, 0, TestName = "S3 Hybrid Brake Standstill 50km/h SoC: 0.25, level"), + TestCase(50, 0.65, 0, TestName = "S3 Hybrid Brake Standstill 50km/h SoC: 0.65, level") + ] + public void S3HybridBrakeStandstill(double vmax, double initialSoC, double slope) + { + //var dst = + var cycleData = string.Format( + @" 0, {0}, {1}, 0 + 200, 0, {1}, 3", vmax, slope); + var cycle = SimpleDrivingCycles.CreateCycleData(cycleData); + + const bool largeMotor = true; + + var modFilename = $"SimpleParallelHybrid-S3_stop_{vmax}-{initialSoC}_{slope}.vmod"; + const PowertrainPosition pos = PowertrainPosition.BatteryElectricE3; + var job = CreateEngineeringRun( + cycle, modFilename, initialSoC, pos, 1.0, largeMotor: true); + var run = job.Runs.First().Run; + + var hybridController = (SerialHybridController)((VehicleContainer)run.GetContainer()).HybridController; + Assert.NotNull(hybridController); + //var strategy = (DelegateParallelHybridStrategy)hybridController.Strategy; + //Assert.NotNull(strategy); + + var modData = ((ModalDataContainer)((VehicleContainer)run.GetContainer()).ModData).Data; + + run.Run(); + Assert.IsTrue(run.FinishedWithoutErrors); + + Assert.IsTrue(modData.Rows.Count > 0); + + var graphWriter = GetGraphWriter(new[] { ModalResultField.P_electricMotor_mech_B3, ModalResultField.P_electricMotor_mech_Gen }); + graphWriter.Write(modFilename); + } + + + [ + TestCase("LongHaul", 2000, 0.5, 0, TestName = "S3 Hybrid DriveCycle LongHaul, SoC: 0.5 Payload: 2t P_auxEl: 0kW"), + TestCase("RegionalDelivery", 2000, 0.5, 0, TestName = "S3 Hybrid DriveCycle RegionalDelivery, SoC: 0.5 Payload: 2t P_auxEl: 0kW"), + TestCase("UrbanDelivery", 2000, 0.5, 0, TestName = "S3 Hybrid DriveCycle UrbanDelivery, SoC: 0.5 Payload: 2t P_auxEl: 0kW"), + TestCase("Construction", 2000, 0.5, 0, TestName = "S3 Hybrid DriveCycle Construction, SoC: 0.5 Payload: 2t P_auxEl: 0kW"), + TestCase("Urban", 2000, 0.5, 0, TestName = "S3 Hybrid DriveCycle Urban, SoC: 0.5 Payload: 2t P_auxEl: 0kW"), + TestCase("Suburban", 2000, 0.5, 0, TestName = "S3 Hybrid DriveCycle SubUrban, SoC: 0.5 Payload: 2t P_auxEl: 0kW"), + TestCase("Interurban", 2000, 0.5, 0, TestName = "S3 Hybrid DriveCycle InterUrban, SoC: 0.5 Payload: 2t P_auxEl: 0kW"), + TestCase("Coach", 2000, 0.5, 0, TestName = "S3 Hybrid DriveCycle Coach, SoC: 0.5 Payload: 2t P_auxEl: 0kW"), + ] + public void S3HybridDriveCycle(string declarationMission, double payload, double initialSoC, double pAuxEl) + { + var cycleData = RessourceHelper.ReadStream( + DeclarationData.DeclarationDataResourcePrefix + ".MissionCycles." + + declarationMission + + Constants.FileExtensions.CycleFile); + var cycle = DrivingCycleDataReader.ReadFromStream(cycleData, CycleType.DistanceBased, "", false); + + const bool largeMotor = true; + + var modFilename = $"SimpleParallelHybrid-S3_cycle_{declarationMission}-{initialSoC}_{payload}_{pAuxEl}.vmod"; + const PowertrainPosition pos = PowertrainPosition.BatteryElectricE3; + var job = CreateEngineeringRun( + cycle, modFilename, initialSoC, pos, 1.0, largeMotor: true, pAuxEl: pAuxEl, payload: payload.SI<Kilogram>()); + var run = job.Runs.First().Run; + + var hybridController = (SerialHybridController)((VehicleContainer)run.GetContainer()).HybridController; + Assert.NotNull(hybridController); + + var modData = ((ModalDataContainer)((VehicleContainer)run.GetContainer()).ModData).Data; + + var data = run.GetContainer().RunData; + //File.WriteAllText( + // $"{modFilename}.json", + // JsonConvert.SerializeObject(data, Formatting.Indented)); + + run.Run(); + Assert.IsTrue(run.FinishedWithoutErrors); + + Assert.IsTrue(modData.Rows.Count > 0); + + var graphWriter = GetGraphWriter(new[] { ModalResultField.P_electricMotor_mech_B3, ModalResultField.P_electricMotor_mech_Gen }); + graphWriter.Write(modFilename); + } + + + // ================================================= + + public static JobContainer CreateEngineeringRun(DrivingCycleData cycleData, string modFileName, + double initialSoc, PowertrainPosition pos, double ratio, bool largeMotor = false, bool largeGen = false, double pAuxEl = 0, + Kilogram payload = null, Watt maxDriveTrainPower = null, GearboxType gearboxType = GearboxType.NoGearbox) + { + var fileWriter = new FileOutputWriter(Path.GetFileNameWithoutExtension(modFileName)); + var sumData = new SummaryDataContainer(fileWriter); + var jobContainer = new JobContainer(sumData); + var container = CreateSerialHybridPowerTrain( + cycleData, modFileName, initialSoc, largeMotor, largeGen, sumData, pAuxEl, pos, ratio, payload, + maxDriveTrainPower, gearboxType); + var run = new DistanceRun(container); + jobContainer.AddRun(run); + return jobContainer; + } + + public static VehicleContainer CreateSerialHybridPowerTrain(DrivingCycleData cycleData, string modFileName, + double initialBatCharge, bool largeMotor, bool largeGen, SummaryDataContainer sumData, double pAuxEl, + PowertrainPosition pos, double ratio, Kilogram payload = null, Watt maxDriveTrainPower = null, GearboxType gearboxType = GearboxType.NoGearbox) + { + var gearboxData = CreateGearboxData(gearboxType); + var axleGearData = CreateAxleGearData(gearboxType); + + var vehicleData = CreateVehicleData(payload ?? 3300.SI<Kilogram>()); + var airdragData = CreateAirdragData(); + var driverData = CreateDriverData(AccelerationFile, true); + + var emFile = largeMotor ? MotorFile240kW : MotorFile; + var electricMotorData = MockSimulationDataFactory.CreateElectricMotorData(emFile, 2, pos, ratio, 1); + + var genFile = GeneratorFile; + electricMotorData.AddRange( + MockSimulationDataFactory.CreateElectricMotorData(genFile, 1, PowertrainPosition.Generator, 2.6, 1)); + + var batFile = BatFile; + var batteryData = MockSimulationDataFactory.CreateBatteryData(batFile, initialBatCharge); + //batteryData.TargetSoC = 0.5; + + var engineData = MockSimulationDataFactory.CreateEngineDataFromFile( + Truck40tPowerTrain.EngineFile, gearboxData.Gears.Count); + + foreach (var entry in gearboxData.Gears) { + entry.Value.ShiftPolygon = DeclarationData.Gearbox.ComputeEfficiencyShiftPolygon( + (int)entry.Key, engineData.FullLoadCurves[entry.Key], new TransmissionInputData().Repeat(gearboxData.Gears.Count + 1).Cast<ITransmissionInputData>().ToList(), engineData, axleGearData.AxleGear.Ratio, + vehicleData.DynamicTyreRadius); + } + + var runData = new VectoRunData() { + //PowertrainConfiguration = PowertrainConfiguration.ParallelHybrid, + JobRunId = 0, + JobType = VectoSimulationJobType.SerialHybridVehicle, + DriverData = driverData, + AxleGearData = axleGearData, + GearboxData = gearboxData, + VehicleData = vehicleData, + AirdragData = airdragData, + JobName = Path.GetFileNameWithoutExtension(modFileName), + Cycle = cycleData, + Retarder = new RetarderData() { Type = RetarderType.None }, + Aux = new List<VectoRunData.AuxData>(), + ElectricMachinesData = electricMotorData, + EngineData = engineData, + BatteryData = batteryData, + GearshiftParameters = CreateGearshiftData(gearboxData, axleGearData.AxleGear.Ratio, engineData.IdleSpeed), + HybridStrategyParameters = CreateHybridStrategyData(maxDriveTrainPower), + ElectricAuxDemand = pAuxEl.SI<Watt>() + }; + var fileWriter = new FileOutputWriter(modFileName); + var modDataFilter = new IModalDataFilter[] { }; //new IModalDataFilter[] { new ActualModalDataFilter(), }; + var modData = new ModalDataContainer(runData, fileWriter, null, modDataFilter) { + WriteModalResults = true, + }; + var container = new VehicleContainer( + ExecutionMode.Engineering, modData, x => { sumData?.Write(x, 1, 1, runData); }); + container.RunData = runData; + + var strategy = new SerialHybridStrategy(runData, container); + var es = new ElectricSystem(container); + var battery = new BatterySystem(container, batteryData); + battery.Initialize(initialBatCharge); + + //var clutch = gearboxType.AutomaticTransmission() ? null : new SwitchableClutch(container, runData.EngineData); + var ctl = new SerialHybridController(container, strategy, es); + + es.Connect(battery); + + var engine = new StopStartCombustionEngine(container, runData.EngineData); + + //var hybridStrategy = new DelegateParallelHybridStrategy(); + + var idleController = engine.IdleController; + ctl.Engine = engine; + + var cycle = new DistanceBasedDrivingCycle(container, cycleData); + + var aux = new ElectricAuxiliary(container); + aux.AddConstant("P_aux_el", pAuxEl.SI<Watt>()); + es.Connect(aux); + + var powertrain = cycle + .AddComponent(new Driver(container, runData.DriverData, new DefaultDriverStrategy(container))) + .AddComponent(new Vehicle(container, runData.VehicleData, runData.AirdragData)) + .AddComponent(new Wheels(container, runData.VehicleData.DynamicTyreRadius, + runData.VehicleData.WheelsInertia)) + .AddComponent(ctl) + .AddComponent(new Brakes(container)); + + switch (pos) { + case PowertrainPosition.HybridPositionNotSet: + throw new VectoException("invalid powertrain position"); + case PowertrainPosition.BatteryElectricE2: + var gearbox = gearboxType.AutomaticTransmission() + ? (IHybridControlledGearbox)new ATGearbox(container, ctl.ShiftStrategy) + : new Gearbox(container, ctl.ShiftStrategy); + powertrain = powertrain.AddComponent(new AxleGear(container, runData.AxleGearData)) + .AddComponent(runData.AngledriveData != null + ? new Angledrive(container, runData.AngledriveData) + : null) + .AddComponent((IGearbox)gearbox, runData.Retarder, container) + .AddComponent(GetElectricMachine(PowertrainPosition.BatteryElectricE2, runData.ElectricMachinesData, + container, + es, ctl)); + ctl.Gearbox = gearbox; + + break; + + case PowertrainPosition.BatteryElectricE3: + powertrain = powertrain.AddComponent(new AxleGear(container, runData.AxleGearData)) + .AddComponent(GetElectricMachine(PowertrainPosition.BatteryElectricE3, runData.ElectricMachinesData, + container, + es, ctl)); + new DummyGearboxInfo(container); + //new MockEngineInfo(container); + new ATClutchInfo(container); + runData.GearboxData = null; + break; + case PowertrainPosition.BatteryElectricE4: + powertrain = powertrain.AddComponent(GetElectricMachine(PowertrainPosition.BatteryElectricE4, runData.ElectricMachinesData, + container, + es, ctl)); + new DummyGearboxInfo(container); + //new MockEngineInfo(container); + new ATClutchInfo(container); + runData.GearboxData = null; + break; + case PowertrainPosition.HybridP0: + case PowertrainPosition.HybridP1: + case PowertrainPosition.HybridP2_5: + case PowertrainPosition.HybridP2: + case PowertrainPosition.HybridP3: + case PowertrainPosition.HybridP4: + + throw new VectoException("testcase does not support parallel powertrain configurations"); + default: + throw new ArgumentOutOfRangeException(nameof(pos), pos, null); + } + + ctl.GenSet.AddComponent(GetElectricMachine(PowertrainPosition.Generator, runData.ElectricMachinesData, container, + es, ctl)) + .AddComponent(engine, idleController) + .AddAuxiliaries(container, runData); + + return container; + } + + private static HybridStrategyParameters CreateHybridStrategyData(Watt maxDriveTrainPower) + { + return new HybridStrategyParameters() { + EquivalenceFactorDischarge = 2.5, + EquivalenceFactorCharge = 2.5, + MinSoC = 0.22, + MaxSoC = 0.8, + TargetSoC = 0.7, + AuxReserveTime = 5.SI<Second>(), + AuxReserveChargeTime = 2.SI<Second>(), + MinICEOnTime = 3.SI<Second>(), + ICEStartPenaltyFactor = 0, + //MaxDrivetrainPower = maxDriveTrainPower ?? 1e12.SI<Watt>(), + CostFactorSOCExponent = 5, + // todo: keep this factor? + //SerialHybridLoadpointFactor = 0.8, + }; + } + + public static ShiftStrategyParameters CreateGearshiftData(GearboxData gbx, double axleRatio, PerSecond engineIdlingSpeed) + { + var retVal = new ShiftStrategyParameters { + TimeBetweenGearshifts = 2.SI<Second>(), + TorqueReserve = 0.2, + StartTorqueReserve = 0.2, + DownshiftAfterUpshiftDelay = DeclarationData.Gearbox.DownshiftAfterUpshiftDelay, + UpshiftAfterDownshiftDelay = DeclarationData.Gearbox.UpshiftAfterDownshiftDelay, + UpshiftMinAcceleration = DeclarationData.Gearbox.UpshiftMinAcceleration, + StartSpeed = 2.SI<MeterPerSecond>(), + StartAcceleration = 0.6.SI<MeterPerSquareSecond>(), + + StartVelocity = DeclarationData.GearboxTCU.StartSpeed, + //StartAcceleration = DeclarationData.GearboxTCU.StartAcceleration, + GearResidenceTime = DeclarationData.GearboxTCU.GearResidenceTime, + DnT99L_highMin1 = DeclarationData.GearboxTCU.DnT99L_highMin1, + DnT99L_highMin2 = DeclarationData.GearboxTCU.DnT99L_highMin2, + AllowedGearRangeUp = gbx.Type.AutomaticTransmission() ? 1 : DeclarationData.GearboxTCU.AllowedGearRangeUp, + AllowedGearRangeDown = gbx.Type.AutomaticTransmission() ? 1 : DeclarationData.GearboxTCU.AllowedGearRangeDown, + LookBackInterval = DeclarationData.GearboxTCU.LookBackInterval, + DriverAccelerationLookBackInterval = DeclarationData.GearboxTCU.DriverAccelerationLookBackInterval, + DriverAccelerationThresholdLow = DeclarationData.GearboxTCU.DriverAccelerationThresholdLow, + AverageCardanPowerThresholdPropulsion = DeclarationData.GearboxTCU.AverageCardanPowerThresholdPropulsion, + CurrentCardanPowerThresholdPropulsion = DeclarationData.GearboxTCU.CurrentCardanPowerThresholdPropulsion, + TargetSpeedDeviationFactor = DeclarationData.GearboxTCU.TargetSpeedDeviationFactor, + EngineSpeedHighDriveOffFactor = DeclarationData.GearboxTCU.EngineSpeedHighDriveOffFactor, + RatingFactorCurrentGear = gbx.Type.AutomaticTransmission() + ? DeclarationData.GearboxTCU.RatingFactorCurrentGearAT + : DeclarationData.GearboxTCU.RatingFactorCurrentGear, + + //-------------------- + RatioEarlyUpshiftFC = DeclarationData.GearboxTCU.RatioEarlyUpshiftFC / axleRatio, + RatioEarlyDownshiftFC = DeclarationData.GearboxTCU.RatioEarlyDownshiftFC / axleRatio, + AllowedGearRangeFC = gbx.Type.AutomaticTransmission() + ? (gbx.Gears.Count > DeclarationData.GearboxTCU.ATSkipGearsThreshold + ? DeclarationData.GearboxTCU.AllowedGearRangeFCATSkipGear + : DeclarationData.GearboxTCU.AllowedGearRangeFCAT) + : DeclarationData.GearboxTCU.AllowedGearRangeFCAMT, + VelocityDropFactor = DeclarationData.GearboxTCU.VelocityDropFactor, + AccelerationFactor = DeclarationData.GearboxTCU.AccelerationFactor, + MinEngineSpeedPostUpshift = 0.RPMtoRad(), + ATLookAheadTime = DeclarationData.GearboxTCU.ATLookAheadTime, + + LoadStageThresoldsUp = DeclarationData.GearboxTCU.LoadStageThresholdsUp, + LoadStageThresoldsDown = DeclarationData.GearboxTCU.LoadStageThresoldsDown, + ShiftSpeedsTCToLocked = DeclarationData.GearboxTCU.ShiftSpeedsTCToLocked + .Select(x => x.Select(y => y + engineIdlingSpeed.AsRPM).ToArray()).ToArray(), + }; + + return retVal; + } + + private static IElectricMotor GetElectricMachine(PowertrainPosition pos, + IList<Tuple<PowertrainPosition, ElectricMotorData>> electricMachinesData, VehicleContainer container, + ElectricSystem es, IHybridController ctl) + { + var motorData = electricMachinesData.FirstOrDefault(x => x.Item1 == pos); + if (motorData == null) { + return null; + } + + container.ModData.AddElectricMotor(pos); + ctl.AddElectricMotor(pos, motorData.Item2); + var motor = new ElectricMotor(container, motorData.Item2, ctl.ElectricMotorControl(pos), pos); + if (pos == PowertrainPosition.Generator) { + es.Connect(new GensetChargerAdapter(motor)); + } else { + motor.Connect(es); + } + + return motor; + } + + private static GearboxData CreateGearboxData(GearboxType gearboxType = GearboxType.NoGearbox) + { + switch (gearboxType) { + + case GearboxType.NoGearbox: + case GearboxType.AMT: + return CreateAMTGearbox(); + //case GearboxType.ATSerial: + // return CreateATSerial(); + //case GearboxType.ATPowerSplit: + // return CreateATPowerSplit(); + default: + throw new ArgumentOutOfRangeException(nameof(gearboxType), gearboxType, null); + } + } + + private static GearboxData CreateAMTGearbox() + { + var ratios = new[] { 14.93, 11.64, 9.02, 7.04, 5.64, 4.4, 3.39, 2.65, 2.05, 1.6, 1.28, 1.0 }; + + return new GearboxData { + Gears = ratios.Select( + (ratio, i) => Tuple.Create( + (uint)i, new GearData { + //MaxTorque = 2300.SI<NewtonMeter>(), + LossMap = + TransmissionLossMapReader.ReadFromFile( + ratio.IsEqual(1) ? GearboxIndirectLoss : GearboxDirectLoss, ratio, + $"Gear {i}"), + Ratio = ratio, + //ShiftPolygon = DeclarationData.Gearbox.ComputeEfficiencyShiftPolygon(i,) + })).ToDictionary(k => k.Item1 + 1, v => v.Item2), + Inertia = 0.SI<KilogramSquareMeter>(), + TractionInterruption = 1.SI<Second>(), + }; + } + + + private static AxleGearData CreateAxleGearData(GearboxType gearboxType) + { + var ratio = 2.59; + switch (gearboxType) { + case GearboxType.ATSerial: + ratio = 6.2; + break; + case GearboxType.ATPowerSplit: + ratio = 5.8; + break; + } + return new AxleGearData { + AxleGear = new GearData { + Ratio = ratio, + LossMap = TransmissionLossMapReader.Create(0.95, ratio, "Axlegear"), + } + }; + } + + private static VehicleData CreateVehicleData(Kilogram loading) + { + var axles = new List<Axle> { + new Axle { + AxleWeightShare = 0.38, + Inertia = 20.SI<KilogramSquareMeter>(), + RollResistanceCoefficient = 0.007, + TwinTyres = false, + TyreTestLoad = 30436.0.SI<Newton>() + }, + new Axle { + AxleWeightShare = 0.62, + Inertia = 18.SI<KilogramSquareMeter>(), + RollResistanceCoefficient = 0.007, + TwinTyres = true, + TyreTestLoad = 30436.SI<Newton>() + }, + }; + return new VehicleData { + AirDensity = DeclarationData.AirDensity, + AxleConfiguration = AxleConfiguration.AxleConfig_4x2, + CurbMass = 11500.SI<Kilogram>(), + Loading = loading, + DynamicTyreRadius = 0.465.SI<Meter>(), + AxleData = axles, + SavedInDeclarationMode = false, + ADAS = new VehicleData.ADASData() { + EngineStopStart = true + } + }; + } + + private static AirdragData CreateAirdragData() + { + return new AirdragData() { + CrossWindCorrectionCurve = + new CrosswindCorrectionCdxALookup( + 3.2634.SI<SquareMeter>(), + CrossWindCorrectionCurveReader.GetNoCorrectionCurve(3.2634.SI<SquareMeter>()), + CrossWindCorrectionMode.NoCorrection), + }; + } + + private static DriverData CreateDriverData(string accelerationFile, bool overspeed = false) + { + return new DriverData { + AccelerationCurve = AccelerationCurveReader.ReadFromFile(accelerationFile), + LookAheadCoasting = new DriverData.LACData { + Enabled = true, + MinSpeed = 50.KMPHtoMeterPerSecond(), + + //Deceleration = -0.5.SI<MeterPerSquareSecond>() + LookAheadDistanceFactor = DeclarationData.Driver.LookAhead.LookAheadDistanceFactor, + LookAheadDecisionFactor = new LACDecisionFactor() + }, + OverSpeed = new DriverData.OverSpeedData() { + Enabled = true, + MinSpeed = 50.KMPHtoMeterPerSecond(), + OverSpeed = 5.KMPHtoMeterPerSecond() + }, + EngineStopStart = new DriverData.EngineStopStartData() { + EngineOffStandStillActivationDelay = DeclarationData.Driver.EngineStopStart.ActivationDelay, + MaxEngineOffTimespan = DeclarationData.Driver.EngineStopStart.MaxEngineOffTimespan, + UtilityFactorStandstill = DeclarationData.Driver.EngineStopStart.UtilityFactor + } + }; + } + + + // ====================== + + private GraphWriter GetGraphWriter(ModalResultField[] emYFields) + { + var Yfields = new[] { + ModalResultField.v_act, ModalResultField.altitude, ModalResultField.acc, ModalResultField.Gear, + ModalResultField.P_ice_out, ModalResultField.REESSStateOfCharge, ModalResultField.FCMap + }.Concat(emYFields).ToArray(); + + var graphWriter = new GraphWriter(); + graphWriter.Xfields = new[] { ModalResultField.dist }; + graphWriter.Yfields = Yfields; + graphWriter.Series1Label = "Hybrid"; + graphWriter.PlotIgnitionState = true; + + if (PlotGraphs) { + graphWriter.Enable(); + } else { + graphWriter.Disable(); + } + + return graphWriter; + } + + } +} \ No newline at end of file diff --git a/VectoCore/VectoCoreTest/TestData/Hybrids/ElectricMotor/GenericDragGenerator.vemd b/VectoCore/VectoCoreTest/TestData/Hybrids/ElectricMotor/GenericDragGenerator.vemd new file mode 100644 index 0000000000000000000000000000000000000000..b4ff91987652279e4b96e2a857b77644cc644126 --- /dev/null +++ b/VectoCore/VectoCoreTest/TestData/Hybrids/ElectricMotor/GenericDragGenerator.vemd @@ -0,0 +1,23 @@ +n [rpm] , T_drag [Nm] +0, -4.35 +80, -4.51 +800, -6 +1600, -7.66 +2400, -9.31 +3200, -10.97 +4000, -12.62 +4800, -14.28 +5600, -15.93 +6400, -17.59 +7200, -19.24 +8000, -20.9 +8800, -22.55 +9600, -24.21 +10400, -25.87 +11200, -27.52 +12000, -29.18 +12800, -30.83 +13600, -32.49 +14400, -34.14 +15200, -35.8 +16000, -37.45 diff --git a/VectoCore/VectoCoreTest/TestData/Hybrids/ElectricMotor/GenericGenerator.vem b/VectoCore/VectoCoreTest/TestData/Hybrids/ElectricMotor/GenericGenerator.vem new file mode 100644 index 0000000000000000000000000000000000000000..6862c4c5594c18d7c15cfe7d0d8a3bb1c0b59de3 --- /dev/null +++ b/VectoCore/VectoCoreTest/TestData/Hybrids/ElectricMotor/GenericGenerator.vem @@ -0,0 +1,20 @@ +{ + "Header": { + "CreatedBy": " ()", + "Date": "2016-10-13T08:54:28.7387223Z", + "AppVersion": "3", + "FileVersion": 1 + }, + "Body": { + "SavedInDeclMode": false, + "Model": "Generic Electric Motor", + "FullLoadCurve": "GenericGenerator.vemp", + "DragCurve": "GenericDragGenerator.vemd", + "EfficiencyMap": "GenericMapGenerator.vemo", + "Inertia": 0.2, + "ContinuousPower": 50000, + "ContinuousPowerSpeed": 2000, + "OverloadTime": 30, + "ThermalOverloadRecoveryFactor": 0.9 + } +} \ No newline at end of file diff --git a/VectoCore/VectoCoreTest/TestData/Hybrids/ElectricMotor/GenericGenerator.vemp b/VectoCore/VectoCoreTest/TestData/Hybrids/ElectricMotor/GenericGenerator.vemp new file mode 100644 index 0000000000000000000000000000000000000000..5b32c7a31cfa3f49020251d69167b1db37ddf78a --- /dev/null +++ b/VectoCore/VectoCoreTest/TestData/Hybrids/ElectricMotor/GenericGenerator.vemp @@ -0,0 +1,24 @@ +n [rpm] , T_drive [Nm] , T_recuperation [Nm] +0, 900.00, -900.00 +80, 900.00, -900.00 +800, 900.00, -900.00 +1600, 900.00, -900.00 +2400, 900.00, -900.00 +3200, 900.00, -900.00 +4000, 900.00, -900.00 +4800, 750.00, -750.00 +5600, 642.86, -642.86 +6400, 562.50, -562.50 +7200, 500.00, -500.00 +8000, 450.00, -450.00 +8800, 409.09, -409.09 +9600, 375.00, -375.00 +10400, 346.15, -346.15 +11200, 321.43, -321.43 +12000, 300.00, -300.00 +12800, 281.25, -281.25 +13600, 264.71, -264.71 +14400, 250.00, -250.00 +15200, 236.84, -236.84 +16000, 225.00, -225.00 + diff --git a/VectoCore/VectoCoreTest/TestData/Hybrids/ElectricMotor/GenericMapGenerator.vemo b/VectoCore/VectoCoreTest/TestData/Hybrids/ElectricMotor/GenericMapGenerator.vemo new file mode 100644 index 0000000000000000000000000000000000000000..0f3ab230b762aa5feb996f9f0cb246efd87efcbf --- /dev/null +++ b/VectoCore/VectoCoreTest/TestData/Hybrids/ElectricMotor/GenericMapGenerator.vemo @@ -0,0 +1,925 @@ +n [rpm], T [Nm], P_bat [W] +0, -900, 0.000 +0, -855, 0.000 +0, -810, 0.000 +0, -765, 0.000 +0, -720, 0.000 +0, -675, 0.000 +0, -630, 0.000 +0, -585, 0.000 +0, -540, -0.069 +0, -495, -0.171 +0, -450, -0.253 +0, -405, -0.316 +0, -360, -0.358 +0, -315, -0.381 +0, -270, -0.383 +0, -225, -0.366 +0, -180, -0.328 +0, -135, -0.271 +0, -90, -0.194 +0, -45, -0.097 +0, -9, -0.005 +0, 9, 0.082 +0, 45, 0.331 +0, 90, 0.662 +0, 135, 1.015 +0, 180, 1.389 +0, 225, 1.785 +0, 270, 2.202 +0, 315, 2.641 +0, 360, 3.102 +0, 405, 3.584 +0, 450, 4.088 +0, 495, 4.614 +0, 540, 5.161 +0, 585, 5.730 +0, 630, 6.320 +0, 675, 6.932 +0, 720, 7.566 +0, 765, 8.221 +0, 810, 8.898 +0, 855, 9.597 +0, 900, 10.317 +80, -900, 0.000 +80, -855, 0.000 +80, -810, 0.000 +80, -765, 0.000 +80, -720, 0.000 +80, -675, 0.000 +80, -630, -0.135 +80, -585, -0.335 +80, -540, -0.502 +80, -495, -0.637 +80, -450, -0.739 +80, -405, -0.808 +80, -360, -0.845 +80, -315, -0.849 +80, -270, -0.820 +80, -225, -0.759 +80, -180, -0.665 +80, -135, -0.539 +80, -90, -0.380 +80, -45, -0.188 +80, -9, -0.011 +80, 9, 0.145 +80, 45, 0.582 +80, 90, 1.159 +80, 135, 1.772 +80, 180, 2.420 +80, 225, 3.104 +80, 270, 3.822 +80, 315, 4.577 +80, 360, 5.367 +80, 405, 6.192 +80, 450, 7.052 +80, 495, 7.949 +80, 540, 8.880 +80, 585, 9.847 +80, 630, 10.849 +80, 675, 11.887 +80, 720, 12.960 +80, 765, 14.068 +80, 810, 15.212 +80, 855, 16.391 +80, 900, 17.606 +800, -900, -62.530 +800, -855, -59.716 +800, -810, -56.868 +800, -765, -53.984 +800, -720, -51.066 +800, -675, -48.112 +800, -630, -45.123 +800, -585, -42.099 +800, -540, -39.040 +800, -495, -35.946 +800, -450, -32.817 +800, -405, -29.652 +800, -360, -26.453 +800, -315, -23.218 +800, -270, -19.949 +800, -225, -16.644 +800, -180, -13.304 +800, -135, -9.929 +800, -90, -6.519 +800, -45, -3.074 +800, -9, -0.292 +800, 9, 1.254 +800, 45, 4.519 +800, 90, 8.635 +800, 135, 12.788 +800, 180, 16.980 +800, 225, 21.210 +800, 270, 25.478 +800, 315, 29.784 +800, 360, 34.129 +800, 405, 38.511 +800, 450, 42.931 +800, 495, 47.390 +800, 540, 51.887 +800, 585, 56.421 +800, 630, 60.994 +800, 675, 65.605 +800, 720, 70.254 +800, 765, 74.941 +800, 810, 79.666 +800, 855, 84.429 +800, 900, 89.231 +1600, -900, -133.005 +1600, -855, -126.707 +1600, -810, -120.367 +1600, -765, -113.984 +1600, -720, -107.560 +1600, -675, -101.094 +1600, -630, -94.586 +1600, -585, -88.035 +1600, -540, -81.443 +1600, -495, -74.809 +1600, -450, -68.133 +1600, -405, -61.415 +1600, -360, -54.654 +1600, -315, -47.852 +1600, -270, -41.008 +1600, -225, -34.122 +1600, -180, -27.194 +1600, -135, -20.224 +1600, -90, -13.212 +1600, -45, -6.158 +1600, -9, -0.484 +1600, 9, 2.616 +1600, 45, 9.026 +1600, 90, 17.080 +1600, 135, 25.179 +1600, 180, 33.324 +1600, 225, 41.515 +1600, 270, 49.751 +1600, 315, 58.033 +1600, 360, 66.360 +1600, 405, 74.733 +1600, 450, 83.151 +1600, 495, 91.615 +1600, 540, 100.124 +1600, 585, 108.679 +1600, 630, 117.280 +1600, 675, 125.926 +1600, 720, 134.617 +1600, 765, 143.354 +1600, 810, 152.137 +1600, 855, 160.965 +1600, 900, 169.839 +2400, -900, -202.436 +2400, -855, -192.737 +2400, -810, -182.985 +2400, -765, -173.180 +2400, -720, -163.322 +2400, -675, -153.410 +2400, -630, -143.446 +2400, -585, -133.428 +2400, -540, -123.357 +2400, -495, -113.233 +2400, -450, -103.055 +2400, -405, -92.824 +2400, -360, -82.540 +2400, -315, -72.203 +2400, -270, -61.813 +2400, -225, -51.370 +2400, -180, -40.873 +2400, -135, -30.323 +2400, -90, -19.720 +2400, -45, -9.064 +2400, -9, -0.500 +2400, 9, 4.170 +2400, 45, 13.727 +2400, 90, 25.727 +2400, 135, 37.783 +2400, 180, 49.898 +2400, 225, 62.070 +2400, 270, 74.300 +2400, 315, 86.588 +2400, 360, 98.933 +2400, 405, 111.337 +2400, 450, 123.798 +2400, 495, 136.316 +2400, 540, 148.893 +2400, 585, 161.527 +2400, 630, 174.219 +2400, 675, 186.968 +2400, 720, 199.775 +2400, 765, 212.640 +2400, 810, 225.563 +2400, 855, 238.544 +2400, 900, 251.582 +3200, -900, -270.769 +3200, -855, -257.755 +3200, -810, -244.672 +3200, -765, -231.520 +3200, -720, -218.299 +3200, -675, -205.010 +3200, -630, -191.652 +3200, -585, -178.225 +3200, -540, -164.729 +3200, -495, -151.165 +3200, -450, -137.531 +3200, -405, -123.829 +3200, -360, -110.059 +3200, -315, -96.219 +3200, -270, -82.311 +3200, -225, -68.334 +3200, -180, -54.288 +3200, -135, -40.174 +3200, -90, -25.990 +3200, -45, -11.738 +3200, -9, -0.287 +3200, 9, 5.972 +3200, 45, 18.679 +3200, 90, 34.631 +3200, 135, 50.657 +3200, 180, 66.757 +3200, 225, 82.933 +3200, 270, 99.182 +3200, 315, 115.507 +3200, 360, 131.906 +3200, 405, 148.380 +3200, 450, 164.928 +3200, 495, 181.551 +3200, 540, 198.249 +3200, 585, 215.021 +3200, 630, 231.868 +3200, 675, 248.789 +3200, 720, 265.785 +3200, 765, 282.856 +3200, 810, 300.001 +3200, 855, 317.221 +3200, 900, 334.515 +4000, -900, -337.953 +4000, -855, -321.708 +4000, -810, -305.374 +4000, -765, -288.951 +4000, -720, -272.440 +4000, -675, -255.840 +4000, -630, -239.151 +4000, -585, -222.374 +4000, -540, -205.508 +4000, -495, -188.553 +4000, -450, -171.510 +4000, -405, -154.378 +4000, -360, -137.157 +4000, -315, -119.848 +4000, -270, -102.450 +4000, -225, -84.963 +4000, -180, -67.388 +4000, -135, -49.724 +4000, -90, -31.971 +4000, -45, -14.130 +4000, -9, 0.000 +4000, 9, 8.079 +4000, 45, 23.938 +4000, 90, 43.849 +4000, 135, 63.856 +4000, 180, 83.959 +4000, 225, 104.159 +4000, 270, 124.454 +4000, 315, 144.846 +4000, 360, 165.334 +4000, 405, 185.918 +4000, 450, 206.599 +4000, 495, 227.376 +4000, 540, 248.249 +4000, 585, 269.218 +4000, 630, 290.283 +4000, 675, 311.445 +4000, 720, 332.703 +4000, 765, 354.057 +4000, 810, 375.507 +4000, 855, 397.053 +4000, 900, 418.696 +4800, -900, -403.935 +4800, -855, -384.544 +4800, -810, -365.039 +4800, -765, -345.422 +4800, -720, -325.691 +4800, -675, -305.848 +4800, -630, -285.892 +4800, -585, -265.823 +4800, -540, -245.641 +4800, -495, -225.346 +4800, -450, -204.938 +4800, -405, -184.417 +4800, -360, -163.784 +4800, -315, -143.037 +4800, -270, -122.178 +4800, -225, -101.205 +4800, -180, -80.120 +4800, -135, -58.922 +4800, -90, -37.611 +4800, -45, -16.186 +4800, -9, 0.000 +4800, 9, 10.547 +4800, 45, 29.560 +4800, 90, 53.438 +4800, 135, 77.438 +4800, 180, 101.560 +4800, 225, 125.805 +4800, 270, 150.172 +4800, 315, 174.662 +4800, 360, 199.274 +4800, 405, 224.009 +4800, 450, 248.867 +4800, 495, 273.847 +4800, 540, 298.949 +4800, 585, 324.174 +4800, 630, 349.522 +4800, 675, 374.992 +4800, 720, 400.584 +4800, 765, 426.300 +4800, 810, 452.137 +4800, 855, 478.097 +4800, 900, 504.180 +5600, -900, -468.664 +5600, -855, -446.211 +5600, -810, -423.616 +5600, -765, -400.880 +5600, -720, -378.002 +5600, -675, -354.983 +5600, -630, -331.822 +5600, -585, -308.520 +5600, -540, -285.076 +5600, -495, -261.491 +5600, -450, -237.764 +5600, -405, -213.896 +5600, -360, -189.886 +5600, -315, -165.735 +5600, -270, -141.442 +5600, -225, -117.008 +5600, -180, -92.432 +5600, -135, -67.715 +5600, -90, -42.856 +5600, -45, -17.856 +5600, -9, 0.000 +5600, 9, 13.433 +5600, 45, 35.603 +5600, 90, 63.454 +5600, 135, 91.458 +5600, 180, 119.616 +5600, 225, 147.928 +5600, 270, 176.393 +5600, 315, 205.011 +5600, 360, 233.783 +5600, 405, 262.709 +5600, 450, 291.788 +5600, 495, 321.021 +5600, 540, 350.407 +5600, 585, 379.947 +5600, 630, 409.640 +5600, 675, 439.487 +5600, 720, 469.487 +5600, 765, 499.641 +5600, 810, 529.949 +5600, 855, 560.410 +5600, 900, 591.025 +6400, -900, -532.087 +6400, -855, -506.657 +6400, -810, -481.052 +6400, -765, -455.273 +6400, -720, -429.320 +6400, -675, -403.192 +6400, -630, -376.890 +6400, -585, -350.413 +6400, -540, -323.762 +6400, -495, -296.936 +6400, -450, -269.936 +6400, -405, -242.762 +6400, -360, -215.413 +6400, -315, -187.889 +6400, -270, -160.191 +6400, -225, -132.319 +6400, -180, -104.272 +6400, -135, -76.051 +6400, -90, -47.656 +6400, -45, -19.086 +6400, -9, 0.000 +6400, 9, 16.794 +6400, 45, 42.122 +6400, 90, 73.954 +6400, 135, 105.975 +6400, 180, 138.185 +6400, 225, 170.584 +6400, 270, 203.172 +6400, 315, 235.950 +6400, 360, 268.917 +6400, 405, 302.074 +6400, 450, 335.419 +6400, 495, 368.954 +6400, 540, 402.678 +6400, 585, 436.592 +6400, 630, 470.695 +6400, 675, 504.987 +6400, 720, 539.468 +6400, 765, 574.139 +6400, 810, 608.999 +6400, 855, 644.048 +6400, 900, 679.286 +7200, -900, -594.152 +7200, -855, -565.829 +7200, -810, -537.295 +7200, -765, -508.549 +7200, -720, -479.592 +7200, -675, -450.423 +7200, -630, -421.042 +7200, -585, -391.449 +7200, -540, -361.645 +7200, -495, -331.629 +7200, -450, -301.401 +7200, -405, -270.962 +7200, -360, -240.311 +7200, -315, -209.448 +7200, -270, -178.373 +7200, -225, -147.087 +7200, -180, -115.589 +7200, -135, -83.879 +7200, -90, -51.957 +7200, -45, -19.824 +7200, -9, 0.000 +7200, 9, 20.685 +7200, 45, 49.175 +7200, 90, 84.994 +7200, 135, 121.043 +7200, 180, 157.322 +7200, 225, 193.830 +7200, 270, 230.568 +7200, 315, 267.535 +7200, 360, 304.733 +7200, 405, 342.160 +7200, 450, 379.817 +7200, 495, 417.704 +7200, 540, 455.820 +7200, 585, 494.166 +7200, 630, 532.742 +7200, 675, 571.547 +7200, 720, 610.583 +7200, 765, 649.848 +7200, 810, 689.342 +7200, 855, 729.067 +7200, 900, 769.021 +8000, -900, -654.806 +8000, -855, -623.677 +8000, -810, -592.293 +8000, -765, -560.657 +8000, -720, -528.767 +8000, -675, -496.624 +8000, -630, -464.227 +8000, -585, -431.578 +8000, -540, -398.674 +8000, -495, -365.518 +8000, -450, -332.108 +8000, -405, -298.445 +8000, -360, -264.528 +8000, -315, -230.358 +8000, -270, -195.935 +8000, -225, -161.259 +8000, -180, -126.329 +8000, -135, -91.146 +8000, -90, -55.709 +8000, -45, -20.019 +8000, -9, 0.000 +8000, 9, 25.165 +8000, 45, 56.818 +8000, 90, 96.631 +8000, 135, 136.720 +8000, 180, 177.084 +8000, 225, 217.722 +8000, 270, 258.636 +8000, 315, 299.824 +8000, 360, 341.287 +8000, 405, 383.025 +8000, 450, 425.038 +8000, 495, 467.326 +8000, 540, 509.888 +8000, 585, 552.726 +8000, 630, 595.838 +8000, 675, 639.226 +8000, 720, 682.888 +8000, 765, 726.825 +8000, 810, 771.037 +8000, 855, 815.524 +8000, 900, 860.286 +8800, -900, -713.999 +8800, -855, -680.147 +8800, -810, -645.995 +8800, -765, -611.543 +8800, -720, -576.793 +8800, -675, -541.743 +8800, -630, -506.394 +8800, -585, -470.745 +8800, -540, -434.798 +8800, -495, -398.550 +8800, -450, -362.004 +8800, -405, -325.158 +8800, -360, -288.013 +8800, -315, -250.569 +8800, -270, -212.826 +8800, -225, -174.783 +8800, -180, -136.441 +8800, -135, -97.799 +8800, -90, -58.858 +8800, -45, -19.618 +8800, -9, 0.000 +8800, 9, 30.288 +8800, 45, 65.107 +8800, 90, 108.922 +8800, 135, 153.063 +8800, 180, 197.528 +8800, 225, 242.318 +8800, 270, 287.432 +8800, 315, 332.872 +8800, 360, 378.636 +8800, 405, 424.725 +8800, 450, 471.138 +8800, 495, 517.877 +8800, 540, 564.940 +8800, 585, 612.328 +8800, 630, 660.041 +8800, 675, 708.078 +8800, 720, 756.441 +8800, 765, 805.128 +8800, 810, 854.139 +8800, 855, 903.476 +8800, 900, 953.137 +9600, -900, -771.678 +9600, -855, -735.187 +9600, -810, -698.347 +9600, -765, -661.157 +9600, -720, -623.617 +9600, -675, -585.728 +9600, -630, -547.489 +9600, -585, -508.900 +9600, -540, -469.962 +9600, -495, -430.675 +9600, -450, -391.037 +9600, -405, -351.051 +9600, -360, -310.714 +9600, -315, -270.028 +9600, -270, -228.992 +9600, -225, -187.607 +9600, -180, -145.872 +9600, -135, -103.788 +9600, -90, -61.353 +9600, -45, -18.570 +9600, -9, 0.000 +9600, 9, 36.112 +9600, 45, 74.098 +9600, 90, 121.923 +9600, 135, 170.127 +9600, 180, 218.710 +9600, 225, 267.672 +9600, 270, 317.014 +9600, 315, 366.735 +9600, 360, 416.836 +9600, 405, 467.316 +9600, 450, 518.175 +9600, 495, 569.414 +9600, 540, 621.032 +9600, 585, 673.029 +9600, 630, 725.406 +9600, 675, 778.162 +9600, 720, 831.297 +9600, 765, 884.812 +9600, 810, 938.706 +9600, 855, 992.979 +9600, 900, 1047.632 +10400, -900, -827.790 +10400, -855, -788.746 +10400, -810, -749.297 +10400, -765, -709.444 +10400, -720, -669.187 +10400, -675, -628.526 +10400, -630, -587.460 +10400, -585, -545.991 +10400, -540, -504.117 +10400, -495, -461.838 +10400, -450, -419.156 +10400, -405, -376.069 +10400, -360, -332.578 +10400, -315, -288.682 +10400, -270, -244.383 +10400, -225, -199.679 +10400, -180, -154.571 +10400, -135, -109.059 +10400, -90, -63.142 +10400, -45, -16.821 +10400, -9, 0.000 +10400, 9, 42.693 +10400, 45, 83.850 +10400, 90, 135.690 +10400, 135, 187.969 +10400, 180, 240.687 +10400, 225, 293.843 +10400, 270, 347.438 +10400, 315, 401.472 +10400, 360, 455.944 +10400, 405, 510.855 +10400, 450, 566.205 +10400, 495, 621.993 +10400, 540, 678.220 +10400, 585, 734.885 +10400, 630, 791.989 +10400, 675, 849.532 +10400, 720, 907.513 +10400, 765, 965.934 +10400, 810, 1024.792 +10400, 855, 1084.090 +10400, 900, 1143.826 +11200, -900, -882.284 +11200, -855, -840.771 +11200, -810, -798.794 +11200, -765, -756.355 +11200, -720, -713.452 +11200, -675, -670.086 +11200, -630, -626.257 +11200, -585, -581.964 +11200, -540, -537.208 +11200, -495, -491.989 +11200, -450, -446.307 +11200, -405, -400.162 +11200, -360, -353.553 +11200, -315, -306.481 +11200, -270, -258.945 +11200, -225, -210.947 +11200, -180, -162.485 +11200, -135, -113.560 +11200, -90, -64.172 +11200, -45, -14.320 +11200, -9, 0.000 +11200, 9, 50.088 +11200, 45, 94.417 +11200, 90, 150.280 +11200, 135, 206.647 +11200, 180, 263.515 +11200, 225, 320.887 +11200, 270, 378.761 +11200, 315, 437.137 +11200, 360, 496.017 +11200, 405, 555.399 +11200, 450, 615.283 +11200, 495, 675.671 +11200, 540, 736.561 +11200, 585, 797.953 +11200, 630, 859.848 +11200, 675, 922.246 +11200, 720, 985.147 +11200, 765, 1048.550 +11200, 810, 1112.456 +11200, 855, 1176.865 +11200, 900, 1241.776 +12000, -900, -935.107 +12000, -855, -891.210 +12000, -810, -846.786 +12000, -765, -801.836 +12000, -720, -756.359 +12000, -675, -710.355 +12000, -630, -663.825 +12000, -585, -616.769 +12000, -540, -569.185 +12000, -495, -521.076 +12000, -450, -472.439 +12000, -405, -423.276 +12000, -360, -373.587 +12000, -315, -323.371 +12000, -270, -272.628 +12000, -225, -221.359 +12000, -180, -169.563 +12000, -135, -117.240 +12000, -90, -64.391 +12000, -45, -11.016 +12000, -9, 0.000 +12000, 9, 58.354 +12000, 45, 105.857 +12000, 90, 165.750 +12000, 135, 226.215 +12000, 180, 287.252 +12000, 225, 348.859 +12000, 270, 411.038 +12000, 315, 473.788 +12000, 360, 537.110 +12000, 405, 601.003 +12000, 450, 665.468 +12000, 495, 730.504 +12000, 540, 796.111 +12000, 585, 862.290 +12000, 630, 929.040 +12000, 675, 996.361 +12000, 720, 1064.254 +12000, 765, 1132.718 +12000, 810, 1201.753 +12000, 855, 1271.360 +12000, 900, 1341.539 +12800, -900, -986.207 +12800, -855, -940.011 +12800, -810, -893.220 +12800, -765, -845.835 +12800, -720, -797.856 +12800, -675, -749.282 +12800, -630, -700.114 +12800, -585, -650.352 +12800, -540, -599.996 +12800, -495, -549.045 +12800, -450, -497.500 +12800, -405, -445.361 +12800, -360, -392.628 +12800, -315, -339.300 +12800, -270, -285.378 +12800, -225, -230.862 +12800, -180, -175.751 +12800, -135, -120.047 +12800, -90, -63.748 +12800, -45, -6.855 +12800, -9, 0.000 +12800, 9, 67.546 +12800, 45, 118.226 +12800, 90, 182.157 +12800, 135, 246.732 +12800, 180, 311.952 +12800, 225, 377.817 +12800, 270, 444.327 +12800, 315, 511.482 +12800, 360, 579.281 +12800, 405, 647.726 +12800, 450, 716.815 +12800, 495, 786.549 +12800, 540, 856.928 +12800, 585, 927.951 +12800, 630, 999.619 +12800, 675, 1071.933 +12800, 720, 1144.891 +12800, 765, 1218.493 +12800, 810, 1292.741 +12800, 855, 1367.633 +12800, 900, 1443.171 +13600, -900, -1035.533 +13600, -855, -987.122 +13600, -810, -938.044 +13600, -765, -888.300 +13600, -720, -837.890 +13600, -675, -786.814 +13600, -630, -735.071 +13600, -585, -682.662 +13600, -540, -629.587 +13600, -495, -575.845 +13600, -450, -521.438 +13600, -405, -466.364 +13600, -360, -410.623 +13600, -315, -354.217 +13600, -270, -297.144 +13600, -225, -239.405 +13600, -180, -180.999 +13600, -135, -121.927 +13600, -90, -62.189 +13600, -45, -1.785 +13600, -9, 0.000 +13600, 9, 77.721 +13600, 45, 131.581 +13600, 90, 199.556 +13600, 135, 268.253 +13600, 180, 337.674 +13600, 225, 407.818 +13600, 270, 478.684 +13600, 315, 550.274 +13600, 360, 622.587 +13600, 405, 695.622 +13600, 450, 769.381 +13600, 495, 843.862 +13600, 540, 919.067 +13600, 585, 994.994 +13600, 630, 1071.644 +13600, 675, 1149.018 +13600, 720, 1227.114 +13600, 765, 1305.933 +13600, 810, 1385.475 +13600, 855, 1465.740 +13600, 900, 1546.729 +14400, -900, -1083.032 +14400, -855, -1032.490 +14400, -810, -981.206 +14400, -765, -929.180 +14400, -720, -876.411 +14400, -675, -822.899 +14400, -630, -768.644 +14400, -585, -713.647 +14400, -540, -657.907 +14400, -495, -601.425 +14400, -450, -544.200 +14400, -405, -486.232 +14400, -360, -427.522 +14400, -315, -368.069 +14400, -270, -307.873 +14400, -225, -246.935 +14400, -180, -185.254 +14400, -135, -122.830 +14400, -90, -59.664 +14400, -45, 0.000 +14400, -9, 0.000 +14400, 9, 88.937 +14400, 45, 145.978 +14400, 90, 218.004 +14400, 135, 290.836 +14400, 180, 364.473 +14400, 225, 438.917 +14400, 270, 514.166 +14400, 315, 590.222 +14400, 360, 667.083 +14400, 405, 744.749 +14400, 450, 823.222 +14400, 495, 902.501 +14400, 540, 982.585 +14400, 585, 1063.475 +14400, 630, 1145.171 +14400, 675, 1227.673 +14400, 720, 1310.980 +14400, 765, 1395.094 +14400, 810, 1480.013 +14400, 855, 1565.738 +14400, 900, 1652.269 +15200, -900, -1128.651 +15200, -855, -1076.065 +15200, -810, -1022.655 +15200, -765, -968.421 +15200, -720, -913.365 +15200, -675, -857.485 +15200, -630, -800.781 +15200, -585, -743.255 +15200, -540, -684.904 +15200, -495, -625.731 +15200, -450, -565.734 +15200, -405, -504.914 +15200, -360, -443.271 +15200, -315, -380.804 +15200, -270, -317.514 +15200, -225, -253.400 +15200, -180, -188.463 +15200, -135, -122.703 +15200, -90, -56.119 +15200, -45, 0.000 +15200, -9, 0.000 +15200, 9, 101.249 +15200, 45, 161.473 +15200, 90, 237.558 +15200, 135, 314.536 +15200, 180, 392.407 +15200, 225, 471.172 +15200, 270, 550.830 +15200, 315, 631.381 +15200, 360, 712.826 +15200, 405, 795.164 +15200, 450, 878.396 +15200, 495, 962.521 +15200, 540, 1047.539 +15200, 585, 1133.451 +15200, 630, 1220.256 +15200, 675, 1307.954 +15200, 720, 1396.546 +15200, 765, 1486.032 +15200, 810, 1576.410 +15200, 855, 1667.682 +15200, 900, 1759.848 +16000, -900, -1172.340 +16000, -855, -1117.793 +16000, -810, -1062.337 +16000, -765, -1005.973 +16000, -720, -948.700 +16000, -675, -890.519 +16000, -630, -831.430 +16000, -585, -771.432 +16000, -540, -710.526 +16000, -495, -648.712 +16000, -450, -585.989 +16000, -405, -522.358 +16000, -360, -457.818 +16000, -315, -392.370 +16000, -270, -326.013 +16000, -225, -258.749 +16000, -180, -190.575 +16000, -135, -121.494 +16000, -90, -51.504 +16000, -45, 0.000 +16000, -9, 0.000 +16000, 9, 114.714 +16000, 45, 178.124 +16000, 90, 258.274 +16000, 135, 339.410 +16000, 180, 421.531 +16000, 225, 504.638 +16000, 270, 588.731 +16000, 315, 673.809 +16000, 360, 759.873 +16000, 405, 846.922 +16000, 450, 934.958 +16000, 495, 1023.979 +16000, 540, 1113.985 +16000, 585, 1204.977 +16000, 630, 1296.955 +16000, 675, 1389.919 +16000, 720, 1483.868 +16000, 765, 1578.803 +16000, 810, 1674.724 +16000, 855, 1771.630 +16000, 900, 1869.523 diff --git a/VectoCore/VectoCoreTest/Utils/MockVehicleContainer.cs b/VectoCore/VectoCoreTest/Utils/MockVehicleContainer.cs index f9a5e6fb20186c2096ada2751fd24fdfafbdfccb..e0a140d76476dd2915b747008636da2ffd07ff46 100644 --- a/VectoCore/VectoCoreTest/Utils/MockVehicleContainer.cs +++ b/VectoCore/VectoCoreTest/Utils/MockVehicleContainer.cs @@ -330,6 +330,7 @@ namespace TUGraz.VectoCore.Tests.Utils public bool HasElectricMotor { get; set; } public PowertrainPosition[] ElectricMotorPositions { get; set; } + public VectoSimulationJobType VehicleArchitecutre { get; } #endregion } diff --git a/VectoCore/VectoCoreTest/VectoCoreTest.csproj b/VectoCore/VectoCoreTest/VectoCoreTest.csproj index 0d6a30ca91032ac382c94b56a1bf8662afe33629..cb1aca2f62b8e1a5e52ed4f3d1c3c143ecc15a32 100644 --- a/VectoCore/VectoCoreTest/VectoCoreTest.csproj +++ b/VectoCore/VectoCoreTest/VectoCoreTest.csproj @@ -121,6 +121,7 @@ <Compile Include="Integration\Declaration\VocationalVehicleTest.cs" /> <Compile Include="Integration\Declaration\TestMaxMassInMUCycle.cs" /> <Compile Include="Integration\DualFuel\DualFuelTests.cs" /> + <Compile Include="Integration\Hybrid\SerialHybridTest.cs" /> <Compile Include="Integration\RoadSweepers\RoadSweeperTests.cs" /> <Compile Include="Integration\Hybrid\ParallelHybridTest.cs" /> <Compile Include="Integration\Multistage\MultistageVehicleTest.cs" /> @@ -664,6 +665,9 @@ <None Include="TestData\Hybrids\ElectricMotor\GenericDrag.vemd"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </None> + <None Include="TestData\Hybrids\ElectricMotor\GenericDragGenerator.vemd"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> <None Include="TestData\Hybrids\ElectricMotor\GenericDragHV.vemd"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </None> @@ -688,6 +692,12 @@ <None Include="TestData\Hybrids\ElectricMotor\GenericEMotorV3.vem"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </None> + <None Include="TestData\Hybrids\ElectricMotor\GenericGenerator.vem"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Hybrids\ElectricMotor\GenericGenerator.vemp"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> <None Include="TestData\Hybrids\ElectricMotor\GenericMap.vemo"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </None> @@ -751,6 +761,9 @@ <None Include="TestData\Hybrids\BusAuxEngineeringMode\MT_6_Bus.vgbx"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </None> + <None Include="TestData\Hybrids\ElectricMotor\GenericMapGenerator.vemo"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> <None Include="TestData\Hybrids\ElectricMotor\GenericMapHV.vemo"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </None>