diff --git a/VectoCommon/VectoCommon/Utils/EnumerableExtensionMethods.cs b/VectoCommon/VectoCommon/Utils/EnumerableExtensionMethods.cs index 46bdc339a4475b4ebfe5bed5c49bde4ca277ab2f..6efd1c9de48c082f7d83e240e2a8a7f1bd65c4c7 100644 --- a/VectoCommon/VectoCommon/Utils/EnumerableExtensionMethods.cs +++ b/VectoCommon/VectoCommon/Utils/EnumerableExtensionMethods.cs @@ -137,6 +137,26 @@ namespace TUGraz.VectoCommon.Utils return Tuple.Create(list[index], list[index + 1]); } + /// <summary> + /// Get the first two adjacent items where the predicate changes from true to false. + /// If the predicate is always false, the first 2 elements are returned. + /// If the predicate is always true, the last 2 elements are returned. + /// </summary> + public static Tuple<T, T> GetSection<T>(this T[] self, Func<T, bool> predicate) + { + var i = 0; + for (; i < self.Length; i++) { + if (!predicate(self[i])) + break; + } + if (i == 0) { + i = 1; + } else if (i == self.Length) { + i--; + } + return Tuple.Create(self[i - 1], self[i]); + } + /// <summary> /// Get the first two adjacent items where the predicate changes from true to false. /// If the predicate never gets true, the last 2 elements are returned. diff --git a/VectoCore/VectoCore/InputData/Reader/ComponentData/PTOIdleLossMapReader.cs b/VectoCore/VectoCore/InputData/Reader/ComponentData/PTOIdleLossMapReader.cs new file mode 100644 index 0000000000000000000000000000000000000000..0f68e375a926398cf0c109a123f83281db74f353 --- /dev/null +++ b/VectoCore/VectoCore/InputData/Reader/ComponentData/PTOIdleLossMapReader.cs @@ -0,0 +1,70 @@ +using System; +using System.Data; +using System.Linq; +using TUGraz.VectoCommon.Exceptions; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Models.SimulationComponent.Data; +using TUGraz.VectoCore.Utils; + +namespace TUGraz.VectoCore.InputData.Reader.ComponentData +{ + public static class PTOIdleLossMapReader + { + /// <summary> + /// Read the retarder loss map from a file. + /// </summary> + /// <param name="fileName"></param> + /// <returns></returns> + public static PTOIdleLossMap ReadFromFile(string fileName) + { + try { + return Create(VectoCSVFile.Read(fileName)); + } catch (Exception ex) { + throw new VectoException("ERROR while loading PTO Idle LossMap: " + ex.Message); + } + } + + /// <summary> + /// Create the pto idle loss map from an appropriate datatable. (2 columns: Engine Speed, PTO Torque) + /// </summary> + public static PTOIdleLossMap Create(DataTable data) + { + if (data.Columns.Count != 2) { + throw new VectoException("PTO Idle LossMap Data File must consist of 2 columns: {0}, {1}", Fields.EngineSpeed, + Fields.PTOTorque); + } + + if (data.Rows.Count < 2) { + throw new VectoException("PTO Idle LossMap must contain at least 2 entries."); + } + + if (!data.Columns.Contains(Fields.EngineSpeed) || !data.Columns.Contains(Fields.PTOTorque)) { + data.Columns[0].ColumnName = Fields.EngineSpeed; + data.Columns[1].ColumnName = Fields.PTOTorque; + LoggingObject.Logger<RetarderLossMap>().Warn( + "PTO Idle LossMap: Header Line is not valid. Expected: '{0}, {1}', Got: '{2}'. Falling back to column index.", + Fields.EngineSpeed, Fields.PTOTorque, ", ".Join(data.Columns.Cast<DataColumn>().Select(c => c.ColumnName))); + } + + return new PTOIdleLossMap(data.Rows.Cast<DataRow>() + .Select(row => new PTOIdleLossMap.Entry { + EngineSpeed = row.ParseDouble(Fields.EngineSpeed).RPMtoRad(), + PTOTorque = row.ParseDouble(Fields.PTOTorque).SI<NewtonMeter>() + }).OrderBy(e => e.EngineSpeed).ToArray()); + } + + private static class Fields + { + /// <summary> + /// [rpm] + /// </summary> + public const string EngineSpeed = "Engine Speed"; + + /// <summary> + /// [Nm] + /// </summary> + public const string PTOTorque = "PTO Torque"; + } + } +} \ No newline at end of file diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Data/PTOIdleLossMap.cs b/VectoCore/VectoCore/Models/SimulationComponent/Data/PTOIdleLossMap.cs new file mode 100644 index 0000000000000000000000000000000000000000..f04dbb04e33273513b83a53d076144a817561c2a --- /dev/null +++ b/VectoCore/VectoCore/Models/SimulationComponent/Data/PTOIdleLossMap.cs @@ -0,0 +1,36 @@ +using System.ComponentModel.DataAnnotations; +using TUGraz.VectoCommon.Utils; + +namespace TUGraz.VectoCore.Models.SimulationComponent.Data +{ + /// <summary> + /// LossMap for PTO Idle losses. + /// </summary> + public class PTOIdleLossMap : SimulationComponentData + { + [ValidateObject] private readonly Entry[] _entries; + + protected internal PTOIdleLossMap(Entry[] entries) + { + _entries = entries; + } + + /// <summary> + /// Calculates the pto torque loss. + /// </summary> + /// <param name="angularVelocity"></param> + /// <returns></returns> + public NewtonMeter PTOTorqueLoss(PerSecond angularVelocity) + { + var s = _entries.GetSection(e => e.EngineSpeed < angularVelocity); + return VectoMath.Interpolate(s.Item1.EngineSpeed, s.Item2.EngineSpeed, s.Item1.PTOTorque, s.Item2.PTOTorque, + angularVelocity); + } + + public class Entry + { + [Required, SIRange(0, double.MaxValue)] public PerSecond EngineSpeed; + [Required, SIRange(0, 1000)] public NewtonMeter PTOTorque; + } + } +} \ No newline at end of file diff --git a/VectoCore/VectoCore/VectoCore.csproj b/VectoCore/VectoCore/VectoCore.csproj index 65809cc45e896b2a87586ddcfd263b2d516de534..8e49b34e5a851907890068154e8b7a43552b32ec 100644 --- a/VectoCore/VectoCore/VectoCore.csproj +++ b/VectoCore/VectoCore/VectoCore.csproj @@ -117,6 +117,7 @@ <Compile Include="InputData\FileIO\JSON\JSONInputDataFactory.cs" /> <Compile Include="InputData\FileIO\JSON\JSONVehicleData.cs" /> <Compile Include="InputData\IVectoRunDataFactory.cs" /> + <Compile Include="InputData\Reader\ComponentData\PTOIdleLossMapReader.cs" /> <Compile Include="InputData\Reader\DataObjectAdapter\AbstractSimulationDataAdapter.cs" /> <Compile Include="InputData\Reader\DataObjectAdapter\DeclarationDataAdapter.cs" /> <Compile Include="InputData\Reader\DataObjectAdapter\EngineeringDataAdapter.cs" /> @@ -140,6 +141,7 @@ <Compile Include="InputData\Reader\ComponentData\TorqueConverterDataReader.cs" /> <Compile Include="InputData\Reader\ComponentData\AuxiliaryDataReader.cs" /> <Compile Include="Models\SimulationComponent\Data\Engine\FuelConsumptionMapReader.cs" /> + <Compile Include="Models\SimulationComponent\Data\PTOIdleLossMap.cs" /> <Compile Include="Utils\ProviderExtensions.cs" /> <Compile Include="Models\Declaration\AirDrag.cs" /> <Compile Include="Models\Declaration\Fan.cs" />