From 5945d78ba5f7283bed7ef6fea7c3f9606e3e119f Mon Sep 17 00:00:00 2001 From: Markus Quaritsch <markus.quaritsch@tugraz.at> Date: Tue, 31 May 2022 17:11:51 +0200 Subject: [PATCH] adding pto component for E2 vehicles: powertrain builder, data adapter, new component --- VECTO/GUI/VehicleForm.vb | 5 + VECTO/GUI/XMLImportJobDialog.vb | 42 +++---- .../EngineeringDataAdapter.cs | 14 +++ .../EngineeringModeVectoRunDataFactory.cs | 8 +- .../Models/Declaration/AuxDemandEntry.cs | 2 + .../Models/Declaration/PTOTransmission.cs | 5 +- .../Simulation/Impl/PowertrainBuilder.cs | 48 +++++++- .../Models/SimulationComponent/Impl/PEVPTO.cs | 116 ++++++++++++++++++ 8 files changed, 212 insertions(+), 28 deletions(-) create mode 100644 VectoCore/VectoCore/Models/SimulationComponent/Impl/PEVPTO.cs diff --git a/VECTO/GUI/VehicleForm.vb b/VECTO/GUI/VehicleForm.vb index 0874ea8567..e22fc89127 100644 --- a/VECTO/GUI/VehicleForm.vb +++ b/VECTO/GUI/VehicleForm.vb @@ -738,6 +738,11 @@ Public Class VehicleForm veh.VehicleTankSystem = CType(If(cbTankSystem.SelectedIndex > 0, cbTankSystem.SelectedValue, Nothing), TankSystem?) End If + if (VehicleType = VectoSimulationJobType.BatteryElectricVehicle) Then + veh.PtoType = CType(cbPTOType.SelectedValue, String) + veh.PtoLossMap.Init(GetPath(file), tbPTOLossMap.Text) + End If + If (VehicleType = VectoSimulationJobType.ParallelHybridVehicle OrElse VehicleType = VectoSimulationJobType.BatteryElectricVehicle OrElse VehicleType = VectoSimulationJobType.SerialHybridVehicle) Then For Each reess As ListViewItem In lvREESSPacks.Items veh.ReessPacks.Add(Tuple.Create(reess.SubItems(REESPackTbl.ReessFile).Text, reess.SubItems(REESPackTbl.Count).Text.ToInt(), reess.SubItems(REESPackTbl.StringId).Text.ToInt())) diff --git a/VECTO/GUI/XMLImportJobDialog.vb b/VECTO/GUI/XMLImportJobDialog.vb index d462a579bd..9afc8e727a 100644 --- a/VECTO/GUI/XMLImportJobDialog.vb +++ b/VECTO/GUI/XMLImportJobDialog.vb @@ -1,27 +1,27 @@ -Imports System.IO - -Public Class XMLImportJobDialog - Private Sub btnBrowseJob_Click(sender As Object, e As EventArgs) Handles btnBrowseJob.Click - Dim dialog As OpenFileDialog = New OpenFileDialog() - If (dialog.ShowDialog() = DialogResult.OK) Then - tbJobFile.Text = Path.GetFullPath(dialog.FileName) - End If - End Sub - - Private Sub btnBrowseOutput_Click(sender As Object, e As EventArgs) Handles btnBrowseOutput.Click +Imports System.IO + +Public Class XMLImportJobDialog + Private Sub btnBrowseJob_Click(sender As Object, e As EventArgs) Handles btnBrowseJob.Click + Dim dialog As OpenFileDialog = New OpenFileDialog() + If (dialog.ShowDialog() = DialogResult.OK) Then + tbJobFile.Text = Path.GetFullPath(dialog.FileName) + End If + End Sub + + Private Sub btnBrowseOutput_Click(sender As Object, e As EventArgs) Handles btnBrowseOutput.Click If Not FolderFileBrowser.OpenDialog("") Then Exit Sub - End If + End If Dim filePath As String = FolderFileBrowser.Files(0) tbDestination.Text = Path.GetFullPath(filePath) - End Sub - - Private Sub btnClose_Click(sender As Object, e As EventArgs) Handles btnClose.Click - Close() - End Sub - - Private Sub btnImport_Click(sender As Object, e As EventArgs) Handles btnImport.Click - ' TODO! - End Sub + End Sub + + Private Sub btnClose_Click(sender As Object, e As EventArgs) Handles btnClose.Click + Close() + End Sub + + Private Sub btnImport_Click(sender As Object, e As EventArgs) Handles btnImport.Click + ' TODO! + End Sub End Class \ No newline at end of file diff --git a/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/EngineeringDataAdapter.cs b/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/EngineeringDataAdapter.cs index 5da50a0bf3..344bbdeb65 100644 --- a/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/EngineeringDataAdapter.cs +++ b/VectoCore/VectoCore/InputData/Reader/DataObjectAdapter/EngineeringDataAdapter.cs @@ -1280,6 +1280,20 @@ namespace TUGraz.VectoCore.InputData.Reader.DataObjectAdapter return retVal; } + public PTOData CreateBatteryElectricPTOTransmissionData(IPTOTransmissionInputData pto) + { + if (pto.PTOTransmissionType != "None") { + var ptoData = new PTOData() { + TransmissionType = pto.PTOTransmissionType, + LossMap = pto.PTOLossMap == null + ? PTOIdleLossMapReader.GetZeroLossMap() + : PTOIdleLossMapReader.Create(pto.PTOLossMap) + }; + return ptoData; + } + + return null; + } } public class IEPCGearboxInputData : IGearboxDeclarationInputData diff --git a/VectoCore/VectoCore/InputData/Reader/Impl/EngineeringModeVectoRunDataFactory.cs b/VectoCore/VectoCore/InputData/Reader/Impl/EngineeringModeVectoRunDataFactory.cs index 572099be39..e3ac366d41 100644 --- a/VectoCore/VectoCore/InputData/Reader/Impl/EngineeringModeVectoRunDataFactory.cs +++ b/VectoCore/VectoCore/InputData/Reader/Impl/EngineeringModeVectoRunDataFactory.cs @@ -311,9 +311,9 @@ namespace TUGraz.VectoCore.InputData.Reader.Impl var crossWindRequired = vehicle.Components.AirdragInputData.CrossWindCorrectionMode == CrossWindCorrectionMode.VAirBetaLookupTable; - //var ptoTransmissionData = dao.CreatePTOTransmissionData(vehicle.Components.PTOTransmissionInputData); + var ptoTransmissionData = dao.CreateBatteryElectricPTOTransmissionData(vehicle.Components.PTOTransmissionInputData); - var drivingCycle = GetDrivingCycle(cycle, crossWindRequired); + var drivingCycle = GetDrivingCycle(cycle, crossWindRequired); var vehicleData = dao.CreateVehicleData(vehicle); yield return new VectoRunData @@ -329,8 +329,8 @@ namespace TUGraz.VectoCore.InputData.Reader.Impl Aux = dao.CreateAuxiliaryData(vehicle.Components.AuxiliaryInputData), BusAuxiliaries = dao.CreateBusAuxiliariesData(vehicle.Components.AuxiliaryInputData, vehicleData, VectoSimulationJobType.BatteryElectricVehicle), Retarder = dao.CreateRetarderData(vehicle.Components.RetarderInputData, powertrainPosition), - //PTO = ptoTransmissionData, - Cycle = new DrivingCycleProxy(drivingCycle, cycle.Name), + PTO = ptoTransmissionData, + Cycle = new DrivingCycleProxy(drivingCycle, cycle.Name), ExecutionMode = ExecutionMode.Engineering, ElectricMachinesData = electricMachinesData, //HybridStrategyParameters = dao.CreateHybridStrategyParameters(InputDataProvider.JobInputData.HybridStrategyParameters), diff --git a/VectoCore/VectoCore/Models/Declaration/AuxDemandEntry.cs b/VectoCore/VectoCore/Models/Declaration/AuxDemandEntry.cs index ea94166fb0..b9561d719e 100644 --- a/VectoCore/VectoCore/Models/Declaration/AuxDemandEntry.cs +++ b/VectoCore/VectoCore/Models/Declaration/AuxDemandEntry.cs @@ -36,5 +36,7 @@ namespace TUGraz.VectoCore.Models.Declaration public struct AuxDemandEntry { public Watt PowerDemand; + + public NewtonMeter TorqueLoss; } } \ No newline at end of file diff --git a/VectoCore/VectoCore/Models/Declaration/PTOTransmission.cs b/VectoCore/VectoCore/Models/Declaration/PTOTransmission.cs index 61cb57c6f3..5d0eadeb40 100644 --- a/VectoCore/VectoCore/Models/Declaration/PTOTransmission.cs +++ b/VectoCore/VectoCore/Models/Declaration/PTOTransmission.cs @@ -48,7 +48,10 @@ namespace TUGraz.VectoCore.Models.Declaration { Data = table.Rows.Cast<DataRow>().ToDictionary( r => r.Field<string>("technology"), - r => new AuxDemandEntry { PowerDemand = r.ParseDouble("powerloss").SI<Watt>() }); + r => new AuxDemandEntry { + PowerDemand = r.ParseDouble("powerloss").SI<Watt>(), + TorqueLoss = r.ParseDouble("torqueloss").SI<NewtonMeter>() + }); } public string[] GetTechnologies() diff --git a/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs b/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs index 8bf4c9418e..81ffafc6af 100644 --- a/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs +++ b/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs @@ -78,7 +78,7 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl case VectoSimulationJobType.ConventionalVehicle: return BuildFullPowertrainConventional(data); case VectoSimulationJobType.ParallelHybridVehicle: return BuildFullPowertrainParallelHybrid(data); case VectoSimulationJobType.SerialHybridVehicle: return BuildFullPowertrainSerialHybrid(data); - case VectoSimulationJobType.BatteryElectricVehicle: return BuildBatteryElectricPowertrain(data); + case VectoSimulationJobType.BatteryElectricVehicle: return BuildFulPowertrainBatteryElectric(data); case VectoSimulationJobType.EngineOnlySimulation: return BuildEngineOnly(data); case VectoSimulationJobType.IEPC_E: return BuildFullPowertrainIEPCE(data); case VectoSimulationJobType.IEPC_S: return BuildFullPowertrainIEPCSerial(data); @@ -662,7 +662,7 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl /// └Engine E2 /// </code> /// </summary> - private IVehicleContainer BuildBatteryElectricPowertrain(VectoRunData data) + private IVehicleContainer BuildFulPowertrainBatteryElectric(VectoRunData data) { if (data.Cycle.CycleType != CycleType.DistanceBased) { throw new VectoException("CycleType must be DistanceBased"); @@ -725,6 +725,7 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl .AddComponent(GetRetarder(RetarderType.TransmissionOutputRetarder, data.Retarder, container)) .AddComponent(gearbox) .AddComponent(GetRetarder(RetarderType.TransmissionInputRetarder, data.Retarder, container)) + .AddComponent(data.PTO != null ? GetPEVPTO(container, data): null) .AddComponent(em); new ATClutchInfo(container); @@ -754,6 +755,49 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl return container; } + private IPowerTrainComponent GetPEVPTO(VehicleContainer container, VectoRunData data) + { + if (data.PTO == null) { + return null; + } + var pto = new PEVPTO(container); + + RoadSweeperAuxiliary rdSwpAux = null; + PTODriveAuxiliary ptoDrive = null; + if (data.ExecutionMode == ExecutionMode.Engineering && data.Cycle.Entries.Any(x => x.PTOActive == PTOActivity.PTOActivityRoadSweeping)) { + if (data.DriverData.PTODriveMinSpeed == null) { + throw new VectoSimulationException("PTO activity 'road sweeping' requested, but no min. engine speed or gear provided"); + } + rdSwpAux = new RoadSweeperAuxiliary(container); + pto.Add(Constants.Auxiliaries.IDs.PTORoadsweeping, (nEng, absTime, dt, dryRun) => rdSwpAux.PowerDemand(nEng, absTime, dt, dryRun) / nEng); + container.ModalData?.AddAuxiliary(Constants.Auxiliaries.IDs.PTORoadsweeping, Constants.Auxiliaries.PowerPrefix + Constants.Auxiliaries.IDs.PTORoadsweeping); + } + + if (data.ExecutionMode == ExecutionMode.Engineering && + data.Cycle.Entries.Any(x => x.PTOActive == PTOActivity.PTOActivityWhileDrive)) { + if (data.PTOCycleWhileDrive == null) { + throw new VectoException("PTO activation while drive requested in cycle but no PTO cycle provided"); + } + + ptoDrive = new PTODriveAuxiliary(container, data.PTOCycleWhileDrive); + pto.Add(Constants.Auxiliaries.IDs.PTODuringDrive, (nEng, absTime, dt, dryRun) => ptoDrive.PowerDemand(nEng, absTime, dt, dryRun) / nEng); + container.ModalData?.AddAuxiliary(Constants.Auxiliaries.IDs.PTODuringDrive, Constants.Auxiliaries.PowerPrefix + Constants.Auxiliaries.IDs.PTODuringDrive); + } + if (data.PTO != null) { + pto.AddConstant(Constants.Auxiliaries.IDs.PTOTransmission, + DeclarationData.PTOTransmission.Lookup(data.PTO.TransmissionType).TorqueLoss); + container.ModalData?.AddAuxiliary(Constants.Auxiliaries.IDs.PTOTransmission, + Constants.Auxiliaries.PowerPrefix + Constants.Auxiliaries.IDs.PTOTransmission); + + pto.Add(Constants.Auxiliaries.IDs.PTOConsumer, + (n, absTime, dt, dryRun) => container.DrivingCycleInfo.PTOActive || (rdSwpAux?.Active(absTime) ?? false) || (ptoDrive?.Active(absTime) ?? false) ? null : data.PTO.LossMap.GetTorqueLoss(n)); + container.ModalData?.AddAuxiliary(Constants.Auxiliaries.IDs.PTOConsumer, + Constants.Auxiliaries.PowerPrefix + Constants.Auxiliaries.IDs.PTOConsumer); + } + + return pto; + } + private static Retarder GetRetarder(RetarderType type, RetarderData data, IVehicleContainer container) => type == data.Type ? new Retarder(container, data.LossMap, data.Ratio) : null; diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/PEVPTO.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/PEVPTO.cs new file mode 100644 index 0000000000..6fcfa4e524 --- /dev/null +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/PEVPTO.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Configuration; +using TUGraz.VectoCore.Models.Connector.Ports; +using TUGraz.VectoCore.Models.Declaration; +using TUGraz.VectoCore.Models.Simulation; +using TUGraz.VectoCore.Models.SimulationComponent.Data; +using TUGraz.VectoCore.OutputData; + +namespace TUGraz.VectoCore.Models.SimulationComponent.Impl +{ + public class PEVPTO : StatefulProviderComponent<PEVPTO.State, ITnOutPort, ITnInPort, ITnOutPort>, + IPowerTrainComponent, ITnInPort, ITnOutPort + { + public class State + { + public Dictionary<string, NewtonMeter> PowerDemands { get; set; } + public PerSecond OutAngularVelocity { get; set; } + } + + protected readonly Dictionary<string, Func<PerSecond, Second, Second, bool, NewtonMeter>> Auxiliaries = + new Dictionary<string, Func<PerSecond, Second, Second, bool, NewtonMeter>>(); + + public PEVPTO(IVehicleContainer container) : base(container) + { + + } + + public void AddConstant(string auxId, NewtonMeter torqueLoss) + { + Add(auxId, (nEng, absTime, dt, dryRun) => torqueLoss); + } + + public void Add(string auxId, Func<PerSecond, Second, Second, bool, NewtonMeter> torqueLossFunction) + { + Auxiliaries[auxId] = torqueLossFunction; + } + + #region Implementation of ITnOutPort + + public IResponse Initialize(NewtonMeter outTorque, PerSecond outAngularVelocity) + { + PreviousState.OutAngularVelocity = outAngularVelocity; + var torqueLoss = outAngularVelocity.IsEqual(0) + ? 0.SI<NewtonMeter>() + : ComputeTorqueLoss(0.SI<Second>(), Constants.SimulationSettings.TargetTimeInterval, outAngularVelocity, + false); + + return NextComponent.Initialize(outTorque + torqueLoss, outAngularVelocity); + } + + public IResponse Request(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, bool dryRun) + { + var avgAngularSpeed = PreviousState.OutAngularVelocity != null + ? (outAngularVelocity + PreviousState.OutAngularVelocity) / 2.0 + : outAngularVelocity; + + var torqueLoss = 0.SI<NewtonMeter>(); + if (!DataBus.GearboxInfo.GearEngaged(absTime)) { + var powerDemands = new Dictionary<string, NewtonMeter>(Auxiliaries.Count); + foreach (var aux in Auxiliaries) { + powerDemands[aux.Key] = 0.SI<NewtonMeter>(); + } + if (!dryRun) { + CurrentState.PowerDemands = powerDemands; + } + } else { + if (outAngularVelocity != null && !avgAngularSpeed.IsEqual(0)) { + torqueLoss = ComputeTorqueLoss(absTime, dt, avgAngularSpeed, dryRun); + } + } + + if (!dryRun) { + CurrentState.OutAngularVelocity = outAngularVelocity; + } + + return NextComponent.Request(absTime, dt, outTorque + torqueLoss, outAngularVelocity, dryRun); + } + + + #endregion + + private NewtonMeter ComputeTorqueLoss(Second absTime, Second dt, PerSecond avgAngularSpeed, bool dryRun) + { + var powerDemands = new Dictionary<string, NewtonMeter>(Auxiliaries.Count); + foreach (var item in Auxiliaries) { + var value = item.Value(avgAngularSpeed, absTime, dt, dryRun); + if (value != null) { + powerDemands[item.Key] = value; + } + } + if (!dryRun) { + CurrentState.PowerDemands = powerDemands; + } + + return powerDemands.Sum(kv => kv.Value) ?? 0.SI<NewtonMeter>(); + } + + + #region Overrides of VectoSimulationComponent + + protected override void DoWriteModalResults(Second time, Second simulationInterval, IModalDataContainer container) + { + var avgAngularSpeed = PreviousState.OutAngularVelocity != null + ? (CurrentState.OutAngularVelocity + PreviousState.OutAngularVelocity) / 2.0 + : CurrentState.OutAngularVelocity; + foreach (var kv in CurrentState.PowerDemands) { + container[kv.Key] = kv.Value * avgAngularSpeed; + } + } + + #endregion + } +} \ No newline at end of file -- GitLab