diff --git a/VectoCore/FileIO/DeclarationFile/VehicleFileDecl.cs b/VectoCore/FileIO/DeclarationFile/VehicleFileDecl.cs index 513e9ed4bbea9504e70ee7955556df2cf53b82d3..45904d9eb812be18228cc7bd6bdbbf5c704a6128 100644 --- a/VectoCore/FileIO/DeclarationFile/VehicleFileDecl.cs +++ b/VectoCore/FileIO/DeclarationFile/VehicleFileDecl.cs @@ -42,7 +42,8 @@ namespace TUGraz.VectoCore.FileIO.DeclarationFile public AxleConfiguration AxleConfigurationType() { - return (AxleConfiguration) Enum.Parse(typeof (AxleConfiguration), AxleConfig.TypeStr, true); + // TODO: @@@quam better use of enum-prefix + return (AxleConfiguration) Enum.Parse(typeof (AxleConfiguration), "AxleConfig_" + AxleConfig.TypeStr, true); } public class AxleConfigData diff --git a/VectoCore/FileIO/Reader/Impl/AbstractSimulationDataReader.cs b/VectoCore/FileIO/Reader/Impl/AbstractSimulationDataReader.cs index a440e493ed7a932ec54e5690611d4d518e413571..ca4b55eaf78354c143c67a1367b25a834a073655 100644 --- a/VectoCore/FileIO/Reader/Impl/AbstractSimulationDataReader.cs +++ b/VectoCore/FileIO/Reader/Impl/AbstractSimulationDataReader.cs @@ -73,12 +73,10 @@ namespace TUGraz.VectoCore.FileIO.Reader.Impl internal VehicleData SetCommonVehicleData(VehicleFileV5Declaration vehicle) { var data = ((dynamic) vehicle).Body; - return new VehicleData { + var retVal = new VehicleData { SavedInDeclarationMode = data.SavedInDeclarationMode, VehicleCategory = data.VehicleCategory(), - AxleConfiguration = - (AxleConfiguration) Enum.Parse(typeof (AxleConfiguration), "AxleConfig_" + data.AxleConfig.TypeStr), - // TODO: @@@quam better use of enum-prefix + AxleConfiguration = vehicle.Body.AxleConfigurationType(), CurbWeight = SIConvert<Kilogram>(data.CurbWeight), //CurbWeigthExtra = data.CurbWeightExtra.SI<Kilogram>(), //Loading = data.Loading.SI<Kilogram>(), @@ -89,13 +87,19 @@ namespace TUGraz.VectoCore.FileIO.Reader.Impl CrossSectionAreaRigidTruck = SIConvert<SquareMeter>(data.CrossSectionAreaRigidTruck), //TyreRadius = data.TyreRadius.SI().Milli.Meter.Cast<Meter>(), Rim = data.RimStr, - Retarder = new RetarderData() { - LossMap = RetarderLossMap.ReadFromFile(Path.Combine(vehicle.BasePath, data.Retarder.File)), - Type = - (RetarderData.RetarderType) Enum.Parse(typeof (RetarderData.RetarderType), data.Retarder.TypeStr.ToString(), true), - Ratio = data.Retarder.Ratio - } }; + + var retarder = new RetarderData() { + Type = + (RetarderData.RetarderType) Enum.Parse(typeof (RetarderData.RetarderType), data.Retarder.TypeStr.ToString(), true), + }; + if (retarder.Type != RetarderData.RetarderType.None) { + retarder.LossMap = RetarderLossMap.ReadFromFile(Path.Combine(vehicle.BasePath, data.Retarder.File)); + retarder.Ratio = data.Retarder.Ratio; + } + retVal.Retarder = retarder; + + return retVal; } internal CombustionEngineData SetCommonCombustionEngineData(EngineFileV2Declaration engine) diff --git a/VectoCore/FileIO/Reader/Impl/DeclarationModeSimulationDataReader.cs b/VectoCore/FileIO/Reader/Impl/DeclarationModeSimulationDataReader.cs index 286a170f693b7a821342dd0e7b94e4f164d939c2..2c7b921a663ee0e5ec650e926724e2a4b46fe9f7 100644 --- a/VectoCore/FileIO/Reader/Impl/DeclarationModeSimulationDataReader.cs +++ b/VectoCore/FileIO/Reader/Impl/DeclarationModeSimulationDataReader.cs @@ -46,22 +46,31 @@ namespace TUGraz.VectoCore.FileIO.Reader.Impl protected void CheckForDeclarationMode(InputFileReader.VersionInfo info, string msg) { if (!info.SavedInDeclarationMode) { - throw new VectoException("File not saved in Declaration Mode! - " + msg); + // throw new VectoException("File not saved in Declaration Mode! - " + msg); + Log.WarnFormat("File not saved in Declaration Mode! - {0}", msg); } } public override IEnumerable<VectoRunData> NextRun() { - var segment = GetVehicleClassification((dynamic) Vehicle); + var segment = GetVehicleClassification(((dynamic) Vehicle).Body); foreach (var mission in segment.Missions) { foreach (var loading in mission.Loadings) { + var engineData = CreateEngineData((dynamic) Engine); + var parser = new DrivingCycleData.DistanceBasedDataParser(); + var data = VectoCSVFile.ReadStream(mission.CycleFile); + var cycleEntries = parser.Parse(data).ToList(); var simulationRunData = new VectoRunData() { VehicleData = CreateVehicleData((dynamic) Vehicle, mission, loading), - EngineData = CreateEngineData((dynamic) Engine), - GearboxData = CreateGearboxData((dynamic) Gearbox), - // @@@ TODO: cycle + EngineData = engineData, + GearboxData = CreateGearboxData((dynamic) Gearbox, engineData), // @@@ TODO: auxiliaries // @@@ TODO: ... + Cycle = new DrivingCycleData() { + Name = "Dummy", + SavedInDeclarationMode = true, + Entries = cycleEntries + }, IsEngineOnly = false, JobFileName = Job.JobFile, }; @@ -97,6 +106,7 @@ namespace TUGraz.VectoCore.FileIO.Reader.Impl case 2: Job = JsonConvert.DeserializeObject<VectoJobFileV2Declaration>(json); Job.BasePath = Path.GetDirectoryName(file) + Path.DirectorySeparatorChar; + Job.JobFile = Path.GetFileName(file); break; default: throw new UnsupportedFileVersionException("Unsupported version of job-file. Got version " + fileInfo.Version); @@ -145,6 +155,7 @@ namespace TUGraz.VectoCore.FileIO.Reader.Impl switch (fileInfo.Version) { case 4: Gearbox = JsonConvert.DeserializeObject<GearboxFileV4Declaration>(json); + Gearbox.BasePath = Path.GetDirectoryName(file); break; default: throw new UnsupportedFileVersionException("Unsopported Version of gearbox-file. Got version " + fileInfo.Version); @@ -155,7 +166,7 @@ namespace TUGraz.VectoCore.FileIO.Reader.Impl internal Segment GetVehicleClassification(VehicleFileV5Declaration.DataBodyDecl vehicle) { return new DeclarationSegments().Lookup(vehicle.VehicleCategory(), vehicle.AxleConfigurationType(), - vehicle.GrossVehicleMassRating.SI<Kilogram>(), vehicle.CurbWeight.SI<Kilogram>()); + vehicle.GrossVehicleMassRating.SI<Ton>().Cast<Kilogram>(), vehicle.CurbWeight.SI<Kilogram>()); } @@ -166,6 +177,8 @@ namespace TUGraz.VectoCore.FileIO.Reader.Impl retVal.BasePath = vehicle.BasePath; + retVal.GrossVehicleMassRating = vehicle.Body.GrossVehicleMassRating.SI<Ton>().Cast<Kilogram>(); + retVal.CurbWeigthExtra = mission.MassExtra; retVal.Loading = loading; retVal.DynamicTyreRadius = @@ -213,7 +226,7 @@ namespace TUGraz.VectoCore.FileIO.Reader.Impl return retVal; } - internal GearboxData CreateGearboxData(GearboxFileV4Declaration gearbox) + internal GearboxData CreateGearboxData(GearboxFileV4Declaration gearbox, CombustionEngineData engine) { var retVal = SetCommonGearboxData(gearbox.Body); @@ -242,22 +255,48 @@ namespace TUGraz.VectoCore.FileIO.Reader.Impl var lossMapPath = Path.Combine(gearbox.BasePath, gearSettings.LossMap); TransmissionLossMap lossMap = TransmissionLossMap.ReadFromFile(lossMapPath, gearSettings.Ratio); - var shiftPolygon = ComputeShiftPolygon(); - var gear = new GearData(lossMap, shiftPolygon, gearSettings.Ratio, false); if (i == 0) { - retVal.AxleGearData = gear; + retVal.AxleGearData = new GearData(lossMap, null, gearSettings.Ratio, false); } else { - retVal._gearData.Add(i, gear); + var shiftPolygon = ComputeShiftPolygon(engine, i); + retVal._gearData.Add(i, new GearData(lossMap, shiftPolygon, gearSettings.Ratio, false)); } } return retVal; } - internal ShiftPolygon ComputeShiftPolygon() + internal ShiftPolygon ComputeShiftPolygon(CombustionEngineData engine, uint gear) { - throw new NotImplementedException(); + var fullLoadCurve = engine.GetFullLoadCurve(gear); + var idleSpeed = engine.IdleSpeed; + + var maxTorque = fullLoadCurve.MaxLoadTorque; + + var entriesDown = new List<ShiftPolygon.ShiftPolygonEntry>(); + var entriesUp = new List<ShiftPolygon.ShiftPolygonEntry>(); + + entriesDown.Add(new ShiftPolygon.ShiftPolygonEntry() { AngularSpeed = idleSpeed, Torque = 0.SI<NewtonMeter>() }); + + var tq1 = maxTorque * idleSpeed / (fullLoadCurve.PreferredSpeed + fullLoadCurve.LoSpeed - idleSpeed); + entriesDown.Add(new ShiftPolygon.ShiftPolygonEntry() { AngularSpeed = idleSpeed, Torque = tq1 }); + + var speed1 = (fullLoadCurve.PreferredSpeed + fullLoadCurve.LoSpeed) / 2; + entriesDown.Add(new ShiftPolygon.ShiftPolygonEntry() { AngularSpeed = speed1, Torque = maxTorque }); + + + entriesUp.Add(new ShiftPolygon.ShiftPolygonEntry() { + AngularSpeed = fullLoadCurve.PreferredSpeed, + Torque = 0.SI<NewtonMeter>() + }); + + tq1 = maxTorque * (fullLoadCurve.PreferredSpeed - idleSpeed) / (fullLoadCurve.N95hSpeed - idleSpeed); + entriesUp.Add(new ShiftPolygon.ShiftPolygonEntry() { AngularSpeed = fullLoadCurve.PreferredSpeed, Torque = tq1 }); + + entriesUp.Add(new ShiftPolygon.ShiftPolygonEntry() { AngularSpeed = fullLoadCurve.N95hSpeed, Torque = maxTorque }); + + return new ShiftPolygon(entriesDown, entriesUp); } } } \ No newline at end of file diff --git a/VectoCore/Models/Declaration/DeclarationSegments.cs b/VectoCore/Models/Declaration/DeclarationSegments.cs index b702c8f7661f276cd9923d9d287a4ed7aa522dc9..9defe2489f77f205712d2175e8a6efe2e34e9524 100644 --- a/VectoCore/Models/Declaration/DeclarationSegments.cs +++ b/VectoCore/Models/Declaration/DeclarationSegments.cs @@ -31,10 +31,12 @@ namespace TUGraz.VectoCore.Models.Declaration public override Segment Lookup(VehicleCategory vehicleCategory, AxleConfiguration axleConfiguration, Kilogram grossVehicleMassRating, Kilogram curbWeight) { - var row = SegmentTable.Rows.Cast<DataRow>().First(r => r.Field<string>("tvehcat") == vehicleCategory.ToString() - && r.Field<string>("taxleconf") == axleConfiguration.GetName() - && r.ParseDouble("gvw_min").SI<Ton>() <= grossVehicleMassRating - && r.ParseDouble("gvw_max").SI<Ton>() > grossVehicleMassRating); + var row = + SegmentTable.Rows.Cast<DataRow>() + .First(r => r.Field<string>("valid") == "1" && r.Field<string>("tvehcat") == vehicleCategory.ToString() + && r.Field<string>("taxleconf") == axleConfiguration.GetName() + && r.ParseDouble("gvw_min").SI<Ton>() <= grossVehicleMassRating + && r.ParseDouble("gvw_max").SI<Ton>() > grossVehicleMassRating); var segment = new Segment { GrossVehicleWeightMin = row.ParseDouble("gvw_min").SI().Ton.Cast<Kilogram>(), GrossVehicleWeightMax = row.ParseDouble("gvw_max").SI().Ton.Cast<Kilogram>(), diff --git a/VectoCore/Models/Simulation/Impl/SimulatorFactory.cs b/VectoCore/Models/Simulation/Impl/SimulatorFactory.cs index 6dc257552d560e8ef113baf5a70245ecf5e41ab0..666269b6123c8627641fc8f5cafb12b33c943185 100644 --- a/VectoCore/Models/Simulation/Impl/SimulatorFactory.cs +++ b/VectoCore/Models/Simulation/Impl/SimulatorFactory.cs @@ -62,7 +62,7 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl /// Creates powertrain and initializes it with the component's data. /// </summary> /// <returns>new VectoRun Instance</returns> - public IEnumerable<IVectoRun> NextRun() + public IEnumerable<IVectoRun> SimulationRuns() { var i = 0; foreach (var data in DataReader.NextRun()) { @@ -80,7 +80,7 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl yield return new VectoRun(builder.Build(data)); } //_runCreator.SetJobFile(jobFile); - //foreach (var data in _runCreator.NextRun()) { + //foreach (var data in _runCreator.Runs()) { // //for (var i = 0; i < data.Cycles.Count; i++) { // var cycleName = data.Cycle; // var jobName = string.Format("{0}-{1}", jobNumber, i); diff --git a/VectoCore/Models/Simulation/Impl/VehicleContainer.cs b/VectoCore/Models/Simulation/Impl/VehicleContainer.cs index c80dbb3582132fb7eb7943f06eae14d122e51931..6628f506f27102b22970344bb701a3f3936fb7a0 100644 --- a/VectoCore/Models/Simulation/Impl/VehicleContainer.cs +++ b/VectoCore/Models/Simulation/Impl/VehicleContainer.cs @@ -12,15 +12,15 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl { public class VehicleContainer : IVehicleContainer { - private readonly IList<VectoSimulationComponent> _components = new List<VectoSimulationComponent>(); - private IEngineCockpit _engine; - private IGearboxCockpit _gearbox; - private IVehicleCockpit _vehicle; + internal readonly IList<VectoSimulationComponent> _components = new List<VectoSimulationComponent>(); + internal IEngineCockpit _engine; + internal IGearboxCockpit _gearbox; + internal IVehicleCockpit _vehicle; - private IDrivingCycleOutPort _cycle; + internal IDrivingCycleOutPort _cycle; - private ISummaryDataWriter _sumWriter; - private IModalDataWriter _dataWriter; + internal ISummaryDataWriter _sumWriter; + internal IModalDataWriter _dataWriter; private ILog _logger; diff --git a/VectoCore/Models/SimulationComponent/Data/CombustionEngineData.cs b/VectoCore/Models/SimulationComponent/Data/CombustionEngineData.cs index d56e96152e35ce70697b5be3603b07d4a4c11792..048ca995e80c3af7a42cb26da66c101fb4a201ab 100644 --- a/VectoCore/Models/SimulationComponent/Data/CombustionEngineData.cs +++ b/VectoCore/Models/SimulationComponent/Data/CombustionEngineData.cs @@ -70,6 +70,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data { var range = new Range(gears); if (!_fullLoadCurves.ContainsKey(range)) { + fullLoadCurve.EngineData = this; _fullLoadCurves.Add(range, fullLoadCurve); } else { throw new VectoException(String.Format("FullLoadCurve for gears {0} already specified!", gears)); diff --git a/VectoCore/Models/SimulationComponent/Data/DrivingCycleData.cs b/VectoCore/Models/SimulationComponent/Data/DrivingCycleData.cs index dc74fc72a9c44f455491f0bba84a9b7943188a08..f19289f388c4ef6c25a02334f13f967bf15e7c2e 100644 --- a/VectoCore/Models/SimulationComponent/Data/DrivingCycleData.cs +++ b/VectoCore/Models/SimulationComponent/Data/DrivingCycleData.cs @@ -238,7 +238,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data } } - private class DistanceBasedDataParser : IDataParser + internal class DistanceBasedDataParser : IDataParser { public IEnumerable<DrivingCycleEntry> Parse(DataTable table) { diff --git a/VectoCore/Models/SimulationComponent/Data/Engine/FullLoadCurve.cs b/VectoCore/Models/SimulationComponent/Data/Engine/FullLoadCurve.cs index 4ec462ac349e44a7e499598c81827143a2574187..214de74d3aea8b246c584fbf8bc0659ebd137118 100644 --- a/VectoCore/Models/SimulationComponent/Data/Engine/FullLoadCurve.cs +++ b/VectoCore/Models/SimulationComponent/Data/Engine/FullLoadCurve.cs @@ -20,6 +20,14 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine private List<FullLoadCurveEntry> _fullLoadEntries; private LookupData<PerSecond, Second> _pt1Data; + private Watt _maxPower; + + private PerSecond _ratedSpeed; + private PerSecond _preferredSpeed; + private PerSecond _engineSpeedLo; // 55% of Pmax + private PerSecond _engineSpeedHi; // 70% of Pmax + private PerSecond _n95hSpeed; // 95% of Pmax + public static FullLoadCurve ReadFromFile(string fileName, bool declarationMode = false) { var data = VectoCSVFile.Read(fileName); @@ -91,6 +99,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine }).ToList(); } + public CombustionEngineData EngineData { get; internal set; } + /// <summary> /// [rad/s] => [Nm] /// </summary> @@ -150,11 +160,79 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine return _pt1Data.Lookup(angularVelocity); } + /// <summary> /// Get the engine's rated speed from the given full-load curve (i.e. engine speed with max. power) /// </summary> /// <returns>[1/s]</returns> - public PerSecond RatedSpeed() + public PerSecond RatedSpeed + { + get + { + if (_ratedSpeed == null) { + ComputeRatedSpeed(); + } + return _ratedSpeed; + } + } + + public Watt MaxPower + { + get + { + if (_maxPower == null) { + ComputeRatedSpeed(); + } + return _maxPower; + } + } + + /// <summary> + /// Get the engine's preferred speed from the given full-load curve (i.e. Speed at 51% torque/speed-integral between idling and N95h.) + /// </summary> + public PerSecond PreferredSpeed + { + get + { + if (_preferredSpeed == null) { + ComputePreferredSpeed(); + } + return _preferredSpeed; + } + } + + public PerSecond N95hSpeed + { + get { return _n95hSpeed ?? (_n95hSpeed = FindEngineSpeedForPower(0.95 * MaxPower).Last()); } + } + + + public PerSecond LoSpeed + { + get { return _engineSpeedLo ?? (_engineSpeedLo = FindEngineSpeedForPower(0.55 * MaxPower).First()); } + } + + public PerSecond HiSpeed + { + get { return _engineSpeedHi ?? (_engineSpeedHi = FindEngineSpeedForPower(0.7 * MaxPower).Last()); } + } + + + public NewtonMeter MaxLoadTorque + { + get { return _fullLoadEntries.Max(x => x.TorqueFullLoad); } + } + + public NewtonMeter MaxDragTorque + { + get { return _fullLoadEntries.Min(x => x.TorqueDrag); } + } + + /// <summary> + /// Compute the engine's rated speed from the given full-load curve (i.e. engine speed with max. power) + /// </summary> + /// <returns>[1/s]</returns> + private void ComputeRatedSpeed() { var max = new Tuple<PerSecond, Watt>(0.SI<PerSecond>(), 0.SI<Watt>()); for (var idx = 1; idx < _fullLoadEntries.Count; idx++) { @@ -164,9 +242,59 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine } } - return max.Item1; + _ratedSpeed = max.Item1; + _maxPower = max.Item2; + } + + + private void ComputePreferredSpeed() + { + var maxArea = ComputeArea(EngineData.IdleSpeed, N95hSpeed); + + var area = 0.0; + var idx = 0; + while (++idx < _fullLoadEntries.Count) { + var additionalArea = ComputeArea(_fullLoadEntries[idx - 1].EngineSpeed, _fullLoadEntries[idx].EngineSpeed); + if (area + additionalArea > 0.51 * maxArea) { + var deltaArea = 0.51 * maxArea - area; + _preferredSpeed = ComputeEngineSpeedForSegmentArea(_fullLoadEntries[idx - 1], _fullLoadEntries[idx], deltaArea); + return; + } + area += additionalArea; + } + Log.WarnFormat("Could not compute preferred speed, check FullLoadCurve! N95h: {0}, maxArea: {1}", N95hSpeed, maxArea); } + private PerSecond ComputeEngineSpeedForSegmentArea(FullLoadCurveEntry p1, FullLoadCurveEntry p2, double area) + { + var k = (p2.TorqueFullLoad - p1.TorqueFullLoad) / (p2.EngineSpeed - p1.EngineSpeed); + var d = p2.TorqueFullLoad - k * p2.EngineSpeed; + + if (k.Double().IsEqual(0.0)) { + // rectangle + return (p1.EngineSpeed + (area / d.Double())); + } + + var a = k.Double() / 2.0; + var b = d.Double(); + var c = (k * p1.EngineSpeed * p1.EngineSpeed + 2 * p1.EngineSpeed * d).Double(); + + var D = b * b - 4 * a * c; + + var retVal = new List<PerSecond>(); + if (D < 0) { + Log.InfoFormat("No real solution found for requested area: P: {0}, p1: {1}, p2: {2}", area, p1, p2); + return null; + } else if (D > 0) { + // two solutions possible + retVal.Add((-b + Math.Sqrt(D) / (2 * a)).SI<PerSecond>()); + retVal.Add((-b - Math.Sqrt(D) / (2 * a)).SI<PerSecond>()); + } else { + // only one solution possible + retVal.Add((-b / (4 * a * c)).SI<PerSecond>()); + } + return retVal.First(x => x >= p1.EngineSpeed && x <= p2.EngineSpeed); + } /// <summary> /// [rad/s] => index. Get item index for angularVelocity. @@ -189,6 +317,73 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine return idx; } + private List<PerSecond> FindEngineSpeedForPower(Watt power) + { + var retVal = new List<PerSecond>(); + for (var idx = 1; idx < _fullLoadEntries.Count; idx++) { + var solutions = FindEngineSpeedForPower(_fullLoadEntries[idx - 1], _fullLoadEntries[idx], power); + retVal.AddRange(solutions); + } + retVal.Sort(); + return retVal; + } + + private List<PerSecond> FindEngineSpeedForPower(FullLoadCurveEntry p1, FullLoadCurveEntry p2, Watt power) + { + var k = (p2.TorqueFullLoad - p1.TorqueFullLoad) / (p2.EngineSpeed - p1.EngineSpeed); + var d = p2.TorqueFullLoad - k * p2.EngineSpeed; + + var retVal = new List<PerSecond>(); + if (k.Double().IsEqual(0, 0.0001)) { + // constant torque, solve linear equation + retVal.Add((power.Double() / d.Double()).SI<PerSecond>()); + } else { + // non-constant torque, solve quadratic equation + var a = k.Double(); + var b = d.Double(); + var c = -power.Double(); + + var D = b * b - 4 * a * c; + if (D < 0) { + Log.InfoFormat("No real solution found for requested power demand: P: {0}, p1: {1}, p2: {2}", power, p1, p2); + } else if (D > 0) { + // two solutions possible + retVal.Add(((-b + Math.Sqrt(D)) / (2 * a)).SI<PerSecond>()); + retVal.Add(((-b - Math.Sqrt(D)) / (2 * a)).SI<PerSecond>()); + } else { + // only one solution possible + retVal.Add((-b / (2 * a)).SI<PerSecond>()); + } + } + retVal = retVal.Where(x => x >= p1.EngineSpeed && x <= p2.EngineSpeed).ToList(); + return retVal; + } + + private double ComputeArea(PerSecond lowEngineSpeed, PerSecond highEngineSpeed) + { + var startSegment = FindIndex(lowEngineSpeed); + var endSegment = FindIndex(highEngineSpeed); + + var area = 0.0; + if (lowEngineSpeed < _fullLoadEntries[startSegment].EngineSpeed) { + // add part of the first segment + area += ((_fullLoadEntries[startSegment].EngineSpeed - lowEngineSpeed) * + (FullLoadStationaryTorque(lowEngineSpeed) + _fullLoadEntries[startSegment].TorqueFullLoad) / 2.0).Double(); + } + for (var i = startSegment + 1; i <= endSegment; i++) { + var speedHigh = _fullLoadEntries[i].EngineSpeed; + var torqueHigh = _fullLoadEntries[i].TorqueFullLoad; + if (highEngineSpeed < _fullLoadEntries[i].EngineSpeed) { + // add part of the last segment + speedHigh = highEngineSpeed; + torqueHigh = FullLoadStationaryTorque(highEngineSpeed); + } + area += ((speedHigh - _fullLoadEntries[i - 1].EngineSpeed) * + (torqueHigh + _fullLoadEntries[i - 1].TorqueFullLoad) / 2.0).Double(); + } + return area; + } + private Tuple<PerSecond, Watt> FindMaxPower(FullLoadCurveEntry p1, FullLoadCurveEntry p2) { if (p1.EngineSpeed == p2.EngineSpeed) { diff --git a/VectoCore/Models/SimulationComponent/Data/Gearbox/ShiftPolygon.cs b/VectoCore/Models/SimulationComponent/Data/Gearbox/ShiftPolygon.cs index 07f5d5f0902c7d41fa07135347b02acae72c283d..ab8f23ef124dafc4484be161b77844392638457e 100644 --- a/VectoCore/Models/SimulationComponent/Data/Gearbox/ShiftPolygon.cs +++ b/VectoCore/Models/SimulationComponent/Data/Gearbox/ShiftPolygon.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Data; using System.Linq; using System.Runtime.Remoting.Messaging; @@ -11,7 +12,14 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox { public class ShiftPolygon : SimulationComponentData { - private List<ShiftPolygonEntry> _entries; + private List<ShiftPolygonEntry> _upshiftPolygon; + private List<ShiftPolygonEntry> _downshifPolygon; + + internal ShiftPolygon(List<ShiftPolygonEntry> downshift, List<ShiftPolygonEntry> upshift) + { + _upshiftPolygon = upshift; + _downshifPolygon = downshift; + } public static ShiftPolygon ReadFromFile(string fileName) { @@ -25,23 +33,30 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox throw new VectoException("ShiftPolygon must consist of at least tow lines with numeric values (below file header)"); } - List<ShiftPolygonEntry> entries; + List<ShiftPolygonEntry> entriesDown, entriesUp; if (HeaderIsValid(data.Columns)) { - entries = CreateFromColumnNames(data); + entriesDown = CreateFromColumnNames(data, Fields.AngluarSpeedDown); + entriesUp = CreateFromColumnNames(data, Fields.AngularSpeedUp); } else { var log = LogManager.GetLogger<ShiftPolygon>(); log.WarnFormat( "ShiftPolygon: Header Line is not valid. Expected: '{0}, {1}, {2}', Got: '{3}'. Falling back to column index", Fields.Torque, Fields.AngularSpeedUp, Fields.AngluarSpeedDown, string.Join(", ", data.Columns.Cast<DataColumn>().Select(c => c.ColumnName).Reverse())); - entries = CreateFromColumnIndizes(data); + entriesDown = CreateFromColumnIndizes(data, 1); + entriesUp = CreateFromColumnIndizes(data, 2); } - return new ShiftPolygon { _entries = entries }; + return new ShiftPolygon(entriesDown, entriesUp); } - public ShiftPolygonEntry this[int i] + public ReadOnlyCollection<ShiftPolygonEntry> Upshift { - get { return _entries[i]; } + get { return _upshiftPolygon.AsReadOnly(); } + } + + public ReadOnlyCollection<ShiftPolygonEntry> Downshift + { + get { return _downshifPolygon.AsReadOnly(); } } private static bool HeaderIsValid(DataColumnCollection columns) @@ -50,24 +65,22 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox columns.Contains((Fields.AngluarSpeedDown)); } - private static List<ShiftPolygonEntry> CreateFromColumnNames(DataTable data) + private static List<ShiftPolygonEntry> CreateFromColumnNames(DataTable data, string columnName) { return (from DataRow row in data.Rows select new ShiftPolygonEntry { Torque = row.ParseDouble(Fields.Torque).SI<NewtonMeter>(), - AngularSpeedDown = row.ParseDouble(Fields.AngluarSpeedDown).RPMtoRad(), - AngularSpeedUp = row.ParseDouble(Fields.AngularSpeedUp).RPMtoRad() + AngularSpeed = row.ParseDouble(columnName).RPMtoRad(), }).ToList(); } - private static List<ShiftPolygonEntry> CreateFromColumnIndizes(DataTable data) + private static List<ShiftPolygonEntry> CreateFromColumnIndizes(DataTable data, int column) { return (from DataRow row in data.Rows select new ShiftPolygonEntry { Torque = row.ParseDouble(0).SI<NewtonMeter>(), - AngularSpeedDown = row.ParseDouble(1).RPMtoRad(), - AngularSpeedUp = row.ParseDouble(2).RPMtoRad() + AngularSpeed = row.ParseDouble(column).RPMtoRad(), }).ToList(); } @@ -97,14 +110,9 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Gearbox public NewtonMeter Torque { get; set; } /// <summary> - /// [1/s] angular velocity threshold for downshift - /// </summary> - public PerSecond AngularSpeedDown { get; set; } - - /// <summary> - /// [1/s] angular velocity threshold for upshift + /// [1/s] angular velocity threshold /// </summary> - public PerSecond AngularSpeedUp { get; set; } + public PerSecond AngularSpeed { get; set; } } } } \ No newline at end of file diff --git a/VectoCore/Models/SimulationComponent/Impl/Clutch.cs b/VectoCore/Models/SimulationComponent/Impl/Clutch.cs index 5c378cf3cdbe49d82fe40f3765c9124c4422909c..3a57e7667eae70d9b3e81cac36a043cf4a56e554 100644 --- a/VectoCore/Models/SimulationComponent/Impl/Clutch.cs +++ b/VectoCore/Models/SimulationComponent/Impl/Clutch.cs @@ -27,7 +27,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl : base(cockpit) { _idleSpeed = engineData.IdleSpeed; - _ratedSpeed = engineData.GetFullLoadCurve(0).RatedSpeed(); + _ratedSpeed = engineData.GetFullLoadCurve(0).RatedSpeed; } public ClutchState State() diff --git a/VectoCore/Models/SimulationComponent/Impl/Gearbox.cs b/VectoCore/Models/SimulationComponent/Impl/Gearbox.cs index eee4e0e391824181bafea7928e8e06d747cccb7f..36823d7ee2bf8712351859a9115b185e6db214ee 100644 --- a/VectoCore/Models/SimulationComponent/Impl/Gearbox.cs +++ b/VectoCore/Models/SimulationComponent/Impl/Gearbox.cs @@ -12,7 +12,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl { protected ITnOutPort Next; - protected GearboxData Data; + internal GearboxData Data; public Gearbox(IVehicleContainer container, GearboxData gearboxData) : base(container) { diff --git a/VectoCore/Properties/AssemblyInfo.cs b/VectoCore/Properties/AssemblyInfo.cs index b5de5732b5ef9e9c915651f4887fd253aef95184..df0c9973ba0b690d98d43b7ea5751b41a9141eb5 100644 --- a/VectoCore/Properties/AssemblyInfo.cs +++ b/VectoCore/Properties/AssemblyInfo.cs @@ -36,4 +36,5 @@ using System.Runtime.InteropServices; // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file +[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("VectoCoreTest")] \ No newline at end of file diff --git a/VectoCoreTest/Models/Simulation/SimulationTests.cs b/VectoCoreTest/Models/Simulation/SimulationTests.cs index c9df48928844fd4279ac755085435aaa149cfa27..16da8d874b0aff36ec14e58b25320f7177cde711 100644 --- a/VectoCoreTest/Models/Simulation/SimulationTests.cs +++ b/VectoCoreTest/Models/Simulation/SimulationTests.cs @@ -71,7 +71,7 @@ namespace TUGraz.VectoCore.Tests.Models.Simulation }; factory.DataReader.SetJobFile(EngineOnlyJob); - var runs = factory.NextRun(); + var runs = factory.SimulationRuns(); return runs.First(); //var run = SimulatorFactory.CreateTimeBasedEngineOnlyRun(EngineFile, CycleFile, jobFileName: "", jobName: "", @@ -111,7 +111,7 @@ namespace TUGraz.VectoCore.Tests.Models.Simulation factory.SetJobFile(jobFile); var jobContainer = new JobContainer(new TestSumWriter()); -// jobContainer.AddRuns(factory.NextRun()); +// jobContainer.AddRuns(factory.Runs()); jobContainer.Execute(); ResultFileHelper.TestSumFile(@"TestData\Results\EngineOnlyCycles\24t Coach.vsum", @"TestData\Jobs\24t Coach.vsum"); diff --git a/VectoCoreTest/Models/SimulationComponentData/FullLoadCurveTest.cs b/VectoCoreTest/Models/SimulationComponentData/FullLoadCurveTest.cs index 1e8e0942e09581d08fcb0b45a06d297e3e66db01..cd5feb3699a488ccf97129cc3fe7dd31c86ad2e7 100644 --- a/VectoCoreTest/Models/SimulationComponentData/FullLoadCurveTest.cs +++ b/VectoCoreTest/Models/SimulationComponentData/FullLoadCurveTest.cs @@ -1,6 +1,7 @@ using System; using Microsoft.VisualStudio.TestTools.UnitTesting; using TUGraz.VectoCore.Exceptions; +using TUGraz.VectoCore.FileIO.Reader.Impl; using TUGraz.VectoCore.Models.SimulationComponent.Data.Engine; using TUGraz.VectoCore.Utils; @@ -9,9 +10,21 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponentData [TestClass] public class FullLoadCurveTest { + private const string CoachEngine = @"TestData\Components\24t Coach.veng"; + private const string CoachEngineFLD = @"TestData\Components\24t Coach.vfld"; private const double Tolerance = 0.0001; + + [TestMethod] + public void TestFullLoadCurveDerivedProperties() + { + var engineData = EngineeringModeSimulationDataReader.CreateEngineDataFromFile(CoachEngine); + + var preferredSpeed = engineData.GetFullLoadCurve(1).PreferredSpeed; + Assert.AreEqual(130.691151551712, preferredSpeed.Double(), 0.0001); + } + [TestMethod] public void TestFullLoadStaticTorque() { @@ -26,7 +39,7 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponentData public void TestFullLoadEngineSpeedRated() { var fldCurve = FullLoadCurve.ReadFromFile(CoachEngineFLD); - Assert.AreEqual(181.8444, (double) fldCurve.RatedSpeed(), Tolerance); + Assert.AreEqual(181.8444, fldCurve.RatedSpeed.Double(), Tolerance); } [TestMethod] diff --git a/VectoCoreTest/Models/SimulationComponentData/GearboxDataTest.cs b/VectoCoreTest/Models/SimulationComponentData/GearboxDataTest.cs index 4de68da32203a546ac39cb0a860d3ba0df2038c1..613b0e519684f0a9569e6cc770381601cbb72d70 100644 --- a/VectoCoreTest/Models/SimulationComponentData/GearboxDataTest.cs +++ b/VectoCoreTest/Models/SimulationComponentData/GearboxDataTest.cs @@ -19,7 +19,7 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponentData public void TestGearboxDataReadTest() { var gbxData = EngineeringModeSimulationDataReader.CreateGearboxDataFromFile(GearboxFile); - //GearboxData.ReadFromFile(GearboxFile); + //GearboxData.ReadFromFile(GearboxFile); Assert.AreEqual(GearboxData.GearboxType.AMT, gbxData.Type); Assert.AreEqual(1.0, gbxData.TractionInterruption.Double(), 0.0001); @@ -28,9 +28,9 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponentData Assert.AreEqual(3.240355, gbxData.AxleGearData.Ratio, 0.0001); Assert.AreEqual(1.0, gbxData[7].Ratio, 0.0001); - Assert.AreEqual(-400, gbxData[1].ShiftPolygon[0].Torque.Double(), 0.0001); - Assert.AreEqual(560.RPMtoRad().Double(), gbxData[1].ShiftPolygon[0].AngularSpeedDown.Double(), 0.0001); - Assert.AreEqual(1289.RPMtoRad().Double(), gbxData[1].ShiftPolygon[0].AngularSpeedUp.Double(), 0.0001); + Assert.AreEqual(-400, gbxData[1].ShiftPolygon.Downshift[0].Torque.Double(), 0.0001); + Assert.AreEqual(560.RPMtoRad().Double(), gbxData[1].ShiftPolygon.Downshift[0].AngularSpeed.Double(), 0.0001); + Assert.AreEqual(1289.RPMtoRad().Double(), gbxData[1].ShiftPolygon.Upshift[0].AngularSpeed.Double(), 0.0001); Assert.AreEqual(200.RPMtoRad().Double(), gbxData[1].LossMap[15].InputSpeed.Double(), 0.0001); Assert.AreEqual(-350, gbxData[1].LossMap[15].InputTorque.Double(), 0.0001); diff --git a/VectoCoreTest/TestData/Components/12t Delivery Truck.vfld b/VectoCoreTest/TestData/Components/12t Delivery Truck.vfld new file mode 100644 index 0000000000000000000000000000000000000000..f2a82ee536175e1ba584d5638939604d7a7f10da --- /dev/null +++ b/VectoCoreTest/TestData/Components/12t Delivery Truck.vfld @@ -0,0 +1,20 @@ +n in rpm,M_max in Nm,M_min in Nm,PT1 in s +600,586,-44,0.60 +800,755,-54,0.60 +1000,883,-62,0.60 +1200,899,-74,0.60 +1300,899,-80,0.60 +1400,899,-87,0.60 +1500,899,-92,0.60 +1600,899,-97,0.60 +1700,890,-100,0.60 +1800,881,-103,0.60 +1900,867,-107,0.60 +2000,853,-111,0.43 +2150,811,-118,0.29 +2200,802,-125,0.25 +2300,755,-130,0.25 +2400,705,-135,0.25 +2500,644,-140,0.25 +2600,479,-145,0.25 +2700,0,-149,0.25 \ No newline at end of file diff --git a/VectoCoreTest/TestData/Components/12t Delivery Truck.vmap b/VectoCoreTest/TestData/Components/12t Delivery Truck.vmap new file mode 100644 index 0000000000000000000000000000000000000000..f7ad107b968d22126c862db3a0d24a78c7ba3f14 --- /dev/null +++ b/VectoCoreTest/TestData/Components/12t Delivery Truck.vmap @@ -0,0 +1,186 @@ +engine speed [1/min],torque [Nm],fuel consumption [g/h] +600,-45,0 +600,0,767 +600,100,1759 +600,200,2890 +600,300,4185 +600,400,5404 +600,500,6535 +600,587,7442 +800,-55,0 +800,0,951 +800,100,2346 +800,200,3653 +800,300,5328 +800,400,6903 +800,500,8503 +800,600,10003 +800,700,11641 +800,756,12557 +1000,-63,0 +1000,0,1006 +1000,100,2932 +1000,200,4503 +1000,300,6472 +1000,400,8503 +1000,500,10472 +1000,600,12504 +1000,700,14514 +1000,800,16546 +1000,884,18243 +1200,-75,0 +1200,0,1467 +1200,100,3063 +1200,200,5359 +1200,300,7701 +1200,400,10082 +1200,500,12504 +1200,600,14902 +1200,700,17182 +1200,800,19569 +1200,900,21989 +1300,-81,0 +1300,0,1684 +1300,100,3302 +1300,200,5828 +1300,300,8367 +1300,400,10926 +1300,500,13533 +1300,600,16046 +1300,700,18591 +1300,800,21172 +1300,900,23733 +1400,-88,0 +1400,0,1943 +1400,100,3660 +1400,200,6304 +1400,300,9031 +1400,400,11783 +1400,500,14466 +1400,600,17180 +1400,700,20015 +1400,800,22828 +1400,900,25498 +1500,-93,0 +1500,0,2167 +1500,100,3963 +1500,200,6793 +1500,300,9721 +1500,400,12670 +1500,500,15534 +1500,600,18413 +1500,700,21467 +1500,800,24495 +1500,900,27363 +1600,-98,0 +1600,0,2391 +1600,100,4272 +1600,200,7257 +1600,300,10398 +1600,400,13535 +1600,500,16711 +1600,600,19835 +1600,700,22965 +1600,800,26115 +1600,900,29164 +1700,-101,0 +1700,0,2641 +1700,100,4578 +1700,200,7768 +1700,300,11114 +1700,400,14439 +1700,500,17759 +1700,600,21069 +1700,700,24380 +1700,800,27739 +1700,891,30707 +1800,-104,0 +1800,0,2890 +1800,100,4965 +1800,200,8233 +1800,300,11783 +1800,400,15307 +1800,500,18849 +1800,600,22267 +1800,700,25749 +1800,800,29389 +1800,882,32310 +1900,-108,0 +1900,0,3192 +1900,100,5416 +1900,200,8777 +1900,300,12531 +1900,400,16204 +1900,500,19993 +1900,600,23620 +1900,700,27255 +1900,800,31168 +1900,868,33790 +2000,-112,0 +2000,0,3496 +2000,100,5853 +2000,200,9345 +2000,300,13315 +2000,400,17188 +2000,500,21137 +2000,600,25058 +2000,700,28927 +2000,800,33026 +2000,854,35268 +2150,-119,117 +2150,0,4067 +2150,100,6490 +2150,200,10226 +2150,300,14474 +2150,400,18647 +2150,500,22797 +2150,600,27142 +2150,700,31624 +2150,800,36035 +2150,812,36568 +2200,-126,0 +2200,0,4247 +2200,100,6689 +2200,200,10535 +2200,300,14855 +2200,400,19151 +2200,500,23395 +2200,600,27834 +2200,700,32507 +2200,803,37265 +2300,-131,0 +2300,0,4523 +2300,100,7178 +2300,200,11221 +2300,300,15658 +2300,400,20237 +2300,500,24761 +2300,600,29476 +2300,700,34611 +2300,756,37404 +2400,-136,0 +2400,0,4945 +2400,100,7525 +2400,200,11830 +2400,300,16443 +2400,400,21307 +2400,500,26324 +2400,600,31334 +2400,706,37034 +2500,-141,0 +2500,0,5338 +2500,100,7731 +2500,200,12385 +2500,300,17231 +2500,400,22333 +2500,500,27940 +2500,645,35727 +2600,-146,0 +2600,0,5500 +2600,100,7796 +2600,200,12887 +2600,300,18021 +2600,400,23315 +2600,480,28351 +2700,-150,0 +2700,0,5900 \ No newline at end of file diff --git a/VectoCoreTest/VectoCoreTest.csproj b/VectoCoreTest/VectoCoreTest.csproj index 703bac1776b3c46fb32ef1c4df18928355c2bf5e..81838a3cf065c19fe8967cc3e0adc937863e6253 100644 --- a/VectoCoreTest/VectoCoreTest.csproj +++ b/VectoCoreTest/VectoCoreTest.csproj @@ -119,9 +119,15 @@ <None Include="TestData\Components\12t Delivery Truck.veng"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </None> + <None Include="TestData\Components\12t Delivery Truck.vfld"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> <None Include="TestData\Components\12t Delivery Truck.vgbx"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </None> + <None Include="TestData\Components\12t Delivery Truck.vmap"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> <None Include="TestData\Components\12t Delivery Truck.vveh"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </None>