diff --git a/.gitignore b/.gitignore index 3465df3450809b5de0771313c41e45a5bc60f548..802d8393ef028d7fc7c5294ce6ee481b391c67ae 100644 --- a/.gitignore +++ b/.gitignore @@ -202,3 +202,5 @@ Coverage/ Documentation/VehiclesReleaseComparisonDeclarationMode/*.vmod Documentation/VehiclesReleaseComparisonDeclarationMode/*.vsum +HashingTool/TestData/ +EPTP/ diff --git a/VectoCore/VectoCore/InputData/Reader/ShiftStrategy/PredictionDurationLookupReader.cs b/VectoCore/VectoCore/InputData/Reader/ShiftStrategy/PredictionDurationLookupReader.cs new file mode 100644 index 0000000000000000000000000000000000000000..a9d7b69f5a82e24157f5960eece684a41ec47f39 --- /dev/null +++ b/VectoCore/VectoCore/InputData/Reader/ShiftStrategy/PredictionDurationLookupReader.cs @@ -0,0 +1,78 @@ +using System; +using System.Data; +using System.IO; +using System.Linq; +using TUGraz.VectoCommon.Exceptions; +using TUGraz.VectoCommon.InputData; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCore.InputData.Reader.ComponentData; +using TUGraz.VectoCore.Models.SimulationComponent.Data; +using TUGraz.VectoCore.Models.SimulationComponent.Data.ShiftStrategy; +using TUGraz.VectoCore.Utils; + +namespace TUGraz.VectoCore.InputData.Reader.ShiftStrategy +{ + public static class PredictionDurationLookupReader + { + public static PredictionDurationLookup ReadFromStream(Stream stream) + { + var data = VectoCSVFile.ReadStream(stream); + return Create(data); + } + + public static PredictionDurationLookup ReadFromFile(string filename) + { + try { + var data = VectoCSVFile.Read(filename); + return Create(data); + } catch (Exception e) { + throw new VectoException("Error while reading ShiftStrategy PredictionDurationLookup File: " + e.Message); + } + } + + private static PredictionDurationLookup Create(TableData data) + { + if (data.Columns.Count != 2) { + throw new VectoException("ShiftStrategy PredictionDuration must consist of 2 columns."); + } + + if (data.Rows.Count < 2) { + throw new VectoException("ShiftStrategy PredictionDuration must consist of at least two rows."); + } + + if (!HeaderIsValid(data.Columns)) { + LoggingObject.Logger<PredictionDurationLookup>() + .Warn( + "ShiftStrategy PredictionDuration Curve: Header Line is not valid. Expected: '{0}, {1}', Got: {3}", + Fields.SpeedRatio, Fields.PredictionTimeRatio, + string.Join(", ", data.Columns.Cast<DataColumn>().Select(c => c.ColumnName))); + + data.Columns[0].Caption = Fields.SpeedRatio; + data.Columns[1].Caption = Fields.PredictionTimeRatio; + } + + return new PredictionDurationLookup( + data.Rows.Cast<DataRow>() + .Select( + r => new PredictionDurationLookup.Entry() { + SpeedRatio = r.ParseDouble(Fields.SpeedRatio), + PredictionTimeRatio = r.ParseDouble(Fields.PredictionTimeRatio) + }) + .OrderBy(x => x.SpeedRatio) + .ToList()); + } + + private static bool HeaderIsValid(DataColumnCollection columns) + { + return columns.Contains(Fields.SpeedRatio) && + columns.Contains(Fields.PredictionTimeRatio); + } + + public static class Fields + { + public const string SpeedRatio = "v_post/v_curr"; + + public const string PredictionTimeRatio = "dt_pred/dt_shift"; + } + } +} diff --git a/VectoCore/VectoCore/Models/Simulation/Data/ShiftStrategyParameters.cs b/VectoCore/VectoCore/Models/Simulation/Data/ShiftStrategyParameters.cs new file mode 100644 index 0000000000000000000000000000000000000000..eaa913769f70495058e6eed920bf87bd5fb2d3fb --- /dev/null +++ b/VectoCore/VectoCore/Models/Simulation/Data/ShiftStrategyParameters.cs @@ -0,0 +1,8 @@ +using TUGraz.VectoCore.Models.SimulationComponent.Data.ShiftStrategy; + +namespace TUGraz.VectoCore.Models.Simulation.Data { + public class ShiftStrategyParameters + { + public PredictionDurationLookup PredictionDurationLookup { get; internal set; } + } +} \ No newline at end of file diff --git a/VectoCore/VectoCore/Models/Simulation/Data/VectoRunData.cs b/VectoCore/VectoCore/Models/Simulation/Data/VectoRunData.cs index 21cfcb0a6f79ecf87b4841cdf21d8030ef374f06..68b1d5586697a26691e12d94a11fb0776aab5da3 100644 --- a/VectoCore/VectoCore/Models/Simulation/Data/VectoRunData.cs +++ b/VectoCore/VectoCore/Models/Simulation/Data/VectoRunData.cs @@ -110,6 +110,8 @@ namespace TUGraz.VectoCore.Models.Simulation.Data public VTPData VTPData { get; set; } + public ShiftStrategyParameters GearshiftParameters { get; set; } + public class AuxData { // ReSharper disable once InconsistentNaming diff --git a/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs b/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs index 9bb55807a74ac487f67691393616b506646e8580..84318f94e59223fb3b19dc1f9bf092d95259cb22 100644 --- a/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs +++ b/VectoCore/VectoCore/Models/Simulation/Impl/PowertrainBuilder.cs @@ -353,7 +353,7 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl IShiftStrategy strategy; switch (runData.GearboxData.Type) { case GearboxType.AMT: - strategy = new AMTShiftStrategy(runData, container); + strategy = new AMTShiftStrategyV2(runData, container); break; case GearboxType.MT: strategy = new MTShiftStrategy(runData, container); diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Data/AccelerationCurve.cs b/VectoCore/VectoCore/Models/SimulationComponent/Data/AccelerationCurve.cs index 97aa23fab09fea8b3d5a6f64488cee374ffc280e..d9cd748cd32b25a93a161709900b26fecfddf866 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Data/AccelerationCurve.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Data/AccelerationCurve.cs @@ -29,140 +29,140 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Diagnostics; -using System.Linq; -using TUGraz.VectoCommon.Utils; - -namespace TUGraz.VectoCore.Models.SimulationComponent.Data -{ - public class AccelerationCurveData : SimulationComponentData - { - [Required, ValidateObject] private readonly List<KeyValuePair<MeterPerSecond, AccelerationEntry>> _entries; - - protected internal AccelerationCurveData(List<KeyValuePair<MeterPerSecond, AccelerationEntry>> entries) - { - _entries = entries; - var smallValues = _entries.Where(e => e.Key < 5.KMPHtoMeterPerSecond()).OrderBy(e => e.Key).ToList(); - if (smallValues.Count >= 2) { - Log.Error("Found small velocity entries in Driver-Acceleration/Deceleration file. Values dismissed:" + - string.Join(", ", smallValues.Skip(1).Select(e => e.Key.AsKmph.ToString("F1")))); - foreach (var kv in smallValues.Skip(1)) { - _entries.Remove(kv); - } - } - } - - public AccelerationEntry Lookup(MeterPerSecond key) - { - var index = FindIndex(key); - - return new AccelerationEntry { - Acceleration = - VectoMath.Interpolate(_entries[index - 1].Key, _entries[index].Key, - _entries[index - 1].Value.Acceleration, - _entries[index].Value.Acceleration, key), - Deceleration = - VectoMath.Interpolate(_entries[index - 1].Key, _entries[index].Key, - _entries[index - 1].Value.Deceleration, - _entries[index].Value.Deceleration, key) - }; - } - - protected int FindIndex(MeterPerSecond key) - { - var index = 1; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Diagnostics; +using System.Linq; +using TUGraz.VectoCommon.Utils; + +namespace TUGraz.VectoCore.Models.SimulationComponent.Data +{ + public class AccelerationCurveData : SimulationComponentData + { + [Required, ValidateObject] private readonly List<KeyValuePair<MeterPerSecond, AccelerationEntry>> _entries; + + protected internal AccelerationCurveData(List<KeyValuePair<MeterPerSecond, AccelerationEntry>> entries) + { + _entries = entries; + var smallValues = _entries.Where(e => e.Key < 5.KMPHtoMeterPerSecond()).OrderBy(e => e.Key).ToList(); + if (smallValues.Count >= 2) { + Log.Error("Found small velocity entries in Driver-Acceleration/Deceleration file. Values dismissed:" + + string.Join(", ", smallValues.Skip(1).Select(e => e.Key.AsKmph.ToString("F1")))); + foreach (var kv in smallValues.Skip(1)) { + _entries.Remove(kv); + } + } + } + + public AccelerationEntry Lookup(MeterPerSecond key) + { + var index = FindIndex(key); + + return new AccelerationEntry { + Acceleration = + VectoMath.Interpolate(_entries[index - 1].Key, _entries[index].Key, + _entries[index - 1].Value.Acceleration, + _entries[index].Value.Acceleration, key), + Deceleration = + VectoMath.Interpolate(_entries[index - 1].Key, _entries[index].Key, + _entries[index - 1].Value.Deceleration, + _entries[index].Value.Deceleration, key) + }; + } + + protected int FindIndex(MeterPerSecond key) + { + var index = 1; if (key < _entries[0].Key) { Log.Error("requested velocity below minimum - extrapolating. velocity: {0}, min: {1}", key.ConvertToKiloMeterPerHour(), _entries[0].Key.ConvertToKiloMeterPerHour()); - } else { - index = _entries.FindIndex(x => x.Key > key); - if (index <= 0) { - index = key > _entries[0].Key ? _entries.Count - 1 : 1; - } - } - return index; - } - - public MeterPerSquareSecond MaxDeceleration() - { - return _entries.Min(x => x.Value.Deceleration); - } - - public MeterPerSquareSecond MaxAcceleration() - { - return _entries.Max(x => x.Value.Acceleration); - } - - [DebuggerDisplay("Acceleration: {Acceleration}, Deceleration: {Deceleration}")] - public class AccelerationEntry - { - [Required, SIRange(0.05, 20)] - public MeterPerSquareSecond Acceleration { get; set; } - - [Required, SIRange(-20, -0.05)] - public MeterPerSquareSecond Deceleration { get; set; } - } - - /// <summary> - /// - /// </summary> - /// <param name="v1">current speed of the vehicle</param> - /// <param name="v2">desired speed of the vehicle at the end of acceleration/deceleration phase</param> - /// <returns>distance required to accelerate/decelerate the vehicle from v1 to v2 according to the acceleration curve</returns> - public Meter ComputeAccelerationDistance(MeterPerSecond v1, MeterPerSecond v2) - { - var index1 = FindIndex(v1); - var index2 = FindIndex(v2); - - var distance = 0.SI<Meter>(); - for (var i = index2; i <= index1; i++) { - distance += ComputeAccelerationSegmentDistance(i, v1, v2); - } - return distance; - } - - /// <summary> - /// - /// </summary> - /// <param name="i">segment of the acceleration curve to use [(i-1) ... i]</param> - /// <param name="v1">current speed of the vehicle</param> - /// <param name="v2">desired speed of the vehicle at the end of acceleration/deceleration phase</param> - /// <returns>distance required to accelerate/decelerate the vehicle from v1 to v2 according to the acceleration curve</returns> - private Meter ComputeAccelerationSegmentDistance(int i, MeterPerSecond v1, MeterPerSecond v2) - { - var leftEntry = _entries[i - 1]; // entry with lower velocity - var rightEntry = _entries[i]; // entry with higher velocity - - v2 = VectoMath.Max(v2, leftEntry.Key); // min. velocity within current segment - v1 = VectoMath.Min(v1, rightEntry.Key); // max. velocity within current segment - - if (leftEntry.Value.Deceleration.IsEqual(rightEntry.Value.Deceleration)) { - // v(t) = a * t + v1 => t = (v2 - v1) / a - // s(t) = a/2 * t^2 + v1 * t + s0 {s0 == 0} => s(t) - var acceleration = v2 > v1 ? leftEntry.Value.Acceleration : leftEntry.Value.Deceleration; - return ((v2 - v1) * (v2 - v1) / 2.0 / acceleration + v1 * (v2 - v1) / acceleration).Cast<Meter>(); - } - - // a(v) = k * v + d - // dv/dt = a(v) = d * v + d ==> v(t) = sgn(k * v1 + d) * exp(-k * c) / k * exp(t * k) - d / k - // v(0) = v1 => c = - ln(|v1 * k + d|) / k - // v(t) = (v1 + d / k) * exp(t * k) - d / k => t = 1 / k * ln((v2 * k + d) / (v1 * k + d)) - // s(t) = m / k* exp(t * k) + b * t + c' {m = v1 + d / k, b = -d / k} - - var k = (leftEntry.Value.Deceleration - rightEntry.Value.Deceleration) / (leftEntry.Key - rightEntry.Key); - var d = leftEntry.Value.Deceleration - k * leftEntry.Key; - if (v2 > v1) { - k = (leftEntry.Value.Acceleration - rightEntry.Value.Acceleration) / (leftEntry.Key - rightEntry.Key); - d = leftEntry.Value.Acceleration - k * leftEntry.Key; - } - var m = v1 + d / k; - var b = -d / k; - var c = 0.SI<Meter>() - m / k; - var t = Math.Log(((v2 * k + d) / (v1 * k + d)).Cast<Scalar>()) / k; - return m / k * Math.Exp((k * t).Value()) + b * t + c; - } - } + } else { + index = _entries.FindIndex(x => x.Key > key); + if (index <= 0) { + index = key > _entries[0].Key ? _entries.Count - 1 : 1; + } + } + return index; + } + + public MeterPerSquareSecond MaxDeceleration() + { + return _entries.Min(x => x.Value.Deceleration); + } + + public MeterPerSquareSecond MaxAcceleration() + { + return _entries.Max(x => x.Value.Acceleration); + } + + [DebuggerDisplay("Acceleration: {Acceleration}, Deceleration: {Deceleration}")] + public class AccelerationEntry + { + [Required, SIRange(0.05, 20)] + public MeterPerSquareSecond Acceleration { get; set; } + + [Required, SIRange(-20, -0.05)] + public MeterPerSquareSecond Deceleration { get; set; } + } + + /// <summary> + /// + /// </summary> + /// <param name="v1">current speed of the vehicle</param> + /// <param name="v2">desired speed of the vehicle at the end of acceleration/deceleration phase</param> + /// <returns>distance required to accelerate/decelerate the vehicle from v1 to v2 according to the acceleration curve</returns> + public Meter ComputeAccelerationDistance(MeterPerSecond v1, MeterPerSecond v2) + { + var index1 = FindIndex(v1); + var index2 = FindIndex(v2); + + var distance = 0.SI<Meter>(); + for (var i = index2; i <= index1; i++) { + distance += ComputeAccelerationSegmentDistance(i, v1, v2); + } + return distance; + } + + /// <summary> + /// + /// </summary> + /// <param name="i">segment of the acceleration curve to use [(i-1) ... i]</param> + /// <param name="v1">current speed of the vehicle</param> + /// <param name="v2">desired speed of the vehicle at the end of acceleration/deceleration phase</param> + /// <returns>distance required to accelerate/decelerate the vehicle from v1 to v2 according to the acceleration curve</returns> + private Meter ComputeAccelerationSegmentDistance(int i, MeterPerSecond v1, MeterPerSecond v2) + { + var leftEntry = _entries[i - 1]; // entry with lower velocity + var rightEntry = _entries[i]; // entry with higher velocity + + v2 = VectoMath.Max(v2, leftEntry.Key); // min. velocity within current segment + v1 = VectoMath.Min(v1, rightEntry.Key); // max. velocity within current segment + + if (leftEntry.Value.Deceleration.IsEqual(rightEntry.Value.Deceleration)) { + // v(t) = a * t + v1 => t = (v2 - v1) / a + // s(t) = a/2 * t^2 + v1 * t + s0 {s0 == 0} => s(t) + var acceleration = v2 > v1 ? leftEntry.Value.Acceleration : leftEntry.Value.Deceleration; + return ((v2 - v1) * (v2 - v1) / 2.0 / acceleration + v1 * (v2 - v1) / acceleration).Cast<Meter>(); + } + + // a(v) = k * v + d + // dv/dt = a(v) = d * v + d ==> v(t) = sgn(k * v1 + d) * exp(-k * c) / k * exp(t * k) - d / k + // v(0) = v1 => c = - ln(|v1 * k + d|) / k + // v(t) = (v1 + d / k) * exp(t * k) - d / k => t = 1 / k * ln((v2 * k + d) / (v1 * k + d)) + // s(t) = m / k* exp(t * k) + b * t + c' {m = v1 + d / k, b = -d / k} + + var k = (leftEntry.Value.Deceleration - rightEntry.Value.Deceleration) / (leftEntry.Key - rightEntry.Key); + var d = leftEntry.Value.Deceleration - k * leftEntry.Key; + if (v2 > v1) { + k = (leftEntry.Value.Acceleration - rightEntry.Value.Acceleration) / (leftEntry.Key - rightEntry.Key); + d = leftEntry.Value.Acceleration - k * leftEntry.Key; + } + var m = v1 + d / k; + var b = -d / k; + var c = 0.SI<Meter>() - m / k; + var t = Math.Log(((v2 * k + d) / (v1 * k + d)).Cast<Scalar>()) / k; + return m / k * Math.Exp((k * t).Value()) + b * t + c; + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Data/Gearbox/GearData.cs b/VectoCore/VectoCore/Models/SimulationComponent/Data/Gearbox/GearData.cs index 739dd37e2300dd9d3ca20a832a9b932d9f4f0678..602fc709c8b79149e60c470b29adde3f9fb46d6b 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Data/Gearbox/GearData.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Data/Gearbox/GearData.cs @@ -29,70 +29,70 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System.ComponentModel.DataAnnotations; -using System.Linq; -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCommon.Utils; - -namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox -{ - public class TransmissionData - { - [ValidateObject] - public TransmissionLossMap LossMap { get; internal set; } - - [Required, RangeOrNaN(double.Epsilon, 25)] - public double Ratio { get; internal set; } - } - - [CustomValidation(typeof(GearData), "ValidateGearData")] - public class GearData : TransmissionData - { - public GearData() - { - TorqueConverterRatio = double.NaN; - } - - public bool HasTorqueConverter - { - get { return !double.IsNaN(TorqueConverterRatio) && TorqueConverterGearLossMap != null; } - } - - public bool HasLockedGear - { - get { return !double.IsNaN(Ratio) && LossMap != null; } - } - - [ValidateObject] - public ShiftPolygon ShiftPolygon { get; internal set; } - - public double TorqueConverterRatio { get; internal set; } - - public TransmissionLossMap TorqueConverterGearLossMap { get; internal set; } - - public PerSecond MaxSpeed { get; internal set; } - - public ShiftPolygon TorqueConverterShiftPolygon { get; set; } - - // ReSharper disable once UnusedMember.Global -- used via validation - public static ValidationResult ValidateGearData(GearData gearData, ValidationContext context) - { - var validationService = - context.GetService(typeof(VectoValidationModeServiceContainer)) as VectoValidationModeServiceContainer; - var mode = validationService != null ? validationService.Mode : ExecutionMode.Declaration; - var gbxType = validationService != null ? validationService.GearboxType : GearboxType.MT; - var emsMission = validationService != null && validationService.IsEMSCycle; - - if (gearData.HasTorqueConverter) { - if (gearData.TorqueConverterShiftPolygon == null) { - return new ValidationResult("Shift Polygon for Torque Converter Gear required!"); - } - var result = gearData.TorqueConverterShiftPolygon.Validate(mode, gbxType, emsMission); - if (result.Any()) { - return new ValidationResult("Validation of GearData failed", result.Select(x => x.ErrorMessage)); - } - } - return ValidationResult.Success; - } - } +using System.ComponentModel.DataAnnotations; +using System.Linq; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; + +namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox +{ + public class TransmissionData + { + [ValidateObject] + public TransmissionLossMap LossMap { get; internal set; } + + [Required, RangeOrNaN(double.Epsilon, 25)] + public double Ratio { get; internal set; } + } + + [CustomValidation(typeof(GearData), "ValidateGearData")] + public class GearData : TransmissionData + { + public GearData() + { + TorqueConverterRatio = double.NaN; + } + + public bool HasTorqueConverter + { + get { return !double.IsNaN(TorqueConverterRatio) && TorqueConverterGearLossMap != null; } + } + + public bool HasLockedGear + { + get { return !double.IsNaN(Ratio) && LossMap != null; } + } + + [ValidateObject] + public ShiftPolygon ShiftPolygon { get; internal set; } + + public double TorqueConverterRatio { get; internal set; } + + public TransmissionLossMap TorqueConverterGearLossMap { get; internal set; } + + public PerSecond MaxSpeed { get; internal set; } + + public ShiftPolygon TorqueConverterShiftPolygon { get; set; } + + // ReSharper disable once UnusedMember.Global -- used via validation + public static ValidationResult ValidateGearData(GearData gearData, ValidationContext context) + { + var validationService = + context.GetService(typeof(VectoValidationModeServiceContainer)) as VectoValidationModeServiceContainer; + var mode = validationService != null ? validationService.Mode : ExecutionMode.Declaration; + var gbxType = validationService != null ? validationService.GearboxType : GearboxType.MT; + var emsMission = validationService != null && validationService.IsEMSCycle; + + if (gearData.HasTorqueConverter) { + if (gearData.TorqueConverterShiftPolygon == null) { + return new ValidationResult("Shift Polygon for Torque Converter Gear required!"); + } + var result = gearData.TorqueConverterShiftPolygon.Validate(mode, gbxType, emsMission); + if (result.Any()) { + return new ValidationResult("Validation of GearData failed", result.Select(x => x.ErrorMessage)); + } + } + return ValidationResult.Success; + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Data/GearboxData.cs b/VectoCore/VectoCore/Models/SimulationComponent/Data/GearboxData.cs index a4eca6c9b870f8defb0ff5006e6023f417d43ef0..552224c3b99b05704bcf2cec4473f4f4c348dc48 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Data/GearboxData.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Data/GearboxData.cs @@ -29,108 +29,108 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Diagnostics; -using System.Linq; -using System.Runtime.Serialization; -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox; - -namespace TUGraz.VectoCore.Models.SimulationComponent.Data -{ - /// <summary> - /// Class for Gearbox Data. Gears can be accessed via Gears-Dictionary and range from 1 upwards. - /// </summary> - /// <remarks>The Axle Gear has its own Property "AxleGearData" and is *not included* in the Gears-Dictionary.</remarks> - [DataContract, CustomValidation(typeof(GearboxData), "ValidateGearboxData")] - [DebuggerDisplay("GearboxData({Type}, #Gears: {Gears.Count}, ...)")] - public class GearboxData : SimulationComponentData - { - public GearboxType Type { get; internal set; } - - [Required, ValidateObject] public Dictionary<uint, GearData> Gears = new Dictionary<uint, GearData>(); - - public TorqueConverterData TorqueConverterData { get; internal set; } - - [Required, SIRange(0, 10)] - public KilogramSquareMeter Inertia { get; internal set; } - - [Required, SIRange(0, 5)] - public Second TractionInterruption { get; internal set; } - - /// <summary> - /// [%] (0-1) The torque reserve for shift strategy (early upshift, skipgears) - /// </summary> - [Required, Range(0, 0.5)] - public double TorqueReserve { get; internal set; } - - /// <summary> - /// Gets the minimum time between shifts. - /// </summary> - [Required, SIRange(0, 5)] - public Second ShiftTime { get; internal set; } - - /// <summary> - /// [%] (0-1) The starting torque reserve for finding the starting gear after standstill. - /// </summary> - [Required, Range(0, 0.5)] - public double StartTorqueReserve { get; internal set; } - - // MQ: TODO: move to Driver Data ? - [Required, SIRange(double.Epsilon, 5)] - public MeterPerSecond StartSpeed { get; internal set; } - - // MQ: TODO: move to Driver Data ? - [Required, SIRange(double.Epsilon, 2)] - public MeterPerSquareSecond StartAcceleration { get; internal set; } - - [Required, SIRange(0, double.MaxValue)] - public Second UpshiftAfterDownshiftDelay { get; internal set; } - - [Required, SIRange(0, double.MaxValue)] - public Second DownshiftAfterUpshiftDelay { get; internal set; } - - [Required, SIRange(0, double.MaxValue)] - public MeterPerSquareSecond UpshiftMinAcceleration { get; internal set; } - - [SIRange(0.5, 1)] - public Second PowershiftShiftTime { get; internal set; } - - // ReSharper disable once UnusedMember.Global -- used via Validation - public static ValidationResult ValidateGearboxData(GearboxData gearboxData, ValidationContext validationContext) - { - var mode = GetExecutionMode(validationContext); - //var gbxType = GetGearboxType(validationContext); - var emsMission = GetEmsMode(validationContext); - - var result = new List<ValidationResult>(); - - if (gearboxData.Gears.Any(g => g.Value.HasTorqueConverter)) { - if (!gearboxData.Type.AutomaticTransmission()) { - return new ValidationResult("Torque Converter can only be used with AT gearbox model"); - } - } else { - if (gearboxData.Type.AutomaticTransmission()) { - return new ValidationResult("AT gearbox model requires torque converter"); - } - } - if (gearboxData.Type.AutomaticTransmission()) { - gearboxData.TorqueConverterData.RequiredSpeedRatio = - Math.Round(gearboxData.Gears[1].TorqueConverterRatio / gearboxData.Gears[1].Ratio, 4) * 0.95; - result.AddRange(gearboxData.TorqueConverterData.Validate(mode, gearboxData.Type, emsMission)); - //result.AddRange(gearboxData.PowershiftShiftTime.Validate(mode, gearboxData.Type)); - //result.AddRange(gearboxData.PowershiftInertiaFactor.Validate(mode, gearboxData.Type)); - validationContext.MemberName = "PowershiftShiftTime"; - Validator.TryValidateProperty(gearboxData.PowershiftShiftTime, validationContext, result); - } - - if (result.Any()) { - return new ValidationResult("Validation of Gearbox Data failed", result.Select(x => x.ErrorMessage)); - } - return ValidationResult.Success; - } - } +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Diagnostics; +using System.Linq; +using System.Runtime.Serialization; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox; + +namespace TUGraz.VectoCore.Models.SimulationComponent.Data +{ + /// <summary> + /// Class for Gearbox Data. Gears can be accessed via Gears-Dictionary and range from 1 upwards. + /// </summary> + /// <remarks>The Axle Gear has its own Property "AxleGearData" and is *not included* in the Gears-Dictionary.</remarks> + [DataContract, CustomValidation(typeof(GearboxData), "ValidateGearboxData")] + [DebuggerDisplay("GearboxData({Type}, #Gears: {Gears.Count}, ...)")] + public class GearboxData : SimulationComponentData + { + public GearboxType Type { get; internal set; } + + [Required, ValidateObject] public Dictionary<uint, GearData> Gears = new Dictionary<uint, GearData>(); + + public TorqueConverterData TorqueConverterData { get; internal set; } + + [Required, SIRange(0, 10)] + public KilogramSquareMeter Inertia { get; internal set; } + + [Required, SIRange(0, 5)] + public Second TractionInterruption { get; internal set; } + + /// <summary> + /// [%] (0-1) The torque reserve for shift strategy (early upshift, skipgears) + /// </summary> + [Required, Range(0, 0.5)] + public double TorqueReserve { get; internal set; } + + /// <summary> + /// Gets the minimum time between shifts. + /// </summary> + [Required, SIRange(0, 5)] + public Second ShiftTime { get; internal set; } + + /// <summary> + /// [%] (0-1) The starting torque reserve for finding the starting gear after standstill. + /// </summary> + [Required, Range(0, 0.5)] + public double StartTorqueReserve { get; internal set; } + + // MQ: TODO: move to Driver Data ? + [Required, SIRange(double.Epsilon, 5)] + public MeterPerSecond StartSpeed { get; internal set; } + + // MQ: TODO: move to Driver Data ? + [Required, SIRange(double.Epsilon, 2)] + public MeterPerSquareSecond StartAcceleration { get; internal set; } + + [Required, SIRange(0, double.MaxValue)] + public Second UpshiftAfterDownshiftDelay { get; internal set; } + + [Required, SIRange(0, double.MaxValue)] + public Second DownshiftAfterUpshiftDelay { get; internal set; } + + [Required, SIRange(0, double.MaxValue)] + public MeterPerSquareSecond UpshiftMinAcceleration { get; internal set; } + + [SIRange(0.5, 1)] + public Second PowershiftShiftTime { get; internal set; } + + // ReSharper disable once UnusedMember.Global -- used via Validation + public static ValidationResult ValidateGearboxData(GearboxData gearboxData, ValidationContext validationContext) + { + var mode = GetExecutionMode(validationContext); + //var gbxType = GetGearboxType(validationContext); + var emsMission = GetEmsMode(validationContext); + + var result = new List<ValidationResult>(); + + if (gearboxData.Gears.Any(g => g.Value.HasTorqueConverter)) { + if (!gearboxData.Type.AutomaticTransmission()) { + return new ValidationResult("Torque Converter can only be used with AT gearbox model"); + } + } else { + if (gearboxData.Type.AutomaticTransmission()) { + return new ValidationResult("AT gearbox model requires torque converter"); + } + } + if (gearboxData.Type.AutomaticTransmission()) { + gearboxData.TorqueConverterData.RequiredSpeedRatio = + Math.Round(gearboxData.Gears[1].TorqueConverterRatio / gearboxData.Gears[1].Ratio, 4) * 0.95; + result.AddRange(gearboxData.TorqueConverterData.Validate(mode, gearboxData.Type, emsMission)); + //result.AddRange(gearboxData.PowershiftShiftTime.Validate(mode, gearboxData.Type)); + //result.AddRange(gearboxData.PowershiftInertiaFactor.Validate(mode, gearboxData.Type)); + validationContext.MemberName = "PowershiftShiftTime"; + Validator.TryValidateProperty(gearboxData.PowershiftShiftTime, validationContext, result); + } + + if (result.Any()) { + return new ValidationResult("Validation of Gearbox Data failed", result.Select(x => x.ErrorMessage)); + } + return ValidationResult.Success; + } + } } \ No newline at end of file diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Data/ShiftStrategy/PredictionDurationLookup.cs b/VectoCore/VectoCore/Models/SimulationComponent/Data/ShiftStrategy/PredictionDurationLookup.cs new file mode 100644 index 0000000000000000000000000000000000000000..828ecdf5330a11905c8cef8695eae6304ba437ea --- /dev/null +++ b/VectoCore/VectoCore/Models/SimulationComponent/Data/ShiftStrategy/PredictionDurationLookup.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using TUGraz.VectoCommon.Utils; + +namespace TUGraz.VectoCore.Models.SimulationComponent.Data.ShiftStrategy +{ + public class PredictionDurationLookup : SimulationComponentData + { + private List<KeyValuePair<double, double>> _entries; + + protected internal PredictionDurationLookup(List<KeyValuePair<double, double>> entries) + { + _entries = entries; + } + + public double Lookup(double speedRatio) + { + var index = FindIndex(speedRatio); + + return VectoMath.Interpolate( + _entries[index - 1].Key, _entries[index].Key, + _entries[index - 1].Value, _entries[index].Value, speedRatio); + } + + private int FindIndex(double speedRatio) + { + var index = 1; + if (speedRatio < _entries[0].Key) { + Log.Error("requested speed ratio below minimum - extrapolating. speed ratio: {0}, min: {1}", + speedRatio, _entries[0].Key); + } else { + index = _entries.FindIndex(x => x.Key > speedRatio); + if (index <= 0) { + index = speedRatio > _entries[0].Key ? _entries.Count - 1 : 1; + } + } + return index; + } + + } +} diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/AbstractGearbox.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/AbstractGearbox.cs index c5fc0df602aa043c92b8e4b9d2d43132097d7cd4..4922c5827d9f9334ee33e471e783b81eec4c741b 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/AbstractGearbox.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/AbstractGearbox.cs @@ -29,132 +29,132 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ -using System.ComponentModel.DataAnnotations; -using System.Diagnostics; -using TUGraz.VectoCommon.Models; -using TUGraz.VectoCommon.Utils; -using TUGraz.VectoCore.Models.Connector.Ports; -using TUGraz.VectoCore.Models.Simulation; -using TUGraz.VectoCore.Models.Simulation.Data; -using TUGraz.VectoCore.Models.Simulation.DataBus; -using TUGraz.VectoCore.Models.SimulationComponent.Data; -using TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox; - -namespace TUGraz.VectoCore.Models.SimulationComponent.Impl -{ - public abstract class AbstractGearbox<TStateType> : - StatefulProviderComponent<TStateType, ITnOutPort, ITnInPort, ITnOutPort>, ITnOutPort, ITnInPort, IGearbox, - IClutchInfo - where TStateType : GearboxState, new() - { - /// <summary> - /// The data and settings for the gearbox. - /// </summary> - [Required, ValidateObject] internal readonly GearboxData ModelData; - - protected AbstractGearbox(IVehicleContainer container, VectoRunData runData) : base(container) - { - ModelData = runData.GearboxData; - } - - #region ITnOutPort - - public abstract IResponse Request(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, - bool dryRun = false); - - public abstract IResponse Initialize(NewtonMeter outTorque, PerSecond outAngularVelocity); - - #endregion - - #region IGearboxCockpit - - public GearboxType GearboxType - { - get { return ModelData.Type; } - } - - /// <summary> - /// The current gear. - /// </summary> - public uint Gear { get; protected internal set; } - - [DebuggerHidden] - public MeterPerSecond StartSpeed - { - get { return ModelData.StartSpeed; } - } - - [DebuggerHidden] - public MeterPerSquareSecond StartAcceleration - { - get { return ModelData.StartAcceleration; } - } - - public Watt GearboxLoss() - { - var ratio = ModelData.Gears[PreviousState.Gear].HasLockedGear - ? ModelData.Gears[PreviousState.Gear].Ratio - : ModelData.Gears[PreviousState.Gear].TorqueConverterRatio; - - return (PreviousState.TransmissionTorqueLoss + - PreviousState.InertiaTorqueLossOut) / ratio * PreviousState.InAngularVelocity; - } - - public Second LastShift { get; protected set; } - - public GearData GetGearData(uint gear) - { - return ModelData.Gears[gear]; - } - - public abstract GearInfo NextGear { get; } - - public virtual Second TractionInterruption - { - get { return ModelData.TractionInterruption; } - } - - public uint NumGears - { - get { return (uint)ModelData.Gears.Count; } - } - - #endregion - - public abstract bool ClutchClosed(Second absTime); - - protected bool ConsiderShiftLosses(GearInfo nextGear, NewtonMeter torqueOut) - { - if (ModelData.Type.ManualTransmission()) { - return false; - } - if (torqueOut.IsSmaller(0)) { - return false; - } - if (nextGear.Gear == 0) { - return false; - } - if (ModelData.Gears[2].HasTorqueConverter) { - return nextGear.TorqueConverterLocked; // || nextGear.Gear == 2; - } - return nextGear.TorqueConverterLocked; - } - - protected internal WattSecond ComputeShiftLosses(NewtonMeter outTorque, PerSecond outAngularVelocity) - { - var torqueGbxIn = outTorque / ModelData.Gears[Gear].Ratio; - var deltaClutchSpeed = (DataBus.EngineSpeed - PreviousState.OutAngularVelocity * ModelData.Gears[Gear].Ratio) / 2; - var shiftLossEnergy = torqueGbxIn * deltaClutchSpeed * ModelData.PowershiftShiftTime; - - return shiftLossEnergy.Abs(); - } - } - - public class GearboxState : SimpleComponentState - { - public NewtonMeter InertiaTorqueLossOut = 0.SI<NewtonMeter>(); - public NewtonMeter TransmissionTorqueLoss = 0.SI<NewtonMeter>(); - public uint Gear; - public TransmissionLossMap.LossMapResult TorqueLossResult; - } +using System.ComponentModel.DataAnnotations; +using System.Diagnostics; +using TUGraz.VectoCommon.Models; +using TUGraz.VectoCommon.Utils; +using TUGraz.VectoCore.Models.Connector.Ports; +using TUGraz.VectoCore.Models.Simulation; +using TUGraz.VectoCore.Models.Simulation.Data; +using TUGraz.VectoCore.Models.Simulation.DataBus; +using TUGraz.VectoCore.Models.SimulationComponent.Data; +using TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox; + +namespace TUGraz.VectoCore.Models.SimulationComponent.Impl +{ + public abstract class AbstractGearbox<TStateType> : + StatefulProviderComponent<TStateType, ITnOutPort, ITnInPort, ITnOutPort>, ITnOutPort, ITnInPort, IGearbox, + IClutchInfo + where TStateType : GearboxState, new() + { + /// <summary> + /// The data and settings for the gearbox. + /// </summary> + [Required, ValidateObject] internal readonly GearboxData ModelData; + + protected AbstractGearbox(IVehicleContainer container, VectoRunData runData) : base(container) + { + ModelData = runData.GearboxData; + } + + #region ITnOutPort + + public abstract IResponse Request(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, + bool dryRun = false); + + public abstract IResponse Initialize(NewtonMeter outTorque, PerSecond outAngularVelocity); + + #endregion + + #region IGearboxCockpit + + public GearboxType GearboxType + { + get { return ModelData.Type; } + } + + /// <summary> + /// The current gear. + /// </summary> + public uint Gear { get; protected internal set; } + + [DebuggerHidden] + public MeterPerSecond StartSpeed + { + get { return ModelData.StartSpeed; } + } + + [DebuggerHidden] + public MeterPerSquareSecond StartAcceleration + { + get { return ModelData.StartAcceleration; } + } + + public Watt GearboxLoss() + { + var ratio = ModelData.Gears[PreviousState.Gear].HasLockedGear + ? ModelData.Gears[PreviousState.Gear].Ratio + : ModelData.Gears[PreviousState.Gear].TorqueConverterRatio; + + return (PreviousState.TransmissionTorqueLoss + + PreviousState.InertiaTorqueLossOut) / ratio * PreviousState.InAngularVelocity; + } + + public Second LastShift { get; protected set; } + + public GearData GetGearData(uint gear) + { + return ModelData.Gears[gear]; + } + + public abstract GearInfo NextGear { get; } + + public virtual Second TractionInterruption + { + get { return ModelData.TractionInterruption; } + } + + public uint NumGears + { + get { return (uint)ModelData.Gears.Count; } + } + + #endregion + + public abstract bool ClutchClosed(Second absTime); + + protected bool ConsiderShiftLosses(GearInfo nextGear, NewtonMeter torqueOut) + { + if (ModelData.Type.ManualTransmission()) { + return false; + } + if (torqueOut.IsSmaller(0)) { + return false; + } + if (nextGear.Gear == 0) { + return false; + } + if (ModelData.Gears[2].HasTorqueConverter) { + return nextGear.TorqueConverterLocked; // || nextGear.Gear == 2; + } + return nextGear.TorqueConverterLocked; + } + + protected internal WattSecond ComputeShiftLosses(NewtonMeter outTorque, PerSecond outAngularVelocity) + { + var torqueGbxIn = outTorque / ModelData.Gears[Gear].Ratio; + var deltaClutchSpeed = (DataBus.EngineSpeed - PreviousState.OutAngularVelocity * ModelData.Gears[Gear].Ratio) / 2; + var shiftLossEnergy = torqueGbxIn * deltaClutchSpeed * ModelData.PowershiftShiftTime; + + return shiftLossEnergy.Abs(); + } + } + + public class GearboxState : SimpleComponentState + { + public NewtonMeter InertiaTorqueLossOut = 0.SI<NewtonMeter>(); + public NewtonMeter TransmissionTorqueLoss = 0.SI<NewtonMeter>(); + public uint Gear; + public TransmissionLossMap.LossMapResult TorqueLossResult; + } } \ No newline at end of file diff --git a/VectoCore/VectoCore/Resources/Declaration/GearshiftParameters/PredictionTimeLookup.csv b/VectoCore/VectoCore/Resources/Declaration/GearshiftParameters/PredictionTimeLookup.csv new file mode 100644 index 0000000000000000000000000000000000000000..c2a33c8b7f40e29da1ae61e14e7a838a922c3d20 --- /dev/null +++ b/VectoCore/VectoCore/Resources/Declaration/GearshiftParameters/PredictionTimeLookup.csv @@ -0,0 +1,5 @@ +v_post/v_curr, dt_pred/dt_shift +0.0 , 1.0 +0.8 , 1.0 +0.9 , 0.5 +2.0 , 0.5 \ No newline at end of file diff --git a/VectoCore/VectoCore/VectoCore.csproj b/VectoCore/VectoCore/VectoCore.csproj index fa0105351100d5e92cc8020092c99fa84e6171ad..5333e84a473a842461bb6721b457dbe5e61eb0af 100644 --- a/VectoCore/VectoCore/VectoCore.csproj +++ b/VectoCore/VectoCore/VectoCore.csproj @@ -176,6 +176,7 @@ <Compile Include="Models\SimulationComponent\Data\AngledriveData.cs" /> <Compile Include="Models\SimulationComponent\Data\Engine\FuelConsumptionMapReader.cs" /> <Compile Include="Models\SimulationComponent\Data\PTOData.cs" /> + <Compile Include="Models\SimulationComponent\Data\ShiftStrategy\PredictionDurationLookup.cs" /> <Compile Include="Models\SimulationComponent\ILossMap.cs" /> <Compile Include="Models\SimulationComponent\Data\PTOLossMap.cs" /> <Compile Include="Models\SimulationComponent\Impl\AbstractGearbox.cs" /> @@ -199,6 +200,7 @@ <Compile Include="Models\Simulation\Data\ModalResultField.cs" /> <Compile Include="InputData\Reader\Impl\EngineeringVTPModeVectoRunDataFactory.cs" /> <Compile Include="Models\SimulationComponent\Impl\VTPCycle.cs" /> + <Compile Include="Models\Simulation\Data\ShiftStrategyParameters.cs" /> <Compile Include="Models\Simulation\ISimulationPreprocessor.cs" /> <Compile Include="OutputData\XML\XMLVTPReport.cs" /> <Compile Include="OutputData\VTPReport.cs" />