diff --git a/VectoCore/FileIO/Reader/DataObjectAdaper/AbstractSimulationDataAdapter.cs b/VectoCore/FileIO/Reader/DataObjectAdaper/AbstractSimulationDataAdapter.cs index 8d2ecad9f20f4adfe4799823c5c9278fd851526c..cbaf59f9a19df6ff1fe0c30e6bd90d97479a8ab6 100644 --- a/VectoCore/FileIO/Reader/DataObjectAdaper/AbstractSimulationDataAdapter.cs +++ b/VectoCore/FileIO/Reader/DataObjectAdaper/AbstractSimulationDataAdapter.cs @@ -11,13 +11,9 @@ namespace TUGraz.VectoCore.FileIO.Reader.DataObjectAdaper public abstract class AbstractSimulationDataAdapter { public abstract VehicleData CreateVehicleData(VectoVehicleFile vehicle, Mission mission, Kilogram loading); - public abstract VehicleData CreateVehicleData(VectoVehicleFile vehicle); - public abstract CombustionEngineData CreateEngineData(VectoEngineFile engine); - public abstract GearboxData CreateGearboxData(VectoGearboxFile gearbox, CombustionEngineData engine); - // ========================= internal VehicleData SetCommonVehicleData(VehicleFileV7Declaration.DataBodyDecl data, string basePath) @@ -35,14 +31,16 @@ namespace TUGraz.VectoCore.FileIO.Reader.DataObjectAdaper //DragCoefficientRigidTruck = data.DragCoefficientRigidTruck, //CrossSectionAreaRigidTruck = data.CrossSectionAreaRigidTruck.SI<SquareMeter>(), //TyreRadius = data.TyreRadius.SI().Milli.Meter.Cast<Meter>(), - Rim = data.RimStr, + Rim = data.RimStr }; var retarder = new RetarderData { Type = - (RetarderData.RetarderType)Enum.Parse(typeof(RetarderData.RetarderType), data.Retarder.TypeStr.ToString(), true), + (RetarderData.RetarderType) + Enum.Parse(typeof(RetarderData.RetarderType), data.Retarder.TypeStr, true) }; - if (retarder.Type == RetarderData.RetarderType.Primary || retarder.Type == RetarderData.RetarderType.Secondary) { + if (retarder.Type == RetarderData.RetarderType.Primary || + retarder.Type == RetarderData.RetarderType.Secondary) { retarder.LossMap = RetarderLossMap.ReadFromFile(Path.Combine(basePath, data.Retarder.File)); retarder.Ratio = data.Retarder.Ratio; } @@ -51,7 +49,8 @@ namespace TUGraz.VectoCore.FileIO.Reader.DataObjectAdaper return retVal; } - internal CombustionEngineData SetCommonCombustionEngineData(EngineFileV3Declaration.DataBodyDecl data, string basePath) + internal CombustionEngineData SetCommonCombustionEngineData(EngineFileV3Declaration.DataBodyDecl data, + string basePath) { var retVal = new CombustionEngineData { SavedInDeclarationMode = data.SavedInDeclarationMode, @@ -61,7 +60,7 @@ namespace TUGraz.VectoCore.FileIO.Reader.DataObjectAdaper ConsumptionMap = FuelConsumptionMap.ReadFromFile(Path.Combine(basePath, data.FuelMap)), WHTCUrban = data.WHTCUrban.SI<KilogramPerWattSecond>(), WHTCMotorway = data.WHTCMotorway.SI<KilogramPerWattSecond>(), - WHTCRural = data.WHTCRural.SI<KilogramPerWattSecond>(), + WHTCRural = data.WHTCRural.SI<KilogramPerWattSecond>() }; return retVal; } diff --git a/VectoCore/FileIO/Reader/DataObjectAdaper/DeclarationDataAdapter.cs b/VectoCore/FileIO/Reader/DataObjectAdaper/DeclarationDataAdapter.cs index cca4596af963ce05f783a2e83ef4f819097aba2b..1b6690546a833ef57c4ce48fae0abfc70fc41f86 100644 --- a/VectoCore/FileIO/Reader/DataObjectAdaper/DeclarationDataAdapter.cs +++ b/VectoCore/FileIO/Reader/DataObjectAdaper/DeclarationDataAdapter.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.IO; using System.Linq; using TUGraz.VectoCore.Configuration; @@ -79,24 +80,24 @@ namespace TUGraz.VectoCore.FileIO.Reader.DataObjectAdaper UnderSpeed = DeclarationData.Driver.OverSpeedEcoRoll.UnderSpeed }; if (!DeclarationData.Driver.OverSpeedEcoRoll.AllowedModes.Contains(overspeedData.Mode)) { - throw new VectoSimulationException("Specified Overspeed/EcoRoll Mode not allowed in declaration mode! {0}", + throw new VectoSimulationException( + "Specified Overspeed/EcoRoll Mode not allowed in declaration mode! {0}", overspeedData.Mode); } var startstopData = new VectoRunData.StartStopData { Enabled = data.StartStop.Enabled, Delay = DeclarationData.Driver.StartStop.Delay, MinTime = DeclarationData.Driver.StartStop.MinTime, - MaxSpeed = DeclarationData.Driver.StartStop.MaxSpeed, + MaxSpeed = DeclarationData.Driver.StartStop.MaxSpeed }; var retVal = new DriverData { LookAheadCoasting = lookAheadData, OverSpeedEcoRoll = overspeedData, - StartStop = startstopData, + StartStop = startstopData }; return retVal; } - internal VehicleData CreateVehicleData(VehicleFileV7Declaration vehicle, Mission mission, Kilogram loading) { var data = vehicle.Body; @@ -109,17 +110,20 @@ namespace TUGraz.VectoCore.FileIO.Reader.DataObjectAdaper retVal.CurbWeigthExtra = mission.MassExtra; retVal.Loading = loading; retVal.DynamicTyreRadius = - DeclarationData.DynamicTyreRadius(data.AxleConfig.Axles[DeclarationData.PoweredAxle()].WheelsStr, data.RimStr); + DeclarationData.DynamicTyreRadius(data.AxleConfig.Axles[DeclarationData.PoweredAxle()].WheelsStr, + data.RimStr); - retVal.CrossWindCorrectionMode = CrossWindCorrectionMode.DeclarationModeCorrection; retVal.AerodynamicDragAera = mission.UseCdA2 ? data.DragCoefficientRigidTruck.SI<SquareMeter>() : data.DragCoefficient.SI<SquareMeter>(); + + retVal.CrossWindCorrectionCurve = GetDeclarationAirResistanceCurve(retVal.VehicleCategory, + retVal.AerodynamicDragAera); + if (data.AxleConfig.Axles.Count < mission.AxleWeightDistribution.Length) { - throw new VectoException( - string.Format("Vehicle does not contain sufficient axles. {0} axles defined, {1} axles required", - data.AxleConfig.Axles.Count, mission.AxleWeightDistribution.Count())); + throw new VectoException("Vehicle does not contain sufficient axles. {0} axles defined, {1} axles required", + data.AxleConfig.Axles.Count, mission.AxleWeightDistribution.Count()); } var axleData = new List<Axle>(); for (var i = 0; i < mission.AxleWeightDistribution.Length; i++) { @@ -129,7 +133,7 @@ namespace TUGraz.VectoCore.FileIO.Reader.DataObjectAdaper TwinTyres = axleInput.TwinTyres, RollResistanceCoefficient = axleInput.RollResistanceCoefficient, TyreTestLoad = axleInput.TyreTestLoad.SI<Newton>(), - Inertia = DeclarationData.Wheels.Lookup(axleInput.WheelsStr.Replace(" ", "")).Inertia, + Inertia = DeclarationData.Wheels.Lookup(axleInput.WheelsStr.Replace(" ", "")).Inertia }; axleData.Add(axle); } @@ -149,8 +153,9 @@ namespace TUGraz.VectoCore.FileIO.Reader.DataObjectAdaper { var retVal = SetCommonCombustionEngineData(engine.Body, engine.BasePath); retVal.Inertia = DeclarationData.Engine.EngineInertia(retVal.Displacement); - retVal.FullLoadCurve = EngineFullLoadCurve.ReadFromFile(Path.Combine(engine.BasePath, engine.Body.FullLoadCurve), - true); + retVal.FullLoadCurve = + EngineFullLoadCurve.ReadFromFile(Path.Combine(engine.BasePath, engine.Body.FullLoadCurve), + true); retVal.FullLoadCurve.EngineData = retVal; return retVal; } @@ -160,7 +165,8 @@ namespace TUGraz.VectoCore.FileIO.Reader.DataObjectAdaper var retVal = SetCommonGearboxData(gearbox.Body); switch (retVal.Type) { case GearboxType.AT: - throw new VectoSimulationException("Automatic Transmission currently not supported in DeclarationMode!"); + throw new VectoSimulationException( + "Automatic Transmission currently not supported in DeclarationMode!"); case GearboxType.Custom: throw new VectoSimulationException("Custom Transmission not supported in DeclarationMode!"); } @@ -183,12 +189,18 @@ namespace TUGraz.VectoCore.FileIO.Reader.DataObjectAdaper retVal.HasTorqueConverter = false; var axleGear = gearbox.Body.Gears.First(); - var axleLossMap = TransmissionLossMap.ReadFromFile(Path.Combine(gearbox.BasePath, axleGear.LossMap), axleGear.Ratio, + var axleLossMap = TransmissionLossMap.ReadFromFile(Path.Combine(gearbox.BasePath, axleGear.LossMap), + axleGear.Ratio, "AxleGear"); - retVal.AxleGearData = new GearData { LossMap = axleLossMap, Ratio = axleGear.Ratio, TorqueConverterActive = false }; + retVal.AxleGearData = new GearData { + LossMap = axleLossMap, + Ratio = axleGear.Ratio, + TorqueConverterActive = false + }; retVal.Gears = gearbox.Body.Gears.Skip(1).Select((gear, i) => { - var gearLossMap = TransmissionLossMap.ReadFromFile(Path.Combine(gearbox.BasePath, gear.LossMap), gear.Ratio, + var gearLossMap = TransmissionLossMap.ReadFromFile(Path.Combine(gearbox.BasePath, gear.LossMap), + gear.Ratio, string.Format("Gear {0}", i)); var gearFullLoad = (string.IsNullOrWhiteSpace(gear.FullLoadCurve) || gear.FullLoadCurve == "<NOFILE>") ? engine.FullLoadCurve @@ -209,11 +221,13 @@ namespace TUGraz.VectoCore.FileIO.Reader.DataObjectAdaper } /// <summary> - /// Intersects full load curves. + /// Intersects full load curves. /// </summary> - /// <param name="curves">full load curves</param> + /// <param name="engineCurve">engine's full-load curve</param> + /// <param name="gearCurve">gearbox' full-load curve for a certain gear</param> /// <returns>A combined EngineFullLoadCurve with the minimum full load torque over all inputs curves.</returns> - private static EngineFullLoadCurve IntersectFullLoadCurves(EngineFullLoadCurve engineCurve, FullLoadCurve gearCurve) + private static EngineFullLoadCurve IntersectFullLoadCurves(EngineFullLoadCurve engineCurve, + FullLoadCurve gearCurve) { var entries = gearCurve.FullLoadEntries.Concat(engineCurve.FullLoadEntries) .Select(entry => entry.EngineSpeed) @@ -222,7 +236,8 @@ namespace TUGraz.VectoCore.FileIO.Reader.DataObjectAdaper .Select(engineSpeed => new FullLoadCurve.FullLoadCurveEntry { EngineSpeed = engineSpeed, TorqueFullLoad = - VectoMath.Min(engineCurve.FullLoadStationaryTorque(engineSpeed), gearCurve.FullLoadStationaryTorque(engineSpeed)) + VectoMath.Min(engineCurve.FullLoadStationaryTorque(engineSpeed), + gearCurve.FullLoadStationaryTorque(engineSpeed)) }); var flc = new EngineFullLoadCurve { @@ -264,5 +279,49 @@ namespace TUGraz.VectoCore.FileIO.Reader.DataObjectAdaper yield return aux; } } + + public static CrossWindCorrectionCurve GetDeclarationAirResistanceCurve(VehicleCategory vehicleCategory, + SquareMeter aerodynamicDragAera) + { + var values = DeclarationData.AirDrag.Lookup(vehicleCategory); + var points = new List<CrossWindCorrectionCurve.CrossWindCorrectionEntry> { + new CrossWindCorrectionCurve.CrossWindCorrectionEntry { + Velocity = 0.SI<MeterPerSecond>(), + EffectiveCrossSectionArea = 0.SI<SquareMeter>() + } + }; + + for (var speed = 60; speed <= 100; speed += 5) { + var vVeh = speed.KMPHtoMeterPerSecond(); + var cdASum = 0.0.SI<SquareMeter>(); + for (var alpha = 0; alpha <= 180; alpha += 10) { + var vWindX = Physics.BaseWindSpeed * Math.Cos(alpha.ToRadian()); + var vWindY = Physics.BaseWindSpeed * Math.Sin(alpha.ToRadian()); + var vAirX = vVeh + vWindX; + var vAirY = vWindY; +// var vAir = VectoMath.Sqrt<MeterPerSecond>(vAirX * vAirX + vAirY * vAirY); + var beta = Math.Atan((vAirY / vAirX).Value()).ToDegree(); + var deltaCdA = ComputeDeltaCd(beta, values); + var cdA = aerodynamicDragAera + deltaCdA; + + var degreeShare = ((alpha != 0 && alpha != 180) ? 10.0 / 180.0 : 5.0 / 180.0); + +// cdASum += degreeShare * cdA * (vAir * vAir / (vVeh * vVeh)).Cast<Scalar>(); + cdASum += degreeShare * cdA * ((vAirX * vAirX + vAirY * vAirY) / (vVeh * vVeh)).Cast<Scalar>(); + } + points.Add(new CrossWindCorrectionCurve.CrossWindCorrectionEntry { + Velocity = vVeh, + EffectiveCrossSectionArea = cdASum + }); + } + + points[0].EffectiveCrossSectionArea = points[1].EffectiveCrossSectionArea; + return new CrossWindCorrectionCurve(points, CrossWindCorrectionMode.DeclarationModeCorrection); + } + + protected static SquareMeter ComputeDeltaCd(double beta, AirDrag.AirDragEntry values) + { + return (values.A1 * beta + values.A2 * beta * beta + values.A3 * beta * beta * beta).SI<SquareMeter>(); + } } } \ No newline at end of file diff --git a/VectoCore/FileIO/Reader/DataObjectAdaper/EngineeringDataAdapter.cs b/VectoCore/FileIO/Reader/DataObjectAdaper/EngineeringDataAdapter.cs index ba80fcbb6e292140523e4859c9c70871d93d7184..1dec2481b497d3c3186f263049996f3d03a71907 100644 --- a/VectoCore/FileIO/Reader/DataObjectAdaper/EngineeringDataAdapter.cs +++ b/VectoCore/FileIO/Reader/DataObjectAdaper/EngineeringDataAdapter.cs @@ -1,4 +1,5 @@ -using System.IO; +using System; +using System.IO; using System.Linq; using TUGraz.VectoCore.Exceptions; using TUGraz.VectoCore.FileIO.EngineeringFile; @@ -68,32 +69,32 @@ namespace TUGraz.VectoCore.FileIO.Reader.DataObjectAdaper var lookAheadData = new DriverData.LACData { Enabled = data.LookAheadCoasting.Enabled, Deceleration = data.LookAheadCoasting.Dec.SI<MeterPerSquareSecond>(), - MinSpeed = data.LookAheadCoasting.MinSpeed.KMPHtoMeterPerSecond(), + MinSpeed = data.LookAheadCoasting.MinSpeed.KMPHtoMeterPerSecond() }; var overspeedData = new DriverData.OverSpeedEcoRollData { Mode = DriverData.ParseDriverMode(data.OverSpeedEcoRoll.Mode), MinSpeed = data.OverSpeedEcoRoll.MinSpeed.KMPHtoMeterPerSecond(), OverSpeed = data.OverSpeedEcoRoll.OverSpeed.KMPHtoMeterPerSecond(), - UnderSpeed = data.OverSpeedEcoRoll.UnderSpeed.KMPHtoMeterPerSecond(), + UnderSpeed = data.OverSpeedEcoRoll.UnderSpeed.KMPHtoMeterPerSecond() }; var startstopData = new VectoRunData.StartStopData { Enabled = data.StartStop.Enabled, Delay = data.StartStop.Delay.SI<Second>(), MinTime = data.StartStop.MinTime.SI<Second>(), - MaxSpeed = data.StartStop.MaxSpeed.KMPHtoMeterPerSecond(), + MaxSpeed = data.StartStop.MaxSpeed.KMPHtoMeterPerSecond() }; var retVal = new DriverData { AccelerationCurve = accelerationData, LookAheadCoasting = lookAheadData, OverSpeedEcoRoll = overspeedData, - StartStop = startstopData, + StartStop = startstopData }; return retVal; } /// <summary> - /// convert datastructure representing file-contents into internal datastructure - /// Vehicle, file-format version 5 + /// convert datastructure representing file-contents into internal datastructure + /// Vehicle, file-format version 5 /// </summary> /// <param name="vehicle">VehicleFileV5 container</param> /// <returns>VehicleData instance</returns> @@ -108,24 +109,47 @@ namespace TUGraz.VectoCore.FileIO.Reader.DataObjectAdaper retVal.Loading = data.Loading.SI<Kilogram>(); retVal.DynamicTyreRadius = data.DynamicTyreRadius.SI().Milli.Meter.Cast<Meter>(); - retVal.CrossWindCorrectionMode = CrossWindCorrectionModeHelper.Parse(data.CrossWindCorrectionModeStr); + //retVal.CrossWindCorrectionMode = CrossWindCorrectionModeHelper.Parse(data.CrossWindCorrectionModeStr); retVal.AerodynamicDragAera = data.DragCoefficient.SI<SquareMeter>(); + var crosswindCorrectionMode = CrossWindCorrectionModeHelper.Parse(data.CrossWindCorrectionModeStr); + switch (crosswindCorrectionMode) { + case CrossWindCorrectionMode.NoCorrection: + retVal.CrossWindCorrectionCurve = + CrossWindCorrectionCurve.GetNoCorrectionCurve(retVal.AerodynamicDragAera); + break; + case CrossWindCorrectionMode.SpeedDependentCorrectionFactor: + retVal.CrossWindCorrectionCurve = + CrossWindCorrectionCurve.ReadSpeedDependentCorrectionFromFile( + Path.Combine(vehicle.BasePath, data.CrossWindCorrectionFile), + retVal.AerodynamicDragAera); + break; + case CrossWindCorrectionMode.VAirBetaLookupTable: + throw new VectoException("CrosswindCorrection mode {0} not implemented", crosswindCorrectionMode); + case CrossWindCorrectionMode.DeclarationModeCorrection: + retVal.CrossWindCorrectionCurve = + DeclarationDataAdapter.GetDeclarationAirResistanceCurve(retVal.VehicleCategory, + retVal.AerodynamicDragAera); + break; + default: + throw new ArgumentOutOfRangeException(); + } + + retVal.AxleData = data.AxleConfig.Axles.Select(axle => new Axle { Inertia = axle.Inertia.SI<KilogramSquareMeter>(), TwinTyres = axle.TwinTyres, RollResistanceCoefficient = axle.RollResistanceCoefficient, AxleWeightShare = axle.AxleWeightShare, - TyreTestLoad = axle.TyreTestLoad.SI<Newton>(), + TyreTestLoad = axle.TyreTestLoad.SI<Newton>() //Wheels = axle.WheelsStr }).ToList(); return retVal; } - /// <summary> - /// convert datastructure representing the file-contents into internal data structure - /// Engine, file-format version 2 + /// convert datastructure representing the file-contents into internal data structure + /// Engine, file-format version 2 /// </summary> /// <param name="engine">Engin-Data file (Engineering mode)</param> /// <returns></returns> @@ -133,15 +157,15 @@ namespace TUGraz.VectoCore.FileIO.Reader.DataObjectAdaper { var retVal = SetCommonCombustionEngineData(engine.Body, engine.BasePath); retVal.Inertia = engine.Body.Inertia.SI<KilogramSquareMeter>(); - retVal.FullLoadCurve = EngineFullLoadCurve.ReadFromFile(Path.Combine(engine.BasePath, engine.Body.FullLoadCurve)); + retVal.FullLoadCurve = + EngineFullLoadCurve.ReadFromFile(Path.Combine(engine.BasePath, engine.Body.FullLoadCurve)); retVal.FullLoadCurve.EngineData = retVal; return retVal; } - /// <summary> - /// convert datastructure representing the file-contents into internal data structure - /// Gearbox, File-format Version 4 + /// convert datastructure representing the file-contents into internal data structure + /// Gearbox, File-format Version 4 /// </summary> /// <param name="gearbox"></param> /// <param name="engineData"></param> @@ -177,7 +201,8 @@ namespace TUGraz.VectoCore.FileIO.Reader.DataObjectAdaper gearSettings.ShiftPolygon != "<NOFILE>" ? ShiftPolygon.ReadFromFile(Path.Combine(gearbox.BasePath, gearSettings.ShiftPolygon)) : null; - var fullLoad = !string.IsNullOrEmpty(gearSettings.FullLoadCurve) && gearSettings.FullLoadCurve != "<NOFILE>" && + var fullLoad = !string.IsNullOrEmpty(gearSettings.FullLoadCurve) && + gearSettings.FullLoadCurve != "<NOFILE>" && gearSettings.FullLoadCurve != "-" ? FullLoadCurve.ReadFromFile(Path.Combine(gearbox.BasePath, gearSettings.FullLoadCurve)) : null; diff --git a/VectoCore/Models/Declaration/AirDrag.cs b/VectoCore/Models/Declaration/AirDrag.cs index 1b66bee4583411ae8306e248319088675ac08b47..1e1d886ba788f4485e8010f375b7baf9d9baff62 100644 --- a/VectoCore/Models/Declaration/AirDrag.cs +++ b/VectoCore/Models/Declaration/AirDrag.cs @@ -58,7 +58,7 @@ namespace TUGraz.VectoCore.Models.Declaration if (ReferenceEquals(this, obj)) { return true; } - if (obj.GetType() != this.GetType()) { + if (obj.GetType() != GetType()) { return false; } return Equals((AirDragEntry)obj); diff --git a/VectoCore/Models/SimulationComponent/Data/CrossWindCorrectionCurve.cs b/VectoCore/Models/SimulationComponent/Data/CrossWindCorrectionCurve.cs new file mode 100644 index 0000000000000000000000000000000000000000..3a8d5a4ee9f4ab893b6f48e5a2465d9cce145e56 --- /dev/null +++ b/VectoCore/Models/SimulationComponent/Data/CrossWindCorrectionCurve.cs @@ -0,0 +1,125 @@ +using System.Collections.Generic; +using System.Data; +using System.IO; +using System.Linq; +using TUGraz.VectoCore.Exceptions; +using TUGraz.VectoCore.Utils; + +namespace TUGraz.VectoCore.Models.SimulationComponent.Data +{ + public class CrossWindCorrectionCurve : LoggingObject + { + protected List<CrossWindCorrectionEntry> Entries; + + public CrossWindCorrectionCurve(List<CrossWindCorrectionEntry> entries, CrossWindCorrectionMode correctionMode) + { + CorrectionMode = correctionMode; + Entries = entries; + } + + public CrossWindCorrectionMode CorrectionMode { get; internal set; } + + public static CrossWindCorrectionCurve ReadSpeedDependentCorrectionCurveFromStream(Stream inputData, + SquareMeter aerodynamicDragArea) + { + var data = VectoCSVFile.ReadStream(inputData); + return Parse(data, aerodynamicDragArea); + } + + public static CrossWindCorrectionCurve ReadSpeedDependentCorrectionFromFile(string fileName, + SquareMeter aerodynamicDragArea) + { + var data = VectoCSVFile.Read(fileName); + return Parse(data, aerodynamicDragArea); + } + + private static CrossWindCorrectionCurve Parse(DataTable data, + SquareMeter aerodynamicDragArea) + { + if (data.Columns.Count != 2) { + throw new VectoException("Crosswind correction file must consist of 2 columns."); + } + if (data.Rows.Count < 2) { + throw new VectoException("Crosswind correction file must consist of at least two entries"); + } + + if (HeaderIsValid(data.Columns)) { + return new CrossWindCorrectionCurve(ReadFromColumnNames(data, aerodynamicDragArea), + CrossWindCorrectionMode.SpeedDependentCorrectionFactor); + } + Logger<CrossWindCorrectionCurve>() + .Warn( + "Crosswind correction file: Header line is not valid. Expected: '{0}, {1}', Got: '{2}'. Falling back to column index.", + Fields.Velocity, Fields.Cd, + string.Join(", ", data.Columns.Cast<DataColumn>().Select(c => c.ColumnName).Reverse())); + return new CrossWindCorrectionCurve(ReadFromColumnIndizes(data, aerodynamicDragArea), + CrossWindCorrectionMode.SpeedDependentCorrectionFactor); + } + + private static List<CrossWindCorrectionEntry> ReadFromColumnIndizes(DataTable data, + SquareMeter aerodynamicDragArea) + { + return (from DataRow row in data.Rows + select new CrossWindCorrectionEntry { + Velocity = row.ParseDouble(0).KMPHtoMeterPerSecond(), + EffectiveCrossSectionArea = row.ParseDouble(1) * aerodynamicDragArea + }).ToList(); + } + + private static List<CrossWindCorrectionEntry> ReadFromColumnNames(DataTable data, + SquareMeter aerodynamicDragArea) + { + return (from DataRow row in data.Rows + select new CrossWindCorrectionEntry { + Velocity = row.ParseDouble(Fields.Velocity).KMPHtoMeterPerSecond(), + EffectiveCrossSectionArea = row.ParseDouble(Fields.Cd) * aerodynamicDragArea + }).ToList(); + } + + private static bool HeaderIsValid(DataColumnCollection columns) + { + return columns.Contains(Fields.Velocity) && columns.Contains(Fields.Cd); + } + + public static CrossWindCorrectionCurve GetNoCorrectionCurve(SquareMeter aerodynamicDragArea) + { + return new CrossWindCorrectionCurve(new[] { + new CrossWindCorrectionEntry { + Velocity = 0.KMPHtoMeterPerSecond(), + EffectiveCrossSectionArea = aerodynamicDragArea + }, + new CrossWindCorrectionEntry { + Velocity = 100.KMPHtoMeterPerSecond(), + EffectiveCrossSectionArea = aerodynamicDragArea + } + }.ToList(), CrossWindCorrectionMode.NoCorrection); + } + + public SquareMeter EffectiveAirDragArea(MeterPerSecond x) + { + var p = Entries.GetSection(c => c.Velocity < x); + + if (x < p.Item1.Velocity || p.Item2.Velocity < x) { + //Log.Error(_data.CrossWindCorrectionMode == CrossWindCorrectionMode.VAirBetaLookupTable + // ? string.Format("CdExtrapol β = {0}", x) + // : string.Format("CdExtrapol v = {0}", x)); + Log.Error("CdExtrapol v = {0}", x); + } + + return VectoMath.Interpolate(p.Item1.Velocity, p.Item2.Velocity, + p.Item1.EffectiveCrossSectionArea, p.Item2.EffectiveCrossSectionArea, x); + } + + public class Fields + { + public static readonly string Velocity = "v"; + public static readonly string Cd = "Cd"; + } + + public class CrossWindCorrectionEntry + { + public SquareMeter EffectiveCrossSectionArea; + public MeterPerSecond Velocity; + } + } +} \ No newline at end of file diff --git a/VectoCore/Models/SimulationComponent/Data/CycleData.cs b/VectoCore/Models/SimulationComponent/Data/CycleData.cs index 27eac5780579226c28d332055041c96f9b0164cd..76c9d656fb7cff153cf9c70addd46d43105677aa 100644 --- a/VectoCore/Models/SimulationComponent/Data/CycleData.cs +++ b/VectoCore/Models/SimulationComponent/Data/CycleData.cs @@ -5,23 +5,23 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data public class CycleData { /// <summary> - /// The left data sample of the current driving cycle position. (current start point) + /// The current absolute distance in the driving cycle. /// </summary> - public DrivingCycleData.DrivingCycleEntry LeftSample; + public Meter AbsDistance; /// <summary> - /// The right data sample of the current driving cycle position. (current end point) + /// The current absolute time in the driving cycle. /// </summary> - public DrivingCycleData.DrivingCycleEntry RightSample; + public Second AbsTime; /// <summary> - /// The current absolute distance in the driving cycle. + /// The left data sample of the current driving cycle position. (current start point) /// </summary> - public Meter AbsDistance; + public DrivingCycleData.DrivingCycleEntry LeftSample; /// <summary> - /// The current absolute time in the driving cycle. + /// The right data sample of the current driving cycle position. (current end point) /// </summary> - public Second AbsTime; + public DrivingCycleData.DrivingCycleEntry RightSample; } } \ No newline at end of file diff --git a/VectoCore/Models/SimulationComponent/Data/FullLoadCurve.cs b/VectoCore/Models/SimulationComponent/Data/FullLoadCurve.cs index c0a624ebe874cde1a5c9d1d61ab0f973360db9cf..ba085914c605b7467c21853b08380e8b22ed9caf 100644 --- a/VectoCore/Models/SimulationComponent/Data/FullLoadCurve.cs +++ b/VectoCore/Models/SimulationComponent/Data/FullLoadCurve.cs @@ -12,11 +12,23 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data { public class FullLoadCurve : SimulationComponentData { + protected Watt _maxPower; + protected PerSecond _ratedSpeed; internal List<FullLoadCurveEntry> FullLoadEntries; internal LookupData<PerSecond, Second> PT1Data; - protected PerSecond _ratedSpeed; - protected Watt _maxPower; + /// <summary> + /// Get the rated speed from the given full-load curve (i.e. speed with max. power) + /// </summary> + public PerSecond RatedSpeed + { + get { return (_ratedSpeed ?? ComputeRatedSpeed().Item1); } + } + + public Watt MaxPower + { + get { return (_maxPower ?? ComputeRatedSpeed().Item2); } + } public static FullLoadCurve ReadFromFile(string fileName, bool declarationMode = false) { @@ -77,7 +89,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data select new FullLoadCurveEntry { EngineSpeed = row.ParseDouble(Fields.EngineSpeed).RPMtoRad(), TorqueFullLoad = row.ParseDouble(Fields.TorqueFullLoad).SI<NewtonMeter>(), - TorqueDrag = row.ParseDouble(Fields.TorqueDrag).SI<NewtonMeter>(), + TorqueDrag = row.ParseDouble(Fields.TorqueDrag).SI<NewtonMeter>() //PT1 = row.ParseDouble(Fields.PT1).SI<Second>() }).ToList(); } @@ -89,27 +101,13 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data select new FullLoadCurveEntry { EngineSpeed = row.ParseDouble(0).RPMtoRad(), TorqueFullLoad = row.ParseDouble(1).SI<NewtonMeter>(), - TorqueDrag = row.ParseDouble(2).SI<NewtonMeter>(), + TorqueDrag = row.ParseDouble(2).SI<NewtonMeter>() //PT1 = row.ParseDouble(3).SI<Second>() }).ToList(); } /// <summary> - /// Get the rated speed from the given full-load curve (i.e. speed with max. power) - /// </summary> - public PerSecond RatedSpeed - { - get { return (_ratedSpeed ?? ComputeRatedSpeed().Item1); } - } - - public Watt MaxPower - { - get { return (_maxPower ?? ComputeRatedSpeed().Item2); } - } - - - /// <summary> - /// Compute the engine's rated speed from the given full-load curve (i.e. engine speed with max. power) + /// Compute the engine's rated speed from the given full-load curve (i.e. engine speed with max. power) /// </summary> protected Tuple<PerSecond, Watt> ComputeRatedSpeed() { @@ -189,11 +187,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data internal class FullLoadCurveEntry { public PerSecond EngineSpeed { get; set; } - public NewtonMeter TorqueFullLoad { get; set; } - public NewtonMeter TorqueDrag { get; set; } - //public Second PT1 { get; set; } #region Equality members diff --git a/VectoCore/Models/SimulationComponent/Data/RetarderLossMap.cs b/VectoCore/Models/SimulationComponent/Data/RetarderLossMap.cs index 4ae104eeacc067304e382a92b1146a4c984cde8e..3ce828596cfe5bc428ee097473a17ecbfe319519 100644 --- a/VectoCore/Models/SimulationComponent/Data/RetarderLossMap.cs +++ b/VectoCore/Models/SimulationComponent/Data/RetarderLossMap.cs @@ -11,7 +11,6 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data { private List<RetarderLossEntry> _entries; - public static RetarderLossMap ReadFromFile(string fileName) { DataTable data; @@ -25,7 +24,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data } if (data.Rows.Count < 2) { - throw new VectoException("RetarderLossMap must consist of at leas two entries."); + throw new VectoException("RetarderLossMap must consist of at least two entries."); } List<RetarderLossEntry> entries; @@ -53,7 +52,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data int idx; if (angularVelocity < _entries[0].RetarderSpeed) { Log.Info("requested rpm below minimum rpm in retarder loss map - extrapolating. n: {0}, rpm_min: {1}", - angularVelocity.ConvertTo().Rounds.Per.Minute, _entries[0].RetarderSpeed.ConvertTo().Rounds.Per.Minute); + angularVelocity.ConvertTo().Rounds.Per.Minute, + _entries[0].RetarderSpeed.ConvertTo().Rounds.Per.Minute); idx = 1; } else { idx = _entries.FindIndex(x => x.RetarderSpeed > angularVelocity); @@ -91,19 +91,18 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data private class RetarderLossEntry { public PerSecond RetarderSpeed { get; set; } - public NewtonMeter TorqueLoss { get; set; } } private static class Fields { /// <summary> - /// [rpm] + /// [rpm] /// </summary> public const string RetarderSpeed = "Retarder Speed"; /// <summary> - /// [Nm] + /// [Nm] /// </summary> public const string TorqueLoss = "Torque Loss"; } diff --git a/VectoCore/Models/SimulationComponent/Data/VehicleData.cs b/VectoCore/Models/SimulationComponent/Data/VehicleData.cs index 84778ba4c49b931fe21799550f87bc8705af11ad..9791589edccb199933d22a6034d000dd829994cc 100644 --- a/VectoCore/Models/SimulationComponent/Data/VehicleData.cs +++ b/VectoCore/Models/SimulationComponent/Data/VehicleData.cs @@ -8,20 +8,17 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data { public class VehicleData : SimulationComponentData { + private List<Axle> _axleData; public string BasePath { get; internal set; } - public VehicleCategory VehicleCategory { get; internal set; } - public VehicleClass VehicleClass { get; internal set; } + //public CrossWindCorrectionMode CrossWindCorrectionMode { get; internal set; } - public CrossWindCorrectionMode CrossWindCorrectionMode { get; internal set; } - + public CrossWindCorrectionCurve CrossWindCorrectionCurve { get; internal set; } public RetarderData Retarder { get; internal set; } - private List<Axle> _axleData; - /// <summary> - /// Set the properties for all axles of the vehicle + /// Set the properties for all axles of the vehicle /// </summary> public List<Axle> AxleData { @@ -34,12 +31,15 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data } public AxleConfiguration AxleConfiguration { get; internal set; } - public Kilogram CurbWeight { get; internal set; } - public Kilogram CurbWeigthExtra { get; internal set; } - public Kilogram Loading { get; internal set; } + public Kilogram GrossVehicleMassRating { get; internal set; } + public SquareMeter AerodynamicDragAera { get; internal set; } + public Meter DynamicTyreRadius { get; internal set; } + public Kilogram ReducedMassWheels { get; private set; } + public string Rim { get; internal set; } + public double TotalRollResistanceCoefficient { get; private set; } public Kilogram TotalVehicleWeight() { @@ -58,22 +58,11 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data return retVal; } - public Kilogram GrossVehicleMassRating { get; internal set; } - - public SquareMeter AerodynamicDragAera { get; internal set; } - - public Meter DynamicTyreRadius { get; internal set; } - - public Kilogram ReducedMassWheels { get; private set; } - - public string Rim { get; internal set; } - - public double TotalRollResistanceCoefficient { get; private set; } - protected void ComputeRollResistanceAndReducedMassWheels() { if (TotalVehicleWeight() == 0.SI<Kilogram>()) { - throw new VectoException("Total vehicle weight must be greater than 0! Set CurbWeight and Loading before!"); + throw new VectoException( + "Total vehicle weight must be greater than 0! Set CurbWeight and Loading before!"); } if (DynamicTyreRadius == null) { throw new VectoException("Dynamic tyre radius must be set before axles!"); @@ -85,7 +74,8 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data var nrWheels = axle.TwinTyres ? 4 : 2; RRC += axle.AxleWeightShare * axle.RollResistanceCoefficient * Math.Pow( - (axle.AxleWeightShare * TotalVehicleWeight() * Physics.GravityAccelleration / axle.TyreTestLoad / + (axle.AxleWeightShare * TotalVehicleWeight() * Physics.GravityAccelleration / + axle.TyreTestLoad / nrWheels).Value(), Physics.RollResistanceExponent - 1); mRed0 += nrWheels * (axle.Inertia / DynamicTyreRadius / DynamicTyreRadius).Cast<Kilogram>(); } diff --git a/VectoCore/Models/SimulationComponent/Impl/Vehicle.cs b/VectoCore/Models/SimulationComponent/Impl/Vehicle.cs index 4402ce894926474fb208780460e22c2422e303ae..7ef951a3a7936f2127651f2caefad0e697b70074 100644 --- a/VectoCore/Models/SimulationComponent/Impl/Vehicle.cs +++ b/VectoCore/Models/SimulationComponent/Impl/Vehicle.cs @@ -1,8 +1,5 @@ using System; -using System.Collections.Generic; -using System.Runtime.InteropServices.WindowsRuntime; using TUGraz.VectoCore.Configuration; -using TUGraz.VectoCore.Exceptions; using TUGraz.VectoCore.Models.Connector.Ports; using TUGraz.VectoCore.Models.Declaration; using TUGraz.VectoCore.Models.Simulation; @@ -13,322 +10,245 @@ using TUGraz.VectoCore.Utils; namespace TUGraz.VectoCore.Models.SimulationComponent.Impl { - public class Vehicle : VectoSimulationComponent, IVehicle, IMileageCounter, IFvInPort, IDriverDemandOutPort - { - protected IFvOutPort NextComponent; - private VehicleState _previousState; - private VehicleState _currentState; - private readonly VehicleData _data; - - private readonly Point[] _airResistanceCurve; - - public MeterPerSecond VehicleSpeed - { - get { return _previousState.Velocity; } - } - - public Kilogram VehicleMass - { - get { return _data.TotalCurbWeight(); } - } - - public Kilogram VehicleLoading - { - get { return _data.Loading; } - } - - public Kilogram TotalMass - { - get { return _data.TotalVehicleWeight(); } - } - - public Meter Distance - { - get { return _previousState.Distance; } - } - - - public Vehicle(IVehicleContainer container, VehicleData data) : base(container) - { - _data = data; - _previousState = new VehicleState { Distance = 0.SI<Meter>(), Velocity = 0.SI<MeterPerSecond>() }; - _currentState = new VehicleState { Distance = 0.SI<Meter>(), Velocity = 0.SI<MeterPerSecond>() }; - - var values = DeclarationData.AirDrag.Lookup(_data.VehicleCategory); - _airResistanceCurve = CalculateAirResistanceCurve(values); - } - - - public IFvInPort InPort() - { - return this; - } - - public IDriverDemandOutPort OutPort() - { - return this; - } - - public void Connect(IFvOutPort other) - { - NextComponent = other; - } - - public IResponse Initialize(MeterPerSecond vehicleSpeed, Radian roadGradient) - { - _previousState = new VehicleState { - Distance = DataBus.CycleStartDistance, - Velocity = vehicleSpeed, - RollingResistance = RollingResistance(roadGradient), - SlopeResistance = SlopeResistance(roadGradient) - }; - _previousState.AirDragResistance = AirDragResistance(0.SI<MeterPerSquareSecond>(), - Constants.SimulationSettings.TargetTimeInterval); - _previousState.VehicleAccelerationForce = _previousState.RollingResistance - + _previousState.AirDragResistance - + _previousState.SlopeResistance; - - _currentState = new VehicleState { - Distance = DataBus.CycleStartDistance, - Velocity = vehicleSpeed, - AirDragResistance = _previousState.AirDragResistance, - RollingResistance = _previousState.RollingResistance, - SlopeResistance = _previousState.SlopeResistance, - VehicleAccelerationForce = _previousState.VehicleAccelerationForce, - }; - - - return NextComponent.Initialize(_currentState.VehicleAccelerationForce, vehicleSpeed); - } - - public IResponse Initialize(MeterPerSecond vehicleSpeed, MeterPerSquareSecond startAcceleration, - Radian roadGradient) - { - var tmp = _previousState.Velocity; - // set vehicle speed to get accurate airdrag resistance - _previousState.Velocity = vehicleSpeed; - _currentState.Velocity = vehicleSpeed + startAcceleration * Constants.SimulationSettings.TargetTimeInterval; - var vehicleAccelerationForce = DriverAcceleration(startAcceleration) + RollingResistance(roadGradient) + - AirDragResistance(startAcceleration, - Constants.SimulationSettings.TargetTimeInterval) + - SlopeResistance(roadGradient); - - var retVal = NextComponent.Initialize(vehicleAccelerationForce, vehicleSpeed); - - _previousState.Velocity = tmp; - _currentState.Velocity = tmp; - return retVal; - } - - public IResponse Request(Second absTime, Second dt, MeterPerSquareSecond acceleration, Radian gradient, - bool dryRun = false) - { - Log.Debug("from Wheels: acceleration: {0}", acceleration); - _currentState.dt = dt; - _currentState.Acceleration = acceleration; - _currentState.Velocity = _previousState.Velocity + acceleration * dt; - if (_currentState.Velocity.IsEqual(0.SI<MeterPerSecond>(), - Constants.SimulationSettings.VehicleSpeedHaltTolerance)) { - _currentState.Velocity = 0.SI<MeterPerSecond>(); - } - _currentState.Distance = _previousState.Distance + _previousState.Velocity * dt + acceleration * dt * dt / 2; - - _currentState.DriverAcceleration = DriverAcceleration(acceleration); - _currentState.RollingResistance = RollingResistance(gradient); - _currentState.AirDragResistance = AirDragResistance(acceleration, dt); - _currentState.SlopeResistance = SlopeResistance(gradient); - - // DriverAcceleration = vehicleAccelerationForce - RollingResistance - AirDragResistance - SlopeResistance - _currentState.VehicleAccelerationForce = _currentState.DriverAcceleration - + _currentState.RollingResistance - + _currentState.AirDragResistance - + _currentState.SlopeResistance; - - var retval = NextComponent.Request(absTime, dt, _currentState.VehicleAccelerationForce, - _currentState.Velocity, - dryRun); - return retval; - } - - protected override void DoWriteModalResults(IModalDataWriter writer) - { - var averageVelocity = (_previousState.Velocity + _currentState.Velocity) / 2; - - writer[ModalResultField.v_act] = averageVelocity; - writer[ModalResultField.PaVeh] = ((_previousState.VehicleAccelerationForce * _previousState.Velocity + - _currentState.VehicleAccelerationForce * _currentState.Velocity) / 2.0) - .Cast<Watt>(); - writer[ModalResultField.Pgrad] = ((_previousState.SlopeResistance * _previousState.Velocity + - _currentState.SlopeResistance * _currentState.Velocity) / 2.0).Cast<Watt> - (); - writer[ModalResultField.Proll] = ((_previousState.RollingResistance * _previousState.Velocity + - _currentState.RollingResistance * _currentState.Velocity) / 2.0) - .Cast<Watt>(); - - writer[ModalResultField.Pair] = ComputeAirDragPowerLoss(_previousState.Velocity, _currentState.Velocity, - _currentState.dt); - - - // sanity check: is the vehicle in step with the cycle? - if (writer[ModalResultField.dist] == DBNull.Value) { - Log.Warn("distance field is not set!"); - } else { - var distance = (SI)writer[ModalResultField.dist]; - if (!distance.IsEqual(_currentState.Distance, 1e-12.SI<Meter>())) { - Log.Warn("distance diverges: {0}, distance: {1}", (distance - _currentState.Distance).Value(), - distance); - } - } - } - - - protected override void DoCommitSimulationStep() - { - _previousState = _currentState; - _currentState = new VehicleState(); - } - - protected Newton RollingResistance(Radian gradient) - { - var retVal = (Math.Cos(gradient.Value()) * _data.TotalVehicleWeight() * - Physics.GravityAccelleration * - _data.TotalRollResistanceCoefficient).Cast<Newton>(); - Log.Debug("RollingResistance: {0}", retVal); - return retVal; - } - - - protected Newton DriverAcceleration(MeterPerSquareSecond accelleration) - { - var retVal = ((_data.TotalVehicleWeight() + _data.ReducedMassWheels) * accelleration).Cast<Newton>(); - Log.Debug("DriverAcceleration: {0}", retVal); - return retVal; - } - - - protected internal Newton SlopeResistance(Radian gradient) - { - var retVal = - (_data.TotalVehicleWeight() * Physics.GravityAccelleration * Math.Sin(gradient.Value())).Cast<Newton>(); - Log.Debug("SlopeResistance: {0}", retVal); - return retVal; - } - - - protected internal Newton AirDragResistance(MeterPerSquareSecond acceleration, Second dt) - { - var vAverage = _previousState.Velocity + acceleration * dt / 2; - if (vAverage.IsEqual(0)) { - return 0.SI<Newton>(); - } - var result = - (ComputeAirDragPowerLoss(_previousState.Velocity, _previousState.Velocity + acceleration * dt, dt) / - vAverage).Cast<Newton>(); - - Log.Debug("AirDragResistance: {0}", result); - return result; - } - - private Watt ComputeAirDragPowerLoss(MeterPerSecond v1, MeterPerSecond v2, Second dt) - { - var vAverage = (v1 + v2) / 2; - var CdA = ComputeEffectiveAirDragArea(vAverage); - Watt averageAirDragPower; - if (v1.IsEqual(v2)) { - averageAirDragPower = (Physics.AirDensity / 2.0 * CdA * vAverage * vAverage * vAverage).Cast<Watt>(); - } else { - // compute the average force within the current simulation interval - // P(t) = k * v(t)^3 , v(t) = v0 + a * t // a != 0 - // => P_avg = (CdA * rho/2)/(4*a * dt) * (v2^4 - v1^4) - var acceleration = (v2 - v1) / dt; - averageAirDragPower = - (Physics.AirDensity / 2.0 * CdA * (v2 * v2 * v2 * v2 - v1 * v1 * v1 * v1) / (4 * acceleration * dt)) - .Cast<Watt>(); - } - return averageAirDragPower; - } - - protected internal SquareMeter ComputeEffectiveAirDragArea(MeterPerSecond velocity) - { - var CdA = _data.AerodynamicDragAera; - switch (_data.CrossWindCorrectionMode) { - case CrossWindCorrectionMode.NoCorrection: - break; - case CrossWindCorrectionMode.DeclarationModeCorrection: - CdA = AirDragInterpolate(velocity); - break; - default: - throw new NotImplementedException(string.Format("CrossWindcorrection {0} is not implemented", - _data.CrossWindCorrectionMode)); - } - return CdA; - } - - private SquareMeter AirDragInterpolate(MeterPerSecond x) - { - var p = _airResistanceCurve.GetSection(c => c.X < x); - - if (x < p.Item1.X || p.Item2.X < x) { - Log.Error(_data.CrossWindCorrectionMode == CrossWindCorrectionMode.VAirBetaLookupTable - ? string.Format("CdExtrapol β = {0}", x) - : string.Format("CdExtrapol v = {0}", x)); - } - - return VectoMath.Interpolate(p.Item1.X, p.Item2.X, p.Item1.Y, p.Item2.Y, x); - } - - protected Point[] CalculateAirResistanceCurve(AirDrag.AirDragEntry values) - { - var points = new List<Point> { new Point { X = 0.SI<MeterPerSecond>(), Y = 0.SI<SquareMeter>() } }; - - for (var speed = 60; speed <= 100; speed += 5) { - var vVeh = speed.KMPHtoMeterPerSecond(); - var cdASum = 0.0.SI<SquareMeter>(); - for (var alpha = 0; alpha <= 180; alpha += 10) { - var vWindX = Physics.BaseWindSpeed * Math.Cos(alpha.ToRadian()); - var vWindY = Physics.BaseWindSpeed * Math.Sin(alpha.ToRadian()); - var vAirX = vVeh + vWindX; - var vAirY = vWindY; -// var vAir = VectoMath.Sqrt<MeterPerSecond>(vAirX * vAirX + vAirY * vAirY); - var beta = Math.Atan((vAirY / vAirX).Value()).ToDegree(); - var deltaCdA = ComputeDeltaCd(beta, values); - var cdA = _data.AerodynamicDragAera + deltaCdA; - - var degreeShare = ((alpha != 0 && alpha != 180) ? 10.0 / 180.0 : 5.0 / 180.0); - -// cdASum += degreeShare * cdA * (vAir * vAir / (vVeh * vVeh)).Cast<Scalar>(); - cdASum += degreeShare * cdA * ((vAirX * vAirX + vAirY * vAirY) / (vVeh * vVeh)).Cast<Scalar>(); - } - points.Add(new Point { X = vVeh, Y = cdASum }); - } - - points[0].Y = points[1].Y; - return points.ToArray(); - } - - protected SquareMeter ComputeDeltaCd(double beta, AirDrag.AirDragEntry values) - { - return (values.A1 * beta + values.A2 * beta * beta + values.A3 * beta * beta * beta).SI<SquareMeter>(); - } - - public class VehicleState - { - public MeterPerSecond Velocity; - public Second dt; - public Meter Distance; - - public Newton VehicleAccelerationForce; - public Newton DriverAcceleration; - public Newton SlopeResistance; - public Newton AirDragResistance; - public Newton RollingResistance; - public MeterPerSquareSecond Acceleration { get; set; } - } - - public class Point - { - public MeterPerSecond X; - public SquareMeter Y; - } - } + public class Vehicle : VectoSimulationComponent, IVehicle, IMileageCounter, IFvInPort, IDriverDemandOutPort + { + private readonly CrossWindCorrectionCurve _airResistanceCurve; + private readonly VehicleData _data; + private VehicleState _currentState; + private VehicleState _previousState; + protected IFvOutPort NextComponent; + + public Vehicle(IVehicleContainer container, VehicleData data) : base(container) + { + _data = data; + _previousState = new VehicleState { Distance = 0.SI<Meter>(), Velocity = 0.SI<MeterPerSecond>() }; + _currentState = new VehicleState { Distance = 0.SI<Meter>(), Velocity = 0.SI<MeterPerSecond>() }; + + var values = DeclarationData.AirDrag.Lookup(_data.VehicleCategory); + _airResistanceCurve = data.CrossWindCorrectionCurve; + } + + public IResponse Initialize(MeterPerSecond vehicleSpeed, Radian roadGradient) + { + _previousState = new VehicleState { + Distance = DataBus.CycleStartDistance, + Velocity = vehicleSpeed, + RollingResistance = RollingResistance(roadGradient), + SlopeResistance = SlopeResistance(roadGradient) + }; + _previousState.AirDragResistance = AirDragResistance(0.SI<MeterPerSquareSecond>(), + Constants.SimulationSettings.TargetTimeInterval); + _previousState.VehicleAccelerationForce = _previousState.RollingResistance + + _previousState.AirDragResistance + + _previousState.SlopeResistance; + + _currentState = new VehicleState { + Distance = DataBus.CycleStartDistance, + Velocity = vehicleSpeed, + AirDragResistance = _previousState.AirDragResistance, + RollingResistance = _previousState.RollingResistance, + SlopeResistance = _previousState.SlopeResistance, + VehicleAccelerationForce = _previousState.VehicleAccelerationForce + }; + + + return NextComponent.Initialize(_currentState.VehicleAccelerationForce, vehicleSpeed); + } + + public IResponse Initialize(MeterPerSecond vehicleSpeed, MeterPerSquareSecond startAcceleration, + Radian roadGradient) + { + var tmp = _previousState.Velocity; + // set vehicle speed to get accurate airdrag resistance + _previousState.Velocity = vehicleSpeed; + _currentState.Velocity = vehicleSpeed + startAcceleration * Constants.SimulationSettings.TargetTimeInterval; + var vehicleAccelerationForce = DriverAcceleration(startAcceleration) + RollingResistance(roadGradient) + + AirDragResistance(startAcceleration, + Constants.SimulationSettings.TargetTimeInterval) + + SlopeResistance(roadGradient); + + var retVal = NextComponent.Initialize(vehicleAccelerationForce, vehicleSpeed); + + _previousState.Velocity = tmp; + _currentState.Velocity = tmp; + return retVal; + } + + public IResponse Request(Second absTime, Second dt, MeterPerSquareSecond acceleration, Radian gradient, + bool dryRun = false) + { + Log.Debug("from Wheels: acceleration: {0}", acceleration); + _currentState.dt = dt; + _currentState.Acceleration = acceleration; + _currentState.Velocity = _previousState.Velocity + acceleration * dt; + if (_currentState.Velocity.IsEqual(0.SI<MeterPerSecond>(), + Constants.SimulationSettings.VehicleSpeedHaltTolerance)) { + _currentState.Velocity = 0.SI<MeterPerSecond>(); + } + _currentState.Distance = _previousState.Distance + _previousState.Velocity * dt + acceleration * dt * dt / 2; + + _currentState.DriverAcceleration = DriverAcceleration(acceleration); + _currentState.RollingResistance = RollingResistance(gradient); + _currentState.AirDragResistance = AirDragResistance(acceleration, dt); + _currentState.SlopeResistance = SlopeResistance(gradient); + + // DriverAcceleration = vehicleAccelerationForce - RollingResistance - AirDragResistance - SlopeResistance + _currentState.VehicleAccelerationForce = _currentState.DriverAcceleration + + _currentState.RollingResistance + + _currentState.AirDragResistance + + _currentState.SlopeResistance; + + var retval = NextComponent.Request(absTime, dt, _currentState.VehicleAccelerationForce, + _currentState.Velocity, + dryRun); + return retval; + } + + public void Connect(IFvOutPort other) + { + NextComponent = other; + } + + public Meter Distance + { + get { return _previousState.Distance; } + } + + public MeterPerSecond VehicleSpeed + { + get { return _previousState.Velocity; } + } + + public Kilogram VehicleMass + { + get { return _data.TotalCurbWeight(); } + } + + public Kilogram VehicleLoading + { + get { return _data.Loading; } + } + + public Kilogram TotalMass + { + get { return _data.TotalVehicleWeight(); } + } + + public IFvInPort InPort() + { + return this; + } + + public IDriverDemandOutPort OutPort() + { + return this; + } + + protected override void DoWriteModalResults(IModalDataWriter writer) + { + var averageVelocity = (_previousState.Velocity + _currentState.Velocity) / 2; + + writer[ModalResultField.v_act] = averageVelocity; + writer[ModalResultField.PaVeh] = ((_previousState.VehicleAccelerationForce * _previousState.Velocity + + _currentState.VehicleAccelerationForce * _currentState.Velocity) / 2.0) + .Cast<Watt>(); + writer[ModalResultField.Pgrad] = ((_previousState.SlopeResistance * _previousState.Velocity + + _currentState.SlopeResistance * _currentState.Velocity) / 2.0).Cast<Watt> + (); + writer[ModalResultField.Proll] = ((_previousState.RollingResistance * _previousState.Velocity + + _currentState.RollingResistance * _currentState.Velocity) / 2.0) + .Cast<Watt>(); + + writer[ModalResultField.Pair] = ComputeAirDragPowerLoss(_previousState.Velocity, _currentState.Velocity, + _currentState.dt); + + + // sanity check: is the vehicle in step with the cycle? + if (writer[ModalResultField.dist] == DBNull.Value) { + Log.Warn("distance field is not set!"); + } else { + var distance = (SI)writer[ModalResultField.dist]; + if (!distance.IsEqual(_currentState.Distance, 1e-12.SI<Meter>())) { + Log.Warn("distance diverges: {0}, distance: {1}", (distance - _currentState.Distance).Value(), + distance); + } + } + } + + protected override void DoCommitSimulationStep() + { + _previousState = _currentState; + _currentState = new VehicleState(); + } + + protected Newton RollingResistance(Radian gradient) + { + var retVal = (Math.Cos(gradient.Value()) * _data.TotalVehicleWeight() * + Physics.GravityAccelleration * + _data.TotalRollResistanceCoefficient).Cast<Newton>(); + Log.Debug("RollingResistance: {0}", retVal); + return retVal; + } + + protected Newton DriverAcceleration(MeterPerSquareSecond accelleration) + { + var retVal = ((_data.TotalVehicleWeight() + _data.ReducedMassWheels) * accelleration).Cast<Newton>(); + Log.Debug("DriverAcceleration: {0}", retVal); + return retVal; + } + + protected internal Newton SlopeResistance(Radian gradient) + { + var retVal = + (_data.TotalVehicleWeight() * Physics.GravityAccelleration * Math.Sin(gradient.Value())).Cast<Newton>(); + Log.Debug("SlopeResistance: {0}", retVal); + return retVal; + } + + protected internal Newton AirDragResistance(MeterPerSquareSecond acceleration, Second dt) + { + var vAverage = _previousState.Velocity + acceleration * dt / 2; + if (vAverage.IsEqual(0)) { + return 0.SI<Newton>(); + } + var result = + (ComputeAirDragPowerLoss(_previousState.Velocity, _previousState.Velocity + acceleration * dt, dt) / + vAverage).Cast<Newton>(); + + Log.Debug("AirDragResistance: {0}", result); + return result; + } + + private Watt ComputeAirDragPowerLoss(MeterPerSecond v1, MeterPerSecond v2, Second dt) + { + var vAverage = (v1 + v2) / 2; + var CdA = _airResistanceCurve.EffectiveAirDragArea(vAverage); + Watt averageAirDragPower; + if (v1.IsEqual(v2)) { + averageAirDragPower = (Physics.AirDensity / 2.0 * CdA * vAverage * vAverage * vAverage).Cast<Watt>(); + } else { + // compute the average force within the current simulation interval + // P(t) = k * v(t)^3 , v(t) = v0 + a * t // a != 0 + // => P_avg = (CdA * rho/2)/(4*a * dt) * (v2^4 - v1^4) + var acceleration = (v2 - v1) / dt; + averageAirDragPower = + (Physics.AirDensity / 2.0 * CdA * (v2 * v2 * v2 * v2 - v1 * v1 * v1 * v1) / (4 * acceleration * dt)) + .Cast<Watt>(); + } + return averageAirDragPower; + } + + public class VehicleState + { + public Newton AirDragResistance; + public Meter Distance; + public Newton DriverAcceleration; + public Second dt; + public Newton RollingResistance; + public Newton SlopeResistance; + public Newton VehicleAccelerationForce; + public MeterPerSecond Velocity; + public MeterPerSquareSecond Acceleration { get; set; } + } + } } \ No newline at end of file diff --git a/VectoCore/Utils/VectoCSVFile.cs b/VectoCore/Utils/VectoCSVFile.cs index 143579a18abcb4f7a1c13824ba36965613c55fb3..9ca70bc5ee025d5812cd50bf5031f7de440d9a18 100644 --- a/VectoCore/Utils/VectoCSVFile.cs +++ b/VectoCore/Utils/VectoCSVFile.cs @@ -31,7 +31,7 @@ namespace TUGraz.VectoCore.Utils private const char Comment = '#'; /// <summary> - /// Reads a CSV file which is stored in Vecto-CSV-Format. + /// Reads a CSV file which is stored in Vecto-CSV-Format. /// </summary> /// <param name="fileName"></param> /// <param name="ignoreEmptyColumns"></param> @@ -143,8 +143,8 @@ namespace TUGraz.VectoCore.Utils } /// <summary> - /// Writes the datatable to the csv file. - /// Uses the column caption as header (with fallback to column name) for the csv header. + /// Writes the datatable to the csv file. + /// Uses the column caption as header (with fallback to column name) for the csv header. /// </summary> /// <param name="fileName">Path to the file.</param> /// <param name="table">The Datatable.</param> diff --git a/VectoCore/VectoCore.csproj b/VectoCore/VectoCore.csproj index 15f97d845e62541e329ea6e78aada94432882616..b002955bc531c2672ca6fa7ba8a90e3ad32ea55c 100644 --- a/VectoCore/VectoCore.csproj +++ b/VectoCore/VectoCore.csproj @@ -148,6 +148,7 @@ <Compile Include="Models\Declaration\VehicleClass.cs" /> <Compile Include="Models\Declaration\Wheels.cs" /> <Compile Include="Models\Declaration\WHTCCorrection.cs" /> + <Compile Include="Models\SimulationComponent\Data\CrossWindCorrectionCurve.cs" /> <Compile Include="Models\SimulationComponent\Data\AuxiliaryData.cs" /> <Compile Include="Models\SimulationComponent\Data\AuxSupplyPowerReader.cs" /> <Compile Include="Models\SimulationComponent\Data\CycleData.cs" /> diff --git a/VectoCoreTest/Integration/CoachPowerTrain.cs b/VectoCoreTest/Integration/CoachPowerTrain.cs index 2ed08020c52b409d2b51088a17e5c74f4f355d5d..74efb5b4b24118463fc96761d1c75f9d5e19a624 100644 --- a/VectoCoreTest/Integration/CoachPowerTrain.cs +++ b/VectoCoreTest/Integration/CoachPowerTrain.cs @@ -17,26 +17,23 @@ namespace TUGraz.VectoCore.Tests.Integration public class CoachPowerTrain { public const string AccelerationFile = @"TestData\Components\Truck.vacc"; - public const string EngineFile = @"TestData\Components\24t Coach.veng"; - public const string AxleGearLossMap = @"TestData\Components\Axle.vtlm"; public const string GearboxIndirectLoss = @"TestData\Components\Indirect Gear.vtlm"; public const string GearboxDirectLoss = @"TestData\Components\Direct Gear.vtlm"; - public const string GearboxShiftPolygonFile = @"TestData\Components\ShiftPolygons.vgbs"; - public const string GearboxFullLoadCurveFile = @"TestData\Components\Gearbox.vfld"; - public static VectoRun CreateEngineeringRun(DrivingCycleData cycleData, string modFileName, bool overspeed = false) + public static VectoRun CreateEngineeringRun(DrivingCycleData cycleData, string modFileName, + bool overspeed = false) { var container = CreatePowerTrain(cycleData, modFileName, overspeed); return new DistanceRun("", container); } - - public static VehicleContainer CreatePowerTrain(DrivingCycleData cycleData, string modFileName, bool overspeed = false) + public static VehicleContainer CreatePowerTrain(DrivingCycleData cycleData, string modFileName, + bool overspeed = false) { var modalWriter = new ModalDataWriter(modFileName); var container = new VehicleContainer(modalWriter); @@ -56,7 +53,8 @@ namespace TUGraz.VectoCore.Tests.Integration tmp = Port.AddComponent(tmp, new Wheels(container, vehicleData.DynamicTyreRadius)); tmp = Port.AddComponent(tmp, new Brakes(container)); tmp = Port.AddComponent(tmp, new AxleGear(container, axleGearData)); - tmp = Port.AddComponent(tmp, new Gearbox(container, gearboxData, new AMTShiftStrategy(gearboxData, container))); + tmp = Port.AddComponent(tmp, + new Gearbox(container, gearboxData, new AMTShiftStrategy(gearboxData, container))); tmp = Port.AddComponent(tmp, clutch); var aux = new Auxiliary(container); @@ -71,7 +69,6 @@ namespace TUGraz.VectoCore.Tests.Integration return container; } - private static GearboxData CreateGearboxData() { var ratios = new[] { 6.38, 4.63, 3.44, 2.59, 1.86, 1.35, 1, 0.76 }; @@ -82,8 +79,10 @@ namespace TUGraz.VectoCore.Tests.Integration new GearData { FullLoadCurve = FullLoadCurve.ReadFromFile(GearboxFullLoadCurveFile), LossMap = (ratio != 1.0) - ? TransmissionLossMap.ReadFromFile(GearboxIndirectLoss, ratio, string.Format("Gear {0}", i)) - : TransmissionLossMap.ReadFromFile(GearboxDirectLoss, ratio, string.Format("Gear {0}", i)), + ? TransmissionLossMap.ReadFromFile(GearboxIndirectLoss, ratio, + string.Format("Gear {0}", i)) + : TransmissionLossMap.ReadFromFile(GearboxDirectLoss, ratio, + string.Format("Gear {0}", i)), Ratio = ratio, ShiftPolygon = ShiftPolygon.ReadFromFile(GearboxShiftPolygonFile) })) @@ -95,7 +94,7 @@ namespace TUGraz.VectoCore.Tests.Integration StartAcceleration = 0.6.SI<MeterPerSquareSecond>(), StartTorqueReserve = 0.2, SkipGears = true, - TorqueReserve = 0.2, + TorqueReserve = 0.2 }; } @@ -136,14 +135,15 @@ namespace TUGraz.VectoCore.Tests.Integration return new VehicleData { AxleConfiguration = AxleConfiguration.AxleConfig_6x2, AerodynamicDragAera = 3.2634.SI<SquareMeter>(), - CrossWindCorrectionMode = CrossWindCorrectionMode.NoCorrection, + //CrossWindCorrectionMode = CrossWindCorrectionMode.NoCorrection, + CrossWindCorrectionCurve = CrossWindCorrectionCurve.GetNoCorrectionCurve(3.2634.SI<SquareMeter>()), CurbWeight = 15700.SI<Kilogram>(), CurbWeigthExtra = 0.SI<Kilogram>(), Loading = loading, DynamicTyreRadius = 0.52.SI<Meter>(), Retarder = new RetarderData { Type = RetarderData.RetarderType.None }, AxleData = axles, - SavedInDeclarationMode = false, + SavedInDeclarationMode = false }; } @@ -154,19 +154,19 @@ namespace TUGraz.VectoCore.Tests.Integration LookAheadCoasting = new DriverData.LACData { Enabled = true, MinSpeed = 50.KMPHtoMeterPerSecond(), - Deceleration = -0.5.SI<MeterPerSquareSecond>(), + Deceleration = -0.5.SI<MeterPerSquareSecond>() }, OverSpeedEcoRoll = overspeed - ? new DriverData.OverSpeedEcoRollData() { + ? new DriverData.OverSpeedEcoRollData { Mode = DriverData.DriverMode.Overspeed, MinSpeed = 50.KMPHtoMeterPerSecond(), - OverSpeed = 5.KMPHtoMeterPerSecond(), + OverSpeed = 5.KMPHtoMeterPerSecond() } : new DriverData.OverSpeedEcoRollData { Mode = DriverData.DriverMode.Off }, StartStop = new VectoRunData.StartStopData { - Enabled = false, + Enabled = false } }; } diff --git a/VectoCoreTest/Integration/SimulationRuns/FullPowertrain.cs b/VectoCoreTest/Integration/SimulationRuns/FullPowertrain.cs index 65764e6bff8c4a58ca394f07873d88fdf502b1c2..0bba865a0ce1d725df17550d5ca54c3ea62ddc07 100644 --- a/VectoCoreTest/Integration/SimulationRuns/FullPowertrain.cs +++ b/VectoCoreTest/Integration/SimulationRuns/FullPowertrain.cs @@ -23,17 +23,14 @@ namespace TUGraz.VectoCore.Tests.Integration.SimulationRuns [TestClass] public class FullPowerTrain { - private static Logger Log = LogManager.GetLogger(typeof(FullPowerTrain).ToString()); - public const string CycleFile = @"TestData\Integration\FullPowerTrain\1-Gear-Test-dist.vdri"; public const string CoachCycleFile = @"TestData\Integration\FullPowerTrain\Coach.vdri"; public const string EngineFile = @"TestData\Components\24t Coach.veng"; - public const string AccelerationFile = @"TestData\Components\Coach.vacc"; - public const string GearboxLossMap = @"TestData\Components\Indirect Gear.vtlm"; public const string GearboxShiftPolygonFile = @"TestData\Components\ShiftPolygons.vgbs"; public const string GearboxFullLoadCurveFile = @"TestData\Components\Gearbox.vfld"; + private static readonly Logger Log = LogManager.GetLogger(typeof(FullPowerTrain).ToString()); [TestMethod] public void Test_FullPowertrain_SimpleGearbox() @@ -74,7 +71,7 @@ namespace TUGraz.VectoCore.Tests.Integration.SimulationRuns response = cyclePort.Request(absTime, ds); response.Switch(). Case<ResponseDrivingCycleDistanceExceeded>(r => ds = r.MaxDistance). - Case<ResponseCycleFinished>(r => {}). + Case<ResponseCycleFinished>(r => { }). Case<ResponseSuccess>(r => { container.CommitSimulationStep(absTime, r.SimulationInterval); absTime += r.SimulationInterval; @@ -146,10 +143,8 @@ namespace TUGraz.VectoCore.Tests.Integration.SimulationRuns response.Switch(). Case<ResponseDrivingCycleDistanceExceeded>(r => ds = r.MaxDistance). - Case<ResponseCycleFinished>(r => {}). - Case<ResponseGearShift>(r => { - Log.Debug("Gearshift"); - }). + Case<ResponseCycleFinished>(r => { }). + Case<ResponseGearShift>(r => { Log.Debug("Gearshift"); }). Case<ResponseSuccess>(r => { container.CommitSimulationStep(absTime, r.SimulationInterval); absTime += r.SimulationInterval; @@ -188,7 +183,8 @@ namespace TUGraz.VectoCore.Tests.Integration.SimulationRuns tmp = Port.AddComponent(tmp, new Wheels(container, vehicleData.DynamicTyreRadius)); tmp = Port.AddComponent(tmp, new Brakes(container)); tmp = Port.AddComponent(tmp, new AxleGear(container, axleGearData)); - tmp = Port.AddComponent(tmp, new Gearbox(container, gearboxData, new AMTShiftStrategy(gearboxData, container))); + tmp = Port.AddComponent(tmp, + new Gearbox(container, gearboxData, new AMTShiftStrategy(gearboxData, container))); var engine = new CombustionEngine(container, engineData); var clutch = new Clutch(container, engineData, engine.IdleController); tmp = Port.AddComponent(tmp, clutch); @@ -219,10 +215,8 @@ namespace TUGraz.VectoCore.Tests.Integration.SimulationRuns response.Switch(). Case<ResponseDrivingCycleDistanceExceeded>(r => ds = r.MaxDistance). - Case<ResponseCycleFinished>(r => {}). - Case<ResponseGearShift>(r => { - Log.Debug("Gearshift"); - }). + Case<ResponseCycleFinished>(r => { }). + Case<ResponseGearShift>(r => { Log.Debug("Gearshift"); }). Case<ResponseSuccess>(r => { container.CommitSimulationStep(absTime, r.SimulationInterval); absTime += r.SimulationInterval; @@ -262,7 +256,6 @@ namespace TUGraz.VectoCore.Tests.Integration.SimulationRuns @"TestData\job_1-Gear-Test-dist.vmod", testRowCount: false); } - // todo: add realistic FullLoadCurve private static GearboxData CreateGearboxData() { @@ -273,7 +266,8 @@ namespace TUGraz.VectoCore.Tests.Integration.SimulationRuns Tuple.Create((uint)i, new GearData { FullLoadCurve = FullLoadCurve.ReadFromFile(GearboxFullLoadCurveFile), - LossMap = TransmissionLossMap.ReadFromFile(GearboxLossMap, ratio, string.Format("Gear {0}", i)), + LossMap = + TransmissionLossMap.ReadFromFile(GearboxLossMap, ratio, string.Format("Gear {0}", i)), Ratio = ratio, ShiftPolygon = ShiftPolygon.ReadFromFile(GearboxShiftPolygonFile) })) @@ -288,7 +282,6 @@ namespace TUGraz.VectoCore.Tests.Integration.SimulationRuns }; } - private static GearData CreateAxleGearData() { var ratio = 3.240355; @@ -350,14 +343,15 @@ namespace TUGraz.VectoCore.Tests.Integration.SimulationRuns return new VehicleData { AxleConfiguration = AxleConfiguration.AxleConfig_6x2, AerodynamicDragAera = 3.2634.SI<SquareMeter>(), - CrossWindCorrectionMode = CrossWindCorrectionMode.NoCorrection, + //CrossWindCorrectionMode = CrossWindCorrectionMode.NoCorrection, + CrossWindCorrectionCurve = CrossWindCorrectionCurve.GetNoCorrectionCurve(3.2634.SI<SquareMeter>()), CurbWeight = 15700.SI<Kilogram>(), CurbWeigthExtra = 0.SI<Kilogram>(), Loading = loading, DynamicTyreRadius = 0.52.SI<Meter>(), Retarder = new RetarderData { Type = RetarderData.RetarderType.None }, AxleData = axles, - SavedInDeclarationMode = false, + SavedInDeclarationMode = false }; } @@ -373,7 +367,7 @@ namespace TUGraz.VectoCore.Tests.Integration.SimulationRuns Mode = DriverData.DriverMode.Off }, StartStop = new VectoRunData.StartStopData { - Enabled = false, + Enabled = false } }; } diff --git a/VectoCoreTest/Integration/SimulationRuns/MinimalPowertrain.cs b/VectoCoreTest/Integration/SimulationRuns/MinimalPowertrain.cs index 39a3e1c293aa54b952473bde11e50bb9e26105e5..2a0206f5ae60e46c791aab8e0e11af3b775545fc 100644 --- a/VectoCoreTest/Integration/SimulationRuns/MinimalPowertrain.cs +++ b/VectoCoreTest/Integration/SimulationRuns/MinimalPowertrain.cs @@ -3,7 +3,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using TUGraz.VectoCore.Configuration; using TUGraz.VectoCore.FileIO.Reader; using TUGraz.VectoCore.FileIO.Reader.Impl; -using TUGraz.VectoCore.Models.Connector.Ports; using TUGraz.VectoCore.Models.Connector.Ports.Impl; using TUGraz.VectoCore.Models.Declaration; using TUGraz.VectoCore.Models.Simulation.Data; @@ -25,14 +24,10 @@ namespace TUGraz.VectoCore.Tests.Integration.SimulationRuns public const string EngineFile = @"TestData\Integration\MinimalPowerTrain\24t Coach.veng"; public const string GearboxFile = @"TestData\Integration\MinimalPowerTrain\24t Coach-1Gear.vgbx"; public const string GbxLossMap = @"TestData\Integration\MinimalPowerTrain\NoLossGbxMap.vtlm"; - - public const string AccelerationFile = @"TestData\Components\Coach.vacc"; public const string AccelerationFile2 = @"TestData\Components\Truck.vacc"; - public const double Tolerance = 0.001; - [TestMethod] public void TestWheelsAndEngineInitialize() { @@ -64,7 +59,8 @@ namespace TUGraz.VectoCore.Tests.Integration.SimulationRuns gbx.Gear = 1; - var response = driverPort.Initialize(18.KMPHtoMeterPerSecond(), VectoMath.InclinationToAngle(2.842372037 / 100)); + var response = driverPort.Initialize(18.KMPHtoMeterPerSecond(), + VectoMath.InclinationToAngle(2.842372037 / 100)); var absTime = 0.SI<Second>(); @@ -81,7 +77,6 @@ namespace TUGraz.VectoCore.Tests.Integration.SimulationRuns Assert.AreEqual(323.7562, engine.PreviousState.EngineTorque.Value(), Tolerance); } - [TestMethod] public void TestWheelsAndEngine() { @@ -131,14 +126,15 @@ namespace TUGraz.VectoCore.Tests.Integration.SimulationRuns response = cyclePort.Request(absTime, ds); response.Switch(). Case<ResponseDrivingCycleDistanceExceeded>(r => ds = r.MaxDistance). - Case<ResponseCycleFinished>(r => {}). + Case<ResponseCycleFinished>(r => { }). Case<ResponseSuccess>(r => { vehicleContainer.CommitSimulationStep(absTime, r.SimulationInterval); absTime += r.SimulationInterval; ds = vehicleContainer.VehicleSpeed.IsEqual(0) ? Constants.SimulationSettings.DriveOffDistance - : (Constants.SimulationSettings.TargetTimeInterval * vehicleContainer.VehicleSpeed).Cast<Meter>(); + : (Constants.SimulationSettings.TargetTimeInterval * vehicleContainer.VehicleSpeed) + .Cast<Meter>(); if (cnt++ % 100 == 0) { modalWriter.Finish(VectoRun.Status.Success); @@ -203,7 +199,8 @@ namespace TUGraz.VectoCore.Tests.Integration.SimulationRuns ds = vehicleContainer.VehicleSpeed.IsEqual(0) ? Constants.SimulationSettings.DriveOffDistance - : (Constants.SimulationSettings.TargetTimeInterval * vehicleContainer.VehicleSpeed).Cast<Meter>(); + : (Constants.SimulationSettings.TargetTimeInterval * vehicleContainer.VehicleSpeed) + .Cast<Meter>(); modalWriter.Finish(VectoRun.Status.Success); }); @@ -220,7 +217,6 @@ namespace TUGraz.VectoCore.Tests.Integration.SimulationRuns }; } - private static VehicleData CreateVehicleData(Kilogram loading) { var axles = new List<Axle> { @@ -249,14 +245,15 @@ namespace TUGraz.VectoCore.Tests.Integration.SimulationRuns return new VehicleData { AxleConfiguration = AxleConfiguration.AxleConfig_6x2, AerodynamicDragAera = 3.2634.SI<SquareMeter>(), - CrossWindCorrectionMode = CrossWindCorrectionMode.NoCorrection, + //CrossWindCorrectionMode = CrossWindCorrectionMode.NoCorrection, + CrossWindCorrectionCurve = CrossWindCorrectionCurve.GetNoCorrectionCurve(3.2634.SI<SquareMeter>()), CurbWeight = 15700.SI<Kilogram>(), CurbWeigthExtra = 0.SI<Kilogram>(), Loading = loading, DynamicTyreRadius = 0.52.SI<Meter>(), Retarder = new RetarderData { Type = RetarderData.RetarderType.None }, AxleData = axles, - SavedInDeclarationMode = false, + SavedInDeclarationMode = false }; } @@ -272,7 +269,7 @@ namespace TUGraz.VectoCore.Tests.Integration.SimulationRuns Mode = DriverData.DriverMode.Off }, StartStop = new VectoRunData.StartStopData { - Enabled = false, + Enabled = false } }; } diff --git a/VectoCoreTest/Integration/Truck40tPowerTrain.cs b/VectoCoreTest/Integration/Truck40tPowerTrain.cs index b3fba6eb62e7bab75fcdeeabd15071b6fb5ed34d..cbfc822fa55229e27fe4b4a7af88eaded3b7b7c0 100644 --- a/VectoCoreTest/Integration/Truck40tPowerTrain.cs +++ b/VectoCoreTest/Integration/Truck40tPowerTrain.cs @@ -15,184 +15,191 @@ using Wheels = TUGraz.VectoCore.Models.SimulationComponent.Impl.Wheels; namespace TUGraz.VectoCore.Tests.Integration { - // ReSharper disable once InconsistentNaming - public class Truck40tPowerTrain - { - public const string ShiftPolygonFile = @"TestData\Components\ShiftPolygons.vgbs"; - public const string AccelerationFile = @"TestData\Components\Truck.vacc"; - public const string EngineFile = @"TestData\Components\40t_Long_Haul_Truck.veng"; - public const string AxleGearLossMap = @"TestData\Components\Axle 40t Truck.vtlm"; - public const string GearboxIndirectLoss = @"TestData\Components\Indirect Gear.vtlm"; - public const string GearboxDirectLoss = @"TestData\Components\Direct Gear.vtlm"; - public const string GearboxShiftPolygonFile = @"TestData\Components\ShiftPolygons.vgbs"; - public const string GearboxFullLoadCurveFile = @"TestData\Components\Gearbox.vfld"; - - public static VectoRun CreateEngineeringRun(DrivingCycleData cycleData, string modFileName, bool overspeed = false) - { - var container = CreatePowerTrain(cycleData, modFileName, 7500.SI<Kilogram>(), 19300.SI<Kilogram>(), overspeed); - - return new DistanceRun("", container); - } - - public static VectoRun CreateEngineeringRun(DrivingCycleData cycleData, string modFileName, Kilogram massExtra, - Kilogram loading, bool overspeed = false) - { - var container = CreatePowerTrain(cycleData, modFileName, massExtra, loading, overspeed); - - return new DistanceRun("", container); - } - - public static VehicleContainer CreatePowerTrain(DrivingCycleData cycleData, string modFileName, Kilogram massExtra, - Kilogram loading, bool overspeed = false) - { - var modalWriter = new ModalDataWriter(modFileName); - var container = new VehicleContainer(modalWriter); - - var engineData = EngineeringModeSimulationDataReader.CreateEngineDataFromFile(EngineFile); - var axleGearData = CreateAxleGearData(); - var gearboxData = CreateGearboxData(engineData); - var vehicleData = CreateVehicleData(massExtra, loading); - var driverData = CreateDriverData(AccelerationFile, overspeed); - - var cycle = new DistanceBasedDrivingCycle(container, cycleData); - var engine = new CombustionEngine(container, engineData); - var clutch = new Clutch(container, engineData, engine.IdleController); - - dynamic tmp = Port.AddComponent(cycle, new Driver(container, driverData, new DefaultDriverStrategy())); - tmp = Port.AddComponent(tmp, new Vehicle(container, vehicleData)); - tmp = Port.AddComponent(tmp, new Wheels(container, vehicleData.DynamicTyreRadius)); - tmp = Port.AddComponent(tmp, new Brakes(container)); - tmp = Port.AddComponent(tmp, new AxleGear(container, axleGearData)); - tmp = Port.AddComponent(tmp, new Gearbox(container, gearboxData, new AMTShiftStrategy(gearboxData, container))); - tmp = Port.AddComponent(tmp, clutch); - - var aux = new Auxiliary(container); - aux.AddConstant("", 0.SI<Watt>()); - - tmp = Port.AddComponent(tmp, aux); - - Port.AddComponent(tmp, engine); - engine.IdleController.RequestPort = clutch.IdleControlPort; - - return container; - } - - private static GearboxData CreateGearboxData(CombustionEngineData engineData) - { - var ratios = new[] { 14.93, 11.64, 9.02, 7.04, 5.64, 4.4, 3.39, 2.65, 2.05, 1.6, 1.28, 1.0, }; - - return new GearboxData { - Gears = ratios.Select((ratio, i) => - Tuple.Create((uint)i, - new GearData { - FullLoadCurve = FullLoadCurve.ReadFromFile(GearboxFullLoadCurveFile), - LossMap = - (ratio != 1.0) - ? TransmissionLossMap.ReadFromFile(GearboxIndirectLoss, ratio, string.Format("Gear {0}", i)) - : TransmissionLossMap.ReadFromFile(GearboxDirectLoss, ratio, string.Format("Gear {0}", i)), - Ratio = ratio, - ShiftPolygon = ShiftPolygon.ReadFromFile(ShiftPolygonFile), - //ShiftPolygon = DeclarationData.Gearbox.ComputeShiftPolygon(engineData.FullLoadCurve, engineData.IdleSpeed) - })) - .ToDictionary(k => k.Item1 + 1, v => v.Item2), - ShiftTime = 2.SI<Second>(), - Inertia = 0.SI<KilogramSquareMeter>(), - TractionInterruption = 1.SI<Second>(), - StartAcceleration = 0.6.SI<MeterPerSquareSecond>(), - StartSpeed = 2.SI<MeterPerSecond>(), - TorqueReserve = 0.2, - StartTorqueReserve = 0.2, - SkipGears = true, - EarlyShiftUp = true, - }; - } - - private static GearData CreateAxleGearData() - { - const double ratio = 2.59; - return new GearData { - Ratio = ratio, - LossMap = TransmissionLossMap.ReadFromFile(AxleGearLossMap, ratio, "AxleGear") - }; - } - - private static VehicleData CreateVehicleData(Kilogram massExtra, Kilogram loading) - { - var axles = new List<Axle> { - new Axle { - AxleWeightShare = 0.2, - Inertia = 14.9.SI<KilogramSquareMeter>(), - RollResistanceCoefficient = 0.0055, - TwinTyres = false, - TyreTestLoad = 31300.SI<Newton>() - }, - new Axle { - AxleWeightShare = 0.25, - Inertia = 14.9.SI<KilogramSquareMeter>(), - RollResistanceCoefficient = 0.0065, - TwinTyres = true, - TyreTestLoad = 31300.SI<Newton>() - }, - - // trailer - declaration wheel data - new Axle { - AxleWeightShare = 0.55 / 3, - TwinTyres = DeclarationData.Trailer.TwinTyres, - RollResistanceCoefficient = DeclarationData.Trailer.RollResistanceCoefficient, - TyreTestLoad = DeclarationData.Trailer.TyreTestLoad.SI<Newton>(), - Inertia = DeclarationData.Wheels.Lookup(DeclarationData.Trailer.WheelsType).Inertia - }, - new Axle { - AxleWeightShare = 0.55 / 3, - TwinTyres = DeclarationData.Trailer.TwinTyres, - RollResistanceCoefficient = DeclarationData.Trailer.RollResistanceCoefficient, - TyreTestLoad = DeclarationData.Trailer.TyreTestLoad.SI<Newton>(), - Inertia = DeclarationData.Wheels.Lookup(DeclarationData.Trailer.WheelsType).Inertia - }, - new Axle { - AxleWeightShare = 0.55 / 3, - TwinTyres = DeclarationData.Trailer.TwinTyres, - RollResistanceCoefficient = DeclarationData.Trailer.RollResistanceCoefficient, - TyreTestLoad = DeclarationData.Trailer.TyreTestLoad.SI<Newton>(), - Inertia = DeclarationData.Wheels.Lookup(DeclarationData.Trailer.WheelsType).Inertia - } - }; - return new VehicleData { - AxleConfiguration = AxleConfiguration.AxleConfig_4x2, - AerodynamicDragAera = 6.2985.SI<SquareMeter>(), - CrossWindCorrectionMode = CrossWindCorrectionMode.NoCorrection, - CurbWeight = 7100.SI<Kilogram>(), - CurbWeigthExtra = massExtra, - Loading = loading, - DynamicTyreRadius = 0.4882675.SI<Meter>(), - Retarder = new RetarderData { Type = RetarderData.RetarderType.None }, - AxleData = axles, - SavedInDeclarationMode = false, - }; - } - - private static DriverData CreateDriverData(string accelerationFile, bool overspeed = false) - { - return new DriverData { - AccelerationCurve = AccelerationCurveData.ReadFromFile(accelerationFile), - LookAheadCoasting = new DriverData.LACData { - Enabled = true, - MinSpeed = 50.KMPHtoMeterPerSecond(), - Deceleration = -0.5.SI<MeterPerSquareSecond>(), - }, - OverSpeedEcoRoll = overspeed - ? new DriverData.OverSpeedEcoRollData() { - Mode = DriverData.DriverMode.Overspeed, - MinSpeed = 50.KMPHtoMeterPerSecond(), - OverSpeed = 5.KMPHtoMeterPerSecond(), - } - : new DriverData.OverSpeedEcoRollData { - Mode = DriverData.DriverMode.Off - }, - StartStop = new VectoRunData.StartStopData { - Enabled = false, - } - }; - } - } + // ReSharper disable once InconsistentNaming + public class Truck40tPowerTrain + { + public const string ShiftPolygonFile = @"TestData\Components\ShiftPolygons.vgbs"; + public const string AccelerationFile = @"TestData\Components\Truck.vacc"; + public const string EngineFile = @"TestData\Components\40t_Long_Haul_Truck.veng"; + public const string AxleGearLossMap = @"TestData\Components\Axle 40t Truck.vtlm"; + public const string GearboxIndirectLoss = @"TestData\Components\Indirect Gear.vtlm"; + public const string GearboxDirectLoss = @"TestData\Components\Direct Gear.vtlm"; + public const string GearboxShiftPolygonFile = @"TestData\Components\ShiftPolygons.vgbs"; + public const string GearboxFullLoadCurveFile = @"TestData\Components\Gearbox.vfld"; + + public static VectoRun CreateEngineeringRun(DrivingCycleData cycleData, string modFileName, + bool overspeed = false) + { + var container = CreatePowerTrain(cycleData, modFileName, 7500.SI<Kilogram>(), 19300.SI<Kilogram>(), + overspeed); + + return new DistanceRun("", container); + } + + public static VectoRun CreateEngineeringRun(DrivingCycleData cycleData, string modFileName, Kilogram massExtra, + Kilogram loading, bool overspeed = false) + { + var container = CreatePowerTrain(cycleData, modFileName, massExtra, loading, overspeed); + + return new DistanceRun("", container); + } + + public static VehicleContainer CreatePowerTrain(DrivingCycleData cycleData, string modFileName, + Kilogram massExtra, + Kilogram loading, bool overspeed = false) + { + var modalWriter = new ModalDataWriter(modFileName); + var container = new VehicleContainer(modalWriter); + + var engineData = EngineeringModeSimulationDataReader.CreateEngineDataFromFile(EngineFile); + var axleGearData = CreateAxleGearData(); + var gearboxData = CreateGearboxData(engineData); + var vehicleData = CreateVehicleData(massExtra, loading); + var driverData = CreateDriverData(AccelerationFile, overspeed); + + var cycle = new DistanceBasedDrivingCycle(container, cycleData); + var engine = new CombustionEngine(container, engineData); + var clutch = new Clutch(container, engineData, engine.IdleController); + + dynamic tmp = Port.AddComponent(cycle, new Driver(container, driverData, new DefaultDriverStrategy())); + tmp = Port.AddComponent(tmp, new Vehicle(container, vehicleData)); + tmp = Port.AddComponent(tmp, new Wheels(container, vehicleData.DynamicTyreRadius)); + tmp = Port.AddComponent(tmp, new Brakes(container)); + tmp = Port.AddComponent(tmp, new AxleGear(container, axleGearData)); + tmp = Port.AddComponent(tmp, + new Gearbox(container, gearboxData, new AMTShiftStrategy(gearboxData, container))); + tmp = Port.AddComponent(tmp, clutch); + + var aux = new Auxiliary(container); + aux.AddConstant("", 0.SI<Watt>()); + + tmp = Port.AddComponent(tmp, aux); + + Port.AddComponent(tmp, engine); + engine.IdleController.RequestPort = clutch.IdleControlPort; + + return container; + } + + private static GearboxData CreateGearboxData(CombustionEngineData engineData) + { + var ratios = new[] { 14.93, 11.64, 9.02, 7.04, 5.64, 4.4, 3.39, 2.65, 2.05, 1.6, 1.28, 1.0, }; + + return new GearboxData { + Gears = ratios.Select((ratio, i) => + Tuple.Create((uint)i, + new GearData { + FullLoadCurve = FullLoadCurve.ReadFromFile(GearboxFullLoadCurveFile), + LossMap = + (ratio != 1.0) + ? TransmissionLossMap.ReadFromFile(GearboxIndirectLoss, ratio, + string.Format("Gear {0}", i)) + : TransmissionLossMap.ReadFromFile(GearboxDirectLoss, ratio, + string.Format("Gear {0}", i)), + Ratio = ratio, + ShiftPolygon = ShiftPolygon.ReadFromFile(ShiftPolygonFile), + //ShiftPolygon = DeclarationData.Gearbox.ComputeShiftPolygon(engineData.FullLoadCurve, engineData.IdleSpeed) + })) + .ToDictionary(k => k.Item1 + 1, v => v.Item2), + ShiftTime = 2.SI<Second>(), + Inertia = 0.SI<KilogramSquareMeter>(), + TractionInterruption = 1.SI<Second>(), + StartAcceleration = 0.6.SI<MeterPerSquareSecond>(), + StartSpeed = 2.SI<MeterPerSecond>(), + TorqueReserve = 0.2, + StartTorqueReserve = 0.2, + SkipGears = true, + EarlyShiftUp = true, + }; + } + + private static GearData CreateAxleGearData() + { + const double ratio = 2.59; + return new GearData { + Ratio = ratio, + LossMap = TransmissionLossMap.ReadFromFile(AxleGearLossMap, ratio, "AxleGear") + }; + } + + private static VehicleData CreateVehicleData(Kilogram massExtra, Kilogram loading) + { + var axles = new List<Axle> { + new Axle { + AxleWeightShare = 0.2, + Inertia = 14.9.SI<KilogramSquareMeter>(), + RollResistanceCoefficient = 0.0055, + TwinTyres = false, + TyreTestLoad = 31300.SI<Newton>() + }, + new Axle { + AxleWeightShare = 0.25, + Inertia = 14.9.SI<KilogramSquareMeter>(), + RollResistanceCoefficient = 0.0065, + TwinTyres = true, + TyreTestLoad = 31300.SI<Newton>() + }, + + // trailer - declaration wheel data + new Axle { + AxleWeightShare = 0.55 / 3, + TwinTyres = DeclarationData.Trailer.TwinTyres, + RollResistanceCoefficient = DeclarationData.Trailer.RollResistanceCoefficient, + TyreTestLoad = DeclarationData.Trailer.TyreTestLoad.SI<Newton>(), + Inertia = DeclarationData.Wheels.Lookup(DeclarationData.Trailer.WheelsType).Inertia + }, + new Axle { + AxleWeightShare = 0.55 / 3, + TwinTyres = DeclarationData.Trailer.TwinTyres, + RollResistanceCoefficient = DeclarationData.Trailer.RollResistanceCoefficient, + TyreTestLoad = DeclarationData.Trailer.TyreTestLoad.SI<Newton>(), + Inertia = DeclarationData.Wheels.Lookup(DeclarationData.Trailer.WheelsType).Inertia + }, + new Axle { + AxleWeightShare = 0.55 / 3, + TwinTyres = DeclarationData.Trailer.TwinTyres, + RollResistanceCoefficient = DeclarationData.Trailer.RollResistanceCoefficient, + TyreTestLoad = DeclarationData.Trailer.TyreTestLoad.SI<Newton>(), + Inertia = DeclarationData.Wheels.Lookup(DeclarationData.Trailer.WheelsType).Inertia + } + }; + return new VehicleData { + AxleConfiguration = AxleConfiguration.AxleConfig_4x2, + AerodynamicDragAera = 6.2985.SI<SquareMeter>(), + //CrossWindCorrectionMode = CrossWindCorrectionMode.NoCorrection, + CrossWindCorrectionCurve = CrossWindCorrectionCurve.GetNoCorrectionCurve(6.2985.SI<SquareMeter>()), + CurbWeight = 7100.SI<Kilogram>(), + CurbWeigthExtra = massExtra, + Loading = loading, + DynamicTyreRadius = 0.4882675.SI<Meter>(), + Retarder = new RetarderData { Type = RetarderData.RetarderType.None }, + AxleData = axles, + SavedInDeclarationMode = false, + }; + } + + private static DriverData CreateDriverData(string accelerationFile, bool overspeed = false) + { + return new DriverData { + AccelerationCurve = AccelerationCurveData.ReadFromFile(accelerationFile), + LookAheadCoasting = new DriverData.LACData { + Enabled = true, + MinSpeed = 50.KMPHtoMeterPerSecond(), + Deceleration = -0.5.SI<MeterPerSquareSecond>(), + }, + OverSpeedEcoRoll = overspeed + ? new DriverData.OverSpeedEcoRollData() { + Mode = DriverData.DriverMode.Overspeed, + MinSpeed = 50.KMPHtoMeterPerSecond(), + OverSpeed = 5.KMPHtoMeterPerSecond(), + } + : new DriverData.OverSpeedEcoRollData { + Mode = DriverData.DriverMode.Off + }, + StartStop = new VectoRunData.StartStopData { + Enabled = false, + } + }; + } + } } \ No newline at end of file diff --git a/VectoCoreTest/Models/Declaration/DeclarationDataTest.cs b/VectoCoreTest/Models/Declaration/DeclarationDataTest.cs index 87ebc5eed8d5a4318c0437f670f1b9352fc928c2..76252cfe08c4fcc0c1e50ced60697f38f938003d 100644 --- a/VectoCoreTest/Models/Declaration/DeclarationDataTest.cs +++ b/VectoCoreTest/Models/Declaration/DeclarationDataTest.cs @@ -4,6 +4,7 @@ using System.IO; using System.Linq; using Microsoft.VisualStudio.TestTools.UnitTesting; using TUGraz.VectoCore.Exceptions; +using TUGraz.VectoCore.FileIO.Reader.DataObjectAdaper; using TUGraz.VectoCore.Models.Declaration; using TUGraz.VectoCore.Models.SimulationComponent.Data; using TUGraz.VectoCore.Tests.Utils; @@ -92,7 +93,8 @@ namespace TUGraz.VectoCore.Tests.Models.Declaration var rural = r.NextDouble() * 2; var motorway = r.NextDouble() * 2; var whtcValue = whtc.Lookup(Missions[i], urban, rural, motorway); - Assert.AreEqual(urban * factors.urban[i] + rural * factors.rural[i] + motorway * factors.motorway[i], whtcValue); + Assert.AreEqual(urban * factors.urban[i] + rural * factors.rural[i] + motorway * factors.motorway[i], + whtcValue); } } @@ -113,11 +115,15 @@ namespace TUGraz.VectoCore.Tests.Models.Declaration } var expectedCat = new Dictionary<VehicleCategory, AirDrag.AirDragEntry> { - { VehicleCategory.RigidTruck, new AirDrag.AirDragEntry { A1 = 0.013526, A2 = 0.017746, A3 = -0.000666 } }, + { + VehicleCategory.RigidTruck, new AirDrag.AirDragEntry { A1 = 0.013526, A2 = 0.017746, A3 = -0.000666 } + }, { VehicleCategory.Tractor, new AirDrag.AirDragEntry { A1 = 0.034767, A2 = 0.039367, A3 = -0.001897 } }, { VehicleCategory.CityBus, new AirDrag.AirDragEntry { A1 = -0.000794, A2 = 0.02109, A3 = -0.00109 } }, - { VehicleCategory.Coach, new AirDrag.AirDragEntry { A1 = -0.000794, A2 = 0.02109, A3 = -0.00109 } }, - { VehicleCategory.InterurbanBus, new AirDrag.AirDragEntry { A1 = -0.000794, A2 = 0.02109, A3 = -0.00109 } } + { VehicleCategory.Coach, new AirDrag.AirDragEntry { A1 = -0.000794, A2 = 0.02109, A3 = -0.00109 } }, { + VehicleCategory.InterurbanBus, + new AirDrag.AirDragEntry { A1 = -0.000794, A2 = 0.02109, A3 = -0.00109 } + } }; foreach (var kv in expectedCat) { @@ -125,6 +131,35 @@ namespace TUGraz.VectoCore.Tests.Models.Declaration } } + [TestMethod] + public void CrossWindCorrectionTest() + { + var crossWindCorrectionCurve = + DeclarationDataAdapter.GetDeclarationAirResistanceCurve(VehicleCategory.Tractor, + 6.46.SI<SquareMeter>()); + + var tmp = crossWindCorrectionCurve.EffectiveAirDragArea(0.KMPHtoMeterPerSecond()); + Assert.AreEqual(8.12204, tmp.Value(), Tolerance); + + tmp = crossWindCorrectionCurve.EffectiveAirDragArea(60.KMPHtoMeterPerSecond()); + Assert.AreEqual(8.12204, tmp.Value(), Tolerance); + + tmp = crossWindCorrectionCurve.EffectiveAirDragArea(75.KMPHtoMeterPerSecond()); + Assert.AreEqual(7.67058, tmp.Value(), Tolerance); + + tmp = crossWindCorrectionCurve.EffectiveAirDragArea(100.KMPHtoMeterPerSecond()); + Assert.AreEqual(7.23735, tmp.Value(), Tolerance); + + tmp = crossWindCorrectionCurve.EffectiveAirDragArea(52.1234.KMPHtoMeterPerSecond()); + Assert.AreEqual(8.12196, tmp.Value(), Tolerance); + + tmp = crossWindCorrectionCurve.EffectiveAirDragArea(73.5432.KMPHtoMeterPerSecond()); + Assert.AreEqual(7.70815, tmp.Value(), Tolerance); + + tmp = crossWindCorrectionCurve.EffectiveAirDragArea(92.8765.KMPHtoMeterPerSecond()); + Assert.AreEqual(7.33443, tmp.Value(), Tolerance); + } + [TestMethod] public void DefaultTCTest() { @@ -159,7 +194,7 @@ namespace TUGraz.VectoCore.Tests.Models.Declaration // extrapolated points new { nu = 0.5, mu = 1.0, torque = 0.0 }, - new { nu = 12.0, mu = 1.0, torque = -18674.133 }, // = (12-4.4)*(-16540.98- -2462.17)/(11-4.4)+ -2462.17 + new { nu = 12.0, mu = 1.0, torque = -18674.133 } // = (12-4.4)*(-16540.98- -2462.17)/(11-4.4)+ -2462.17 }; var referenceSpeed = 150.SI<PerSecond>(); @@ -184,10 +219,30 @@ namespace TUGraz.VectoCore.Tests.Models.Declaration var expected = new[] { new { Mission = MissionType.LongHaul, Base = 1240.SI<Watt>(), LED = 1190.SI<Watt>(), Efficiency = 0.7 }, - new { Mission = MissionType.RegionalDelivery, Base = 1055.SI<Watt>(), LED = 1005.SI<Watt>(), Efficiency = 0.7 }, - new { Mission = MissionType.UrbanDelivery, Base = 974.SI<Watt>(), LED = 924.SI<Watt>(), Efficiency = 0.7 }, - new { Mission = MissionType.MunicipalUtility, Base = 974.SI<Watt>(), LED = 924.SI<Watt>(), Efficiency = 0.7 }, - new { Mission = MissionType.Construction, Base = 975.SI<Watt>(), LED = 925.SI<Watt>(), Efficiency = 0.7 }, + new { + Mission = MissionType.RegionalDelivery, + Base = 1055.SI<Watt>(), + LED = 1005.SI<Watt>(), + Efficiency = 0.7 + }, + new { + Mission = MissionType.UrbanDelivery, + Base = 974.SI<Watt>(), + LED = 924.SI<Watt>(), + Efficiency = 0.7 + }, + new { + Mission = MissionType.MunicipalUtility, + Base = 974.SI<Watt>(), + LED = 924.SI<Watt>(), + Efficiency = 0.7 + }, + new { + Mission = MissionType.Construction, + Base = 975.SI<Watt>(), + LED = 925.SI<Watt>(), + Efficiency = 0.7 + }, new { Mission = MissionType.HeavyUrban, Base = 0.SI<Watt>(), LED = 0.SI<Watt>(), Efficiency = 1.0 }, new { Mission = MissionType.Urban, Base = 0.SI<Watt>(), LED = 0.SI<Watt>(), Efficiency = 1.0 }, new { Mission = MissionType.Suburban, Base = 0.SI<Watt>(), LED = 0.SI<Watt>(), Efficiency = 1.0 }, @@ -197,8 +252,8 @@ namespace TUGraz.VectoCore.Tests.Models.Declaration Assert.AreEqual(expected.Length, Enum.GetValues(typeof(MissionType)).Length); foreach (var expectation in expected) { - var baseConsumption = es.Lookup(expectation.Mission, technologies: null); - var leds = es.Lookup(expectation.Mission, technologies: new[] { "LED lights" }); + var baseConsumption = es.Lookup(expectation.Mission, null); + var leds = es.Lookup(expectation.Mission, new[] { "LED lights" }); AssertHelper.AreRelativeEqual(expectation.Base / expectation.Efficiency, baseConsumption); AssertHelper.AreRelativeEqual(expectation.LED / expectation.Efficiency, leds); @@ -250,12 +305,12 @@ namespace TUGraz.VectoCore.Tests.Models.Declaration for (var i = 0; i < Missions.Length; i++) { // default tech - Watt defaultValue = fan.Lookup(Missions[i], ""); + var defaultValue = fan.Lookup(Missions[i], ""); Assert.AreEqual(expected[defaultFan][i], defaultValue.Value(), Tolerance); // all fan techs foreach (var expect in expected) { - Watt value = fan.Lookup(Missions[i], expect.Key); + var value = fan.Lookup(Missions[i], expect.Key); Assert.AreEqual(expect.Value[i], value.Value(), Tolerance); } } @@ -283,7 +338,7 @@ namespace TUGraz.VectoCore.Tests.Models.Declaration for (var i = 0; i < Missions.Length; i++) { foreach (var expect in expected) { - Watt value = hvac.Lookup(Missions[i], expect.Key); + var value = hvac.Lookup(Missions[i], expect.Key); Assert.AreEqual(expect.Value[i], value.Value(), Tolerance); } } @@ -311,7 +366,7 @@ namespace TUGraz.VectoCore.Tests.Models.Declaration for (var i = 0; i < Missions.Length; i++) { foreach (var expect in expected) { - Watt value = ps.Lookup(Missions[i], expect.Key); + var value = ps.Lookup(Missions[i], expect.Key); Assert.AreEqual(expect.Value[i], value.Value(), Tolerance); } } @@ -370,7 +425,7 @@ namespace TUGraz.VectoCore.Tests.Models.Declaration foreach (var hdvClasses in expect.Value) { var hdvClass = hdvClasses.Key; for (var i = 0; i < Missions.Length; i++) { - Watt value = sp.Lookup(Missions[i], hdvClass, technology); + var value = sp.Lookup(Missions[i], hdvClass, technology); Assert.AreEqual(hdvClasses.Value[i], value.Value(), Tolerance); } } @@ -429,8 +484,10 @@ namespace TUGraz.VectoCore.Tests.Models.Declaration Assert.IsTrue(!string.IsNullOrEmpty(new StreamReader(regionalDeliveryMission.CycleFile).ReadLine())); Assert.AreEqual(0.SI<Kilogram>(), regionalDeliveryMission.MinLoad); - Assert.AreEqual(0.3941 * vehicleData.GrossVehicleMassRating - 1705.9.SI<Kilogram>(), regionalDeliveryMission.RefLoad); - Assert.AreEqual(vehicleData.GrossVehicleMassRating - regionalDeliveryMission.MassExtra - vehicleData.CurbWeight, + Assert.AreEqual(0.3941 * vehicleData.GrossVehicleMassRating - 1705.9.SI<Kilogram>(), + regionalDeliveryMission.RefLoad); + Assert.AreEqual( + vehicleData.GrossVehicleMassRating - regionalDeliveryMission.MassExtra - vehicleData.CurbWeight, regionalDeliveryMission.MaxLoad); var urbanDeliveryMission = segment.Missions[2]; @@ -446,12 +503,15 @@ namespace TUGraz.VectoCore.Tests.Models.Declaration Assert.IsTrue(!string.IsNullOrEmpty(new StreamReader(urbanDeliveryMission.CycleFile).ReadLine())); Assert.AreEqual(0.SI<Kilogram>(), urbanDeliveryMission.MinLoad); - Assert.AreEqual(0.3941 * vehicleData.GrossVehicleMassRating - 1705.9.SI<Kilogram>(), urbanDeliveryMission.RefLoad); - Assert.AreEqual(vehicleData.GrossVehicleMassRating - urbanDeliveryMission.MassExtra - vehicleData.CurbWeight, + Assert.AreEqual(0.3941 * vehicleData.GrossVehicleMassRating - 1705.9.SI<Kilogram>(), + urbanDeliveryMission.RefLoad); + Assert.AreEqual( + vehicleData.GrossVehicleMassRating - urbanDeliveryMission.MassExtra - vehicleData.CurbWeight, urbanDeliveryMission.MaxLoad); } - public void EqualAcceleration(AccelerationCurveData data, double velocity, double acceleration, double deceleration) + public void EqualAcceleration(AccelerationCurveData data, double velocity, double acceleration, + double deceleration) { var entry = data.Lookup(velocity.KMPHtoMeterPerSecond()); Assert.AreEqual(entry.Acceleration.Value(), acceleration, Tolerance); diff --git a/VectoCoreTest/Models/SimulationComponent/DriverTest.cs b/VectoCoreTest/Models/SimulationComponent/DriverTest.cs index df4a0d5b45ea0b7b399d8e8e517c485d87b1d2b0..1c2d869fccccc71ee156a30851c4a82bcd0dc19f 100644 --- a/VectoCoreTest/Models/SimulationComponent/DriverTest.cs +++ b/VectoCoreTest/Models/SimulationComponent/DriverTest.cs @@ -2,7 +2,6 @@ using System.Linq; using Microsoft.VisualStudio.TestTools.UnitTesting; using TUGraz.VectoCore.Configuration; -using TUGraz.VectoCore.Exceptions; using TUGraz.VectoCore.FileIO.Reader.Impl; using TUGraz.VectoCore.Models.Connector.Ports; using TUGraz.VectoCore.Models.Connector.Ports.Impl; @@ -22,15 +21,10 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponent public class DriverTest { public const string JobFile = @"TestData\Jobs\24t Coach EngineOnly.vecto"; - public const string EngineFile = @"TestData\Components\24t Coach.veng"; - public const string AccelerationFile = @"TestData\Components\Coach.vacc"; - - public const double Tolerance = 0.001; - [TestMethod] public void DriverCoastingTest() { @@ -143,7 +137,6 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponent modalWriter.Finish(VectoRun.Status.Success); } - [TestMethod] public void DriverOverloadTest() { @@ -153,7 +146,8 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponent var driverData = CreateDriverData(); - var modalWriter = new ModalDataWriter("Coach_MinimalPowertrain.vmod", SimulatorFactory.FactoryMode.EngineeringMode); + var modalWriter = new ModalDataWriter("Coach_MinimalPowertrain.vmod", + SimulatorFactory.FactoryMode.EngineeringMode); var vehicleContainer = new VehicleContainer(modalWriter); var cycle = new MockDrivingCycle(vehicleContainer, null); @@ -222,8 +216,10 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponent 1.01570922, 1.384540943, 1.364944972, 1.350793466, 1.331848649, 1.314995215, 1.2999934, 1.281996392, 1.255462262 }; - var simulationIntervals = new[] - { 1.403234648, 0.553054094, 0.405255346, 0.33653593, 0.294559444, 0.26555781, 0.243971311, 0.22711761, 0.213554656 }; + var simulationIntervals = new[] { + 1.403234648, 0.553054094, 0.405255346, 0.33653593, 0.294559444, 0.26555781, 0.243971311, 0.22711761, + 0.213554656 + }; // accelerate from 0 to just below the target velocity and test derived simulation intervals & accelerations @@ -236,7 +232,8 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponent vehicleContainer.CommitSimulationStep(absTime, tmpResponse.SimulationInterval); absTime += tmpResponse.SimulationInterval; - vehicle.MyVehicleSpeed += (tmpResponse.SimulationInterval * vehicle.LastRequest.acceleration).Cast<MeterPerSecond>(); + vehicle.MyVehicleSpeed += + (tmpResponse.SimulationInterval * vehicle.LastRequest.acceleration).Cast<MeterPerSecond>(); } // full acceleration would exceed target velocity, driver should limit acceleration such that target velocity is reached... @@ -263,7 +260,6 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponent Assert.AreEqual(0.2, response.SimulationInterval.Value(), Tolerance); } - [TestMethod] public void DriverDecelerationTest() { @@ -288,13 +284,17 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponent // var response = driver.OutPort().Request(absTime, ds, targetVelocity, gradient); var accelerations = new[] { - -0.68799597, -0.690581291, -0.693253225, -0.696020324, -0.698892653, -0.701882183, -0.695020765, -0.677731071, - -0.660095846, -0.642072941, -0.623611107, -0.604646998, -0.58510078, -0.56497051, -0.547893288, -0.529859078, + -0.68799597, -0.690581291, -0.693253225, -0.696020324, -0.698892653, -0.701882183, -0.695020765, + -0.677731071, + -0.660095846, -0.642072941, -0.623611107, -0.604646998, -0.58510078, -0.56497051, -0.547893288, + -0.529859078, -0.510598641, -0.489688151, -0.466386685, -0.425121905 }; var simulationIntervals = new[] { - 0.202830428, 0.20884052, 0.215445127, 0.222749141, 0.230885341, 0.240024719, 0.250311822, 0.26182762, 0.274732249, - 0.289322578, 0.305992262, 0.325276486, 0.34792491, 0.37502941, 0.408389927, 0.451003215, 0.5081108, 0.590388012, + 0.202830428, 0.20884052, 0.215445127, 0.222749141, 0.230885341, 0.240024719, 0.250311822, 0.26182762, + 0.274732249, + 0.289322578, 0.305992262, 0.325276486, 0.34792491, 0.37502941, 0.408389927, 0.451003215, 0.5081108, + 0.590388012, 0.724477573, 1.00152602 }; @@ -309,7 +309,8 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponent vehicleContainer.CommitSimulationStep(absTime, tmpResponse.SimulationInterval); absTime += tmpResponse.SimulationInterval; - vehicle.MyVehicleSpeed += (tmpResponse.SimulationInterval * vehicle.LastRequest.acceleration).Cast<MeterPerSecond>(); + vehicle.MyVehicleSpeed += + (tmpResponse.SimulationInterval * vehicle.LastRequest.acceleration).Cast<MeterPerSecond>(); } var response = driver.OutPort().Request(absTime, ds, targetVelocity, gradient); @@ -326,7 +327,6 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponent Assert.AreEqual(targetVelocity.Value(), vehicle.MyVehicleSpeed.Value(), Tolerance); } - //================== private static VehicleData CreateVehicleData(Kilogram loading) @@ -357,14 +357,15 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponent return new VehicleData { AxleConfiguration = AxleConfiguration.AxleConfig_4x2, AerodynamicDragAera = 3.2634.SI<SquareMeter>(), - CrossWindCorrectionMode = CrossWindCorrectionMode.NoCorrection, + //CrossWindCorrectionMode = CrossWindCorrectionMode.NoCorrection, + CrossWindCorrectionCurve = CrossWindCorrectionCurve.GetNoCorrectionCurve(3.2634.SI<SquareMeter>()), CurbWeight = 15700.SI<Kilogram>(), CurbWeigthExtra = 0.SI<Kilogram>(), Loading = loading, DynamicTyreRadius = 0.52.SI<Meter>(), Retarder = new RetarderData { Type = RetarderData.RetarderType.None }, AxleData = axles, - SavedInDeclarationMode = false, + SavedInDeclarationMode = false }; } @@ -380,12 +381,11 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponent Mode = DriverData.DriverMode.Off }, StartStop = new VectoRunData.StartStopData { - Enabled = false, + Enabled = false } }; } - // ======================== protected virtual IDriver AddComponent(IDrivingCycle prev, IDriver next) @@ -406,7 +406,6 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponent return next; } - protected virtual ITnOutProvider AddComponent(IWheels prev, ITnOutProvider next) { prev.InPort().Connect(next.OutPort()); diff --git a/VectoCoreTest/Models/SimulationComponent/VehicleTest.cs b/VectoCoreTest/Models/SimulationComponent/VehicleTest.cs index 9a3ccb6191fd73810e22ff7ab118b95ea8b27007..2e9585604ecbb1a01080806c529703a8114b1ef1 100644 --- a/VectoCoreTest/Models/SimulationComponent/VehicleTest.cs +++ b/VectoCoreTest/Models/SimulationComponent/VehicleTest.cs @@ -1,6 +1,9 @@ using System; +using System.IO; using Microsoft.VisualStudio.TestTools.UnitTesting; +using TUGraz.VectoCore.FileIO.Reader.DataObjectAdaper; using TUGraz.VectoCore.FileIO.Reader.Impl; +using TUGraz.VectoCore.Models.Declaration; using TUGraz.VectoCore.Models.Simulation.Data; using TUGraz.VectoCore.Models.Simulation.Impl; using TUGraz.VectoCore.Models.SimulationComponent.Data; @@ -13,11 +16,9 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponent [TestClass] public class VehicleTest { - public static readonly double Tolerance = 0.001; - private const string VehicleDataFileCoach = @"TestData\Components\24t Coach.vveh"; - private const string VehicleDataFileTruck = @"TestData\Components\40t_Long_Haul_Truck.vveh"; + public static readonly double Tolerance = 0.001; [TestMethod] public void VehiclePortTest() @@ -62,28 +63,6 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponent var mockPort = new MockFvOutPort(); vehicle.InPort().Connect(mockPort); - - var tmp = vehicle.ComputeEffectiveAirDragArea(0.KMPHtoMeterPerSecond()); - Assert.AreEqual(8.12204, tmp.Value(), Tolerance); - - tmp = vehicle.ComputeEffectiveAirDragArea(60.KMPHtoMeterPerSecond()); - Assert.AreEqual(8.12204, tmp.Value(), Tolerance); - - tmp = vehicle.ComputeEffectiveAirDragArea(75.KMPHtoMeterPerSecond()); - Assert.AreEqual(7.67058, tmp.Value(), Tolerance); - - tmp = vehicle.ComputeEffectiveAirDragArea(100.KMPHtoMeterPerSecond()); - Assert.AreEqual(7.23735, tmp.Value(), Tolerance); - - tmp = vehicle.ComputeEffectiveAirDragArea(52.1234.KMPHtoMeterPerSecond()); - Assert.AreEqual(8.12196, tmp.Value(), Tolerance); - - tmp = vehicle.ComputeEffectiveAirDragArea(73.5432.KMPHtoMeterPerSecond()); - Assert.AreEqual(7.70815, tmp.Value(), Tolerance); - - tmp = vehicle.ComputeEffectiveAirDragArea(92.8765.KMPHtoMeterPerSecond()); - Assert.AreEqual(7.33443, tmp.Value(), Tolerance); - // ==================== var dt = 0.5.SI<Second>(); @@ -117,13 +96,18 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponent var vehicleData = EngineeringModeSimulationDataReader.CreateVehicleDataFromFile(VehicleDataFileTruck); vehicleData.AerodynamicDragAera = 6.2985.SI<SquareMeter>(); - vehicleData.CrossWindCorrectionMode = CrossWindCorrectionMode.DeclarationModeCorrection; + vehicleData.CrossWindCorrectionCurve = + DeclarationDataAdapter.GetDeclarationAirResistanceCurve(VehicleCategory.Tractor, + vehicleData.AerodynamicDragAera); + //vehicleData.CrossWindCorrectionMode = CrossWindCorrectionMode.DeclarationModeCorrection; var vehicle = new Vehicle(container, vehicleData); var mockPort = new MockFvOutPort(); vehicle.InPort().Connect(mockPort); + // ---- + var writer = new MockModalDataWriter(); vehicle.Initialize(80.KMPHtoMeterPerSecond(), 0.SI<Radian>()); @@ -139,5 +123,58 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponent vehicle.CommitSimulationStep(writer); Assert.AreEqual(49735.26379, ((SI)writer[ModalResultField.Pair]).Value(), 0.1); } + + [TestMethod] + public void VehicleAirDragSpeedDependentTest() + { + var data = new[] { + "v_veh in km/h,Cd factor in -", + "0,1.173 ", + "5,1.173 ", + "10,1.173", + "15,1.173", + "20,1.173", + "25,1.173", + "30,1.173", + "35,1.173", + "40,1.173", + "45,1.173", + "50,1.173", + "55,1.173", + "60,1.173", + "65,1.153", + "70,1.136", + "75,1.121", + "80,1.109", + "85,1.099", + "90,1.090", + "95,1.082", + "100,1.075" + }; + var correctionData = new MemoryStream(); + var writer = new StreamWriter(correctionData); + foreach (var entry in data) { + writer.WriteLine(entry); + } + writer.Flush(); + correctionData.Seek(0, SeekOrigin.Begin); + + var crossSectionArea = 5.19.SI<SquareMeter>(); + var cwcc = CrossWindCorrectionCurve.ReadSpeedDependentCorrectionCurveFromStream(correctionData, crossSectionArea); + + Assert.AreEqual(crossSectionArea.Value() * 1.173, cwcc.EffectiveAirDragArea(0.KMPHtoMeterPerSecond()).Value(), + Tolerance); + Assert.AreEqual(crossSectionArea.Value() * 1.173, cwcc.EffectiveAirDragArea(40.KMPHtoMeterPerSecond()).Value(), + Tolerance); + Assert.AreEqual(crossSectionArea.Value() * 1.173, cwcc.EffectiveAirDragArea(60.KMPHtoMeterPerSecond()).Value(), + Tolerance); + Assert.AreEqual(crossSectionArea.Value() * 1.109, cwcc.EffectiveAirDragArea(80.KMPHtoMeterPerSecond()).Value(), + Tolerance); + Assert.AreEqual(crossSectionArea.Value() * 1.075, cwcc.EffectiveAirDragArea(100.KMPHtoMeterPerSecond()).Value(), + Tolerance); + + Assert.AreEqual(crossSectionArea.Value() * 1.163, cwcc.EffectiveAirDragArea(62.5.KMPHtoMeterPerSecond()).Value(), + Tolerance); + } } } \ No newline at end of file