diff --git a/VectoCore/VectoCore/OutputData/IModalDataContainer.cs b/VectoCore/VectoCore/OutputData/IModalDataContainer.cs index 78de9f4350c6d6124971679b730f8b90ff04bb44..9d00666743739c9211c79c58479a7f17975a2ca0 100644 --- a/VectoCore/VectoCore/OutputData/IModalDataContainer.cs +++ b/VectoCore/VectoCore/OutputData/IModalDataContainer.cs @@ -139,7 +139,7 @@ namespace TUGraz.VectoCore.OutputData WattSecond ElectricMotorMotLosses(PowertrainPosition emPos); WattSecond ElectricMotorTransmissionLosses(PowertrainPosition emPos); - double BatteryStartSoC(); + double REESSStartSoC(); double REESSEndSoC(); WattSecond REESSLoss(); @@ -182,12 +182,15 @@ namespace TUGraz.VectoCore.OutputData KilogramPerSecond FC_WHR_CORR_H { get; } KilogramPerSecond FC_AUXHTR_H { get; } KilogramPerSecond FC_AUXHTR_H_CORR { get; } + KilogramPerSecond FC_REESS_SOC_H { get; } KilogramPerSecond FC_FINAL_H { get; } KilogramPerMeter FC_WHR_CORR_KM { get; } KilogramPerMeter FC_BusAux_PS_CORR_KM { get; } KilogramPerMeter FC_BusAux_ES_CORR_KM { get; } KilogramPerMeter FC_AUXHTR_KM { get; } KilogramPerMeter FC_AUXHTR_KM_CORR { get; } + KilogramPerMeter FC_REESS_SOC_KM { get; } + KilogramPerMeter FC_ESS_CORR_KM { get; } KilogramPerMeter FC_FINAL_KM { get; } VolumePerMeter FuelVolumePerMeter { get; } diff --git a/VectoCore/VectoCore/OutputData/ModalDataContainer.cs b/VectoCore/VectoCore/OutputData/ModalDataContainer.cs index 0f491ee2dcef27afc38dc4a34a097323cb599542..8ef4143f24f0e66e7050bf53fb0e73aadfb93a8d 100644 --- a/VectoCore/VectoCore/OutputData/ModalDataContainer.cs +++ b/VectoCore/VectoCore/OutputData/ModalDataContainer.cs @@ -466,14 +466,14 @@ namespace TUGraz.VectoCore.OutputData return (integral / Duration.Value()).SI<PerSecond>(); } - public double BatteryStartSoC() + public double REESSStartSoC() { - return Data.AsEnumerable().Cast<DataRow>().First().Field<SI>(ModalResultField.REESSStateOfCharge.GetName()).Value() * 100; + return (Data.AsEnumerable().Cast<DataRow>().First().Field<SI>(ModalResultField.REESSStateOfCharge.GetName())?.Value() ?? 0) * 100; } public double REESSEndSoC() { - return Data.AsEnumerable().Cast<DataRow>().Last().Field<SI>(ModalResultField.REESSStateOfCharge.GetName()).Value() * 100; + return (Data.AsEnumerable().Cast<DataRow>().Last().Field<SI>(ModalResultField.REESSStateOfCharge.GetName())?.Value() ?? 0) * 100; } public WattSecond REESSLoss() diff --git a/VectoCore/VectoCore/OutputData/ModalDataPostprocessingCorrection.cs b/VectoCore/VectoCore/OutputData/ModalDataPostprocessingCorrection.cs index 6fd5dea247d2c457d561acb2533c549e13051b8d..72a6b7ecf845b7c59390b64b4d71ef81eb6b4bd1 100644 --- a/VectoCore/VectoCore/OutputData/ModalDataPostprocessingCorrection.cs +++ b/VectoCore/VectoCore/OutputData/ModalDataPostprocessingCorrection.cs @@ -49,6 +49,8 @@ namespace TUGraz.VectoCore.OutputData SetAuxHeaterDemand(modData, r, duration); + SetReesCorrectionDemand(modData, runData, r); + var kilogramCO2PerMeter = 0.SI<KilogramPerMeter>(); var firstFuel = true; @@ -71,6 +73,33 @@ namespace TUGraz.VectoCore.OutputData return r; } + private void SetReesCorrectionDemand(IModalDataContainer modData, VectoRunData runData, + CorrectedModalData r) + { + var em = runData.ElectricMachinesData?.FirstOrDefault(); + + if (em != null) { + var deltaEReess = modData.TimeIntegral<WattSecond>(ModalResultField.P_reess_int.GetName()); + var startSoc = modData.REESSStartSoC(); + var endSoc = modData.REESSEndSoC(); + var emEff = 0.0; + if (endSoc < startSoc) { + var etaEmChg = modData.ElectricMotorEfficiencyGenerate(em.Item1); + var etaReessChg = (modData.WorkREESSChargeInternal() / modData.WorkREESSChargeTerminal()).Value(); + emEff = 1.0 / (etaEmChg * etaReessChg); + } + if (endSoc > startSoc) { + var etaEmDischg = modData.ElectricMotorEfficiencyDrive(em.Item1); + var etaReessDischg = modData.WorkREESSDischargeTerminal() / modData.WorkREESSDischargeInternal(); + emEff = etaEmDischg * etaReessDischg; + } + + r.DeltaEReessMech = -deltaEReess * emEff; + } else { + r.DeltaEReessMech = 0.SI<WattSecond>(); + } + } + private static FuelConsumptionCorrection SetFuelConsumptionCorrection(IModalDataContainer modData, VectoRunData runData, CorrectedModalData r, IFuelProperties fuel) { @@ -89,6 +118,9 @@ namespace TUGraz.VectoCore.OutputData var comp = runData.BusAuxiliaries?.PneumaticUserInputsConfig.CompressorMap .Interpolate(runData.EngineData.IdleSpeed); + + + var f = new FuelConsumptionCorrection { Fuel = fuel, Distance = distance != null && distance.IsGreater(0) ? distance : null, @@ -117,7 +149,7 @@ namespace TUGraz.VectoCore.OutputData FcBusAuxPSDragICEOffDriving = comp == null ? 0.SI<Kilogram>() : comp.PowerOff * r.ICEOffTimeDriving * engLine * (1 - essParams.UtilityFactorDriving), - + FcREESSSoc = r.DeltaEReessMech * engLine, FcBusAuxEs = engLine * r.WorkBusAuxESMech, FcWHR = engLine * r.WorkWHR, FcAuxHtr = 0.SI<Kilogram>() @@ -320,6 +352,7 @@ namespace TUGraz.VectoCore.OutputData public WattSecond EnergyDCDCMissing { get; set; } public NormLiter CorrectedAirDemand { get; set; } public NormLiter DeltaAir { get; set; } + public WattSecond DeltaEReessMech { get; set; } #endregion } @@ -355,6 +388,8 @@ namespace TUGraz.VectoCore.OutputData } public Kilogram FcBusAuxEs { get; set; } public Kilogram FcWHR { get; set; } + public Kilogram FcREESSSoc { get; set; } + public Kilogram FcAuxHtr { get; set; } @@ -362,7 +397,9 @@ namespace TUGraz.VectoCore.OutputData public Kilogram FcBusAuxPsCorr => FcEssCorr + FcBusAuxPs; public Kilogram FcBusAuxEsCorr => FcBusAuxPsCorr + FcBusAuxEs; public Kilogram FcWHRCorr => FcBusAuxEsCorr + FcWHR; - public Kilogram FcAuxHtrCorr => FcWHRCorr + FcAuxHtr; + public Kilogram FcREESSSoCCorr => FcWHRCorr + FcREESSSoc; + + public Kilogram FcAuxHtrCorr => FcREESSSoCCorr + FcAuxHtr; public Kilogram FcFinal => FcAuxHtrCorr; @@ -376,8 +413,10 @@ namespace TUGraz.VectoCore.OutputData public KilogramPerSecond FC_WHR_CORR_H => Duration != null ? (FcWHRCorr / Duration) : null; public KilogramPerSecond FC_AUXHTR_H => Duration != null ? (FcAuxHtr / Duration) : null; public KilogramPerSecond FC_AUXHTR_H_CORR => Duration != null ? (FcAuxHtrCorr / Duration) : null; + public KilogramPerSecond FC_REESS_SOC_H => Duration != null ? (FcREESSSoCCorr / Duration) : null; public KilogramPerSecond FC_FINAL_H => Duration != null ? FcFinal / Duration : null; + public KilogramPerMeter FC_REESS_SOC_KM => Distance != null ? (FcREESSSoCCorr / Distance) : null; public KilogramPerMeter FC_ESS_CORR_KM => Distance != null ? (FcEssCorr / Distance) : null; public KilogramPerMeter FC_WHR_CORR_KM => Distance != null ? (FcWHRCorr / Distance) : null; public KilogramPerMeter FC_BusAux_PS_CORR_KM => Distance != null ? (FcBusAuxPsCorr / Distance) : null; diff --git a/VectoCore/VectoCoreTest/Reports/ModDataPostprocessingTest.cs b/VectoCore/VectoCoreTest/Reports/ModDataPostprocessingTest.cs index 348323577e6277cf48d3faad4a86112386c3b6e5..ecf3fab04ffc80426fd8861429bc9c5855cbc359 100644 --- a/VectoCore/VectoCoreTest/Reports/ModDataPostprocessingTest.cs +++ b/VectoCore/VectoCoreTest/Reports/ModDataPostprocessingTest.cs @@ -18,6 +18,7 @@ using TUGraz.VectoCore.Models.Declaration; using TUGraz.VectoCore.Models.Simulation.Data; using TUGraz.VectoCore.Models.Simulation.Impl; using TUGraz.VectoCore.Models.SimulationComponent.Data; +using TUGraz.VectoCore.Models.SimulationComponent.Data.Battery; using TUGraz.VectoCore.Models.SimulationComponent.Data.Engine; using TUGraz.VectoCore.OutputData; using TUGraz.VectoCore.OutputData.FileIO; @@ -30,10 +31,12 @@ namespace TUGraz.VectoCore.Tests.Reports public class ModDataPostprocessingTest { private double busAuxAlternatorEff = 0.753; + private AmpereSecond BatCapacity = 10000.SI<AmpereSecond>(); const double dcdc_efficiency = 0.926; const double UF_ESS_Driving = 0.821; const double UF_ESS_Standstill = 0.753; const double emEff = 0.95; + const double batEff = 0.982; private const PowertrainPosition emPos = PowertrainPosition.HybridP2; @@ -2438,6 +2441,174 @@ namespace TUGraz.VectoCore.Tests.Reports } + [TestCase(10), + TestCase(-10)] + public void TestREESSoC_ModDataCorrection(double batPowerDemand) + { + var runData = GetRunData(true, alternatorType: AlternatorType.Smart); + runData.JobName = new StackTrace().GetFrame(0).GetMethod().Name; + var writer = new FileOutputWriter("."); + var modData = new ModalDataContainer(runData, writer, null) { + WriteModalResults = true + }; + + modData.AddElectricMotor(emPos); + + var fuel = runData.EngineData.Fuels[0]; + + var absTime = 0.SI<Second>(); + var rnd = new Random(210629); + var dt = 0.SI<Second>(); + + var i = 0; + // constant driving + var n_ice = 800.RPMtoRad(); + var t_ice = 400.SI<NewtonMeter>(); + + var batConditioning = (Math.Sign(batPowerDemand) * -1e3).SI<Watt>(); + var P_bat = batConditioning; + var T1 = 0.SI<Second>(); // 50.135121407888441 ["s"] + var T2 = 0.SI<Second>(); // 101.36683581153247 ["s"] + var soc = 0.5; + + for (; i < 100; i++) { + dt = (rnd.NextDouble() * 0.2 + 0.4).SI<Second>(); + T1 += dt; + soc += (P_bat / 600.SI<Volt>() * dt) / BatCapacity; + + modData[ModalResultField.time] = absTime + dt / 2; + modData[ModalResultField.simulationInterval] = dt; + + modData[ModalResultField.v_act] = 50.KMPHtoMeterPerSecond(); + modData[ModalResultField.ICEOn] = true; + + modData[ModalResultField.n_ice_avg] = n_ice; + modData[ModalResultField.P_ice_fcmap] = n_ice * t_ice; + var fc = fuel.ConsumptionMap.GetFuelConsumption(t_ice, n_ice).Value * + fuel.FuelConsumptionCorrectionFactor; + modData[ModalResultField.FCWHTCc] = fc; + modData[ModalResultField.FCFinal] = fc; + + modData[ModalResultField.P_aux_ESS_mech_ice_off] = 0.SI<Watt>(); + modData[ModalResultField.P_aux_ESS_mech_ice_on] = 0.SI<Watt>(); + + modData[ModalResultField.P_DCDC_missing] = 0.SI<Watt>(); + modData[ModalResultField.Nl_busAux_PS_generated] = 0.SI<NormLiter>(); + modData[ModalResultField.Nl_busAux_PS_consumer] = 0.SI<NormLiter>(); + modData[ModalResultField.Nl_busAux_PS_generated_alwaysOn] = 0.SI<NormLiter>(); + modData[ModalResultField.P_busAux_PS_generated_dragOnly] = 0.SI<Watt>(); + modData[ModalResultField.P_busAux_PS_generated_alwaysOn] = 0.SI<Watt>(); + + modData[ModalResultField.P_EM_electricMotor_el_, emPos] = 120.SI<Watt>() * emEff; + modData[ModalResultField.P_EM_mech_, emPos] = 120.SI<Watt>(); + + modData[ModalResultField.P_reess_int] = P_bat; + modData[ModalResultField.P_reess_terminal] = P_bat * (P_bat < 0 ? batEff : 1/batEff); + modData[ModalResultField.REESSStateOfCharge] = soc.SI(); + + + // WHR + modData[ModalResultField.P_WHR_el_corr] = 0.SI<Watt>(); + modData[ModalResultField.P_WHR_mech_corr] = 0.SI<Watt>(); + + modData.CommitSimulationStep(); + absTime += dt; + } + + P_bat = (batPowerDemand * 1e3).SI<Watt>(); + + // constant driving different speed + modData[ModalResultField.P_ice_start] = 0000.SI<Watt>(); + n_ice = 1200.RPMtoRad(); + for (; i < 300; i++) { + dt = (rnd.NextDouble() * 0.2 + 0.4).SI<Second>(); + T2 += dt; + soc += (P_bat / 600.SI<Volt>() * dt) / BatCapacity; + + modData[ModalResultField.time] = absTime + dt / 2; + modData[ModalResultField.simulationInterval] = dt; + + modData[ModalResultField.v_act] = 50.KMPHtoMeterPerSecond(); + modData[ModalResultField.ICEOn] = true; + + modData[ModalResultField.n_ice_avg] = n_ice; + modData[ModalResultField.P_ice_fcmap] = n_ice * t_ice; + var fc = fuel.ConsumptionMap.GetFuelConsumption(400.SI<NewtonMeter>(), n_ice).Value * + fuel.FuelConsumptionCorrectionFactor; + modData[ModalResultField.FCWHTCc] = fc; + modData[ModalResultField.FCFinal] = fc; + + + modData[ModalResultField.P_aux_ESS_mech_ice_off] = 0.SI<Watt>(); + modData[ModalResultField.P_aux_ESS_mech_ice_on] = 0.SI<Watt>(); + + modData[ModalResultField.P_DCDC_missing] = 0.SI<Watt>(); + modData[ModalResultField.Nl_busAux_PS_generated] = 0.SI<NormLiter>(); + modData[ModalResultField.Nl_busAux_PS_consumer] = 0.SI<NormLiter>(); + modData[ModalResultField.Nl_busAux_PS_generated_alwaysOn] = 0.SI<NormLiter>(); + modData[ModalResultField.P_busAux_PS_generated_dragOnly] = 0.SI<Watt>(); + modData[ModalResultField.P_busAux_PS_generated_alwaysOn] = 0.SI<Watt>(); + + modData[ModalResultField.P_EM_electricMotor_el_, emPos] = -120.SI<Watt>() / emEff; + modData[ModalResultField.P_EM_mech_, emPos] = -120.SI<Watt>(); + + modData[ModalResultField.P_reess_int] = P_bat; + modData[ModalResultField.P_reess_terminal] = P_bat * (P_bat < 0 ? batEff : 1 / batEff); + modData[ModalResultField.REESSStateOfCharge] = soc.SI(); + + // WHR + modData[ModalResultField.P_WHR_el_corr] = 0.SI<Watt>(); + modData[ModalResultField.P_WHR_mech_corr] = 0.SI<Watt>(); + + modData.CommitSimulationStep(); + absTime += dt; + } + + modData.Finish(VectoRun.Status.Success); + var corr = modData.CorrectedModalData as CorrectedModalData; + + var k_engline = 2.6254521511724e-8; + var E_REESS = (T2 * P_bat + batConditioning * T1).Value(); // 963533.23670743615 + var E_REESS_mech = -E_REESS * (P_bat > 0 ? emEff * batEff : 1 / (emEff * batEff)); // -898880.15652436716 + + var fcModSum = 0.306799952; + var fcReessSoc = E_REESS_mech * k_engline; // -0.023599668405930831 + + Assert.AreEqual(k_engline, modData.EngineLineCorrectionFactor(fuel.FuelData).Value(), 1e-15); + Assert.AreEqual(0, corr.WorkWHREl.Value(), 1e-3); + Assert.AreEqual(0, corr.WorkWHRElMech.Value(), 1e-3); + Assert.AreEqual(0, corr.WorkWHRMech.Value()); + + Assert.AreEqual(0, corr.EnergyAuxICEOnStandstill.Value(), 1e-3); + Assert.AreEqual(0, corr.EnergyAuxICEOffStandstill.Value(), 1e-3); + + Assert.AreEqual(0, corr.EnergyAuxICEOnDriving.Value(), 1e-3); + Assert.AreEqual(0, corr.EnergyAuxICEOffDriving.Value(), 1e-3); + + Assert.AreEqual(0, corr.EnergyDCDCMissing.Value(), 1e-3); + + Assert.AreEqual(E_REESS, modData.TimeIntegral<WattSecond>(ModalResultField.P_reess_int.GetName()).Value(), 1e-6); + Assert.AreEqual(E_REESS_mech, corr.DeltaEReessMech.Value(), 1e-6); + + var f = corr.FuelCorrection[fuel.FuelData.FuelType] as FuelConsumptionCorrection; + + Assert.AreEqual(0, f.FcESS_AuxStandstill_ICEOff.Value(), 1e-12); + Assert.AreEqual(0, f.FcESS_AuxStandstill_ICEOn.Value(), 1e-12); + Assert.AreEqual(0, f.FcESS_AuxDriving_ICEOff.Value(), 1e-12); + Assert.AreEqual(0, f.FcESS_AuxDriving_ICEOn.Value(), 1e-12); + + Assert.AreEqual(0, f.FcWHR.Value(), 1e-12); + + Assert.AreEqual(fcReessSoc, f.FcREESSSoc.Value(), 1e-12); + + Assert.AreEqual(fcModSum, modData.TotalFuelConsumption(ModalResultField.FCWHTCc, fuel.FuelData).Value(), 1e-6); + Assert.AreEqual(fcModSum + fcReessSoc, f.FcREESSSoCCorr.Value(), 1e-6); + + Assert.AreEqual(fcModSum + fcReessSoc, f.FcFinal.Value(), 1e-6); + + } + + private VectoRunData GetRunData(bool withBusAux = false, bool smartCompressor = false, AlternatorType alternatorType = AlternatorType.Conventional) { var fcMapHeader = "engine speed [rpm],torque [Nm],fuel consumption [g/h]"; @@ -2466,7 +2637,7 @@ namespace TUGraz.VectoCore.Tests.Reports ConsumptionMap = FuelConsumptionMapReader.ReadFromStream(InputDataHelper.InputDataAsStream(fcMapHeader, fcMapEntries)) } } - } + }, }; if (withBusAux) { diff --git a/VectoCore/VectoCoreTest/Utils/MockModalDataContainer.cs b/VectoCore/VectoCoreTest/Utils/MockModalDataContainer.cs index e6fd434156e2c762d11f7b4d1a3020670e9bad7e..f9f0e82ea6ec14a975bcb26a7327de9af3e52863 100644 --- a/VectoCore/VectoCoreTest/Utils/MockModalDataContainer.cs +++ b/VectoCore/VectoCoreTest/Utils/MockModalDataContainer.cs @@ -316,7 +316,7 @@ namespace TUGraz.VectoCore.Tests.Utils throw new NotImplementedException(); } - public double REESS_StartSoC() + public double REESSStartSoC() { throw new NotImplementedException(); }