From 065e2536ec62b8eb63a266610ec5debd9757a8fa Mon Sep 17 00:00:00 2001 From: Markus Quaritsch <markus.quaritsch@tugraz.at> Date: Fri, 4 May 2018 14:12:42 +0200 Subject: [PATCH] adding validation of VTP input data (cycle), adding testcases for VTP cycle validation, refactoring VTP cycle constructor (remove unused parameters), add info to Fan technologies if only electrical --- .../Utils/SIConvertExtensionMethods.cs | 5 + .../Models/Declaration/DeclarationData.cs | 20 + VectoCore/VectoCore/Models/Declaration/Fan.cs | 19 +- .../Simulation/Impl/PowertrainBuilder.cs | 5 +- .../Simulation/Impl/SimulatorFactory.cs | 2 +- .../Simulation/Impl/VehicleContainer.cs | 15 +- .../Data/Gearbox/TransmissionLossMap.cs | 262 ++++----- .../Impl/BusAuxiliariesAdapter.cs | 502 ++++++++--------- .../Impl/CombustionEngine.cs | 2 +- .../SimulationComponent/Impl/VTPCycle.cs | 115 +++- .../Resources/Declaration/VAUX/Fan-Tech.csv | 24 +- .../VTPCycleValidationTest.cs | 515 ++++++++++++++++++ ...or_4x2_vehicle-class-5_Generic vehicle.xml | 16 +- .../VectoCoreTest/Utils/InputDataHelper.cs | 38 +- VectoCore/VectoCoreTest/VectoCoreTest.csproj | 1 + 15 files changed, 1112 insertions(+), 429 deletions(-) create mode 100644 VectoCore/VectoCoreTest/Models/SimulationComponent/VTPCycleValidationTest.cs diff --git a/VectoCommon/VectoCommon/Utils/SIConvertExtensionMethods.cs b/VectoCommon/VectoCommon/Utils/SIConvertExtensionMethods.cs index 575608ab10..29d55faca6 100644 --- a/VectoCommon/VectoCommon/Utils/SIConvertExtensionMethods.cs +++ b/VectoCommon/VectoCommon/Utils/SIConvertExtensionMethods.cs @@ -206,6 +206,11 @@ namespace TUGraz.VectoCommon.Utils { return new ConvertedSI(value.Value() / Kilo / Kilo, "MJ/kg"); } + + public static ConvertedSI ConvertToMinutes(this Second sec) + { + return new ConvertedSI(sec.Value() / 60.0, "min"); + } } } diff --git a/VectoCore/VectoCore/Models/Declaration/DeclarationData.cs b/VectoCore/VectoCore/Models/Declaration/DeclarationData.cs index f8888def8e..44cda17332 100644 --- a/VectoCore/VectoCore/Models/Declaration/DeclarationData.cs +++ b/VectoCore/VectoCore/Models/Declaration/DeclarationData.cs @@ -507,6 +507,26 @@ namespace TUGraz.VectoCore.Models.Declaration public const MissionType SelectedMission = MissionType.LongHaul; public const LoadingType SelectedLoading = LoadingType.ReferenceLoad; + + // verification of input data + + public const double WheelSpeedDifferenceFactor = 1.4; + public const double WheelTorqueDifferenceFactor = 3; + + public static readonly PerSecond WheelSpeedZeroTolerance = 0.1.RPMtoRad(); + public static readonly PerSecond MaxWheelSpeedDifferenceStandstill = 1.RPMtoRad(); + + public static readonly NewtonMeter WheelTorqueZeroTolerance = 10.SI<NewtonMeter>(); + public static readonly NewtonMeter MaxWheelTorqueZeroDifference = 100.SI<NewtonMeter>(); + + public static readonly PerSecond MinFanSpeed = 20.RPMtoRad(); + public static readonly PerSecond MaxFanSpeed = 4000.RPMtoRad(); + + public static readonly Second SamplingInterval = 0.5.SI<Second>(); + + public static readonly KilogramPerSecond LowerFCThreshold = 180.SI(Unit.SI.Gramm.Per.Hour).Cast<KilogramPerSecond>(); + public static readonly KilogramPerSecond UpperFCThreshold = 600.SI(Unit.SI.Gramm.Per.Hour).Cast<KilogramPerSecond>(); + public static readonly Second FCAccumulationWindow = 10.SI(Unit.SI.Minute).Cast<Second>(); } } } \ No newline at end of file diff --git a/VectoCore/VectoCore/Models/Declaration/Fan.cs b/VectoCore/VectoCore/Models/Declaration/Fan.cs index 3a576c5d04..0f161d59cb 100644 --- a/VectoCore/VectoCore/Models/Declaration/Fan.cs +++ b/VectoCore/VectoCore/Models/Declaration/Fan.cs @@ -30,6 +30,7 @@ */ using System; +using System.Collections.Generic; using System.Data; using System.Linq; using TUGraz.VectoCommon.Utils; @@ -39,6 +40,8 @@ namespace TUGraz.VectoCore.Models.Declaration { public sealed class Fan : LookupData<MissionType, string, AuxDemandEntry>, IDeclarationAuxiliaryTable { + private readonly List<string> FullyElectricFanTechnologies = new List<string>(); + protected override string ResourceId { get { return DeclarationData.DeclarationDataResourcePrefix + ".VAUX.Fan-Tech.csv"; } @@ -53,10 +56,15 @@ namespace TUGraz.VectoCore.Models.Declaration { foreach (DataRow row in table.Rows) { var name = row.Field<string>("technology"); - + var electric = row.ParseBoolean("fullyelectric"); + if (electric) { + FullyElectricFanTechnologies.Add(name); + } foreach (DataColumn col in table.Columns) { - if (col.Caption != "technology") { - Data[Tuple.Create(col.Caption.ParseEnum<MissionType>(), name)] = new AuxDemandEntry(){PowerDemand = row.ParseDouble(col).SI<Watt>()}; + if (col.Caption != "technology" && col.Caption != "fullyelectric") { + Data[Tuple.Create(col.Caption.ParseEnum<MissionType>(), name)] = new AuxDemandEntry { + PowerDemand = row.ParseDouble(col).SI<Watt>(), + }; } } } @@ -70,6 +78,11 @@ namespace TUGraz.VectoCore.Models.Declaration return base.Lookup(mission, technology); } + public string[] FullyElectricTechnologies() + { + return FullyElectricFanTechnologies.ToArray(); + } + public string[] GetTechnologies() { return Data.Keys.Select(x => x.Item2).Distinct().ToArray(); diff --git a/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs b/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs index ce9a92b600..9ce663527c 100644 --- a/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs +++ b/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs @@ -133,12 +133,11 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl throw new VectoException("CycleType must be VTP."); } - var container = new VehicleContainer(ExecutionMode.Engineering, _modData, _sumWriter) { RunData = data }; + var container = new VehicleContainer(data.ExecutionMode, _modData, _sumWriter) { RunData = data }; var gearbox = new VTPGearbox(container, data); // VTPCycle --> AxleGear --> Clutch --> Engine <-- Aux - var powertrain = new VTPCycle(container, data.Cycle, data.AxleGearData.AxleGear.Ratio, data.VehicleData, - gearbox.ModelData.Gears.ToDictionary(g => g.Key, g => g.Value.Ratio)) + var powertrain = new VTPCycle(container, data.Cycle) .AddComponent(new AxleGear(container, data.AxleGearData)) .AddComponent(data.AngledriveData != null ? new Angledrive(container, data.AngledriveData) : null) .AddComponent(gearbox, data.Retarder, container) diff --git a/VectoCore/VectoCore/Models/Simulation/Impl/SimulatorFactory.cs b/VectoCore/VectoCore/Models/Simulation/Impl/SimulatorFactory.cs index d799958c7e..2d3520853d 100644 --- a/VectoCore/VectoCore/Models/Simulation/Impl/SimulatorFactory.cs +++ b/VectoCore/VectoCore/Models/Simulation/Impl/SimulatorFactory.cs @@ -124,7 +124,7 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl public bool Validate { get; set; } - public IVectoRunDataFactory DataReader { get; private set; } + protected internal IVectoRunDataFactory DataReader { get; private set; } public SummaryDataContainer SumData { get; set; } diff --git a/VectoCore/VectoCore/Models/Simulation/Impl/VehicleContainer.cs b/VectoCore/VectoCore/Models/Simulation/Impl/VehicleContainer.cs index 57f4a2e5ea..ee2d540538 100644 --- a/VectoCore/VectoCore/Models/Simulation/Impl/VehicleContainer.cs +++ b/VectoCore/VectoCore/Models/Simulation/Impl/VehicleContainer.cs @@ -36,6 +36,7 @@ using System.Linq; using TUGraz.VectoCommon.Exceptions; using TUGraz.VectoCommon.Models; using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.InputData.Reader.Impl; using TUGraz.VectoCore.Models.Connector.Ports; using TUGraz.VectoCore.Models.Simulation.Data; using TUGraz.VectoCore.Models.Simulation.DataBus; @@ -351,11 +352,15 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl public Meter Distance { get { - if (MilageCounter == null) { - Log.Warn("No MileageCounter in VehicleContainer. Distance cannot be measured."); + if (RunData.SimulationType != SimulationType.DistanceCycle) { return 0.SI<Meter>(); } - return MilageCounter.Distance; + if (MilageCounter != null) { + return MilageCounter.Distance; + } + + Log.Warn("No MileageCounter in VehicleContainer. Distance cannot be measured."); + return 0.SI<Meter>(); } } @@ -411,7 +416,9 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl } public VectoRunData RunData { get; set; } - public ExecutionMode ExecutionMode { get; set; } + public ExecutionMode ExecutionMode { get; } + + public CycleData CycleData { diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Data/Gearbox/TransmissionLossMap.cs b/VectoCore/VectoCore/Models/SimulationComponent/Data/Gearbox/TransmissionLossMap.cs index ccc17e5f94..ea99a0124c 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Data/Gearbox/TransmissionLossMap.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Data/Gearbox/TransmissionLossMap.cs @@ -29,135 +29,135 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Diagnostics; -using TUGraz.VectoCommon.Exceptions; -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.Configuration; -using TUGraz.VectoCore.Utils; - -namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox -{ - public sealed class TransmissionLossMap : LoggingObject - { - [ValidateObject] private readonly IReadOnlyList<GearLossMapEntry> _entries; - - private readonly double _ratio; - - /// <summary> - /// The Loss map. [X=Output EngineSpeed, Y=Output Torque] => Z=Torque Loss - /// </summary> - private readonly DelaunayMap _lossMap; - - /// <summary> - /// The inverted loss map for range sanity checks. [X=Input EngineSpeed, Y=Input Torque] => Z=Output Torque - /// </summary> - private readonly DelaunayMap _invertedLossMap; - - public string GearName { get; private set; } - - public TransmissionLossMap(IReadOnlyList<GearLossMapEntry> entries, double gearRatio, string gearName) - { - GearName = gearName; - _ratio = gearRatio; - _entries = entries; - _lossMap = new DelaunayMap("TransmissionLossMap " + GearName); - _invertedLossMap = new DelaunayMap("TransmissionLossMapInv. " + GearName); - foreach (var entry in _entries) { - _lossMap.AddPoint(entry.InputSpeed.Value(), (entry.InputTorque - entry.TorqueLoss).Value(), entry.TorqueLoss.Value()); - _invertedLossMap.AddPoint(entry.InputSpeed.Value(), entry.InputTorque.Value(), entry.TorqueLoss.Value()); - } - - _lossMap.Triangulate(); - _invertedLossMap.Triangulate(); - } - - /// <summary> - /// Computes the torque loss (input side) given by the output gearbox speed and the output-torque. - /// </summary> - /// <param name="outAngularVelocity">Angular speed at output side.</param> - /// <param name="outTorque">Torque at output side (as requested by the previous componend towards the wheels).</param> - /// <returns>Torque loss as seen on input side (towards the engine).</returns> - public LossMapResult GetTorqueLoss(PerSecond outAngularVelocity, NewtonMeter outTorque) - { - var result = new LossMapResult(); - var torqueLoss = _lossMap.Interpolate(outAngularVelocity.Value() * _ratio, outTorque.Value() / _ratio); - - if (!torqueLoss.HasValue) { - torqueLoss = _lossMap.Extrapolate(outAngularVelocity.Value() * _ratio, outTorque.Value() / _ratio); - result.Extrapolated = true; - } - - result.Value = torqueLoss.Value.SI<NewtonMeter>(); - - Log.Debug("GearboxLoss {0}: {1}, outAngularVelocity: {2}, outTorque: {3}", GearName, torqueLoss, - outAngularVelocity, outTorque); - return result; - } - - [DebuggerDisplay("{Value} (extrapolated: {Extrapolated})")] - public class LossMapResult - { - public bool Extrapolated; - public NewtonMeter Value; - } - - /// <summary> - /// Computes the OUTPUT torque given by the input engineSpeed and the input torque. - /// </summary> - /// <param name="inAngularVelocity">Angular speed at input side.</param> - /// <param name="inTorque">Torque at input side.</param> - /// <param name="allowExtrapolation"></param> - /// <returns>Torque needed at output side (towards the wheels).</returns> - public NewtonMeter GetOutTorque(PerSecond inAngularVelocity, NewtonMeter inTorque, bool allowExtrapolation = false) - { - var torqueLoss = _invertedLossMap.Interpolate(inAngularVelocity.Value(), inTorque.Value()); - if (torqueLoss.HasValue) { - return (inTorque - torqueLoss.Value.SI<NewtonMeter>()) / _ratio; - } - - if (allowExtrapolation) { - torqueLoss = _invertedLossMap.Extrapolate(inAngularVelocity.Value(), inTorque.Value()); - return (inTorque - torqueLoss.Value.SI<NewtonMeter>()) / _ratio; - } - - throw new VectoException("TransmissionLossMap {0}: Interpolation failed. inTorque: {1}, inAngularVelocity: {2}", - GearName, inTorque, - inAngularVelocity.AsRPM); - } - - public GearLossMapEntry this[int i] - { - get { return _entries[i]; } - } - -#if DEBUG - public void DrawGraph() - { - _lossMap.DrawGraph(); - } -#endif - - [DebuggerDisplay("GearLossMapEntry({InputSpeed}, {InputTorque}, {TorqueLoss})")] - public class GearLossMapEntry - { - [Required, SIRange(0, 10000 * Constants.RPMToRad)] - public PerSecond InputSpeed { get; private set; } - - [Required, SIRange(-100000, 100000)] - public NewtonMeter InputTorque { get; private set; } - - [Required, SIRange(0, 100000)] - public NewtonMeter TorqueLoss { get; private set; } - - public GearLossMapEntry(PerSecond inputSpeed, NewtonMeter inputTorque, NewtonMeter torqueLoss) - { - InputSpeed = inputSpeed; - InputTorque = inputTorque; - TorqueLoss = torqueLoss; - } - } - } +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Diagnostics; +using TUGraz.VectoCommon.Exceptions; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Configuration; +using TUGraz.VectoCore.Utils; + +namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox +{ + public sealed class TransmissionLossMap : LoggingObject + { + [ValidateObject] private readonly IReadOnlyList<GearLossMapEntry> _entries; + + private readonly double _ratio; + + /// <summary> + /// The Loss map. [X=Output EngineSpeed, Y=Output Torque] => Z=Torque Loss + /// </summary> + private readonly DelaunayMap _lossMap; + + /// <summary> + /// The inverted loss map for range sanity checks. [X=Input EngineSpeed, Y=Input Torque] => Z=Output Torque + /// </summary> + private readonly DelaunayMap _invertedLossMap; + + public string GearName { get; private set; } + + public TransmissionLossMap(IReadOnlyList<GearLossMapEntry> entries, double gearRatio, string gearName) + { + GearName = gearName; + _ratio = gearRatio; + _entries = entries; + _lossMap = new DelaunayMap("TransmissionLossMap " + GearName); + _invertedLossMap = new DelaunayMap("TransmissionLossMapInv. " + GearName); + foreach (var entry in _entries) { + _lossMap.AddPoint(entry.InputSpeed.Value(), (entry.InputTorque - entry.TorqueLoss).Value(), entry.TorqueLoss.Value()); + _invertedLossMap.AddPoint(entry.InputSpeed.Value(), entry.InputTorque.Value(), entry.TorqueLoss.Value()); + } + + _lossMap.Triangulate(); + _invertedLossMap.Triangulate(); + } + + /// <summary> + /// Computes the torque loss (input side) given by the output gearbox speed and the output-torque. + /// </summary> + /// <param name="outAngularVelocity">Angular speed at output side.</param> + /// <param name="outTorque">Torque at output side (as requested by the previous componend towards the wheels).</param> + /// <returns>Torque loss as seen on input side (towards the engine).</returns> + public LossMapResult GetTorqueLoss(PerSecond outAngularVelocity, NewtonMeter outTorque) + { + var result = new LossMapResult(); + var torqueLoss = _lossMap.Interpolate(outAngularVelocity.Value() * _ratio, outTorque.Value() / _ratio); + + if (!torqueLoss.HasValue) { + torqueLoss = _lossMap.Extrapolate(outAngularVelocity.Value() * _ratio, outTorque.Value() / _ratio); + result.Extrapolated = true; + } + + result.Value = torqueLoss.Value.SI<NewtonMeter>(); + + Log.Debug("GearboxLoss {0}: {1}, outAngularVelocity: {2}, outTorque: {3}", GearName, torqueLoss, + outAngularVelocity, outTorque); + return result; + } + + [DebuggerDisplay("{Value} (extrapolated: {Extrapolated})")] + public class LossMapResult + { + public bool Extrapolated; + public NewtonMeter Value; + } + + /// <summary> + /// Computes the OUTPUT torque given by the input engineSpeed and the input torque. + /// </summary> + /// <param name="inAngularVelocity">Angular speed at input side.</param> + /// <param name="inTorque">Torque at input side.</param> + /// <param name="allowExtrapolation"></param> + /// <returns>Torque needed at output side (towards the wheels).</returns> + public NewtonMeter GetOutTorque(PerSecond inAngularVelocity, NewtonMeter inTorque, bool allowExtrapolation = false) + { + var torqueLoss = _invertedLossMap.Interpolate(inAngularVelocity.Value(), inTorque.Value()); + if (torqueLoss.HasValue) { + return (inTorque - torqueLoss.Value.SI<NewtonMeter>()) / _ratio; + } + + if (allowExtrapolation) { + torqueLoss = _invertedLossMap.Extrapolate(inAngularVelocity.Value(), inTorque.Value()); + return (inTorque - torqueLoss.Value.SI<NewtonMeter>()) / _ratio; + } + + throw new VectoException("TransmissionLossMap {0}: Interpolation failed. inTorque: {1}, inAngularVelocity: {2}", + GearName, inTorque, + inAngularVelocity.AsRPM); + } + + public GearLossMapEntry this[int i] + { + get { return _entries[i]; } + } + +#if DEBUG + public void DrawGraph() + { + _lossMap.DrawGraph(); + } +#endif + + [DebuggerDisplay("GearLossMapEntry({InputSpeed}, {InputTorque}, {TorqueLoss})")] + public class GearLossMapEntry + { + [Required, SIRange(0, 10000 * Constants.RPMToRad)] + public PerSecond InputSpeed { get; private set; } + + [Required, SIRange(-100000, 100000)] + public NewtonMeter InputTorque { get; private set; } + + [Required, SIRange(0, 100000)] + public NewtonMeter TorqueLoss { get; private set; } + + public GearLossMapEntry(PerSecond inputSpeed, NewtonMeter inputTorque, NewtonMeter torqueLoss) + { + InputSpeed = inputSpeed; + InputTorque = inputTorque; + TorqueLoss = torqueLoss; + } + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/BusAuxiliariesAdapter.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/BusAuxiliariesAdapter.cs index 4bdde41d73..af42da7f9b 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/BusAuxiliariesAdapter.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/BusAuxiliariesAdapter.cs @@ -29,255 +29,255 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System; -using System.IO; -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.Models.Declaration; -using TUGraz.VectoCore.Models.Simulation.Data; -using TUGraz.VectoCore.Models.Simulation.DataBus; -using TUGraz.VectoCore.Models.SimulationComponent.Data.Engine; -using TUGraz.VectoCore.OutputData; -using VectoAuxiliaries; -using VectoAuxiliaries.Pneumatics; - -namespace TUGraz.VectoCore.Models.SimulationComponent.Impl -{ - public class BusAuxiliariesAdapter : LoggingObject, IAuxInProvider, IAuxPort - { - protected readonly IDataBus DataBus; - protected internal BusAuxState CurrentState; - protected internal BusAuxState PreviousState; - - protected internal readonly IAuxPort AdditionalAux; - - protected IAdvancedAuxiliaries Auxiliaries; - private readonly FuelConsumptionAdapter _fcMapAdapter; - - public BusAuxiliariesAdapter(IDataBus container, string aauxFile, string cycleName, Kilogram vehicleWeight, - FuelConsumptionMap fcMap, PerSecond engineIdleSpeed, IAuxPort additionalAux = null) - { - // mAAUX_Global.advancedAuxModel.Signals.DeclarationMode = Cfg.DeclMode - // mAAUX_Global.advancedAuxModel.Signals.WHTC = Declaration.WHTCcorrFactor - CurrentState = new BusAuxState(); - PreviousState = new BusAuxState { AngularSpeed = engineIdleSpeed }; - - AdditionalAux = additionalAux; - - DataBus = container; - var tmpAux = new AdvancedAuxiliaries { - VectoInputs = { - Cycle = DetermineCycle(cycleName), - VehicleWeightKG = vehicleWeight - } - }; - - _fcMapAdapter = new FuelConsumptionAdapter() { FcMap = fcMap }; - tmpAux.VectoInputs.FuelMap = _fcMapAdapter; - tmpAux.VectoInputs.FuelDensity = FuelData.Instance().Lookup(container.FuelType).FuelDensity; - - //'Set Signals - tmpAux.Signals.EngineIdleSpeed = engineIdleSpeed; - tmpAux.Initialise(Path.GetFileName(aauxFile), Path.GetDirectoryName(Path.GetFullPath(aauxFile)) + @"\"); - - tmpAux.Signals.TotalCycleTimeSeconds = - tmpAux.actuationsMap.GetNumActuations(new ActuationsKey("CycleTime", tmpAux.VectoInputs.Cycle)); - - // call initialize again _after_ setting the cycle time to get the correct consumtions - tmpAux.Initialise(Path.GetFileName(aauxFile), Path.GetDirectoryName(Path.GetFullPath(aauxFile)) + @"\"); - - - Auxiliaries = tmpAux; - } - - private static string DetermineCycle(string cycleName) - { - var cycle = cycleName.ToLower(); - - if (cycle.Contains("bus")) { - if (cycle.Contains("heavy_urban")) { - return "Heavy urban"; - } - if (cycle.Contains("suburban")) { - return "Suburban"; - } - if (cycle.Contains("interurban")) { - return "Interurban"; - } - if (cycle.Contains("urban")) { - return "Urban"; - } - } - if (cycle.Contains("coach")) { - return "Coach"; - } - Logger<BusAuxiliariesAdapter>() - .Warn("UnServiced Cycle Name '{0}' in Pneumatics Actuations Map 0 Actuations returned", cycleName); - return cycleName; - } - - public IAuxPort Port() - { - return this; - } - - public NewtonMeter Initialize(NewtonMeter torque, PerSecond angularSpeed) - { - //PreviousState.TotalFuelConsumption = 0.SI<Kilogram>(); - PreviousState.AngularSpeed = angularSpeed; - CurrentState.AngularSpeed = angularSpeed; - if (AdditionalAux != null) { - AdditionalAux.Initialize(torque, angularSpeed); - } - PreviousState.PowerDemand = GetBusAuxPowerDemand(0.SI<Second>(), 1.SI<Second>(), torque, torque, angularSpeed); - return PreviousState.PowerDemand / angularSpeed; - } - - - public NewtonMeter TorqueDemand(Second absTime, Second dt, NewtonMeter torquePowerTrain, NewtonMeter torqueEngine, - PerSecond angularSpeed, bool dryRun = false) - { - CurrentState.AngularSpeed = angularSpeed; - CurrentState.dt = dt; - CurrentState.PowerDemand = GetBusAuxPowerDemand(absTime, dt, torquePowerTrain, torqueEngine, angularSpeed, dryRun); - - var avgAngularSpeed = (CurrentState.AngularSpeed + PreviousState.AngularSpeed) / 2.0; - return CurrentState.PowerDemand / avgAngularSpeed; - } - - - protected internal void DoWriteModalResults(IModalDataContainer container) - { - _fcMapAdapter.AllowExtrapolation = true; - // cycleStep has to be called here and not in DoCommit, write is called before Commit! - var message = String.Empty; - Auxiliaries.CycleStep(CurrentState.dt, ref message); - Log.Warn(message); - - CurrentState.TotalFuelConsumption = Auxiliaries.TotalFuelGRAMS; - container[ModalResultField.P_aux] = CurrentState.PowerDemand; - - container[ModalResultField.AA_NonSmartAlternatorsEfficiency] = Auxiliaries.AA_NonSmartAlternatorsEfficiency; - if (Auxiliaries.AA_SmartIdleCurrent_Amps != null) { - container[ModalResultField.AA_SmartIdleCurrent_Amps] = Auxiliaries.AA_SmartIdleCurrent_Amps; - } - container[ModalResultField.AA_SmartIdleAlternatorsEfficiency] = Auxiliaries.AA_SmartIdleAlternatorsEfficiency; - if (Auxiliaries.AA_SmartTractionCurrent_Amps != null) { - container[ModalResultField.AA_SmartTractionCurrent_Amps] = - Auxiliaries.AA_SmartTractionCurrent_Amps; - } - container[ModalResultField.AA_SmartTractionAlternatorEfficiency] = Auxiliaries.AA_SmartTractionAlternatorEfficiency; - if (Auxiliaries.AA_SmartOverrunCurrent_Amps != null) { - container[ModalResultField.AA_SmartOverrunCurrent_Amps] = Auxiliaries.AA_SmartOverrunCurrent_Amps; - } - container[ModalResultField.AA_SmartOverrunAlternatorEfficiency] = Auxiliaries.AA_SmartOverrunAlternatorEfficiency; - if (Auxiliaries.AA_CompressorFlowRate_LitrePerSec != null) { - container[ModalResultField.AA_CompressorFlowRate_LitrePerSec] = - Auxiliaries.AA_CompressorFlowRate_LitrePerSec; - } - container[ModalResultField.AA_OverrunFlag] = Auxiliaries.AA_OverrunFlag; - container[ModalResultField.AA_EngineIdleFlag] = Auxiliaries.AA_EngineIdleFlag; - container[ModalResultField.AA_CompressorFlag] = Auxiliaries.AA_CompressorFlag; - if (Auxiliaries.AA_TotalCycleFC_Grams != null) { - container[ModalResultField.AA_TotalCycleFC_Grams] = Auxiliaries.AA_TotalCycleFC_Grams; - } - if (Auxiliaries.AA_TotalCycleFC_Litres != null) { - container[ModalResultField.AA_TotalCycleFC_Litres] = Auxiliaries.AA_TotalCycleFC_Litres; - } - if (Auxiliaries.AA_AveragePowerDemandCrankHVACMechanicals != null) { - container[ModalResultField.AA_AveragePowerDemandCrankHVACMechanicals] = - Auxiliaries.AA_AveragePowerDemandCrankHVACMechanicals; - } - if (Auxiliaries.AA_AveragePowerDemandCrankHVACElectricals != null) { - container[ModalResultField.AA_AveragePowerDemandCrankHVACElectricals] = - Auxiliaries.AA_AveragePowerDemandCrankHVACElectricals; - } - if (Auxiliaries.AA_AveragePowerDemandCrankElectrics != null) { - container[ModalResultField.AA_AveragePowerDemandCrankElectrics] = - Auxiliaries.AA_AveragePowerDemandCrankElectrics; - } - if (Auxiliaries.AA_AveragePowerDemandCrankPneumatics != null) { - container[ModalResultField.AA_AveragePowerDemandCrankPneumatics] = - Auxiliaries.AA_AveragePowerDemandCrankPneumatics; - } - if (Auxiliaries.AA_TotalCycleFuelConsumptionCompressorOff != null) { - container[ModalResultField.AA_TotalCycleFuelConsumptionCompressorOff] = - Auxiliaries.AA_TotalCycleFuelConsumptionCompressorOff; - } - container[ModalResultField.AA_TotalCycleFuelConsumptionCompressorOn] = - Auxiliaries.AA_TotalCycleFuelConsumptionCompressorOn; - } - - protected internal void DoCommitSimulationStep() - { - PreviousState = CurrentState; - CurrentState = new BusAuxState(); - } - - protected internal KilogramPerSecond AAuxFuelConsumption - { - get { return (CurrentState.TotalFuelConsumption - PreviousState.TotalFuelConsumption) / CurrentState.dt; } - } - - private Watt GetBusAuxPowerDemand(Second absTime, Second dt, NewtonMeter torquePowerTrain, NewtonMeter torqueEngine, - PerSecond angularSpeed, bool dryRun = false) - { - _fcMapAdapter.AllowExtrapolation = true; - - Auxiliaries.Signals.ClutchEngaged = DataBus.ClutchClosed(absTime); - Auxiliaries.Signals.EngineDrivelinePower = torquePowerTrain * angularSpeed; - Auxiliaries.Signals.EngineDrivelineTorque = torquePowerTrain; - Auxiliaries.Signals.InternalEnginePower = torqueEngine * angularSpeed - DataBus.BrakePower; - if (DataBus.DriverBehavior == DrivingBehavior.Coasting) { - // make sure smart aux are _not_ enabled for now - // set internal_engine_power a little bit lower so there is no excessive power for smart aux - Auxiliaries.Signals.InternalEnginePower = 0.9 * torqueEngine * angularSpeed /*- DataBus.BrakePower*/; - // if smart aux should be on during coasting use the following line - // set internal_engine_power to a large value (*10) so that there's excessive power for smart aux (alreadin during search operating point) - //(float)DataBus.EngineDragPower(angularSpeed).Value() / 100; - } else { - if (DataBus.DriverBehavior != DrivingBehavior.Braking) { - Auxiliaries.Signals.InternalEnginePower = 0.SI<Watt>(); - //(float)((0.9 * torqueEngine * angularSpeed - DataBus.BrakePower) / 1000).Value(); - } else { - // smart aux should be on during braking - } - } - Auxiliaries.Signals.EngineMotoringPower = -DataBus.EngineDragPower(angularSpeed); - Auxiliaries.Signals.EngineSpeed = angularSpeed; - var avgAngularSpeed = (PreviousState.AngularSpeed + CurrentState.AngularSpeed) / 2; - Auxiliaries.Signals.PreExistingAuxPower = AdditionalAux != null - ? AdditionalAux.TorqueDemand(absTime, dt, torquePowerTrain, torqueEngine, angularSpeed, dryRun) * avgAngularSpeed - : 0.SI<Watt>(); - //mAAUX_Global.PreExistingAuxPower; - Auxiliaries.Signals.Idle = DataBus.VehicleStopped; - Auxiliaries.Signals.InNeutral = DataBus.Gear == 0; - Auxiliaries.Signals.RunningCalc = true; - - //mAAUX_Global.Internal_Engine_Power; - //'Power coming out of Advanced Model is in Watts. - - return Auxiliaries.AuxiliaryPowerAtCrankWatts + Auxiliaries.Signals.PreExistingAuxPower; - } - - protected class FuelConsumptionAdapter : IFuelConsumptionMap - { - protected internal FuelConsumptionMap FcMap; - - public bool AllowExtrapolation { get; set; } - - public KilogramPerSecond GetFuelConsumption(NewtonMeter torque, PerSecond angularVelocity) - { - return FcMap.GetFuelConsumption(torque, angularVelocity, AllowExtrapolation).Value; - } - } - - public class BusAuxState - { - public Second dt; - public PerSecond AngularSpeed; - public Watt PowerDemand; - public Kilogram TotalFuelConsumption = 0.SI<Kilogram>(); - } - } +using System; +using System.IO; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Models.Declaration; +using TUGraz.VectoCore.Models.Simulation.Data; +using TUGraz.VectoCore.Models.Simulation.DataBus; +using TUGraz.VectoCore.Models.SimulationComponent.Data.Engine; +using TUGraz.VectoCore.OutputData; +using VectoAuxiliaries; +using VectoAuxiliaries.Pneumatics; + +namespace TUGraz.VectoCore.Models.SimulationComponent.Impl +{ + public class BusAuxiliariesAdapter : LoggingObject, IAuxInProvider, IAuxPort + { + protected readonly IDataBus DataBus; + protected internal BusAuxState CurrentState; + protected internal BusAuxState PreviousState; + + protected internal readonly IAuxPort AdditionalAux; + + protected IAdvancedAuxiliaries Auxiliaries; + private readonly FuelConsumptionAdapter _fcMapAdapter; + + public BusAuxiliariesAdapter(IDataBus container, string aauxFile, string cycleName, Kilogram vehicleWeight, + FuelConsumptionMap fcMap, PerSecond engineIdleSpeed, IAuxPort additionalAux = null) + { + // mAAUX_Global.advancedAuxModel.Signals.DeclarationMode = Cfg.DeclMode + // mAAUX_Global.advancedAuxModel.Signals.WHTC = Declaration.WHTCcorrFactor + CurrentState = new BusAuxState(); + PreviousState = new BusAuxState { AngularSpeed = engineIdleSpeed }; + + AdditionalAux = additionalAux; + + DataBus = container; + var tmpAux = new AdvancedAuxiliaries { + VectoInputs = { + Cycle = DetermineCycle(cycleName), + VehicleWeightKG = vehicleWeight + } + }; + + _fcMapAdapter = new FuelConsumptionAdapter() { FcMap = fcMap }; + tmpAux.VectoInputs.FuelMap = _fcMapAdapter; + tmpAux.VectoInputs.FuelDensity = FuelData.Instance().Lookup(container.FuelType).FuelDensity; + + //'Set Signals + tmpAux.Signals.EngineIdleSpeed = engineIdleSpeed; + tmpAux.Initialise(Path.GetFileName(aauxFile), Path.GetDirectoryName(Path.GetFullPath(aauxFile)) + @"\"); + + tmpAux.Signals.TotalCycleTimeSeconds = + tmpAux.actuationsMap.GetNumActuations(new ActuationsKey("CycleTime", tmpAux.VectoInputs.Cycle)); + + // call initialize again _after_ setting the cycle time to get the correct consumtions + tmpAux.Initialise(Path.GetFileName(aauxFile), Path.GetDirectoryName(Path.GetFullPath(aauxFile)) + @"\"); + + + Auxiliaries = tmpAux; + } + + private static string DetermineCycle(string cycleName) + { + var cycle = cycleName.ToLower(); + + if (cycle.Contains("bus")) { + if (cycle.Contains("heavy_urban")) { + return "Heavy urban"; + } + if (cycle.Contains("suburban")) { + return "Suburban"; + } + if (cycle.Contains("interurban")) { + return "Interurban"; + } + if (cycle.Contains("urban")) { + return "Urban"; + } + } + if (cycle.Contains("coach")) { + return "Coach"; + } + Logger<BusAuxiliariesAdapter>() + .Warn("UnServiced Cycle Name '{0}' in Pneumatics Actuations Map 0 Actuations returned", cycleName); + return cycleName; + } + + public IAuxPort Port() + { + return this; + } + + public NewtonMeter Initialize(NewtonMeter torque, PerSecond angularSpeed) + { + //PreviousState.TotalFuelConsumption = 0.SI<Kilogram>(); + PreviousState.AngularSpeed = angularSpeed; + CurrentState.AngularSpeed = angularSpeed; + if (AdditionalAux != null) { + AdditionalAux.Initialize(torque, angularSpeed); + } + PreviousState.PowerDemand = GetBusAuxPowerDemand(0.SI<Second>(), 1.SI<Second>(), torque, torque, angularSpeed); + return PreviousState.PowerDemand / angularSpeed; + } + + + public NewtonMeter TorqueDemand(Second absTime, Second dt, NewtonMeter torquePowerTrain, NewtonMeter torqueEngine, + PerSecond angularSpeed, bool dryRun = false) + { + CurrentState.AngularSpeed = angularSpeed; + CurrentState.dt = dt; + CurrentState.PowerDemand = GetBusAuxPowerDemand(absTime, dt, torquePowerTrain, torqueEngine, angularSpeed, dryRun); + + var avgAngularSpeed = (CurrentState.AngularSpeed + PreviousState.AngularSpeed) / 2.0; + return CurrentState.PowerDemand / avgAngularSpeed; + } + + + protected internal void DoWriteModalResults(IModalDataContainer container) + { + _fcMapAdapter.AllowExtrapolation = true; + // cycleStep has to be called here and not in DoCommit, write is called before Commit! + var message = String.Empty; + Auxiliaries.CycleStep(CurrentState.dt, ref message); + Log.Warn(message); + + CurrentState.TotalFuelConsumption = Auxiliaries.TotalFuelGRAMS; + container[ModalResultField.P_aux] = CurrentState.PowerDemand; + + container[ModalResultField.AA_NonSmartAlternatorsEfficiency] = Auxiliaries.AA_NonSmartAlternatorsEfficiency; + if (Auxiliaries.AA_SmartIdleCurrent_Amps != null) { + container[ModalResultField.AA_SmartIdleCurrent_Amps] = Auxiliaries.AA_SmartIdleCurrent_Amps; + } + container[ModalResultField.AA_SmartIdleAlternatorsEfficiency] = Auxiliaries.AA_SmartIdleAlternatorsEfficiency; + if (Auxiliaries.AA_SmartTractionCurrent_Amps != null) { + container[ModalResultField.AA_SmartTractionCurrent_Amps] = + Auxiliaries.AA_SmartTractionCurrent_Amps; + } + container[ModalResultField.AA_SmartTractionAlternatorEfficiency] = Auxiliaries.AA_SmartTractionAlternatorEfficiency; + if (Auxiliaries.AA_SmartOverrunCurrent_Amps != null) { + container[ModalResultField.AA_SmartOverrunCurrent_Amps] = Auxiliaries.AA_SmartOverrunCurrent_Amps; + } + container[ModalResultField.AA_SmartOverrunAlternatorEfficiency] = Auxiliaries.AA_SmartOverrunAlternatorEfficiency; + if (Auxiliaries.AA_CompressorFlowRate_LitrePerSec != null) { + container[ModalResultField.AA_CompressorFlowRate_LitrePerSec] = + Auxiliaries.AA_CompressorFlowRate_LitrePerSec; + } + container[ModalResultField.AA_OverrunFlag] = Auxiliaries.AA_OverrunFlag; + container[ModalResultField.AA_EngineIdleFlag] = Auxiliaries.AA_EngineIdleFlag; + container[ModalResultField.AA_CompressorFlag] = Auxiliaries.AA_CompressorFlag; + if (Auxiliaries.AA_TotalCycleFC_Grams != null) { + container[ModalResultField.AA_TotalCycleFC_Grams] = Auxiliaries.AA_TotalCycleFC_Grams; + } + if (Auxiliaries.AA_TotalCycleFC_Litres != null) { + container[ModalResultField.AA_TotalCycleFC_Litres] = Auxiliaries.AA_TotalCycleFC_Litres; + } + if (Auxiliaries.AA_AveragePowerDemandCrankHVACMechanicals != null) { + container[ModalResultField.AA_AveragePowerDemandCrankHVACMechanicals] = + Auxiliaries.AA_AveragePowerDemandCrankHVACMechanicals; + } + if (Auxiliaries.AA_AveragePowerDemandCrankHVACElectricals != null) { + container[ModalResultField.AA_AveragePowerDemandCrankHVACElectricals] = + Auxiliaries.AA_AveragePowerDemandCrankHVACElectricals; + } + if (Auxiliaries.AA_AveragePowerDemandCrankElectrics != null) { + container[ModalResultField.AA_AveragePowerDemandCrankElectrics] = + Auxiliaries.AA_AveragePowerDemandCrankElectrics; + } + if (Auxiliaries.AA_AveragePowerDemandCrankPneumatics != null) { + container[ModalResultField.AA_AveragePowerDemandCrankPneumatics] = + Auxiliaries.AA_AveragePowerDemandCrankPneumatics; + } + if (Auxiliaries.AA_TotalCycleFuelConsumptionCompressorOff != null) { + container[ModalResultField.AA_TotalCycleFuelConsumptionCompressorOff] = + Auxiliaries.AA_TotalCycleFuelConsumptionCompressorOff; + } + container[ModalResultField.AA_TotalCycleFuelConsumptionCompressorOn] = + Auxiliaries.AA_TotalCycleFuelConsumptionCompressorOn; + } + + protected internal void DoCommitSimulationStep() + { + PreviousState = CurrentState; + CurrentState = new BusAuxState(); + } + + protected internal KilogramPerSecond AAuxFuelConsumption + { + get { return (CurrentState.TotalFuelConsumption - PreviousState.TotalFuelConsumption) / CurrentState.dt; } + } + + private Watt GetBusAuxPowerDemand(Second absTime, Second dt, NewtonMeter torquePowerTrain, NewtonMeter torqueEngine, + PerSecond angularSpeed, bool dryRun = false) + { + _fcMapAdapter.AllowExtrapolation = true; + + Auxiliaries.Signals.ClutchEngaged = DataBus.ClutchClosed(absTime); + Auxiliaries.Signals.EngineDrivelinePower = torquePowerTrain * angularSpeed; + Auxiliaries.Signals.EngineDrivelineTorque = torquePowerTrain; + Auxiliaries.Signals.InternalEnginePower = torqueEngine * angularSpeed - DataBus.BrakePower; + if (DataBus.DriverBehavior == DrivingBehavior.Coasting) { + // make sure smart aux are _not_ enabled for now + // set internal_engine_power a little bit lower so there is no excessive power for smart aux + Auxiliaries.Signals.InternalEnginePower = 0.9 * torqueEngine * angularSpeed /*- DataBus.BrakePower*/; + // if smart aux should be on during coasting use the following line + // set internal_engine_power to a large value (*10) so that there's excessive power for smart aux (alreadin during search operating point) + //(float)DataBus.EngineDragPower(angularSpeed).Value() / 100; + } else { + if (DataBus.DriverBehavior != DrivingBehavior.Braking) { + Auxiliaries.Signals.InternalEnginePower = 0.SI<Watt>(); + //(float)((0.9 * torqueEngine * angularSpeed - DataBus.BrakePower) / 1000).Value(); + } else { + // smart aux should be on during braking + } + } + Auxiliaries.Signals.EngineMotoringPower = -DataBus.EngineDragPower(angularSpeed); + Auxiliaries.Signals.EngineSpeed = angularSpeed; + var avgAngularSpeed = (PreviousState.AngularSpeed + CurrentState.AngularSpeed) / 2; + Auxiliaries.Signals.PreExistingAuxPower = AdditionalAux != null + ? AdditionalAux.TorqueDemand(absTime, dt, torquePowerTrain, torqueEngine, angularSpeed, dryRun) * avgAngularSpeed + : 0.SI<Watt>(); + //mAAUX_Global.PreExistingAuxPower; + Auxiliaries.Signals.Idle = DataBus.VehicleStopped; + Auxiliaries.Signals.InNeutral = DataBus.Gear == 0; + Auxiliaries.Signals.RunningCalc = true; + + //mAAUX_Global.Internal_Engine_Power; + //'Power coming out of Advanced Model is in Watts. + + return Auxiliaries.AuxiliaryPowerAtCrankWatts + Auxiliaries.Signals.PreExistingAuxPower; + } + + protected class FuelConsumptionAdapter : IFuelConsumptionMap + { + protected internal FuelConsumptionMap FcMap; + + public bool AllowExtrapolation { get; set; } + + public KilogramPerSecond GetFuelConsumption(NewtonMeter torque, PerSecond angularVelocity) + { + return FcMap.GetFuelConsumption(torque, angularVelocity, AllowExtrapolation).Value; + } + } + + public class BusAuxState + { + public Second dt; + public PerSecond AngularSpeed; + public Watt PowerDemand; + public Kilogram TotalFuelConsumption = 0.SI<Kilogram>(); + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs index 032a25d0a6..5881f2ae2f 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/CombustionEngine.cs @@ -366,7 +366,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl var avgEngineSpeed = GetEngineSpeed(CurrentState.EngineSpeed); if (avgEngineSpeed.IsSmaller(EngineIdleSpeed, DataBus.ExecutionMode == ExecutionMode.Engineering ? 20.RPMtoRad() : 1e-3.RPMtoRad())) { - Log.Warn("EngineSpeed below idling speed! n_eng_avg: {0}, n_idle: {1}", avgEngineSpeed, EngineIdleSpeed); + Log.Warn("EngineSpeed below idling speed! n_eng_avg: {0}, n_idle: {1}", avgEngineSpeed.AsRPM, EngineIdleSpeed.AsRPM); } container[ModalResultField.P_eng_fcmap] = CurrentState.EngineTorque * avgEngineSpeed; container[ModalResultField.P_eng_out] = container[ModalResultField.P_eng_out] is DBNull diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/VTPCycle.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/VTPCycle.cs index 48cb3ae007..7735c430b6 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/VTPCycle.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/VTPCycle.cs @@ -36,6 +36,7 @@ using TUGraz.VectoCommon.Models; using TUGraz.VectoCommon.Utils; using TUGraz.VectoCore.Configuration; using TUGraz.VectoCore.Models.Connector.Ports.Impl; +using TUGraz.VectoCore.Models.Declaration; using TUGraz.VectoCore.Models.Simulation.Data; using TUGraz.VectoCore.Models.Simulation.Impl; using TUGraz.VectoCore.Models.SimulationComponent.Data; @@ -48,11 +49,13 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl { private uint StartGear; - public VTPCycle(VehicleContainer container, IDrivingCycleData cycle, double axleGearRatio, - VehicleData vehicleData, Dictionary<uint, double> gearRatios) : base(container, cycle) { } + public VTPCycle(VehicleContainer container, IDrivingCycleData cycle) : base(container, cycle) { } public override IResponse Initialize() { + if (DataBus.ExecutionMode == ExecutionMode.Declaration) { + VerifyInputData(); + } PrepareCycleData(); SelectStartGear(); return base.Initialize(); @@ -68,6 +71,114 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl entry.Torque = wheelSpeed.IsEqual(0, 1e-3) ? 0.SI<NewtonMeter>() : wheelPower / wheelSpeed; } } + + protected internal void VerifyInputData() + { + var electricFanTechs = DeclarationData.Fan.FullyElectricTechnologies(); + var hasElectricFan = RunData.Aux.Any( + x => x.ID == Constants.Auxiliaries.IDs.Fan && x.Technology.Any(t => electricFanTechs.Contains(t))); + + foreach (var tuple in Data.Entries.Pairwise()) { + if (!(tuple.Item2.Time - tuple.Item1.Time).IsEqual( + DeclarationData.VTPMode.SamplingInterval, 0.1 * DeclarationData.VTPMode.SamplingInterval)) { + Log.Error("Cycle Data exceeds expected sampling frequence of {0}: t: {1}, dt: {2}", + DeclarationData.VTPMode.SamplingInterval, tuple.Item1.Time, tuple.Item2.Time - tuple.Item1.Time); + } + } + + foreach (var entry in Data.Entries) { + VerifyWheelSpeeds(entry); + + VerifyWheelTorque(entry); + + VerifyFanSpeed(hasElectricFan, entry); + } + + VerifyFCInput(); + } + + private void VerifyFCInput() + { + var idx = 0L; + int count = Convert.ToInt32(DeclarationData.VTPMode.FCAccumulationWindow / DeclarationData.VTPMode.SamplingInterval); + var sum = 0.SI<Kilogram>(); + var window = 0.SI<Kilogram>().Repeat(count).ToArray(); + + foreach (var entry in Data.Entries.Pairwise()) { + var fc = entry.Item1.Fuelconsumption * (entry.Item2.Time - entry.Item1.Time); + window[idx % count] = fc; + sum += window[idx % count]; + sum -= window[(idx + 1) % count]; + if (idx >= count && sum < DeclarationData.VTPMode.LowerFCThreshold * DeclarationData.VTPMode.FCAccumulationWindow) { + Log.Error("Fuel consumption for the previous {0} below threshold of {1}. t: {2}, FC: {3}", DeclarationData.VTPMode.FCAccumulationWindow.ConvertToMinutes(), + DeclarationData.VTPMode.LowerFCThreshold.ConvertToGrammPerHour(), entry.Item1.Time, (sum / DeclarationData.VTPMode.FCAccumulationWindow).ConvertToGrammPerHour()); + } + if (idx >= count && sum > DeclarationData.VTPMode.UpperFCThreshold * DeclarationData.VTPMode.FCAccumulationWindow) { + Log.Error("Fuel consumption for the previous {0} above threshold of {1}. t: {2}, FC: {3}", DeclarationData.VTPMode.FCAccumulationWindow.ConvertToMinutes(), + DeclarationData.VTPMode.UpperFCThreshold.ConvertToGrammPerHour(), entry.Item1.Time, (sum / DeclarationData.VTPMode.FCAccumulationWindow).ConvertToGrammPerHour()); + } + idx++; + } + } + + private void VerifyFanSpeed(bool hasElectricFan, DrivingCycleData.DrivingCycleEntry entry) + { + if (hasElectricFan) { + if (entry.FanSpeed.IsSmaller(0)) { + Log.Error("Fan speed (electric) below zero! t: {0}, n_fan: {1}", entry.Time, entry.FanSpeed); + } + } else { + if (entry.FanSpeed.IsSmaller(DeclarationData.VTPMode.MinFanSpeed) || + entry.FanSpeed.IsGreater(DeclarationData.VTPMode.MaxFanSpeed)) { + Log.Error( + "Fan speed (non-electric) exceeds range {0} < n_fan < {1}. t: {2}, n_fan: {3}", DeclarationData.VTPMode.MinFanSpeed, + DeclarationData.VTPMode.MaxFanSpeed, entry.Time, entry.FanSpeed); + } + } + } + + private void VerifyWheelTorque(DrivingCycleData.DrivingCycleEntry entry) + { + if (!entry.TorqueWheelLeft.IsEqual(0.SI<NewtonMeter>(), DeclarationData.VTPMode.WheelTorqueZeroTolerance) && + !entry.TorqueWheelRight.IsEqual(0.SI<NewtonMeter>(), DeclarationData.VTPMode.WheelTorqueZeroTolerance)) { + var torqueRatio = VectoMath.Max( + entry.TorqueWheelLeft / entry.TorqueWheelRight, entry.TorqueWheelRight / entry.TorqueWheelLeft); + if (torqueRatio > DeclarationData.VTPMode.WheelTorqueDifferenceFactor) { + Log.Error( + "Torque difference rel. (L/R) too high! t: {0} tq_left: {1}, tq_right: {2}", entry.Time, entry.TorqueWheelLeft, + entry.TorqueWheelRight); + } + } else { + if (VectoMath.Abs(entry.TorqueWheelLeft - entry.TorqueWheelRight) > + DeclarationData.VTPMode.MaxWheelTorqueZeroDifference) { + Log.Error( + "Torque difference abs. (L/R) too high! t: {0} tq_left: {1}, tq_right: {2}", entry.Time, entry.TorqueWheelLeft, + entry.TorqueWheelRight); + } + } + } + + private void VerifyWheelSpeeds(DrivingCycleData.DrivingCycleEntry entry) + { + if (!entry.WheelSpeedLeft.IsEqual(0.RPMtoRad(), DeclarationData.VTPMode.WheelSpeedZeroTolerance) && + !entry.WheelSpeedRight.IsEqual(0.RPMtoRad(), DeclarationData.VTPMode.WheelSpeedZeroTolerance)) { + var wheelSpeedRatio = VectoMath.Max( + entry.WheelSpeedLeft / entry.WheelSpeedRight, entry.WheelSpeedRight / entry.WheelSpeedLeft); + if (wheelSpeedRatio > DeclarationData.VTPMode.WheelSpeedDifferenceFactor) { + Log.Error( + "Wheel-speed difference rel. (L/R) too high! t: {0} n_left: {1}, n_right: {2}", entry.Time, + entry.WheelSpeedLeft.AsRPM, entry.WheelSpeedRight.AsRPM); + } + } else { + if (VectoMath.Abs(entry.WheelSpeedLeft - entry.WheelSpeedRight) > + DeclarationData.VTPMode.MaxWheelSpeedDifferenceStandstill) { + Log.Error( + "Wheel-speed difference abs. (L/R) too high! t: {0} n_left: {1}, n_right: {2}", entry.Time, + entry.WheelSpeedLeft.AsRPM, entry.WheelSpeedRight.AsRPM); + } + } + } + private void SelectStartGear() { var transmissionRatio = RunData.AxleGearData.AxleGear.Ratio * diff --git a/VectoCore/VectoCore/Resources/Declaration/VAUX/Fan-Tech.csv b/VectoCore/VectoCore/Resources/Declaration/VAUX/Fan-Tech.csv index 10e393a595..a09dd8ea95 100644 --- a/VectoCore/VectoCore/Resources/Declaration/VAUX/Fan-Tech.csv +++ b/VectoCore/VectoCore/Resources/Declaration/VAUX/Fan-Tech.csv @@ -1,12 +1,12 @@ -Technology , Long haul , Regional delivery , Urban delivery , Municipal utility , Construction -Crankshaft mounted - Electronically controlled visco clutch , 618 , 671 , 516 , 566 , 1037 -Crankshaft mounted - Bimetallic controlled visco clutch , 818 , 871 , 676 , 766 , 1277 -Crankshaft mounted - Discrete step clutch , 668 , 721 , 616 , 616 , 1157 -Crankshaft mounted - On/off clutch , 718 , 771 , 666 , 666 , 1237 -Belt driven or driven via transm. - Electronically controlled visco clutch , 989 , 1044 , 833 , 933 , 1478 -Belt driven or driven via transm. - Bimetallic controlled visco clutch , 1189 , 1244 , 993 , 1133 , 1718 -Belt driven or driven via transm. - Discrete step clutch , 1039 , 1094 , 983 , 983 , 1598 -Belt driven or driven via transm. - On/off clutch , 1089 , 1144 , 1033 , 1033 , 1678 -Hydraulic driven - Variable displacement pump , 938 , 1155 , 832 , 917 , 1872 -Hydraulic driven - Constant displacement pump , 1200 , 1400 , 1000 , 1100 , 2300 -Electrically driven - Electronically controlled , 700 , 800 , 600 , 600 , 1400 \ No newline at end of file +Technology , fully electric , Long haul , Regional delivery , Urban delivery , Municipal utility , Construction +Crankshaft mounted - Electronically controlled visco clutch , 0 , 618 , 671 , 516 , 566 , 1037 +Crankshaft mounted - Bimetallic controlled visco clutch , 0 , 818 , 871 , 676 , 766 , 1277 +Crankshaft mounted - Discrete step clutch , 0 , 668 , 721 , 616 , 616 , 1157 +Crankshaft mounted - On/off clutch , 0 , 718 , 771 , 666 , 666 , 1237 +Belt driven or driven via transm. - Electronically controlled visco clutch , 0 , 989 , 1044 , 833 , 933 , 1478 +Belt driven or driven via transm. - Bimetallic controlled visco clutch , 0 , 1189 , 1244 , 993 , 1133 , 1718 +Belt driven or driven via transm. - Discrete step clutch , 0 , 1039 , 1094 , 983 , 983 , 1598 +Belt driven or driven via transm. - On/off clutch , 0 , 1089 , 1144 , 1033 , 1033 , 1678 +Hydraulic driven - Variable displacement pump , 0 , 938 , 1155 , 832 , 917 , 1872 +Hydraulic driven - Constant displacement pump , 0 , 1200 , 1400 , 1000 , 1100 , 2300 +Electrically driven - Electronically controlled , 1 , 700 , 800 , 600 , 600 , 1400 \ No newline at end of file diff --git a/VectoCore/VectoCoreTest/Models/SimulationComponent/VTPCycleValidationTest.cs b/VectoCore/VectoCoreTest/Models/SimulationComponent/VTPCycleValidationTest.cs new file mode 100644 index 0000000000..b713e4c8a6 --- /dev/null +++ b/VectoCore/VectoCoreTest/Models/SimulationComponent/VTPCycleValidationTest.cs @@ -0,0 +1,515 @@ +using System.Collections.Generic; +using NLog; +using NLog.Config; +using NLog.Targets; +using NUnit.Framework; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Configuration; +using TUGraz.VectoCore.InputData.Reader; +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.Impl; +using TUGraz.VectoCore.Tests.Integration; +using TUGraz.VectoCore.Tests.Models.SimulationComponentData; +using TUGraz.VectoCore.Tests.Utils; +using TUGraz.VectoCore.Utils; + +namespace TUGraz.VectoCore.Tests.Models.SimulationComponent +{ + [TestFixture] + public class VTPCycleValidationTest + { + public static List<string> LogList = new List<string>(); + + const string Header = "<t> [s],<v> [km/h],<n_eng> [rpm],<n_fan> [rpm],<tq_left> [Nm],<tq_right> [Nm],<n_wh_left> [rpm],<n_wh_right> [rpm],<fc> [g/h],<gear>"; + + + [TestCase()] + public void TestWheelSpeedRatioExceeds_Left() + { + SetupLogging(); + + var wheelSpeed = 100; + + var cycleEntries = string.Format( + @" 0 , 0, 600, 400, 200, 200, {0}, {0} , 100, 3 + 0.5 , 0, 600, 400, 200, 200, {0}, {0} , 100, 3 + 1 , 0, 600, 400, 200, 200, {0}, {1} , 100, 3 + 1.5 , 0, 600, 400, 200, 200, {1}, {1} , 100, 3 + ", wheelSpeed, wheelSpeed * DeclarationData.VTPMode.WheelSpeedDifferenceFactor * 1.1); + + var container = new VehicleContainer(ExecutionMode.Declaration) { + RunData = new VectoRunData() { + Aux = new List<VectoRunData.AuxData>() + } + }; + var cycle = InputDataHelper.InputDataAsStream(Header, cycleEntries.Split('\n')); + var cycleData = DrivingCycleDataReader.ReadFromDataTable(VectoCSVFile.ReadStream(cycle), "VTP Cycle", false); + var vtpCycle = new VTPCycle(container, cycleData); + + vtpCycle.VerifyInputData(); + + Assert.AreEqual(1, LogList.Count); + Assert.IsTrue(LogList[0].Contains("Wheel-speed difference rel.")); + } + + [TestCase()] + public void TestWheelSpeedRatioExceeds_Right() + { + SetupLogging(); + + var wheelSpeed = 100; + + var cycleEntries = string.Format( + @" 0 , 0, 600, 400, 200, 200, {0}, {0} , 100, 3 + 0.5 , 0, 600, 400, 200, 200, {0}, {0} , 100, 3 + 1 , 0, 600, 400, 200, 200, {0}, {1} , 100, 3 + 1.5 , 0, 600, 400, 200, 200, {1}, {1} , 100, 3 + ", wheelSpeed, wheelSpeed * DeclarationData.VTPMode.WheelSpeedDifferenceFactor * 1.1); + + var container = new VehicleContainer(ExecutionMode.Declaration) { + RunData = new VectoRunData() { + Aux = new List<VectoRunData.AuxData>() + } + }; + var cycle = InputDataHelper.InputDataAsStream(Header, cycleEntries.Split('\n')); + var cycleData = DrivingCycleDataReader.ReadFromDataTable(VectoCSVFile.ReadStream(cycle), "VTP Cycle", false); + var vtpCycle = new VTPCycle(container, cycleData); + + vtpCycle.VerifyInputData(); + + Assert.AreEqual(1, LogList.Count); + Assert.IsTrue(LogList[0].Contains("Wheel-speed difference rel.")); + } + + [TestCase()] + public void TestWheelSpeedDifferenceStandstillExceeds_Left() + { + SetupLogging(); + + var wheelSpeed = 0.95 * DeclarationData.VTPMode.WheelSpeedZeroTolerance.AsRPM; + + var cycleEntries = string.Format( + @" 0 , 0, 600, 400, 200, 200, {0}, {0} , 100, 3 + 0.5 , 0, 600, 400, 200, 200, {0}, {0} , 100, 3 + 1 , 0, 600, 400, 200, 200, {1}, {0} , 100, 3 + 1.5 , 0, 600, 400, 200, 200, {1}, {1} , 100, 3 + ", wheelSpeed, wheelSpeed + DeclarationData.VTPMode.MaxWheelSpeedDifferenceStandstill.AsRPM * 1.1); + + var container = new VehicleContainer(ExecutionMode.Declaration) { + RunData = new VectoRunData() { + Aux = new List<VectoRunData.AuxData>() + } + }; + var cycle = InputDataHelper.InputDataAsStream(Header, cycleEntries.Split('\n')); + var cycleData = DrivingCycleDataReader.ReadFromDataTable(VectoCSVFile.ReadStream(cycle), "VTP Cycle", false); + var vtpCycle = new VTPCycle(container, cycleData); + vtpCycle.VerifyInputData(); + + Assert.AreEqual(1, LogList.Count); + Assert.IsTrue(LogList[0].Contains("Wheel-speed difference abs.")); + } + + [TestCase()] + public void TestWheelSpeedDifferenceStandstillExceeds_Right() + { + SetupLogging(); + + var wheelSpeed = 0.95*DeclarationData.VTPMode.WheelSpeedZeroTolerance.AsRPM; + + var cycleEntries = string.Format( + @" 0 , 0, 600, 400, 200, 200, {0}, {0} , 100, 3 + 0.5 , 0, 600, 400, 200, 200, {0}, {0} , 100, 3 + 1 , 0, 600, 400, 200, 200, {0}, {1} , 100, 3 + 1.5 , 0, 600, 400, 200, 200, {1}, {1} , 100, 3 + ", wheelSpeed, wheelSpeed + DeclarationData.VTPMode.MaxWheelSpeedDifferenceStandstill.AsRPM * 1.1); + + var container = new VehicleContainer(ExecutionMode.Declaration) { + RunData = new VectoRunData() { + Aux = new List<VectoRunData.AuxData>() + } + }; + var cycle = InputDataHelper.InputDataAsStream(Header, cycleEntries.Split('\n')); + var cycleData = DrivingCycleDataReader.ReadFromDataTable(VectoCSVFile.ReadStream(cycle), "VTP Cycle", false); + var vtpCycle = new VTPCycle(container, cycleData); + + vtpCycle.VerifyInputData(); + + Assert.AreEqual(1, LogList.Count); + Assert.IsTrue(LogList[0].Contains("Wheel-speed difference abs.")); + } + + + + [TestCase()] + public void TestWheelTorqueRatioExceeds_Left() + { + SetupLogging(); + + var torque = 300; + + var cycleEntries = string.Format( + @" 0 , 0, 600, 400, {0}, {0} , 50 , 50 , 100, 3 + 0.5 , 0, 600, 400, {0}, {0} , 50 , 50 , 100, 3 + 1 , 0, 600, 400, {0}, {1} , 50 , 50 , 100, 3 + 1.5 , 0, 600, 400, {1}, {1} , 50 , 50 , 100, 3 + ", torque, torque * DeclarationData.VTPMode.WheelTorqueDifferenceFactor * 1.1); + + var container = new VehicleContainer(ExecutionMode.Declaration) { + RunData = new VectoRunData() { + Aux = new List<VectoRunData.AuxData>() + } + }; + var cycle = InputDataHelper.InputDataAsStream(Header, cycleEntries.Split('\n')); + var cycleData = DrivingCycleDataReader.ReadFromDataTable(VectoCSVFile.ReadStream(cycle), "VTP Cycle", false); + var vtpCycle = new VTPCycle(container, cycleData); + + vtpCycle.VerifyInputData(); + + Assert.AreEqual(1, LogList.Count); + Assert.IsTrue(LogList[0].Contains("Torque difference rel.")); + } + + + [TestCase()] + public void TestWheelTorqueRatioExceeds_Right() + { + SetupLogging(); + + var torque = 300; + + var cycleEntries = string.Format( + @" 0 , 0, 600, 400, {0}, {0} , 50 , 50 , 100, 3 + 0.5 , 0, 600, 400, {0}, {0} , 50 , 50 , 100, 3 + 1 , 0, 600, 400, {1}, {0} , 50 , 50 , 100, 3 + 1.5 , 0, 600, 400, {1}, {1} , 50 , 50 , 100, 3 + ", torque, torque * DeclarationData.VTPMode.WheelTorqueDifferenceFactor * 1.1); + + var container = new VehicleContainer(ExecutionMode.Declaration) { + RunData = new VectoRunData() { + Aux = new List<VectoRunData.AuxData>() + } + }; + var cycle = InputDataHelper.InputDataAsStream(Header, cycleEntries.Split('\n')); + var cycleData = DrivingCycleDataReader.ReadFromDataTable(VectoCSVFile.ReadStream(cycle), "VTP Cycle", false); + var vtpCycle = new VTPCycle(container, cycleData); + + vtpCycle.VerifyInputData(); + + Assert.AreEqual(1, LogList.Count); + Assert.IsTrue(LogList[0].Contains("Torque difference rel.")); + } + + [TestCase()] + public void TestWheelTorqueDiffExceeds_Left() + { + SetupLogging(); + + var torque = 0.95*DeclarationData.VTPMode.WheelTorqueZeroTolerance.Value(); + + var cycleEntries = string.Format( + @" 0 , 0, 600, 400, {0}, {0} , 50 , 50 , 100, 3 + 0.5 , 0, 600, 400, {0}, {0} , 50 , 50 , 100, 3 + 1 , 0, 600, 400, {0}, {1} , 50 , 50 , 100, 3 + 1.5 , 0, 600, 400, {1}, {1} , 50 , 50 , 100, 3 + ", torque, torque + DeclarationData.VTPMode.MaxWheelTorqueZeroDifference.Value() * 1.1); + + var container = new VehicleContainer(ExecutionMode.Declaration) { + RunData = new VectoRunData() { + Aux = new List<VectoRunData.AuxData>() + } + }; + var cycle = InputDataHelper.InputDataAsStream(Header, cycleEntries.Split('\n')); + var cycleData = DrivingCycleDataReader.ReadFromDataTable(VectoCSVFile.ReadStream(cycle), "VTP Cycle", false); + var vtpCycle = new VTPCycle(container, cycleData); + + vtpCycle.VerifyInputData(); + + Assert.AreEqual(1, LogList.Count); + Assert.IsTrue(LogList[0].Contains("Torque difference abs.")); + } + + [TestCase()] + public void TestWheelTorqueDiffExceeds_Right() + { + SetupLogging(); + + var torque = 0.95 * DeclarationData.VTPMode.WheelTorqueZeroTolerance.Value(); + + var cycleEntries = string.Format( + @" 0 , 0, 600, 400, {0}, {0} , 50 , 50 , 100, 3 + 0.5 , 0, 600, 400, {0}, {0} , 50 , 50 , 100, 3 + 1 , 0, 600, 400, {1}, {0} , 50 , 50 , 100, 3 + 1.5 , 0, 600, 400, {1}, {1} , 50 , 50 , 100, 3 + ", torque, torque + DeclarationData.VTPMode.MaxWheelTorqueZeroDifference.Value() * 1.1); + + var container = new VehicleContainer(ExecutionMode.Declaration) { + RunData = new VectoRunData() { + Aux = new List<VectoRunData.AuxData>() + } + }; + var cycle = InputDataHelper.InputDataAsStream(Header, cycleEntries.Split('\n')); + var cycleData = DrivingCycleDataReader.ReadFromDataTable(VectoCSVFile.ReadStream(cycle), "VTP Cycle", false); + var vtpCycle = new VTPCycle(container, cycleData); + + vtpCycle.VerifyInputData(); + + Assert.AreEqual(1, LogList.Count); + Assert.IsTrue(LogList[0].Contains("Torque difference abs.")); + } + + [TestCase()] + public void TestFanSpeedTooLow() + { + SetupLogging(); + + var fanSpeed = 1.05 * DeclarationData.VTPMode.MinFanSpeed.AsRPM; + + var cycleEntries = string.Format( + @" 0 , 0, 600, {0}, 300 , 290 , 50 , 50 , 100, 3 + 0.5 , 0, 600, {0}, 300 , 290 , 50 , 50 , 100, 3 + 1 , 0, 600, {1}, 300 , 290 , 50 , 50 , 100, 3 + 1.5 , 0, 600, {0}, 300 , 290 , 50 , 50 , 100, 3 + ", fanSpeed, fanSpeed * 0.9); + + var container = new VehicleContainer(ExecutionMode.Declaration) { + RunData = new VectoRunData() { + Aux = new List<VectoRunData.AuxData>() { + new VectoRunData.AuxData() { + ID = Constants.Auxiliaries.IDs.Fan, + Technology = new List<string>() { "Crankshaft mounted - On/off clutch" } + } + } + } + }; + var cycle = InputDataHelper.InputDataAsStream(Header, cycleEntries.Split('\n')); + var cycleData = DrivingCycleDataReader.ReadFromDataTable(VectoCSVFile.ReadStream(cycle), "VTP Cycle", false); + var vtpCycle = new VTPCycle(container, cycleData); + vtpCycle.VerifyInputData(); + + Assert.AreEqual(1, LogList.Count); + Assert.IsTrue(LogList[0].Contains("Fan speed (non-electric) exceeds range")); + } + + [TestCase()] + public void TestFanSpeedTooHigh() + { + SetupLogging(); + + var fanSpeed = 0.95 * DeclarationData.VTPMode.MaxFanSpeed.AsRPM; + + var cycleEntries = string.Format( + @" 0 , 0, 600, {0}, 300 , 290 , 50 , 50 , 100, 3 + 0.5 , 0, 600, {0}, 300 , 290 , 50 , 50 , 100, 3 + 1 , 0, 600, {1}, 300 , 290 , 50 , 50 , 100, 3 + 1.5 , 0, 600, {0}, 300 , 290 , 50 , 50 , 100, 3 + ", fanSpeed, 1.1 * fanSpeed ); + + var container = new VehicleContainer(ExecutionMode.Declaration) { + RunData = new VectoRunData() { + Aux = new List<VectoRunData.AuxData>() { + new VectoRunData.AuxData() { + ID = Constants.Auxiliaries.IDs.Fan, + Technology = new List<string>() { "Crankshaft mounted - On/off clutch" } + } + } + } + }; + var cycle = InputDataHelper.InputDataAsStream(Header, cycleEntries.Split('\n')); + var cycleData = DrivingCycleDataReader.ReadFromDataTable(VectoCSVFile.ReadStream(cycle), "VTP Cycle", false); + var vtpCycle = new VTPCycle(container, cycleData); + vtpCycle.VerifyInputData(); + + Assert.AreEqual(1, LogList.Count); + Assert.IsTrue(LogList[0].Contains("Fan speed (non-electric) exceeds range")); + } + + + [TestCase()] + public void TestFanSpeedElectricLow() + { + SetupLogging(); + + var fanSpeed = 1.05 * DeclarationData.VTPMode.MinFanSpeed.AsRPM; + + var cycleEntries = string.Format( + @" 0 , 0, 600, {0}, 300 , 290 , 50 , 50 , 100, 3 + 0.5 , 0, 600, {0}, 300 , 290 , 50 , 50 , 100, 3 + 1 , 0, 600, {1}, 300 , 290 , 50 , 50 , 100, 3 + 1.5 , 0, 600, {0}, 300 , 290 , 50 , 50 , 100, 3 + ", fanSpeed, fanSpeed * 0.9); + + var container = new VehicleContainer(ExecutionMode.Declaration) { + RunData = new VectoRunData() { + Aux = new List<VectoRunData.AuxData>() { + new VectoRunData.AuxData() { + ID = Constants.Auxiliaries.IDs.Fan, + Technology = new List<string>() { "Electrically driven - Electronically controlled" } + } + } + } + }; + var cycle = InputDataHelper.InputDataAsStream(Header, cycleEntries.Split('\n')); + var cycleData = DrivingCycleDataReader.ReadFromDataTable(VectoCSVFile.ReadStream(cycle), "VTP Cycle", false); + var vtpCycle = new VTPCycle(container, cycleData); + vtpCycle.VerifyInputData(); + + Assert.AreEqual(0, LogList.Count); + } + + [TestCase()] + public void TestFanSpeedElectricHigh() + { + SetupLogging(); + + var fanSpeed = 0.95 * DeclarationData.VTPMode.MaxFanSpeed.AsRPM; + + var cycleEntries = string.Format( + @" 0 , 0, 600, {0}, 300 , 290 , 50 , 50 , 100, 3 + 0.5 , 0, 600, {0}, 300 , 290 , 50 , 50 , 100, 3 + 1 , 0, 600, {1}, 300 , 290 , 50 , 50 , 100, 3 + 1.5 , 0, 600, {0}, 300 , 290 , 50 , 50 , 100, 3 + ", fanSpeed, 1.1 * fanSpeed); + + var container = new VehicleContainer(ExecutionMode.Declaration) { + RunData = new VectoRunData() { + Aux = new List<VectoRunData.AuxData>() { + new VectoRunData.AuxData() { + ID = Constants.Auxiliaries.IDs.Fan, + Technology = new List<string>() { "Electrically driven - Electronically controlled" } + } + } + } + }; + var cycle = InputDataHelper.InputDataAsStream(Header, cycleEntries.Split('\n')); + var cycleData = DrivingCycleDataReader.ReadFromDataTable(VectoCSVFile.ReadStream(cycle), "VTP Cycle", false); + var vtpCycle = new VTPCycle(container, cycleData); + vtpCycle.VerifyInputData(); + + Assert.AreEqual(0, LogList.Count); + + } + + [TestCase()] + public void TestFuelConsumptionTooLow() + { + SetupLogging(); + + var fanSpeed = 0.95 * DeclarationData.VTPMode.MaxFanSpeed.AsRPM; + + var cycleEntries = ""; + for (var i = 0; i < 2000; i++) + cycleEntries += string.Format(" {0} , 0, 600, 400, 300 , 290 , 50 , 50 , {1}, 3 \n", i / 2.0, DeclarationData.VTPMode.LowerFCThreshold.ConvertToGrammPerHour() / 1.01); + + var container = new VehicleContainer(ExecutionMode.Declaration) { + RunData = new VectoRunData() { + Aux = new List<VectoRunData.AuxData>() + } + }; + var cycle = InputDataHelper.InputDataAsStream(Header, cycleEntries.Split('\n')); + var cycleData = DrivingCycleDataReader.ReadFromDataTable(VectoCSVFile.ReadStream(cycle), "VTP Cycle", false); + var vtpCycle = new VTPCycle(container, cycleData); + vtpCycle.VerifyInputData(); + + Assert.Greater(LogList.Count, 1); + + } + + [TestCase()] + public void TestFuelConsumptionLowOK() + { + SetupLogging(); + + var fanSpeed = 0.95 * DeclarationData.VTPMode.MaxFanSpeed.AsRPM; + + var cycleEntries = ""; + for (var i = 0; i < 2000; i++) + cycleEntries += string.Format(" {0} , 0, 600, 400, 300 , 290 , 50 , 50 , {1}, 3 \n", i / 2.0, DeclarationData.VTPMode.LowerFCThreshold.ConvertToGrammPerHour() * 1.01); + + var container = new VehicleContainer(ExecutionMode.Declaration) { + RunData = new VectoRunData() { + Aux = new List<VectoRunData.AuxData>() + } + }; + var cycle = InputDataHelper.InputDataAsStream(Header, cycleEntries.Split('\n')); + var cycleData = DrivingCycleDataReader.ReadFromDataTable(VectoCSVFile.ReadStream(cycle), "VTP Cycle", false); + var vtpCycle = new VTPCycle(container, cycleData); + vtpCycle.VerifyInputData(); + + Assert.AreEqual(0, LogList.Count); + + } + + [TestCase()] + public void TestFuelConsumptionTooHigh() + { + SetupLogging(); + + var fanSpeed = 0.95 * DeclarationData.VTPMode.MaxFanSpeed.AsRPM; + + var cycleEntries = ""; + for (var i = 0; i < 2000; i++) + cycleEntries += string.Format(" {0} , 0, 600, 400, 300 , 290 , 50 , 50 , {1}, 3 \n", i / 2.0, DeclarationData.VTPMode.UpperFCThreshold.ConvertToGrammPerHour() * 1.01); + + var container = new VehicleContainer(ExecutionMode.Declaration) { + RunData = new VectoRunData() { + Aux = new List<VectoRunData.AuxData>() + } + }; + var cycle = InputDataHelper.InputDataAsStream(Header, cycleEntries.Split('\n')); + var cycleData = DrivingCycleDataReader.ReadFromDataTable(VectoCSVFile.ReadStream(cycle), "VTP Cycle", false); + var vtpCycle = new VTPCycle(container, cycleData); + vtpCycle.VerifyInputData(); + + Assert.Greater(LogList.Count, 1); + + } + + [TestCase()] + public void TestFuelConsumptionHighOK() + { + SetupLogging(); + + var fanSpeed = 0.95 * DeclarationData.VTPMode.MaxFanSpeed.AsRPM; + + var cycleEntries = ""; + for (var i = 0; i < 2000; i++) + cycleEntries += string.Format(" {0} , 0, 600, 400, 300 , 290 , 50 , 50 , {1}, 3 \n", i / 2.0, DeclarationData.VTPMode.UpperFCThreshold.ConvertToGrammPerHour() / 1.01); + + var container = new VehicleContainer(ExecutionMode.Declaration) { + RunData = new VectoRunData() { + Aux = new List<VectoRunData.AuxData>() + } + }; + var cycle = InputDataHelper.InputDataAsStream(Header, cycleEntries.Split('\n')); + var cycleData = DrivingCycleDataReader.ReadFromDataTable(VectoCSVFile.ReadStream(cycle), "VTP Cycle", false); + var vtpCycle = new VTPCycle(container, cycleData); + vtpCycle.VerifyInputData(); + + Assert.AreEqual(0, LogList.Count); + + } + + private static void SetupLogging() + { + LogList.Clear(); + var target = new MethodCallTarget { + ClassName = typeof(VTPCycleValidationTest).AssemblyQualifiedName, + MethodName = "LogMethod" + }; + target.Parameters.Add(new MethodCallParameter("${level}")); + target.Parameters.Add(new MethodCallParameter("${message}")); + SimpleConfigurator.ConfigureForTargetLogging(target, LogLevel.Error); + } + + + // ReSharper disable once UnusedMember.Global -- used by logging framework, see SetupLogging method + public static void LogMethod(string level, string message) + { + LogList.Add(message); + } + } +} diff --git a/VectoCore/VectoCoreTest/TestData/Integration/VTPMode/GenericVehicle/Tractor_4x2_vehicle-class-5_Generic vehicle.xml b/VectoCore/VectoCoreTest/TestData/Integration/VTPMode/GenericVehicle/Tractor_4x2_vehicle-class-5_Generic vehicle.xml index dfa7c42f70..634a24cbb6 100644 --- a/VectoCore/VectoCoreTest/TestData/Integration/VTPMode/GenericVehicle/Tractor_4x2_vehicle-class-5_Generic vehicle.xml +++ b/VectoCore/VectoCoreTest/TestData/Integration/VTPMode/GenericVehicle/Tractor_4x2_vehicle-class-5_Generic vehicle.xml @@ -15,7 +15,7 @@ <AxleConfiguration>4x2</AxleConfiguration> <CurbMassChassis>7800</CurbMassChassis> <GrossVehicleMass>40000</GrossVehicleMass> - <IdlingSpeed>600</IdlingSpeed> + <IdlingSpeed>590</IdlingSpeed> <RetarderType>Transmission Output Retarder</RetarderType> <RetarderRatio>1.000</RetarderRatio> <AngledriveType>None</AngledriveType> @@ -32,7 +32,7 @@ <Date>2017-11-20T12:31:47.2109026Z</Date> <AppVersion>VectoCore</AppVersion> <Displacement>13000</Displacement> - <IdlingSpeed>600</IdlingSpeed> + <IdlingSpeed>590</IdlingSpeed> <RatedSpeed>1736</RatedSpeed> <RatedPower>325032</RatedPower> <MaxEngineTorque>2134</MaxEngineTorque> @@ -44,6 +44,18 @@ <CFNCV>1.0000</CFNCV> <FuelType>Diesel CI</FuelType> <FuelConsumptionMap> + <Entry engineSpeed="550.00" torque="-150.00" fuelConsumption="0.00" /> + <Entry engineSpeed="550.00" torque="0.00" fuelConsumption="1488.18" /> + <Entry engineSpeed="550.00" torque="216.90" fuelConsumption="3609.53" /> + <Entry engineSpeed="550.00" torque="433.80" fuelConsumption="6055.65" /> + <Entry engineSpeed="550.00" torque="650.70" fuelConsumption="8756.65" /> + <Entry engineSpeed="550.00" torque="867.60" fuelConsumption="10922.44" /> + <Entry engineSpeed="550.00" torque="1084.50" fuelConsumption="13315.08" /> + <Entry engineSpeed="550.00" torque="1301.40" fuelConsumption="15886.96" /> + <Entry engineSpeed="550.00" torque="1518.30" fuelConsumption="18459.52" /> + <Entry engineSpeed="550.00" torque="1735.20" fuelConsumption="21032.07" /> + <Entry engineSpeed="550.00" torque="1952.10" fuelConsumption="23604.64" /> + <Entry engineSpeed="550.00" torque="2169.00" fuelConsumption="26177.20" /> <Entry engineSpeed="600.00" torque="-150.00" fuelConsumption="0.00" /> <Entry engineSpeed="600.00" torque="0.00" fuelConsumption="1488.18" /> <Entry engineSpeed="600.00" torque="216.90" fuelConsumption="3609.53" /> diff --git a/VectoCore/VectoCoreTest/Utils/InputDataHelper.cs b/VectoCore/VectoCoreTest/Utils/InputDataHelper.cs index 17f6f39a52..c42ea75b75 100644 --- a/VectoCore/VectoCoreTest/Utils/InputDataHelper.cs +++ b/VectoCore/VectoCoreTest/Utils/InputDataHelper.cs @@ -29,23 +29,23 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System.IO; - -namespace TUGraz.VectoCore.Tests.Utils -{ - public class InputDataHelper - { - public static MemoryStream InputDataAsStream(string header, string[] entries) - { - var cycleData = new MemoryStream(); - var writer = new StreamWriter(cycleData); - writer.WriteLine(header); - foreach (var entry in entries) { - writer.WriteLine(entry); - } - writer.Flush(); - cycleData.Seek(0, SeekOrigin.Begin); - return cycleData; - } - } +using System.IO; + +namespace TUGraz.VectoCore.Tests.Utils +{ + public class InputDataHelper + { + public static MemoryStream InputDataAsStream(string header, string[] entries) + { + var cycleData = new MemoryStream(); + var writer = new StreamWriter(cycleData); + writer.WriteLine(header); + foreach (var entry in entries) { + writer.WriteLine(entry); + } + writer.Flush(); + cycleData.Seek(0, SeekOrigin.Begin); + return cycleData; + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCoreTest/VectoCoreTest.csproj b/VectoCore/VectoCoreTest/VectoCoreTest.csproj index 74e7cf04ef..177296fc13 100644 --- a/VectoCore/VectoCoreTest/VectoCoreTest.csproj +++ b/VectoCore/VectoCoreTest/VectoCoreTest.csproj @@ -105,6 +105,7 @@ <Compile Include="Models\SimulationComponent\ATGearboxTest.cs" /> <Compile Include="Models\SimulationComponent\EngineFanAuxTest.cs" /> <Compile Include="Models\SimulationComponent\GearboxShiftLossesTest.cs" /> + <Compile Include="Models\SimulationComponent\VTPCycleValidationTest.cs" /> <Compile Include="Models\Simulation\FactoryTest.cs" /> <Compile Include="Models\Simulation\PTOIdleLossTest.cs" /> <Compile Include="Models\Simulation\LossMapRangeValidationTest.cs" /> -- GitLab